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/README.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

107 lines
4.3 KiB
Markdown

# media-acquisition
Self-hosted BitTorrent + arr-stack + canonical-import pipeline that lands torrents
directly on **nullstone**, through a Proton WireGuard VPN with verified kill-switch,
hardlinks files into the existing ARRFLIX library, and auto-commits catalog rows
to `git.s8n.ru/s8n/beta-flix`.
Replaces the legacy `onyx → rsync → nullstone` round-trip.
## Architecture
```
+-----------------+
| Proton VPN |
| (WireGuard) |
+--------+--------+
| wg0
v
+------------+ indexer queries +-------------------+ torrent traffic
| Prowlarr |-------------------->| gluetun |<------------------+
+-----+------+ (via netns) | kill-switch fw | |
| +-------------------+ |
| search ^ ^ ^ |
v | | | |
+------------+ grabs +----------+ | +----------+ |
| Sonarr/ |----------->| qBittorrent (netns=gluetun) |
| Radarr | | /home/user/media/_downloads/{incomplete,complete}
+-----+------+ +-------------------------------------------------+
|
| OnImport webhook (POST /sonarr or /radarr)
v
+--------------------+
| betaflix-catalog |--+ XFS reflink/hardlink into /home/user/media/{movies,tv}
| (Flask, Python) | |
+--------+-----------+ +--> Jellyfin (tv.s8n.ru) picks up new items
|
| git commit + push (obsidian-ai)
v
+-----------------------------+
| git.s8n.ru/s8n/beta-flix |
| playbooks/import-media/ |
| MEDIA-LIST.md (updated) |
| runs/<slug>.md (new) |
+-----------------------------+
```
Single XFS filesystem at `/home/user/media` → hardlinks / reflinks are free.
## Quickstart
```bash
# Clone on nullstone
ssh user@nullstone
git clone https://git.s8n.ru/s8n/media-acquisition.git /opt/docker/media-acquisition
cd /opt/docker/media-acquisition/compose
# Configure
cp .env.example .env
${EDITOR:-vi} .env # fill in PVPN_WG_PRIVKEY, PVPN_WG_ADDRESSES, FORGEJO_PUSH_TOKEN, etc.
# Bring up
docker compose up -d
# Verify VPN kill-switch (CRITICAL — do not skip)
bash ../scripts/killswitch-test.sh
# Sanity: pick a sacrificial legal torrent in qbt UI, confirm it lands in
# /home/user/media/_downloads/complete/ and arr stack hardlinks it.
```
## Layout
```
README.md This file.
CLAUDE.md Project rules for Claude Code.
docs/
architecture.md The plan in detail. Decision log + reasoning.
migration.md onyx-qbt → nullstone-qbt migration runbook.
trackers.md Tracker schema + IP-pinning notes (user fills in).
compose/
docker-compose.yml Full stack: gluetun + qbt + sonarr + radarr + prowlarr + catalog.
.env.example All env vars documented.
traefik/arr.yml Traefik file-provider for *.s8n.ru subdomains (LAN+TS only).
catalog/
catalog.py Flask webhook receiver → beta-flix catalog updater.
Dockerfile python:3.12-slim base.
requirements.txt Pinned versions.
templates/ Jinja2 templates for run logs and catalog rows.
README.md Catalog service docs.
scripts/
migrate-onyx.sh Phase-2 migration: rsync + .torrent mass-add.
add-tracker.sh Helper: add tracker to Prowlarr via API.
killswitch-test.sh Verify gluetun blocks traffic when VPN drops.
```
## Related
- Plan: `docs/architecture.md`
- Catalog target: `git.s8n.ru/s8n/beta-flix` (`playbooks/import-media/MEDIA-LIST.md`)
- Jellyfin (consumer): `tv.s8n.ru` (`jellyfin-stock` container on nullstone)
- Host docs: `ai-lab/SYSTEM.md`
## Status
Scaffold. Live deploy pending VPN slot allocation + tracker IP-pinning review.
Next step: fill in `compose/.env` and bring up gluetun + qbt only (no arr yet)
to validate kill-switch.