4.8 KiB
Jellystat in Magent Beta
Magent's My Stats page (/insights) reads personal viewing history from an existing Jellystat instance. Jellystat owns playback collection, history and retention. Magent does not install Jellystat, collect sessions or keep a second playback database.
Setup
- Run Jellystat and connect it to the same Jellyfin server Magent uses. Let its initial sync finish.
- Create an API key in Jellystat's settings.
- In Magent, open Configuration → Jellystat, enter its internal URL and API key, save, and test the connection. Include any reverse-proxy base path in the URL.
- Sign in using Jellyfin. Existing Jellyfin accounts can also be linked by Configuration → Jellyfin → Import Jellyfin users. First use of My Stats resolves an existing Jellyfin account against Jellyfin's user directory using its exact username.
Alternatively, set these backend environment variables:
JELLYSTAT_URL=http://jellystat:3000
JELLYSTAT_API_KEY=your-jellystat-api-key
JELLYSTAT_BASE_URL is also accepted. Docker deployments already load the backend environment through .env. These are server settings; no NEXT_PUBLIC_ variables or browser credentials are needed. Saved Configuration values override environment values.
What users see
- Past 7, 30, 90 or 365 days of watch time, distinct movies and episodes played, and total plays.
- Watch-time chart, current/longest streak within the chosen period, active days, favourite titles, players and streaming methods.
- Latest 20 plays in the chosen period and personal request totals from Magent's Seerr cache.
- Clear setup, account-link, no-history and temporary-unavailability states.
The page is personal for admins as well as ordinary users. There is no arbitrary user-ID parameter or server-wide history endpoint in this version. Reports and newsletters can build on this integration in a later beta increment; they are not included here.
Data semantics and boundaries
History comes from Jellystat's POST /api/getUserHistory, with the backend's linked Jellyfin ID in userid, and a fixed date filter. GET /api/getLibraries supplies movie-library classification and the connection test. Authentication uses the x-api-token header. The adapter follows the upstream API routes and playback model; the installed instance exposes its API at /swagger.
- Playback duration is in seconds and displayed as minutes. Positive-duration history entries count as plays, including unfinished watches. Repeat plays add time without inflating distinct movie/episode counts.
- Episodes are identified by
EpisodeId. Movies are identified by their movie library. Mixed libraries or deleted library metadata may leave an item classified as other media; that time still contributes to totals. - Ranges cover a rolling number of days. Charts and streaks use UTC and Jellystat's
ActivityDateInserted, so the first/last chart days can be partial. A streak day requires at least one minute. Streaks are bounded by the selected period. Long charts group days for readability. - Requests use their creation date and the authenticated account's canonical Seerr ID. Exact usernames are only used for legacy requests without an owner ID; conflicting IDs never fall back to a name.
- Pages are fetched at 200 rows per request, up to 50 pages, with a 30-second total timeout. Excess history asks the user to choose a shorter period; it is never presented as a complete partial total.
- A normalized, per-identity response is cached in memory for up to 60 seconds, with a 128-entry bound. The cache is separated by Jellystat URL/key, Jellyfin URL, user ID and period. HTTP responses are marked
no-store. - Browser output excludes raw Jellystat responses, usernames from playback data, user/device IDs, IP addresses, tokens and media stream details. Unexpected account IDs in upstream history are rejected.
- The only new database table is the stable Magent-to-Jellyfin identity mapping. It is scoped to the configured Jellyfin URL and does not automatically transfer ownership after account replacement. A changed Jellyfin URL needs identity resolution again.
Validation
Backend coverage is in backend/tests/test_insights.py. It checks API contracts, pagination, ownership, credential masking, cache separation, time units, dates, repeat plays, media classification and empty/error states.
After building the frontend, scripts/review_insights_ui.cjs checks the page and configuration using fixture-only requests. Set REVIEW_BASE, REVIEW_PLAYWRIGHT, and optionally REVIEW_DIR to save screenshots outside the repository. Live Jellystat verification requires configuring the actual instance.