Tautulli is running at 192.168.1.100:8181, so watch data now comes from get_history rather than Plex's session history. This matters beyond convenience: Plex records that a play started, Tautulli records how far it got. A film three people abandoned after five minutes and a film nobody ever opened are opposite signals for a deletion decision, and Plex reports them identically. - Adds sections 4.8-4.11: Tautulli ingest, completion semantics, fallback, coverage horizon, and the pms_identifier cross-check - Splits MediaProvider into MediaProvider + HistoryProvider so library data and watch data can come from different servers - watch_event gains percent_complete, disposition, source, and session merging; media_item gains partial/abandoned counts and pre_history - New 'rejection' score component, with weights renormalizing when a component is unavailable rather than silently scoring everything lower - Deployment: image built off-box and pushed to Nox's Portainer, versioned tags rather than :latest - Closes three open questions, opens two smaller ones Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GVbG48GAXfCZatcmX123Ra
51 lines
2.3 KiB
Markdown
51 lines
2.3 KiB
Markdown
# MediaShelf
|
|
|
|
A self-hosted web app for figuring out which of the thousands of files in a Plex library
|
|
are actually worth keeping.
|
|
|
|
MediaShelf scans a Plex Media Server over its HTTP API and pulls watch history from
|
|
Tautulli, builds a local snapshot of every movie and TV season, and joins together facts
|
|
that are never shown side by side — date added, size on disk, file path, owning library,
|
|
watch count, last watched, and *how much of it anyone actually finished* — into a
|
|
sortable, filterable, chartable grid with a tunable **reclaim score** that ranks deletion
|
|
candidates.
|
|
|
|
## Status
|
|
|
|
**v1 is report-only.** MediaShelf does not delete, move, or modify anything. It produces
|
|
a ranked list, saved rule sets, and CSV export. Deletion is designed for in the roadmap
|
|
but deliberately not built, so the scanner and the scoring model can be trusted before
|
|
anything destructive is wired up.
|
|
|
|
Nothing is implemented yet — this repository currently holds the design.
|
|
|
|
## What it does
|
|
|
|
- Full-library ingest from Plex, no agent on the Plex host, no filesystem mounts
|
|
- Movies at item level, TV rolled up to **season** level
|
|
- Watch data from **Tautulli**, so plays by *every* account are counted and a play that
|
|
was abandoned after five minutes is distinguished from one that was finished — Plex's
|
|
own history reports those identically. Falls back to Plex session history if Tautulli
|
|
is unavailable, and says so rather than degrading silently
|
|
- Sort and filter on every metric; charts for size by library, additions over time,
|
|
finished vs. abandoned vs. never-opened by size, and size vs. last-watched
|
|
- A weighted reclaim score with live sliders, and grace rules so it never recommends
|
|
something you added last week
|
|
- Named, re-runnable saved views — *"unwatched, older than 2 years, over 10 GB"*,
|
|
*"two people started it and nobody finished it"*
|
|
- CSV export of any view
|
|
|
|
## Planned stack
|
|
|
|
Python + Flask, SQLite (WAL), vanilla JS front-end, single container deployed as a
|
|
Portainer stack behind Nginx Proxy Manager.
|
|
|
|
## Roadmap
|
|
|
|
- **v2** — two-stage quarantine-then-purge deletion, with authentication, a path
|
|
allowlist, and an audit log
|
|
- **v3** — Emby and Jellyfin support behind the existing `MediaProvider` abstraction
|
|
|
|
## Documentation
|
|
|
|
- [`docs/design.md`](docs/design.md) — the full software design
|