seasonpackarr is a config-driven Go service with a small CLI surface. Its main job: accept autobrr-triggered webhook requests, validate/authenticate them, compare season-pack announcements against already-downloaded episode releases in configured torrent clients, optionally fetch extra metadata, parse torrent contents, hardlink matched files into the expected season-pack folder, and import the pack into the torrent client.
main.gocalls Cobra commands incmd/.cmd/start.goloads config, logger, notifications, metadata providers, then starts the HTTP server.internal/http/server.gobuilds/api/healthz,/api/pack, and/api/parse.internal/http/processor.goorchestrates payload decode, auth-adjacent request handling, client inspection, metadata lookups, and release matching;/api/packis match-only, while/api/parseresolves the client's import destination (internal/torrentclientImportDestination), hardlinks matched files in the client-selected layout, and imports the pack into the torrent client (Import). See docs/design-docs/qbittorrent-import-flow.md for the client-side import flow (complete vs partial pack, with diagrams).internal/release/decides whether a client episode and announced season pack are compatible.internal/files/performs the hardlink operation.internal/notification/emits Discord notifications for notable events.
- Implemented in
internal/config/andinternal/domain/config.go - Concerns: defaults, config file discovery, validated immutable snapshots, dynamic reload, config rendering
- Runtime readers acquire one snapshot per request or operation. Reload publishes a candidate only after file parsing, environment overrides, and validation succeed.
- Durable contract surfaces:
config.yaml,schemas/config-schema.json, README config docs
- Implemented in
internal/http/ - Concerns: server lifecycle, middleware, auth, health, webhook handlers
- External contract:
POST /api/packPOST /api/parseGET /api/healthz/liveGET /api/healthz/ready
- Implemented in
internal/release/,internal/format/,internal/slices/ - Concerns: comparing resolution, source, release group, cut, edition, repack state, HDR, streaming service, episode identity
- Risk: false positives cause wrong hardlinks; false negatives cause unnecessary downloads
- Implemented in
internal/torrents/ - Concerns: obtaining torrent bytes from release names, decoding torrent contents, pack file discovery
- Implemented in
internal/metadata/ - Providers: TVDB and TVMaze
- Purpose: estimate total episodes for smart-mode decisions and cross-check provider disagreement
- Lookup strategy: search with the parsed release title first, then retry with progressively shortened title variants (guarded by name/alias/translation matching), because provider searches often miss long or localized titles
- Caching: successful episode counts are cached for 6 hours keyed by normalized title, year and season; concurrent lookups for the same key are collapsed via singleflight, so cross-seed announce bursts trigger only one provider fetch; expired entries are swept on each store, bounding the cache to the keys seen in the last TTL window
- Implemented in
internal/files/ - Concern: create hardlinks safely into target pack directories
- Risk class: high, because pathing mistakes change user disk state
- Implemented in
internal/notification/ - Current primary output: Discord webhook notifications
Preferred dependency direction:
cmd/may depend oninternal/*internal/http/may orchestrate across config, metadata, notifications, release logic, torrents, files- leaf packages should stay narrow:
internal/release/should not know HTTP detailsinternal/files/should not know webhook payloadsinternal/metadata/should not know HTTP transport internals
internal/domain/holds cross-package data shapes and status concepts
If a change starts pushing transport concerns into matching logic or file ops, stop and re-check the boundary.
- autobrr webhook integration
- qBittorrent, Transmission, and Deluge 1.3/2 native RPC access
- TVDB API
- TVMaze API
- filesystem hardlink support
- Docker/systemd packaging and release automation
Current explicit test coverage exists in:
internal/torrentclient/*_test.go(unit tests plus environment-gated Deluge V1/V2 live coverage)internal/release/release_test.gointernal/format/format_test.gointernal/metadata/metadata_test.gointernal/metadata/titles_test.gointernal/metadata/tvdb_test.go(requiresTVDB_API_KEYenv var, skipped otherwise)internal/metadata/tvmaze_test.gointernal/slices/slices_test.go
High-value regression targets:
- fuzzy matching options
- smart mode threshold behavior
- torrent parsing path/name mismatches
- episode-to-pack file matching
- config migrations/default changes
- Design beliefs and lifecycle docs:
docs/design-docs/index.md - Product/user specs:
docs/product-specs/index.md - Plans and tech debt:
docs/PLANS.md - Risk posture:
docs/QUALITY_SCORE.md,docs/RELIABILITY.md,docs/SECURITY.md