Feedback pass 2 and the size-band work landed on main while this branch
was finishing. Brings them in ahead of the merge back.
# Conflicts:
# crates/arr-api/src/movies.rs
# crates/arr-api/src/state.rs
# crates/arr-daemon/src/main.rs
# web/src/main.ts
A pack that hard-failed at import blacklisted its release, put every
episode back to missing and left the season reading 0/10, with nothing
on screen joining the two. Every fact was already recorded.
The blacklist now carries its reason out of the database: deck rows read
`blacklisted · size` instead of a bare `blacklisted`, and say whether the
policy turned the file down — relaxable for this title — or the release
itself failed, which a retry only repeats. A season whose pack was
abandoned says so on its row and above its deck, with the release name,
when it failed, and what it failed on. A row the blacklist no longer
answers for keeps rendering and claims no reason.
Two defects from the integration review of #211 sit in the same code and
are fixed here: a waived row threw away the rule it now carries and read
a bare `below policy`, and the empty-eligible count called every waived
row force-grabbable, since #211 gave those rows the rule `overridable`
reads.
Verified against a real browser: series detail, both season decks and
their buckets, at 1280 and 390 px.
Refs #227, #211
Three words the operator reads change; nothing underneath does. Waivers
are still written, recorded and served under their existing names, the
`blocked` column and flag keep theirs, and the release deck keeps its
name in DESIGN.md §9.3 and in the code.
- `waive + grab` reads `force grab`, and its accessible name says which
rule the click relaxes. The `waived` bucket reads `below policy`, and
so does the verdict chip on its rows — an operator can act on "below
policy" and cannot act on the name the record keeps.
- A waived import already said what was relaxed for two rules; `size`
joins them and the fallback names the rule rather than badging it
`waived`.
- `blocked` reads `no targeted search`, everywhere the flag surfaces.
§6.3 gives it one effect and a bare toggle hid it: the accessible name
carries the RSS half at rest, and a note under the controls spells it
out while the flag is on.
- The season and episode controls are already the #230 search icon; only
their labels still said "deck". They now say what the click does.
`just ci` passes through the gate: 509 tests, biome, tsc, tokens.
Verified in a real browser (agent-browser) on the library, movie detail,
series detail, the episode release view, queues and settings, at 1440
and 390 wide — no horizontal scroll at either.
Refs #232
Trash replaces the remove labels on title pages and season and
episode rows, a magnifier replaces the deck control, the season
on-disk readout carries a drive glyph before its 0/10, and the
TMDB, TVDB, IMDb and Rotten Tomatoes links carry drawn marks
shipped inline (wordmark badges plus a tomato), never remote
images. Every icon-only control keeps an aria-label naming the
action and the row or title it acts on, and the arm-then-confirm
delete speaks a visible amber "confirm" while armed, so the first
hit never destroys.
Shared CSS lives in one block in style.css headed
"icon-only controls (#230)" — .icon, .control-icon, .icon-mark —
for #231 to consume for the settings rows.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The rail, browser back, and Esc already cover navigation — the back
button was a third way to do what two other things already do, and it
cost the page its first line.
- Remove #movie-back and #series-back buttons and their event listeners
- Focus lands on the title element (tabindex=-1) instead of the removed
button on open
- TV releases back button is untouched
- Hero banner now meets the rail with zero top padding on movie/series
- Esc and parent-route behaviour unchanged
- Deep link fallback for TV releases uses #nav-library instead of the
removed #series-back
Adds wanted languages, translation engine (restricted to
available_engines), remote-command timeout, and an ordered
enable/disable list per provider with daily budgets, wired to
the existing GET/PUT /api/settings/subtitles from #198.
A third lane in the attention queues view: one row per movie or
series with a gap chip per language and why (#186's reasons, plus a
sync alass flagged). Reuses the existing deck-group markup and
missingChipLabel wording so it reads like its two siblings; each
row opens the title's own page, where the #203 fetch/translate
panel already carries the resolving actions.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Series detail exposes DELETE /api/series/{id} through the movie
removePanel, generalised over endpoints and file rollup instead of
copied. Season headers and on-disk episode rows get the settings
armed-delete control wired to #174's file endpoints, worded for what
they do: files go, wanted clears, the row stays listed.
Closes#175
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Implements the §9.7 shell rulings (issue #173): "/" renders the library
and the board route is gone — every former board target (Esc, cleared
search, detail parent routes, the not-found fallback) lands on the
library. The signal chain moves into /settings as its first section,
lamps still driven by the health poll; the master lamp stays on the
rail. The wordmark is now a real anchor that navigates home.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the standalone search button from season and episode rows; the
deck is the one control. An empty deck fires a targeted sweep on
open and reports progress in place; a deck with results never sweeps
on open. re-search inside the deck forces a fresh sweep.
Drops #master-verdict entirely - element, .rail-verdict rules and every
line that wrote into it. The lamp is the only header signal; the
unreachable detail moves onto the board's arr module so nothing is lost.
Rail contents move into .rail-inner capped at the deck's 68rem and
centred, leaving the panel full-bleed.
Committed by the blitz orchestrator: the authoring session wedged with
the work complete on disk and stopped accepting input.
DESIGN.md §9.6 no longer carries cast (#163). Removes the cast
sections, the MetadataCastMember schema and field from both metadata
responses, and every .cast-* rule. arr-meta keeps CastMember and the
credits append; the TMDB call is unchanged.
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.
`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
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>