This repository has been archived on 2026-05-20. You can view files and clone it, but cannot push or open issues or pull requests.
media-acquisition/CLAUDE.md
obsidian-ai d300d83ce1 init: media-acquisition pipeline scaffold
Self-hosted BitTorrent + arr-stack + catalog-update pipeline targeting
nullstone (Debian 13). Replaces the legacy onyx -> rsync -> import
round-trip.

Contents:
- README.md          headline + ASCII architecture diagram + quickstart
- CLAUDE.md          project rules (mirrors beta-flix style)
- .gitignore         secrets dirs (.env, gluetun, qbt config, ssh keys)
- .gitleaksignore    allowlist nullstone LAN addr + Tailscale CGNAT
- docs/architecture.md   the plan in detail (gluetun + qbt + arr + catalog)
- docs/migration.md  onyx-qbt -> nullstone-qbt runbook (3 phases)
- docs/trackers.md   tracker schema + IP-pinning + ratio notes (user-curated)
- compose/docker-compose.yml  gluetun v3.40 + qbt 5.0.5 (netns=gluetun) +
                              sonarr/radarr/prowlarr (hotio) + betaflix-catalog
- compose/.env.example       documented env-var template (no secrets)
- compose/traefik/arr.yml    file-provider for qbt/sonarr/radarr/prowlarr
                             .s8n.ru subdomains, LAN+TS only via
                             trusted-only@file + authentik-forwardauth@file
- catalog/catalog.py         Flask service, ~340 LoC, /sonarr + /radarr +
                             /healthz; pulls beta-flix, inserts alphabetic
                             row into MEDIA-LIST.md, writes run log, commits
                             + pushes as obsidian-ai. Idempotent via
                             payload-hash cache.
- catalog/Dockerfile         python:3.12-slim + git + tini
- catalog/requirements.txt   flask + jinja2 + requests + gitpython + pyyaml (pinned)
- catalog/templates/*.j2     run log + catalog row Jinja templates
- catalog/README.md          service docs
- scripts/migrate-onyx.sh    phase-2 helper (rsync + .torrent ship, dry-run by default)
- scripts/add-tracker.sh     Prowlarr API helper
- scripts/killswitch-test.sh gluetun kill-switch verification (3 steps)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-20 01:15:43 +01:00

109 lines
5.2 KiB
Markdown

# CLAUDE.md — media-acquisition
Read this at session start. Rules for managing the nullstone media-acquisition
pipeline.
## What this repo is
The BitTorrent + arr-stack + catalog-update pipeline that feeds the ARRFLIX
library on **nullstone** (Debian 13, `192.168.0.100`). Consumed by:
- **Jellyfin** at `tv.s8n.ru` (container `jellyfin-stock`).
- **Catalog** at `git.s8n.ru/s8n/beta-flix``playbooks/import-media/MEDIA-LIST.md`.
## Source map
```
docs/architecture.md Plan + reasoning. Read this BEFORE editing compose.
docs/migration.md onyx-qbt → nullstone-qbt migration runbook.
docs/trackers.md Tracker schema + IP-pinning risks (user-curated).
compose/docker-compose.yml gluetun + qbt + sonarr + radarr + prowlarr + catalog.
compose/.env.example Env template — secrets live in .env (gitignored).
compose/traefik/arr.yml File-provider routing for arr stack.
catalog/ betaflix-catalog Python service (Flask + webhooks).
scripts/ migrate-onyx.sh, add-tracker.sh, killswitch-test.sh.
```
## Deploy lifecycle
1. **Edit** files locally under `/home/admin/projects/media-acquisition/`.
2. **Push to Forgejo** (this repo's authoritative remote is
`git.s8n.ru/s8n/media-acquisition.git`).
3. **On nullstone**: `cd /opt/docker/media-acquisition && git pull && docker compose up -d`.
4. **CRITICAL — verify kill-switch after every gluetun change**:
`bash scripts/killswitch-test.sh`. If the second curl succeeds, you have a leak;
tear down before re-trying.
## Rules paid for in blood (mirrored from beta-flix where applicable)
### Rule 1 — SSH user
`user@nullstone`. **NOT** `admin@nullstone`. AllowUsers was tightened
2026-05-03; uid 1000 only. Memory: `[[feedback_nullstone_ssh_user]]`.
### Rule 2 — Commit + push to **my git**
Authoritative remote is `git.s8n.ru/s8n/media-acquisition.git` (Forgejo).
No GitHub mirror. Always `git remote -v` before push. Memory:
`[[feedback_always_commit_to_my_git]]`, `[[feedback_check_remote_before_push]]`,
`[[feedback_my_git_is_forgejo]]`.
### Rule 3 — Commit identity
- Human commits: `s8n <admin@s8n.ru>`.
- Bot/automation commits (e.g. catalog service, scripted edits): `obsidian-ai <obsidian-ai@s8n.ru>`.
Memory: `[[user_git_identity]]`.
### Rule 4 — Kill-switch is non-negotiable
Every change to `gluetun` service or VPN env vars MUST be followed by
`scripts/killswitch-test.sh`. A torrent client leaking outside the VPN is the
single failure mode that defines this project — do not "trust" the firewall
based on config inspection. Run the test.
### Rule 5 — No secrets in repo
`.env`, WireGuard keys, Forgejo PATs, deploy keys: all gitignored. Use
`.env.example` to document variable names with placeholders. If you commit a
secret by accident, rotate it (Proton WG: regenerate key, update gluetun;
Forgejo PAT: revoke at `git.s8n.ru/-/user/settings/applications`).
### Rule 6 — Tracker IP pinning
Private trackers may pin sessions to a single source IP. Switching from
onyx public IP → Proton exit IP will trip them. Before adding a new tracker
or migrating an old torrent, check `docs/trackers.md` for the per-tracker
policy. Update `docs/trackers.md` whenever a new tracker is on-boarded.
### Rule 7 — XFS reflinks / hardlinks
`/home/user/media` is XFS, single device. Sonarr/Radarr "Use Hardlinks
instead of Copy" = ON. Catalog service may use `cp --reflink=always` for
divergent-perm scenarios (free inodes, zero block cost). Never `cp` plain;
that doubles disk usage and breaks seeding atomicity.
## Canonical naming
Catalog rows pushed to `beta-flix/playbooks/import-media/MEDIA-LIST.md` follow
the ARRFLIX house style:
- TV: `Series Title (Year)` — alphabetic by title, year tiebreaker.
- Movies: `Movie Title (Year)` — alphabetic by title.
- "Source / Version" column = raw Sonarr/Radarr `sourceTitle` (release name).
Human edits to "Why on arrflix" stay; bot never overwrites that column.
The catalog service is **append + merge only** — never overwrites human-authored
notes.
## How to start a session
1. Read this file.
2. Read `docs/architecture.md` if working on compose or catalog code.
3. Check `git status` and `git remote -v` (must show
`git.s8n.ru/s8n/media-acquisition.git`).
4. Owner says what they want; ship + verify kill-switch + commit to Forgejo.
5. End every turn: commit + push to `git.s8n.ru/s8n/media-acquisition.git`.
## Glossary
| Term | Means |
|-----------------------|----------------------------------------------------------------------------------|
| **ship** / **deploy** | git push to Forgejo → on nullstone, `git pull && docker compose up -d`. Kill-switch test on any gluetun change. |
| **migrate** | Phase-2 onyx→nullstone runbook in `docs/migration.md`. Read `scripts/migrate-onyx.sh` first; dry-run mode mandatory. |
| **add tracker** | `scripts/add-tracker.sh <name> <url>`; then update `docs/trackers.md` with IP-pinning policy + ratio requirements. |
| **killswitch test** | `bash scripts/killswitch-test.sh`. NEVER claim "VPN works" without running this. |
| **owner** | P (xynki.dev@gmail.com). Final say. Executive-override pattern from `[[feedback_s8n_executive_override]]` applies. |