arr-summary/CLAUDE.md
mattie726 9804283396
All checks were successful
Deploy / deploy (push) Successful in 1m54s
Add CLAUDE.md documenting architecture and deploy pipeline
2026-08-25 23:36:06 -07:00

4.2 KiB

Arr Summary (Greendale)

Flask dashboard aggregating status from the user's self-hosted media stack — Sonarr, Radarr, SABnzbd, Tautulli, Prowlarr, Ombi — plus Unraid array stats and a Rotten Tomatoes "what's popular that I don't have yet" feed. Branded "Greendale Media Centre." Runs as one Docker container on the user's Unraid home server. Server-side project directory is named greendale; the container/repo are named arr-summary.

Architecture

  • app.py — single Flask app, session-based single-shared-password auth (LOGIN_PASSWORD env var, hashed comparison; can be changed at runtime via /api/change-password, persisted to settings.json). Supports running behind a reverse-proxy subpath via SCRIPT_NAME + ScriptNameMiddleware + ProxyFix (currently deployed at domain root, not a subpath, but the capability exists — see nginx/ configs for both).
    • Per-service client functions (sonarr_get, radarr_get, sabnzbd_get, tautulli_get, prowlarr_get, ombi_get) each call that service's REST API directly with its API key from env vars.
    • The dashboard route (/) fetches all services in parallel via ThreadPoolExecutor with a hard 5-second wall-clock deadline — any slow/unreachable service degrades to an error dict rather than blocking the whole page. This matters for remote/cellular access.
    • Aggressive per-service caching with different TTLs tuned to how often each actually changes: Sonarr/Radarr library lists 5 min (the biggest latency cost — full Radarr list is ~4.4MB), Tautulli stats 2 min, SABnzbd history 10 min, Ombi requests 4 hours, Rotten Tomatoes scrapes 4 hours. Active streams (Tautulli) and the SABnzbd queue are always fetched live, never cached — those need to be current-second accurate.
    • Rotten Tomatoes / IMDB are scraped directly (requests + BeautifulSoup, JSON-LD parsing), not via an official API — brittle to upstream HTML changes by nature.
  • templates/ — Jinja2 templates (dashboard.html, login.html, settings.html); duplicated at the top level too (dashboard.html etc. outside templates/) — appears to be a leftover from an earlier project layout or the export-to-unraid.sh tooling. Left as-is rather than restructured without confirming with the user first.
  • export-to-unraid.sh — a pre-existing standalone deploy script (build image locally → tarball → rsync + docker load over SSH) that predates the Forgejo pipeline below. Still present, not removed, but the Forgejo pipeline is now the primary deploy path going forward.
  • nginx/ — reference nginx location-block snippets for subdomain vs. subpath reverse-proxy setups; not actually consumed by the app at runtime (NPM handles proxying in practice), kept as documentation/config reference.

Local development

pip install -r requirements.txt
python3 app.py

Runs on port 5000. Needs the various *_API_KEY and *_HOST/ARR_HOST env vars (see .env.example) to reach real services — without them, dashboard cards degrade to "error" status individually rather than crashing the page.

Deployment

Target: Unraid server, container path /mnt/user/appdata/greendale (note the directory name differs from the container/repo name), built from Dockerfile/docker-compose.yml in this repo. Container name arr-summary, port 5055 (overridable via HOST_PORT) → container port 5000.

Deploy mechanism: Forgejo push-to-deploy, same pattern as the other three projects on this box — see card-grader's CLAUDE.md for the full pipeline mechanics. Push to main on the forgejo remote (https://git.hippofam.com/ninja_hippo/arr-summary.git) triggers .forgejo/workflows/deploy.yml, which syncs into /mnt/user/appdata/greendale (excluding .git, .env) and runs docker compose up -d --build.

Persistent state, never touched by deploys: .env holds every API key and LOGIN_PASSWORD — this project was already doing this correctly before the Forgejo migration (compose file uses ${VAR} substitution from .env, no hardcoded secrets), unlike n64-tracker which needed fixing. settings.json (timezone, theme, changed login password) also persists server-side outside git.