Skip to content

About

Self hosted media tracker for movies, tv shows, video games, books and audiobooks

Resources

Stars

1 star

Watchers

1 watching

Forks

 
 

Latest commit

 

History

1,180 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MediaTracker-Plus · GitHub license Docker Image Size Docker Pulls CodeFactor codecov

Self hosted platform for tracking movies, tv shows, video games, books and audiobooks, highly inspired by flox.

This repository is maintained at Guisardo/MediaTrackerPlus.

Fork lineage:

This fork intentionally drifts from both upstream repositories to ship Guisardo-specific features, fixes, Docker images, and release cadence. Runtime and database compatibility with either upstream should be treated as best-effort.

Fork-Specific Enhancements

Area What this fork adds
upnext recommendations Rating an item can asynchronously fetch similar content, add matches to the watchlist, store estimatedRating, and power the Recommended sort.
Related content Details pages resolve provider-similar items against the local library, dedupe them, and age-filter them before rendering.
Age gates and parental metadata Content ratings, descriptors, parental guidance, dateOfBirth-based eligibility, and stable AGE_RESTRICTED responses are applied across browse, details, calendar, statistics, lists, notifications, and related content.
Localized metadata and trailers The client sends Accept-Language; the API resolves configured metadata languages, overlays translated metadata from translation tables, backfills missing translations, and requests localized trailers.
Facets and deeplinks URL-owned filters support genres, years, ratings, languages, creators, publishers, media type, and status; detail metadata pills deep-link back to filtered list views.
Group recommendations Groups and memberships can scope Platform Recommended sorting through cached groupPlatformRating values and group-aware watched exclusions.
Full metadata sync npm run metadata:sync:full runs a one-off forced refresh for every provider-backed item using the server metadata update pipeline.
UI and frontend stack The frontend moved to Vite, React 19, Tailwind CSS 4, Lingui 5, and shadcn/ui patterns with dark-mode and responsive layout improvements.
Deployment and CI hardening Guisardo-owned Docker images, runtime hardening, container security checks, updated GitHub Actions, stricter typing, and broader tests support this fork's release path.

Architecture and Flow Changes

Rating to Recommendations and Rating Cache Fan-out

sequenceDiagram
  actor User
  participant Client
  participant Rating as RatingController
  participant Repos as Rating/Seen/List repositories
  participant Jobs as setImmediate jobs
  participant Service as RecommendationService
  participant Providers as Metadata providers
  participant Writer as WatchlistWriter
  participant GroupCache as Group rating cache

  User->>Client: Rate item
  Client->>Rating: PUT /api/rating
  Rating->>Repos: Upsert rating
  Rating->>Repos: Auto-mark as seen when rating exists
  Rating-->>Client: 200 OK
  Rating->>Jobs: Queue post-response work
  Jobs->>Repos: Recalculate mediaItem.platformRating
  Jobs->>GroupCache: Recalculate groupPlatformRating
  Jobs->>Service: processRating when enabled
  Service->>Providers: similar(mediaItem)
  Providers-->>Service: Similar items
  Service->>Writer: Write watchlist items with estimatedRating
  Writer->>Repos: Insert or update listItem
  Writer->>Repos: Recalculate mediaItem.platformRating
  Writer->>GroupCache: Recalculate groupPlatformRating
Loading

Localized, Age-Gated Details Response

flowchart TD
  A["GET /api/details/:id + Accept-Language"] --> B["MediaItemController"]
  B --> C{"needsDetails?"}
  C -- "yes" --> D["updateMetadata refreshes base metadata"]
  C -- "no" --> E["continue"]
  D --> E
  E --> F["Load user dateOfBirth and compute viewer age"]
  F --> G{"Age eligible?"}
  G -- "no" --> H["403 AGE_RESTRICTED"]
  G -- "yes" --> I["Resolve metadata language candidates"]
  I --> J["Details query"]
  K[("mediaItem / season / episode tables")] --> J
  L[("translation tables")] --> J
  J --> M["Overlay first available translation and metadataLanguage"]
  M --> N["Fetch trailers with primary language"]
  M --> O["Resolve related content"]
  O --> P["Dedupe and age-filter related items"]
  N --> Q["Details payload"]
  P --> Q
  Q --> R["Details page, locale badge, trailers, related content"]
Loading

Faceted Discovery and Group Recommendations

flowchart LR
  A["URL params: facets + orderBy + groupId"] --> B["useFacets + GroupSelector"]
  B --> C["GET /api/items/paginated"]
  B --> D["GET /api/items/facets"]
  C --> E["Validate group, viewer age, and locale preferences"]
  D --> F["Validate group and viewer age"]
  E --> G["getItemsKnex"]
  F --> H["getFacetsKnex"]
  G --> I{"platformRecommended + groupId?"}
  I -- "yes" --> J["groupPlatformRating join + group watched exclusion"]
  I -- "no" --> K["global platformRating or normal library scope"]
  J --> L["shared filters + age gating + translation overlay"]
  K --> L
  H --> M["shared filters + age gating + facet counts"]
  L --> N["items + total + ageGatingActive"]
  M --> O["facet data"]
  N --> P["PaginatedGridItems"]
  O --> P
  P --> Q["group selector, active chips, age-aware empty state"]
Loading

API Documentation

https://guisardo.github.io/MediaTrackerPlus/

Installation

Building from source

git clone https://github.com/Guisardo/MediaTrackerPlus.git
cd MediaTrackerPlus
npm install
npm run build
npm run start

To run a one-off full metadata refresh for every provider-backed item in your configured database:

npm run metadata:sync:full

This root command loads the repo root .env, aborts if .env is missing, and requires installed server dependencies. For lower-level usage where you manage the environment yourself, run npm run metadata:sync:full --prefix server.

Local development

npm install
npm run dev

This starts the Vite client on http://localhost:7000 with a 0.0.0.0 bind address, and the API server on port 7481 bound to 0.0.0.0. Changes under client/ refresh in the browser automatically, and changes under server/ rebuild and restart the local API without manually stopping the process.

With docker

Version Tags

Tag Description
latest stable releases
docker volume create assets
docker run \
    -d \
    --name mediatracker-plus \
    -p 7481:7481 \
    -v /home/YOUR_HOME_DIRECTORY/.config/mediatracker/data:/storage \
    -v assets:/assets \
    -e TMDB_LANG=en \
    -e AUDIBLE_LANG=us \
    -e TZ=Europe/London \
    guisardo/mediatracker-plus:latest

With docker-compose

version: "3"
services:
  mediatracker:
    container_name: mediatracker-plus
    ports:
      - 7481:7481
    volumes:
      - /home/YOUR_HOME_DIRECTORY/.config/mediatracker/data:/storage
      - assetsVolume:/assets
    environment:
      SERVER_LANG: en
      TMDB_LANG: en
      AUDIBLE_LANG: us
      TZ: Europe/London
    image: guisardo/mediatracker-plus:latest

volumes:
  assetsVolume: null

Parameters

Parameter Function
-p 7481 Port web API
-v /storage Directory with database
-v /assets Posters directory
-v /logs Logs directory

Environment variables

Name Description
TMDB_LANG ISO 639-1 country code, one of: om, ab, aa, af, sq, am, ar, hy, as, ay, az, ba, eu, bn, dz, bh, bi, br, bg, my, be, km, ca, zh, co, hr, cs, da, nl, en, eo, et, fo, fj, fi, fr, fy, gl, ka, de, el, kl, gn, gu, ha, he, hi, hu, is, id, ia, ie, ik, iu, ga, it, ja, jw, kn, ks, kk, rw, ky, rn, ko, ku, lo, la, lv, ln, lt, mk, mg, ms, ml, mt, mi, mr, mo, mn, na, ne, no, oc, or, ps, fa, pl, pt, pa, qu, rm, ro, ru, sm, sg, sa, gd, sr, sh, st, tn, sn, sd, si, ss, sk, sl, so, es, su, sw, sv, tl, tg, ta, tt, te, th, bo, ti, to, ts, tr, tk, tw, ug, uk, ur, uz, vi, vo, cy, wo, xh, yi, yo, za, zu
AUDIBLE_LANG ISO 639-1 country code, one of: au, ca, de, es, fr, in, it, jp, gb, us
SERVER_LANG ISO 639-1 country code, one of: da, de, en, es, fr, ko, pt
DATABASE_CLIENT Database client: better-sqlite3 or pg
DATABASE_PATH Only for sqlite, path to database
DATABASE_URL Connection string
DATABASE_HOST Database host
DATABASE_PORT Database port
DATABASE_USER Database user
DATABASE_PASSWORD Database password
DATABASE_DATABASE Database name
IGDB_CLIENT_ID IGDB API key, needed for game lookup
IGDB_CLIENT_SECRET IGDB secret
PUID UserID
PGID GroupID
TZ Timezone, for example Europe/London, see full list
ASSETS_PATH Directory for posters and backdrops, defaults to '$HOME/.mediatracker/img'
LOGS_PATH Directory for logs, defaults to '$HOME/.mediatracker/logs'
HOSTNAME IP address that the server will listen on
PORT Port that the server will listen on

upnext Recommendation Engine

Every time a user submits a rating, MediaTrackerPlus automatically fetches similar content and adds it to the user's watchlist. The process runs asynchronously after the HTTP response is sent, so rating saves are never delayed.

How it works

  • Movies and TV shows — similar items are fetched from the TMDB /similar endpoint. No additional credentials are required beyond the embedded TMDB API key.
  • Games — similar games are fetched from IGDB using the two-step similar_games query. The IGDB_CLIENT_ID and IGDB_CLIENT_SECRET credentials (configured in Settings → Configuration in the UI) must be set for game recommendations to work.
  • Books — related books are retrieved from the OpenLibrary subjects API. No credentials are required; OpenLibrary is a public API.
  • Audiobooks — not supported by the recommendation engine in the current version.

Watchlist sort order

A new Recommended sort option is available in the watchlist view. Items are scored using the formula:

  • When both an estimatedRating (derived from the trigger rating) and a TMDB community rating are available: score = (estimatedRating × 0.6) + (tmdbRating × 0.4)
  • When only estimatedRating is available (games, books, or items without a TMDB rating): score = estimatedRating
  • Items with no estimatedRating sort to the bottom.

Database migration

This feature adds an estimatedRating column to the listItem table. The migration runs automatically on first startup and is idempotent — running it more than once is safe.

Migration file: server/src/migrations/20990101000000_listItemEstimatedRating.ts

Credential requirements

Feature Credential Where to configure
Movie and TV recommendations None (uses embedded TMDB key) —
Game recommendations IGDB_CLIENT_ID and IGDB_CLIENT_SECRET Settings → Configuration in the UI
Book recommendations None (OpenLibrary is public) —

Note: IGDB credentials are also required for game metadata search. If games already appear when you search, game recommendations will work automatically. Credentials can be obtained at https://api-docs.igdb.com/#account-creation.

Building docker image

docker build --tag mediatracker-plus:latest https://github.com/Guisardo/MediaTrackerPlus.git
docker run -p 7481:7481 mediatracker

Features

  • notifications
  • calendar
  • multiple users
  • REST API
  • watchlist
  • upnext recommendations (automatic watchlist population after every rating)
  • docker image
  • import from Trakt
  • import from goodreads

Import

Service Imported data
Trakt Watchlist, watched history, ratings
goodreads Read, Currently Reading, Want to Read, ratings

Metadata providers

Provider Media type Localization
TMDB movie, tv show ✓
IGDB* video game ✗
Audible API audiobooks ✓
Open Library books ✗

* IGDB has a limit of 4 requests per second. Because of that IGDB API key is not provided with MediaTracker, it can be acquired here and set in http://localhost:7481/#/settings/configuration

Notification platforms

Integrations

  • Jellyfin - Plugin, minimum MediaTracker version: 0.1.0
  • Plex - Generate Application token in your MediaTracker instance, and add a webhook in plex [your MediaTracker url]/api/plex?token=[MediaTracker Application Token]
  • Kodi - Plugin, minimum MediaTracker version: 0.1.0

Contributors

Similar projects

About

Self hosted media tracker for movies, tv shows, video games, books and audiobooks

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages