Filter dialog: Language right after Quality

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-25 12:27:12 +01:00
co-authored by Claude Opus 5.5
parent 0fcc5fb7fa
commit 1015135a4b
4 changed files with 9 additions and 7 deletions
+2
View File
@@ -2,6 +2,8 @@
## Unreleased
- **Filter dialog** (Library and release list): Language comes right after Quality, so the two
most used filters are at the top.
- **Downloading episodes in a series' seasons and episodes:** like the Library, the drill-down
marks episodes in Sonarr's download queue with a blue dot and "downloading 45%" as their status
(details: "Downloading 45% · 0:01:40 left"), and seasons with such episodes with a blue dot.
+2 -2
View File
@@ -57,7 +57,7 @@ Notes:
- **Config:** load URLs + API keys from a config file; fail with a clear message if missing or unreachable.
- **Search:** a Movies view (Radarr) and a Series view (Sonarr), each with a search box. Results list with title, year, rating, status, and an "in library" marker. Detail pane with overview, runtime, genres, network/studio.
- **Add:** from a result, open a small form: quality profile, root folder, monitored (yes/no), "search now" (yes/no); for series also monitor mode (all / future / first season / none). Submit calls `POST /movie` or `POST /series` with `addOptions.searchForMovie` / `searchForMissingEpisodes`.
- **Interactive release search:** for a movie (or a series' season/episode) in the library, list releases from indexers (`GET /release`) with title, indexer, size, quality, age, and rejection reasons; sort/filter; grab a chosen one (`POST /release`). Rejected releases can be grabbed only after an explicit confirmation. The list can be filtered by quality, codec (x265/x264/AV1), HDR/DV/SDR, audio format and language; releases carry no media info, so codec and HDR are read from the title, quality and custom formats (a release that does not name its codec never matches a codec filter).
- **Interactive release search:** for a movie (or a series' season/episode) in the library, list releases from indexers (`GET /release`) with title, indexer, size, quality, age, and rejection reasons; sort/filter; grab a chosen one (`POST /release`). Rejected releases can be grabbed only after an explicit confirmation. The list can be filtered by quality, language, codec (x265/x264/AV1), HDR/DV/SDR and audio format; releases carry no media info, so codec and HDR are read from the title, quality and custom formats (a release that does not name its codec never matches a codec filter).
- **Downloads view:** all downloads and queues in one place, auto-refreshing every few seconds:
- SABnzbd queue (name, size, progress, ETA, speed) and history (completed / failed, with retry).
- Radarr and Sonarr queues (status, warnings, import errors), so stuck imports are visible.
@@ -124,7 +124,7 @@ Keybindings (the status bar shows the ones that apply to the current view):
| `/` | Movies, Series, Library: focus the search / text filter |
| `Enter` | Movies, Series: add the selected result (dialog: ↑↓ move, ←→ change dropdowns) |
| `i` | Movies, Series, Library: interactive release search (series: seasons and episodes) |
| `F` | Library and release list: filter by properties (quality, codec, HDR/DV, audio, language) |
| `F` | Library and release list: filter by properties (quality, language, codec, HDR/DV, audio; in this order in the dialog) |
| `f` | Library: cycle the status filter; release list: hide rejected releases |
| `[` `]` `t` `u` | Calendar: week back / forward, today, include unmonitored |
| `d` | Library: remove the item from the library (asks first) |
+2 -2
View File
@@ -35,7 +35,7 @@ var helpSections = []helpSection{
{title: "Library", note: "The dot before a title: green when monitored, grey hollow when not, blue while it is in the Radarr/Sonarr download queue (the details say how far).", items: []helpItem{
{"Tab", "switch between the movies and series lists"},
{"f", "cycle the status filter (all, missing, downloaded, monitored, unmonitored); every list has its own filters"},
{"F", "filter by file properties: quality, codec (x265, x264, AV1), HDR / DV / SDR, audio (Atmos, TrueHD, DTS, DD+ ...), language. Changes apply live behind the dialog, also while you move through an open list; Esc undoes them. Options that would leave no results are not offered. Series files are read on demand."},
{"F", "filter by file properties: quality, language, codec (x265, x264, AV1), HDR / DV / SDR, audio (Atmos, TrueHD, DTS, DD+ ...). Changes apply live behind the dialog, also while you move through an open list; Esc undoes them. Options that would leave no results are not offered. Series files are read on demand."},
{"/", "text filter for the focused list only; each list keeps its own text (Enter or Esc returns to the list)"},
{"t", "toggle monitored"},
{"d", "remove from the library (files are kept unless you tick \"Delete files\")"},
@@ -59,7 +59,7 @@ var helpSections = []helpSection{
{"Enter, g", "grab the selected release"},
{"s", "cycle the sort (best, size, age)"},
{"f", "hide rejected releases"},
{"F", "filter by quality, codec, HDR / DV, audio, language (read from the release title, quality and custom formats)"},
{"F", "filter by quality, language, codec, HDR / DV, audio (read from the release title, quality and custom formats)"},
}},
{title: "Downloads", items: []helpItem{
{"p", "pause / resume the SABnzbd queue"},
+3 -3
View File
@@ -129,10 +129,10 @@ func staticOptions(o []string) func(filterPool) []string {
var facetDefs = []facet{
{"Quality", staticOptions(resOptions), func(f attrFilter) string { return f.res }, func(f attrFilter, v string) attrFilter { f.res = v; return f }, nil, nil},
{"Language", filterPool.languages, func(f attrFilter) string { return f.lang }, func(f attrFilter, v string) attrFilter { f.lang = v; return f }, nil, nil},
{"Codec", staticOptions(codecOptions), func(f attrFilter) string { return f.codec }, func(f attrFilter, v string) attrFilter { f.codec = v; return f }, nil, nil},
{"HDR", staticOptions(hdrOptions), func(f attrFilter) string { return f.hdr }, func(f attrFilter, v string) attrFilter { f.hdr = v; return f }, nil, nil},
{"Audio", staticOptions(audioOptions), func(f attrFilter) string { return f.audio }, func(f attrFilter, v string) attrFilter { f.audio = v; return f }, nil, nil},
{"Language", filterPool.languages, func(f attrFilter) string { return f.lang }, func(f attrFilter, v string) attrFilter { f.lang = v; return f }, nil, nil},
}
// listedValues returns the options a facet offers: those that, together with
@@ -153,8 +153,8 @@ func listedValues(f facet, state attrFilter, pool filterPool) []string {
return vals
}
// openAttrFilter shows the dialog to pick quality, codec, HDR, audio and
// language. Every change is passed to set immediately so the list behind the
// openAttrFilter shows the dialog to pick quality, language, codec, HDR and
// audio (the most used first). Every change is passed to set immediately so the list behind the
// dialog follows along, also while moving through an open list; Cancel and Esc
// restore cur. Entries that would leave no results are not offered. The
// returned function re-evaluates them when the pool has changed; onClose runs