Commit Graph
18 Commits
Author SHA1 Message Date
Miguel PalhasandClaude Fable 5 917aa4fa76 feat: scale size bands by episode runtime
Implements #209 per §5.5 as amended by #208: a band's floor and target
are rates against a 45-minute reference runtime, scaled by the series'
minutes per episode. A missing or zero runtime applies the bands
unscaled, and movies are never scaled. The runtime is stored on the
series row (new migration), filled on add and by the metadata refresh,
which never blanks a known value against TMDB's frequently-empty
episode_run_time. Composes with #210: allow_below_floor waives against
the scaled floor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 22:45:55 +01:00
Miguel PalhasandClaude Opus 5 9fee07f080 feat: let a size rejection be waived
A release below §5.5's floor was rejected with no way through, so a
policy wrong about one title left three Rick and Morty S09 packs
visible and none grabbable.

`allow_below_floor` relaxes the floor for one title into a soft fail,
never a pass: the release is waived, so automatic grabbing still skips
it and the import records a §5.7 waiver. The deck offers the one click
on a rejected row where the rule has an override, which is exactly what
§9.3's override is for.

Stored verdicts are re-derived when a title's overrides change — the
deck and the daemon's grab gate both read that column, so without it
the row the operator just acted on would keep reading `rejected`.

Closes #210

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-24 22:15:14 +01:00
Miguel PalhasandClaude Fable 5 2286cba862 feat(core): score season packs per episode
A size band describes one episode (DESIGN.md §5.5), so both the target
penalty and the floor now compare a release's size divided by the number
of episodes it covers. The caller supplies the count — arr-core has no
IO. Movies and unknown counts divide by one, so movie scoring is
unchanged and pinned by test.

Closes #180

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 20:10:23 +01:00
Miguel PalhasandClaude Opus 5 a3897df0ab fix(db): keep migration checksums stable
ci / web (push) Successful in 38s
ci / rust (push) Successful in 1m4s
e2e / e2e (push) Successful in 1m14s
Issue #155 removed the sqlx 0.8 rebuild workarounds by editing migrations
0007, 0014 and 0021 in place. Editing an applied migration changes its
checksum, and `migrate()` refuses to run when one no longer matches what
`_sqlx_migrations` recorded, so the daemon exited on startup against any
database that had already applied them — production included.

The sqlx 0.9 bump is the fix and survives: a new migration can carry
`-- no-transaction` so `PRAGMA foreign_keys = OFF` holds and a table
rebuild stops cascade-deleting its children. Only the retroactive cleanup
of migrations that already ran is reverted, along with #153's
`CHECK (title <> '')`, which rode on the 0021 edit and needs a migration
of its own rather than a rewrite of history.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 19:14:42 +01:00
Miguel PalhasandClaude Fable 5 93a3485c50 fix(db): drop 0.8 rebuild workarounds, enforce title
With sqlx 0.9 honouring `-- no-transaction`, 0007 loses its
movie_releases_backup stash like 0014 did, and 0021 gains
the CHECK (title <> '') that #153 abandoned because the 0.8
migrator could not run a rebuild with foreign keys off. The
rebuild test now enters at migration 6 so the child links
ride through all three rebuilds, and a new test proves the
'' -> 'TBA' backfill and the rejection of new empty titles.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 18:39:22 +01:00
Miguel PalhasandClaude Fable 5 ef4722e1dd fix(db): bump sqlx to 0.9, honour no-transaction
sqlx-sqlite 0.8 ignored Migration.no_tx and wrapped every
migration in a transaction, where PRAGMA foreign_keys = OFF
is a no-op — so any table rebuild cascade-deleted children.
0.9 honours `-- no-transaction`, so 0014 drops its
movie_releases_backup / episode_releases_backup workaround
and runs the plain rebuild recipe with foreign keys off.
A migration test rebuilds both parents from a pre-0014
database and asserts the child link rows survive.

Closes #155

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 18:10:53 +01:00
Miguel Palhas 8478c0f8a9 feat(db): store poster, backdrop and rating on titles
§9.6 keeps rich detail out of the database except for the three fields
pure-SQL views need. Adds poster_path, backdrop_path and vote_average to
movies and series, written by the daily metadata refresh in both lanes
and filled at add time from the TMDB response the create flows already
fetch.
2026-08-23 22:12:05 +01:00
Miguel Palhas 42a0895975 feat(db): season_releases table and season policy loader 2026-08-23 16:49:42 +01:00
Miguel PalhasandClaude Opus 5 a5b3680746 feat(core): rank resolutions in the score
ci / web (push) Successful in 42s
e2e / e2e (push) Successful in 1m13s
ci / rust (push) Successful in 1m18s
`resolution_pref` only gated eligibility, so every release was scored
against its own resolution's size band and a 23 GB 4K lost to an
at-target 1080p. Each step up the list is now worth `resolution_step`
points, seeded at 300: five gibibytes of 4K overshoot, so a 4K up to
27 GB wins and a bloated one still does not.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 12:01:24 +01:00
naps62-yolo 55ae44fa7b fix(db): scale TV size bands to episode size (#97)
ci / web (push) Successful in 57s
e2e / e2e (push) Successful in 2m31s
ci / rust (push) Successful in 5m9s
2026-08-23 02:31:44 +01:00
naps62-yolo 01af397a40 Hard/soft fail handling and release blacklist (#87)
ci / rust (push) Successful in 1m6s
e2e / e2e (push) Successful in 52s
ci / web (push) Successful in 26s
2026-08-22 23:42:36 +01:00
naps62-yolo 62aba6315c feat(db): align movie state with canonical MediaState (#85)
ci / web (push) Successful in 29s
e2e / e2e (push) Successful in 47s
ci / rust (push) Successful in 2m59s
2026-08-22 23:21:09 +01:00
naps62-yolo d3cea8693b feat(api): series, season and episode endpoints (#81)
ci / web (push) Successful in 26s
e2e / e2e (push) Successful in 47s
ci / rust (push) Successful in 2m39s
2026-08-22 23:02:34 +01:00
naps62-yolo f253e2755b feat(daemon): grab pipeline for wanted movies (#77)
ci / web (push) Successful in 53s
ci / rust (push) Successful in 1m47s
e2e / e2e (push) Successful in 2m1s
2026-08-22 22:38:31 +01:00
naps62-yolo ac6ed8b798 feat(db): add series, season and episode model (#71)
ci / rust (push) Successful in 1m36s
ci / web (push) Successful in 34s
e2e / e2e (push) Successful in 1m41s
2026-08-22 22:04:27 +01:00
naps62-yolo 29d6831c83 feat(core): score by distance from target size (#63)
ci / web (push) Successful in 48s
ci / rust (push) Successful in 1m13s
e2e / e2e (push) Successful in 1m15s
2026-08-22 21:15:26 +01:00
naps62-yolo 84777169d0 feat(db): SQLite schema and movie migrations (#48)
ci / web (push) Successful in 7s
ci / rust (push) Successful in 35s
e2e / e2e (push) Successful in 47s
2026-08-22 19:36:39 +01:00
ClaudeandClaude Opus 5 f4e63f1ac5 chore: cargo workspace skeleton
Eleven empty crates per DESIGN.md §11, versions and lints pinned once in the
root manifest, Justfile carrying the §12 gate, nix dev shell.

The frontend steps in `just ci` no-op until web/ exists. arr-core carries one
placeholder test because `cargo nextest` fails a zero-test run, and relaxing
that would let a broken filter go green later.

Closes #1

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 19:20:47 +01:00