Commit Graph

206 Commits

Author SHA1 Message Date
Miguel Palhas 42a0895975 feat(db): season_releases table and season policy loader 2026-08-23 16:49:42 +01:00
Miguel Palhas e8cea4aec5 refactor(api): extract tv attention lanes 2026-08-23 16:47:38 +01:00
Miguel Palhas 135d4b8247 feat(core): season tracked rule over revealed episodes 2026-08-23 16:46:26 +01:00
Miguel Palhas b801bfbcc3 style: cargo fmt 2026-08-23 16:44:32 +01:00
Miguel Palhas 24f6dab109 feat(api): tv series in the attention queues endpoint 2026-08-23 16:44:16 +01:00
Miguel Palhas 93ccea2de0 fix(api): specials stay out of episode counters 2026-08-23 16:40:38 +01:00
Miguel Palhas a1971ed82c feat(daemon): tv series in the needs-a-decision queue 2026-08-23 16:39:06 +01:00
Miguel Palhas fc93d27f7e Merge #120: series.tvdb_id and tvsearch by ID
Closes #120
2026-08-23 16:35:34 +01:00
Miguel Palhas b911f31b03 Merge #118: exclude season 0 from tracking and status
Closes #118
2026-08-23 16:35:30 +01:00
Miguel Palhas 9f4943a01b style: cargo fmt 2026-08-23 16:34:43 +01:00
Miguel Palhas 1c9caa7478 chore(db): refresh offline query data 2026-08-23 16:32:28 +01:00
Miguel Palhas a5706cf1b4 feat(tv): search indexers by series tvdb id 2026-08-23 16:32:28 +01:00
Miguel Palhas 46de061e68 feat(db): nullable unique series.tvdb_id 2026-08-23 16:32:25 +01:00
Miguel Palhas fa3f9cbd91 feat(meta): look up series external ids 2026-08-23 16:32:25 +01:00
Miguel Palhas 3bd613ec63 feat(core): derived status ignores season 0 2026-08-23 16:32:13 +01:00
Miguel Palhas 2fca8ec09f feat(core): auto-track skips season 0 2026-08-23 16:32:13 +01:00
Miguel Palhas da42467539 Merge #117: amend DESIGN.md for TV tracking
Closes #117
2026-08-23 16:24:17 +01:00
Miguel Palhas 248870bcd0 docs(design): amend TV tracking rules 2026-08-23 16:23:28 +01:00
Miguel Palhas b96fa2486e chore(arr): add tracker config for blitz 2026-08-23 16:17:45 +01:00
Miguel Palhas 0c87bf9436 Merge branch 'issue/116-settings'
ci / web (push) Successful in 31s
e2e / e2e (push) Successful in 59s
ci / rust (push) Successful in 1m3s
2026-08-23 15:15:09 +01:00
Miguel Palhas 71c2741d08 feat(web): settings view for roots and policies
Own route beside library and queues. Roots edit kind, audience, path
and their policy; policies get a form over the real fields — size
bands as number inputs, score and source weights as numbers,
resolution preference and audio/HDR rules as validated lists. Delete
arms before firing; a 409 from a referenced policy or occupied root
surfaces its message.
2026-08-23 15:14:34 +01:00
Miguel Palhas 9fa1f0cc51 feat(api): policy and root CRUD endpoints
Policies and roots were editable only via SQL inside the container.
Full CRUD over both, validated against the vocabulary the policy
engine knows — unknown resolutions or sources answer 422 naming the
field, malformed JSON answers 422, deleting a referenced policy or an
occupied root answers 409. Closes #116 (API half).
2026-08-23 14:56:51 +01:00
Miguel Palhas 951669749b Merge remote-tracking branch 'origin/main' into issue/114-read-score
ci / web (push) Successful in 53s
ci / rust (push) Successful in 2m10s
e2e / e2e (push) Successful in 2m20s
2026-08-23 12:25:08 +01:00
Miguel Palhas 8f8431eed0 fix(api): rescore release decks at read time
GET .../releases returned the stored score column, frozen at
search time. Policy tuning never reached an existing deck. Recompute
from parsed/size/seeders against the current policy and re-sort by
bucket then score; the stored column stays for the daemon's grab-time
winner pick.

Closes #114
2026-08-23 12:25:04 +01:00
Miguel Palhas 401afe5aad Merge branch 'issue/115-avail-search'
ci / web (push) Successful in 34s
e2e / e2e (push) Successful in 1m6s
ci / rust (push) Successful in 1m11s
2026-08-23 12:23:10 +01:00
Miguel Palhas aa6961f56c fix(daemon): search available movies refreshes deck
MovieCommand::Search loaded the movie through the gap filter, so an
available movie fell out and the search was a silent no-op. Split the
lane: a gap still searches and grabs, anything already satisfied
refreshes the release deck (DESIGN.md 9.3) without grabbing, and a
blocked movie still refuses.

Closes #115
2026-08-23 12:22:56 +01:00
Miguel Palhas 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
Miguel Palhas 532eee7dbe Merge branch 'issue/112-name-truncate'
ci / web (push) Successful in 38s
e2e / e2e (push) Successful in 1m33s
ci / rust (push) Successful in 1m42s
2026-08-23 11:26:20 +01:00
Miguel Palhas 24be8eb8d2 fix(web): keep grab on the row at every width 2026-08-23 11:26:07 +01:00
Miguel Palhas 9f0ccb0416 feat(web): score heat scale, drop release row expand
ci / web (push) Successful in 1m28s
ci / rust (push) Successful in 2m33s
e2e / e2e (push) Successful in 3m13s
Score cells interpolate red-to-green relative to the scores in the
current deck; the click-to-expand panel only repeated row content.
2026-08-23 11:13:11 +01:00
Miguel Palhas d6345c5305 fix(api,web): movie delete always removes files
ci / web (push) Successful in 1m5s
ci / rust (push) Successful in 1m30s
e2e / e2e (push) Successful in 1m27s
Drop the delete_files choice: removing a movie now always unlinks
its §7.4 library folder. Removes the query flag from DELETE
/api/movies/{id} and the OpenAPI params, and the toggle from the UI
confirmation panel — the confirmation itself stays. Path-safety and
torrent-untouched behaviour are unchanged.

Closes #110
2026-08-23 10:21:03 +01:00
Miguel Palhas 54b3ea8a4d fix(daemon): park vanished grabs instead of re-grabbing
ci / web (push) Successful in 42s
ci / rust (push) Successful in 1m22s
e2e / e2e (push) Successful in 1m39s
Overrides #86: removing a torrent by hand in Transmission is human
intent, not a gap to refill. Clear `wanted` and mark the target
`parked` (a new movies/episodes state) rather than reopening it as
`missing`, so neither targeted search nor RSS matching pick it back
up. Blacklist stays untouched, since the release never failed policy.

Closes #108
2026-08-23 09:13:37 +01:00
Miguel Palhas 4c73b3e7c6 feat(api,web): remove a movie, files optional
ci / web (push) Successful in 28s
ci / rust (push) Successful in 1m24s
e2e / e2e (push) Successful in 1m19s
`DELETE /api/movies/{id}` took the row and left the files, and no
surface exposed it. It now accepts `delete_files`, which unlinks the
title's §7.4 folder — atomic, so sidecars go with the feature. Targets
come from `media_files`, never from re-deriving the folder name, and a
path outside its root is never touched. The torrent is untouched (§7.3):
it keeps seeding and the reaper owns it.

The release deck grows a quiet REMOVE control opening one inline
confirmation: file count, size and folder first, then a delete-files
toggle that starts off, then what the choice costs.

Closes #104
2026-08-23 09:08:52 +01:00
Miguel Palhas 83ca921501 fix(daemon): consume the MovieCommand channel
ci / web (push) Successful in 36s
ci / rust (push) Successful in 1m23s
e2e / e2e (push) Successful in 1m17s
Nothing drained AppState's movie_commands mpsc, so manual search and
one-click grab were accepted with 202 and then did nothing until the
64-slot buffer filled and the endpoint started 503ing.

A new daemon task drains it: Search resets the movie's backoff and
runs the targeted-search + grab lane immediately; Grab sends the
already-chosen release straight to Transmission.

Closes #107
2026-08-23 09:02:42 +01:00
Miguel Palhas ca8a891347 chore(web): drop probe button and footer rail
ci / web (push) Successful in 28s
ci / rust (push) Successful in 1m0s
e2e / e2e (push) Successful in 1m10s
The 15 s health poll stays; the manual trigger and the rtt/poll-note
footer earned nothing over it.

Closes #106

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 08:44:41 +01:00
Miguel Palhas eed7094d1b fix(web): keep release deck aligned on phones
Under 40rem the seven-column line cannot fit: hdr and audio move
into the expand row, the surviving five columns tighten, and the
column header never wraps at any width.

Closes #105

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 08:43:04 +01:00
Miguel Palhas e36c73ca75 feat(web): add client-side routes for views
ci / web (push) Successful in 27s
ci / rust (push) Successful in 53s
e2e / e2e (push) Successful in 1m1s
Deep-link, refresh and back/forward now land on the view the operator
was on instead of the board. Vanilla History API (pushState/popstate),
no router dependency: /library, /queues, /movies/{id}/releases and
/search?q= all restore on load.

Closes #102
2026-08-23 08:24:36 +01:00
Miguel Palhas 1ce9f11e62 Merge remote-tracking branch 'origin/main' into issue/101-search-feedback
ci / web (push) Successful in 30s
ci / rust (push) Successful in 58s
e2e / e2e (push) Successful in 1m17s
2026-08-23 08:07:53 +01:00
Miguel Palhas 6d78cacce0 fix(web): show sweep in flight, not empty deck
An empty release list has two meanings the deck conflated: a sweep
that has not landed yet and a sweep that found nothing. The movie's
last_searched_at tells them apart, so the deck now shows a probing
'sweeping indexers' state and polls the movie (5 s, 150 s budget)
until the sweep lands, then renders buckets or an honest empty
verdict with the sweep's age. A sweep held by the §6.2 backoff times
out to a message that says so.

Closes #101

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 08:07:33 +01:00
Miguel Palhas 4afe44c812 fix(dl): resolve download links in arr (#100)
ci / web (push) Successful in 36s
e2e / e2e (push) Successful in 1m56s
ci / rust (push) Successful in 4m11s
Transmission has no route to Prowlarr, and Prowlarr redirects a
.torrent link to a magnet that a file fetch cannot follow. arr fetches
the link itself and sends Transmission a magnet or the torrent bytes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-23 08:00:11 +01:00
Miguel Palhas 5db3a8d7a4 chore: add Dockerfile for Dokploy deploy
ci / web (push) Successful in 44s
e2e / e2e (push) Successful in 1m27s
ci / rust (push) Successful in 2m58s
2026-08-23 07:33:19 +01:00
naps62-yolo 02d99ae558 feat: match RSS results by IMDb id (#99)
ci / web (push) Successful in 28s
e2e / e2e (push) Successful in 53s
ci / rust (push) Successful in 2m15s
2026-08-23 02:44:42 +01:00
Miguel Palhas 3082568171 fix(db): renumber colliding 0011 migration to 0012
ci / web (push) Successful in 45s
e2e / e2e (push) Successful in 1m2s
ci / rust (push) Successful in 2m59s
PRs #97 and #98 each added a migration numbered 0011; merged together
sqlx hits UNIQUE on _sqlx_migrations.version.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 02:33:23 +01:00
naps62-yolo bc2da22ea5 fix: reopen the gap for a grab whose torrent vanished (#98)
ci / web (push) Successful in 55s
ci / rust (push) Failing after 3m50s
e2e / e2e (push) Failing after 1m32s
2026-08-23 02:31:50 +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 ad0eb0d9d3 feat: ntfy notifications for imported, needs-decision, broken (#96)
ci / web (push) Successful in 1m0s
e2e / e2e (push) Successful in 3m41s
ci / rust (push) Successful in 5m42s
2026-08-23 02:04:36 +01:00
naps62-yolo 9f812fac11 feat: season-pack vs per-episode grab selection (#94)
ci / web (push) Successful in 24s
e2e / e2e (push) Successful in 54s
ci / rust (push) Successful in 2m11s
2026-08-23 01:40:53 +01:00
naps62-yolo 35391f02fc feat: Jellyfin library refresh on import (#93)
ci / web (push) Successful in 28s
e2e / e2e (push) Successful in 55s
ci / rust (push) Successful in 2m12s
2026-08-23 01:14:46 +01:00
naps62-yolo 225be33b55 feat: RSS sync worker (#91)
ci / web (push) Successful in 26s
e2e / e2e (push) Successful in 53s
ci / rust (push) Successful in 2m13s
2026-08-23 01:04:15 +01:00
naps62-yolo e01505bd53 Targeted-search backoff and release-date gating (#90)
ci / web (push) Successful in 25s
e2e / e2e (push) Successful in 46s
ci / rust (push) Successful in 2m9s
2026-08-23 00:42:13 +01:00