Skip to content

Repository files navigation

Tally: the mark, a blue rounded square with four tally strokes crossed by a fifth, beside the word TALLY

A self-hosted watch tracker that keeps your films, series and anime in step with Plex, in both directions.

Reads your Plex history · talks to plex.tv, TMDB, TheTVDB and MyAnimeList · saves everything in one SQLite file you own

Tally is at 0.6.0 and is a young project. The sync engine, the API and the metadata handling carry 586 tests and are the parts least likely to surprise you; the interface was rebuilt in 0.4.0 and is the newest thing here. Read what is not there yet before you depend on it.

Tally's dashboard: six counters across the top for plays, screen time, films, episodes, anime plays and current streak, and under them the Continue watching shelf with six part-watched episodes, each a poster beside its title and a progress bar. The library navigation runs down the left.

Install

# docker-compose.yml
services:
  tally:
    image: ghcr.io/spillebulle/tally:latest
    ports: ["8080:8080"]
    volumes: ["./data:/data"]
    environment:
      PUBLIC_URL: http://192.168.1.50:8080
    restart: unless-stopped
docker compose up -d

Then open the address you set as PUBLIC_URL and press Continue with Plex. The first account to sign in becomes the administrator.

Where Image
GitHub Container Registry ghcr.io/spillebulle/tally:0.6.0
Docker Hub spillebulle/tally:0.6.0
Build it yourself docker build -t tally .

Both registries serve the same image for linux/amd64 and linux/arm64. :latest moves with every release, so pin a version in production. You need Docker, a Plex account, and about 200 MB of disk for a large library. No API keys are required to start.

PUBLIC_URL must be the address you actually type in the browser. Plex sends you back to it after sign-in, so a wrong value is the one setting that breaks the login flow.

Two-way sync

Tally imports your whole Plex history, then keeps ratings, watch state and your watchlist matching in both directions. It stores the last value it saw on Plex beside your own, which is what lets it tell which side changed rather than guessing:

Local Plex Result
unchanged unchanged nothing happens
changed unchanged pushed to Plex
unchanged changed pulled into Tally
changed changed the more recent change wins

Removing something from your watchlist is remembered as a removal, so the next pull from Plex does not put it back. How the engine decides is in docs/sync.md.

Continue watching

The Continue watching shelf: six cards, each a poster beside an episode title, a progress bar showing how far in you are, and how long ago you watched it.

The dashboard picks up mid-episode playback and the next unwatched episode of anything you have started. Plex drops an item off On Deck after a while, and Tally reads that window from your server so a show you abandoned three years ago does not sit at the top forever. You can set your own window instead, or turn the cut-off off entirely, and nothing is ever deleted either way.


History, three ways

Your watch log reads as a list, a day at a time, every play with its poster, where it came from and what it was played on. The same days as a wall of posters, at whichever of the three sizes you like. Or a calendar, a month at a time, one poster per day and the number of plays on it, which is the only one of the three that shows the shape of a month: the week off, the three nights in a row, the Sunday that took six episodes. Pick a day and its plays open underneath, with the month still on screen.

Days are counted in your own zone, so a film started at half past eleven belongs to that evening.

A month of watching as a calendar: April 2026, each day with plays drawn as the poster of the last thing watched on it and the number of plays in its corner, with the empty days left plain.

Anime, separated

Two rows of the anime grid: twelve posters, each with a small ANIME mark in its top corner and a green tick on the ones already watched.

Anime gets its own section, and "is it animated?" is not the question. Tally scores your library layout, the metadata agent on the item, its genres, its country of origin and a MyAnimeList lookup, so a Western animated film is not filed as anime for being a cartoon. Your per-library override always wins. The signals and their weights are in docs/anime.md.


Stats you can click

The watch activity heatmap: a year of days shaded by how much was watched, the busiest days ranked underneath it, and a bar chart of plays by month below that.

Activity by day and hour, streaks and binges, rewatches, show completion and drop-off, watchlist conversion, and how your ratings compare with the crowd, over any date range and against the period before it. Every bar, heatmap day, decade and studio is a link into the plays behind it with the filters already applied.


Filters, and views worth keeping

The filter bar with four chips reading Genre Crime, Genre Drama, Your rating Rated 7+ and On Plex Yes, and the Filters panel open underneath in three groups: Title, You and Library.

Multi-select and exclusion on genres, ranges for year, runtime, rating and dates, cast and crew, library and server, on the grid, the watchlist and your history alike. The whole query lives in the URL, so a narrowed page is a link you can send. Save a view and it comes back.


Themes

Settings, Appearance: the Dark, Light and Follow the system theme cards with a New theme tile beside them, and the swatch editor for the Graphite theme underneath showing its surface and line colours with their hex values.

Two themes ship, dark and light, and the interface can also follow the device. Beyond that you can make your own: Tally reads and writes .umbertheme files, the same flat table of colours my other applications use, so a theme made in one opens in the others unchanged. Import, export and a swatch editor are under Settings → Appearance, and the format is in docs/themes.md.


Multi-user

Each person signs in with their own Plex account and sees their own history, ratings, watchlist and stats. Ratings and watch state are per-user in Plex too, so Tally holds a token per person rather than reading everyone's data through the server owner's account. The first account created is the administrator.

What is not there yet

  • No mobile app. The interface works on a phone, but it is a web page.
  • One Plex household. Trakt, Jellyfin, Emby and Letterboxd are not imported or exported.
  • No editing of metadata. Titles, artwork and genres come from Plex and the metadata providers; Tally does not let you correct them.
  • No notifications. Nothing emails, pushes or posts to Discord.
  • The database is SQLite, so Tally expects one instance at a time. There is no clustering and no Postgres option.

Configuration

These are the ones that matter on day one. Every setting is an environment variable, and the full list is in docs/configuration.md.

Variable Default What it does
PUBLIC_URL http://localhost:8080 The address you reach Tally on. Used for the Plex sign-in redirect and the webhook URL.
TMDB_API_KEY none Posters, backdrops and descriptions. A free key is the single biggest visual improvement.
PUID / PGID 1000 The user and group to run as. Set them to whoever owns your ./data directory.
TZ UTC The zone the log is written in. It does not decide which day a play is filed under: the interface sends your own zone with every request.

Tally works with no API keys at all, falling back to whatever artwork your Plex server already has.

Documentation

Subject Page
Every setting, with defaults docs/configuration.md
The HTTP API, and API keys docs/api.md
Grafana and Prometheus dashboards docs/integrations/grafana.md, docs/integrations/prometheus.md
Live updates through a Plex webhook docs/integrations/plex.md
How the sync decides who wins docs/sync.md
How anime is detected docs/anime.md
Theme files, and making your own docs/themes.md
Backing up and restoring docs/backups.md
When something is wrong docs/troubleshooting.md

Interactive API documentation, generated from the code and always current, is at /api/docs on your own instance.

Building from source

cd backend && python -m venv .venv && .venv/bin/pip install -r requirements-dev.txt
DATA_DIR=./data .venv/bin/uvicorn app.main:app --reload --port 8080   # API
cd frontend && npm install && npm run dev                             # UI on :5173
cd backend && .venv/bin/python -m pytest -q                           # tests
cd frontend && npm run check:design && npx tsc --noEmit && npm run build

Licence

GNU General Public License v3.0, in LICENSE. Releases up to and including 0.4.0 were published under Apache 2.0. Tally bundles the Archivo typeface under the SIL Open Font Licence and Lucide icons under the ISC licence, both of which the GPL permits.

Tally is not affiliated with Plex, TMDB, TheTVDB or MyAnimeList.

About

Self-hosted watch tracker with two-way Plex sync

Resources

Stars

11 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages