Library: the text filter only acts on the focused list

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 21:00:56 +02:00
co-authored by Claude Sonnet 5.5
parent cd4e3b8841
commit b0a2c3b4fd
3 changed files with 15 additions and 8 deletions
+1 -1
View File
@@ -67,7 +67,7 @@ Notes:
### 4.2 v0.2 (done, M8) ### 4.2 v0.2 (done, M8)
- **Library view:** movies (top) and series (below) with the details of the selected item on the right; Tab switches between the two lists. Filters (all, missing, downloaded, monitored, unmonitored), a file-property filter (`F`: quality 2160p/1080p/720p/SD, codec x265/x264/AV1, HDR/DV/SDR, audio format Atmos/TrueHD/DTS:X/DTS-HD/DTS/DD+/DD/AAC/FLAC/Opus, audio language; changes apply live to the list behind the dialog, including while moving through an open dropdown, and Esc restores the previous filter; each dropdown only lists options that, together with the other chosen criteria, still match at least one item (series files are read when the dialog opens so this is accurate)) and a text filter apply to both lists. Movie properties come from the movie list; series properties are read per series from `GET /episodefile?seriesId=` only while a property filter is active, cached while a series' file count and size stay the same, and a series matches when any of its files does. `t` toggles monitoring, `s` starts an automatic search, `i`/Enter opens the release search (movies) or the drill-down (series). - **Library view:** movies (top) and series (below) with the details of the selected item on the right; Tab switches between the two lists. Filters (all, missing, downloaded, monitored, unmonitored), a file-property filter (`F`: quality 2160p/1080p/720p/SD, codec x265/x264/AV1, HDR/DV/SDR, audio format Atmos/TrueHD/DTS:X/DTS-HD/DTS/DD+/DD/AAC/FLAC/Opus, audio language; changes apply live to the list behind the dialog, including while moving through an open dropdown, and Esc restores the previous filter; each dropdown only lists options that, together with the other chosen criteria, still match at least one item (series files are read when the dialog opens so this is accurate)) apply to both lists; the text filter (`/`) only acts on the focused list, and each list keeps its own text. Movie properties come from the movie list; series properties are read per series from `GET /episodefile?seriesId=` only while a property filter is active, cached while a series' file count and size stay the same, and a series matches when any of its files does. `t` toggles monitoring, `s` starts an automatic search, `i`/Enter opens the release search (movies) or the drill-down (series).
- **Series drill-down:** seasons and episodes, toggle monitoring per season/episode, trigger season/episode search and release search. - **Series drill-down:** seasons and episodes, toggle monitoring per season/episode, trigger season/episode search and release search.
### 4.3 Later / ideas ### 4.3 Later / ideas
+3 -2
View File
@@ -21,14 +21,15 @@ const helpText = `[yellow]Global[-]
[yellow]Library[-] [yellow]Library[-]
Tab switch between the movies and series lists Tab switch between the movies and series lists
f cycle filter (all, missing, downloaded, monitored, unmonitored); f cycle filter (all, missing, downloaded, monitored, unmonitored);
filters apply to both lists the status and property filters apply to both lists
F filter by file properties: quality, codec (x265, x264, AV1), F filter by file properties: quality, codec (x265, x264, AV1),
HDR / DV / SDR, audio (Atmos, TrueHD, DTS, DD+ ...), language. HDR / DV / SDR, audio (Atmos, TrueHD, DTS, DD+ ...), language.
Changes apply live behind the dialog, also while you move through an Changes apply live behind the dialog, also while you move through an
open list; Esc undoes them. Options that would leave no open list; Esc undoes them. Options that would leave no
results are not offered. results are not offered.
Series are read on demand. Series are read on demand.
/ text filter (Enter or Esc returns to the list) / text filter for the focused list only; each list keeps its
own text (Enter or Esc returns to the list)
t toggle monitored t toggle monitored
s automatic search (series: all missing, asks first) s automatic search (series: all missing, asks first)
i, Enter movie: release search; series: seasons and episodes i, Enter movie: release search; series: seasons and episodes
+11 -5
View File
@@ -182,7 +182,8 @@ type libPane struct {
shown []libItem shown []libItem
loaded bool loaded bool
err error err error
gen int // invalidates stale loads gen int // invalidates stale loads
text string // text filter, set with / while this pane is the current one
} }
// libraryView shows the movies of Radarr above the series of Sonarr, with the // libraryView shows the movies of Radarr above the series of Sonarr, with the
@@ -222,7 +223,7 @@ func newLibraryView(app *App, r *radarr.Client, s *sonarr.Client) *libraryView {
v := &libraryView{ v := &libraryView{
app: app, radarr: r, sonarr: s, app: app, radarr: r, sonarr: s,
header: tview.NewTextView().SetDynamicColors(true), header: tview.NewTextView().SetDynamicColors(true),
input: tview.NewInputField().SetLabel("Filter: ").SetFieldWidth(0), input: tview.NewInputField().SetLabel("Filter Movies: ").SetFieldWidth(0),
details: tview.NewTextView().SetDynamicColors(true).SetWordWrap(true), details: tview.NewTextView().SetDynamicColors(true).SetWordWrap(true),
seriesFiles: map[int]seriesFiles{}, seriesFiles: map[int]seriesFiles{},
@@ -238,6 +239,8 @@ func newLibraryView(app *App, r *radarr.Client, s *sonarr.Client) *libraryView {
p.table.SetInputCapture(v.handleKey) p.table.SetInputCapture(v.handleKey)
p.table.SetFocusFunc(func() { p.table.SetFocusFunc(func() {
v.cur = kind v.cur = kind
v.input.SetLabel("Filter " + kind.String() + ": ")
v.input.SetText(p.text)
p.table.SetBorderColor(tcell.ColorYellow) p.table.SetBorderColor(tcell.ColorYellow)
v.renderDetails() v.renderDetails()
}) })
@@ -252,7 +255,10 @@ func newLibraryView(app *App, r *radarr.Client, s *sonarr.Client) *libraryView {
AddItem(lists, 0, 3, true). AddItem(lists, 0, 3, true).
AddItem(v.details, 0, 2, false), 0, 1, true) AddItem(v.details, 0, 2, false), 0, 1, true)
v.input.SetChangedFunc(func(string) { v.render() }) v.input.SetChangedFunc(func(text string) {
v.pane().text = text // the text filter only acts on the current pane
v.render()
})
v.input.SetDoneFunc(func(tcell.Key) { v.app.app.SetFocus(v.pane().table) }) v.input.SetDoneFunc(func(tcell.Key) { v.app.app.SetFocus(v.pane().table) })
v.render() v.render()
return v return v
@@ -381,7 +387,7 @@ func (v *libraryView) renderPane(p *libPane) {
if r, _ := p.table.GetSelection(); r >= 1 && r <= len(p.shown) { if r, _ := p.table.GetSelection(); r >= 1 && r <= len(p.shown) {
selID = p.shown[r-1].id selID = p.shown[r-1].id
} }
p.shown = filterItems(p.all, v.filter, v.input.GetText(), v.attr) p.shown = filterItems(p.all, v.filter, p.text, v.attr)
p.table.Clear() p.table.Clear()
header(p.table, 0, "Title", "Status", "Size") header(p.table, 0, "Title", "Status", "Size")
@@ -511,7 +517,7 @@ func (v *libraryView) openFilterDialog() {
func (v *libraryView) filterPool() filterPool { func (v *libraryView) filterPool() filterPool {
var p filterPool var p filterPool
for _, pane := range v.panes { for _, pane := range v.panes {
for _, it := range filterItems(pane.all, v.filter, v.input.GetText(), attrFilter{}) { for _, it := range filterItems(pane.all, v.filter, pane.text, attrFilter{}) {
if !it.attrsKnown { if !it.attrsKnown {
p.unknown = true p.unknown = true
} }