{"id":46682497,"url":"https://github.com/gioxx/watched-by-all","last_synced_at":"2026-03-09T00:35:18.049Z","repository":{"id":328399706,"uuid":"1113353794","full_name":"gioxx/watched-by-all","owner":"gioxx","description":"Web dashboard for Jellyfin to see what’s been watched and what is watched by all selected users.","archived":false,"fork":false,"pushed_at":"2026-02-22T21:30:55.000Z","size":182,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-22T21:36:38.851Z","etag":null,"topics":["docker","docker-compose","docker-images","jellyfin"],"latest_commit_sha":null,"homepage":"https://hub.docker.com/r/gfsolone/watched-by-all","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gioxx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"gioxx","ko_fi":"gioxx","buy_me_a_coffee":"gioxx"}},"created_at":"2025-12-09T21:33:07.000Z","updated_at":"2026-02-22T20:57:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gioxx/watched-by-all","commit_stats":null,"previous_names":["gioxx/plex-watched-by-all","gioxx/watched-by-all"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/gioxx/watched-by-all","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gioxx%2Fwatched-by-all","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gioxx%2Fwatched-by-all/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gioxx%2Fwatched-by-all/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gioxx%2Fwatched-by-all/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gioxx","download_url":"https://codeload.github.com/gioxx/watched-by-all/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gioxx%2Fwatched-by-all/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30278582,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T20:45:49.896Z","status":"ssl_error","status_checked_at":"2026-03-08T20:45:49.525Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["docker","docker-compose","docker-images","jellyfin"],"created_at":"2026-03-09T00:35:16.479Z","updated_at":"2026-03-09T00:35:18.036Z","avatar_url":"https://github.com/gioxx.png","language":"HTML","funding_links":["https://github.com/sponsors/gioxx","https://ko-fi.com/gioxx","https://buymeacoffee.com/gioxx"],"categories":[],"sub_categories":[],"readme":"# Watched (_former Jellyfin – Watched by Everyone_)\n\nWeb dashboard for Jellyfin to see what’s been watched and what is watched by **all** selected users. It runs as a FastAPI app that serves the static UI.\n\n## Features\n- **Movies**: shows titles marked as watched by every selected user, with runtime/ratings/playcount.\n- **Seasons (complete)**: seasons where every episode was watched by everyone, plus total runtime.\n- **User history**: full history for a chosen user (movies + series). Series cards open a per-series episode detail page grouped by season.\n- **Episode detail page**: chronological view of watched episodes with posters and dates.\n- **UI controls**: user selector, manual refresh, search, language toggle (EN/IT), light/dark toggle (persists), GitHub link.\n\n## Requirements\n- Jellyfin server with an API key.\n- Python 3.11+ (or use Docker).\n- Network reachability from this app to Jellyfin.\n\n## Configuration\nEnvironment variables (see `docker-compose.yml`):\n- `JELLYFIN_URL` (required): base URL of your Jellyfin, e.g. `http://jellyfin:8096`.\n- `JELLYFIN_APIKEY` (required): Jellyfin API key.\n- `WATCH_THRESHOLD` (optional, default `0.95`): fraction (0-1) of an item that counts as watched if `Played` isn’t set.\n- `REFRESH_MINUTES` (optional, default `30`): minimum minutes between automatic refreshes of cached data.\n- `PROXY_IMAGES` (optional, default `true`): when `true`, posters are proxied through this app to avoid mixed-content or private-host issues (useful behind HTTPS/CDN tunnels).\n- `IMAGE_CACHE_SECONDS` (optional, default `86400`): cache-control duration for proxied images.\n- `JELLYFIN_TIMEOUT` (optional, default `5`): per-request timeout (seconds) for Jellyfin API and image proxy.\n- `THUMB_CACHE_DIR` (optional, default `thumb_cache`): local folder for cached posters, served at `/thumbs/*`.\n- `THUMB_CACHE_TTL_HOURS` (optional, default `72`): recache posters after N hours; `0` disables expiry.\n- `THUMB_FETCH_TIMEOUT` (optional, default `5`): timeout for downloading posters into the cache.\n- `THUMB_MAX_HEIGHT` (optional, default `500`): maximum poster height requested to Jellyfin (px); width auto-scales to preserve aspect ratio.\n- `INTERNAL_HTTP_BASE` (optional, default `http://127.0.0.1:8088`): base URL used internally to fetch `/image/...` when caching thumbs.\n\n## Run (Docker)\n```sh\ndocker compose up -d\n```\nThen open http://localhost:8088.\n\n### Prebuilt image (GitHub Container Registry or Docker Hub)\nWhen published, you can pull instead of building locally:\n```sh\n# GitHub Container Registry\ndocker pull ghcr.io/gioxx/watched-by-all:latest\n\n# or Docker Hub\ndocker pull gfsolone/watched-by-all:latest\n\ndocker run -d --name watched \\\n  -p 8088:8088 \\\n  -e JELLYFIN_URL=http://jellyfin:8096 \\\n  -e JELLYFIN_APIKEY=YOUR_JELLYFIN_API_KEY \\\n  -e WATCH_THRESHOLD=0.95 \\\n  -e REFRESH_MINUTES=30 \\\n  ghcr.io/gioxx/watched-by-all:latest\n```\n\n## Run (local Python)\n```sh\npython -m venv .venv\nsource .venv/bin/activate\npip install -r requirements.txt\nJELLYFIN_URL=http://... JELLYFIN_APIKEY=... uvicorn app.main:app --reload --port 8088\n```\nOpen http://localhost:8088.\n\n## Frontend CSS (Tailwind local build)\nThe UI now follows the same Tailwind local workflow used in the sibling project.\n\n```sh\nnpm install\nnpm run build:css\n```\n\nDuring development you can keep the compiler running:\n```sh\nnpm run watch:css\n```\n\n## Using the web app\n- **Tabs**: Movies, Seasons (complete), User history.\n- **Users**: click “Users” to choose which Jellyfin users are considered for the “watched by all” logic (empty selection = everyone).\n- **Refresh**: forces a recount against Jellyfin and updates the summary bar.\n- **Search**: filters the current tab client-side.\n- **History**: pick a user, browse their history; click a series card to open the episode detail page.\n- **Language**: toggle EN/IT in the header (per-browser localStorage).\n- **Theme**: light/dark toggle in the header (per-browser localStorage).\n\n## Localization / customization\n- Locale strings live in `static/locales/en.json` and `static/locales/it.json`. Add another by copying one, translating, and referencing it in `static/index.html` and `static/history_detail.html`.\n- Favicon/logo: `static/watched_icon.webp`.\n- Styles: `static/styles.css` (project-specific overrides), `static/tailwind.input.css` (source), `static/tailwind.css` (compiled).\n\n## API surface (served by FastAPI)\n- `GET /api/summary`: counts for users/movies/seasons + last refresh timestamp.\n- `GET /api/movies`: movies watched by all selected users.\n- `GET /api/shows`: seasons watched by all selected users.\n- `GET /api/users`: detected Jellyfin users + currently selected IDs.\n- `POST /api/selected-users`: `{ \"selected_user_ids\": [\"...\"] }` to persist selection.\n- `POST /api/refresh`: force refresh the cache now.\n- `GET /api/thumb-cache/status`: thumbnail cache stats (files/size/last refresh).\n- `POST /api/thumb-cache/refresh`: refresh cache metadata/thumbnails.\n- `POST /api/thumb-cache/clear`: clear thumbnail cache and rebuild it from scratch.\n- `GET /api/user/{user_id}/history`: full history for a user (movies + episodes).\n- `GET /image/{item_id}?tag=...`: proxies a Jellyfin image (used by the UI when `PROXY_IMAGES=true`).\n- Static assets at `/static/*` serve the UI.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgioxx%2Fwatched-by-all","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgioxx%2Fwatched-by-all","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgioxx%2Fwatched-by-all/lists"}