Swap the Config and Log views (F6 Config, F7 Log)

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-20 23:37:17 +02:00
co-authored by Claude Sonnet 5.5
parent fbf33e076b
commit 394e78ec6a
5 changed files with 22 additions and 22 deletions
+4 -4
View File
@@ -2,16 +2,16 @@
## Unreleased ## Unreleased
- **Config (F7):** edit the settings of the config file inside the program (addresses, API keys, - **Config (F6):** edit the settings of the config file inside the program (addresses, API keys,
add-form defaults, refresh interval, posters, notifications), test the connections, save, and add-form defaults, refresh interval, posters, notifications), test the connections, save, and
have everything take effect immediately. Environment-provided values are never written to the file. have everything take effect immediately. Environment-provided values are never written to the file.
The Log is now on F6. The Log is now on F7.
- **Posters as real images** in kitty and Ghostty (Kitty graphics protocol with Unicode - **Posters as real images** in kitty and Ghostty (Kitty graphics protocol with Unicode
placeholders), at the terminal's full resolution and with the right aspect ratio. Other terminals placeholders), at the terminal's full resolution and with the right aspect ratio. Other terminals
keep the block-character posters, using sextants when fontconfig finds a font with the glyphs keep the block-character posters, using sextants when fontconfig finds a font with the glyphs
(e.g. GNOME Terminal with Adwaita Mono) and quadrants otherwise. `ui.cover_style` gains `kitty`; `auto` is the default. (e.g. GNOME Terminal with Adwaita Mono) and quadrants otherwise. `ui.cover_style` gains `kitty`; `auto` is the default.
- **Calendar (F5):** two weeks of movie releases and airing episodes grouped by day, with poster, - **Calendar (F5):** two weeks of movie releases and airing episodes grouped by day, with poster,
plot, release search and automatic search. The Log moves to F6. plot, release search and automatic search. The Log moves to F7.
- **Download notifications:** popup and log entry when a SABnzbd download finishes or fails, in the - **Download notifications:** popup and log entry when a SABnzbd download finishes or fails, in the
background (`ui.notify_downloads`, optional `ui.bell`). background (`ui.notify_downloads`, optional `ui.bell`).
- **Remove from the library** (`d`), with separate checkboxes for deleting the files and for the - **Remove from the library** (`d`), with separate checkboxes for deleting the files and for the
@@ -35,7 +35,7 @@ First release.
- **Downloads:** SABnzbd queue and history plus the Radarr and Sonarr queues; pause/resume, delete, - **Downloads:** SABnzbd queue and history plus the Radarr and Sonarr queues; pause/resume, delete,
retry, remove and blocklist. retry, remove and blocklist.
- **Posters:** a thumbnail at the top right of the detail panes with the text flowing around it (quadrant or, on capable terminals, sextant block rendering; `ui.cover_style`). - **Posters:** a thumbnail at the top right of the detail panes with the text flowing around it (quadrant or, on capable terminals, sextant block rendering; `ui.cover_style`).
- **Log (F6) and popups:** feedback appears as fading popups; the log keeps the history. - **Log (F7) and popups:** feedback appears as fading popups; the log keeps the history.
- Connection indicators for all three services, context-sensitive key hints, `?` help. - Connection indicators for all three services, context-sensitive key hints, `?` help.
- JSON config with environment overrides (`ARR_TUI_*`), `--version`, cross-platform builds - JSON config with environment overrides (`ARR_TUI_*`), `--version`, cross-platform builds
(`make dist`). (`make dist`).
+3 -3
View File
@@ -26,12 +26,12 @@ A terminal UI to search for movies and series with [Radarr](https://radarr.video
for releases or start an automatic search from there. for releases or start an automatic search from there.
- **Downloads**: SABnzbd queue and history plus the Radarr/Sonarr queues. Pause/resume, delete, - **Downloads**: SABnzbd queue and history plus the Radarr/Sonarr queues. Pause/resume, delete,
retry failed downloads, remove from the arr queue and blocklist. retry failed downloads, remove from the arr queue and blocklist.
- **Config (F7)**: edit everything in the config file from inside the program: service addresses - **Config (F6)**: edit everything in the config file from inside the program: service addresses
and API keys, the add-form defaults, refresh interval, posters, notifications. *Test connections* and API keys, the add-form defaults, refresh interval, posters, notifications. *Test connections*
checks the values you typed before saving; *Save* writes the file (permissions kept, `0600` for a checks the values you typed before saving; *Save* writes the file (permissions kept, `0600` for a
new file) and applies the changes at once, no restart. Values that come from `ARR_TUI_*` new file) and applies the changes at once, no restart. Values that come from `ARR_TUI_*`
environment variables are greyed out and are never written to the file. environment variables are greyed out and are never written to the file.
- **Log (F6)**: actions report through popups that fade away; the log keeps the history. - **Log (F7)**: actions report through popups that fade away; the log keeps the history.
- **Download notifications**: a popup (and a log entry) when a SABnzbd download finishes or fails, - **Download notifications**: a popup (and a log entry) when a SABnzbd download finishes or fails,
whichever view is open. SABnzbd's history is checked every 15 seconds; downloads that finished whichever view is open. SABnzbd's history is checked every 15 seconds; downloads that finished
before arr-tui started are not announced. `"ui": {"notify_downloads": false}` turns it off, before arr-tui started are not announced. `"ui": {"notify_downloads": false}` turns it off,
@@ -72,7 +72,7 @@ Keep the file private (`chmod 600`); it holds your API keys.
| Key | Action | | Key | Action |
|---|---| |---|---|
| `F1`–`F7` | switch view (Movies, Series, Library, Downloads, Calendar, Log, Config) | | `F1`–`F7` | switch view (Movies, Series, Library, Downloads, Calendar, Config, Log) |
| `Tab`, `Shift+Tab` | switch panel within a view | | `Tab`, `Shift+Tab` | switch panel within a view |
| `?` / `F9` | help | | `?` / `F9` | help |
| `/` | focus search box | | `/` | focus search box |
+6 -6
View File
@@ -69,8 +69,8 @@ Notes:
Posters are JPEG/PNG, decoded and downscaled in the process. Library items fetch `/MediaCover/<id>/poster-250.jpg` from their Radarr/Sonarr instance with the API key; search results fall back to the provider's `remoteUrl` (fetched without credentials). Posters are cached in memory (the terminal's copies are deleted when the cache is dropped and on exit), failed downloads are not retried for two minutes, and the poster shrinks or disappears when the pane is too short. `ui.covers: false` disables it. Posters are JPEG/PNG, decoded and downscaled in the process. Library items fetch `/MediaCover/<id>/poster-250.jpg` from their Radarr/Sonarr instance with the API key; search results fall back to the provider's `remoteUrl` (fetched without credentials). Posters are cached in memory (the terminal's copies are deleted when the cache is dropped and on exit), failed downloads are not retried for two minutes, and the poster shrinks or disappears when the pane is too short. `ui.covers: false` disables it.
- **Calendar view (F5):** a two-week window (starting today, moved a week at a time with `[`/`]`, `t` returns to today) with the library's movie releases and airing episodes, grouped by day. Radarr `GET /calendar` supplies the cinema, digital and physical release dates (taken as written: midnight UTC means that calendar day) and Sonarr `GET /calendar?includeSeries=true` the episodes with their air time (shown in local time). Unmonitored items are included with `u`. A movie appears once per release date in the window. Each entry shows type, title, episode or release kind and status (downloaded / missing / upcoming); the detail pane shows poster and plot; `Enter`/`i` starts the release search and `s` an automatic search. - **Calendar view (F5):** a two-week window (starting today, moved a week at a time with `[`/`]`, `t` returns to today) with the library's movie releases and airing episodes, grouped by day. Radarr `GET /calendar` supplies the cinema, digital and physical release dates (taken as written: midnight UTC means that calendar day) and Sonarr `GET /calendar?includeSeries=true` the episodes with their air time (shown in local time). Unmonitored items are included with `u`. A movie appears once per release date in the window. Each entry shows type, title, episode or release kind and status (downloaded / missing / upcoming); the detail pane shows poster and plot; `Enter`/`i` starts the release search and `s` an automatic search.
- **Download notifications:** a background poller (independent of the visible view) reads SABnzbd's history every 15 s and announces downloads that reach `Completed` or `Failed` as a popup and log entry; the first poll only records the current state. `ui.notify_downloads` (default true) and `ui.bell` (default false, rings the terminal bell) control it. Connection errors are not reported here, the indicators and the log already do that. - **Download notifications:** a background poller (independent of the visible view) reads SABnzbd's history every 15 s and announces downloads that reach `Completed` or `Failed` as a popup and log entry; the first poll only records the current state. `ui.notify_downloads` (default true) and `ui.bell` (default false, rings the terminal bell) control it. Connection errors are not reported here, the indicators and the log already do that.
- **Config view (F7):** a form for every setting of the config file, in four sections (Radarr, Sonarr, SABnzbd, Interface) plus Test connections / Save / Revert. The fields start from the settings in use; API keys are masked (a checkbox shows them). `Test connections` builds temporary clients from the typed values and reports each service. `Save` validates like startup does (URLs, non-empty keys, refresh 1–3600 s), then writes the file from the file's own contents plus the edits (`config.LoadFile`), so values that only come from `ARR_TUI_*` environment variables are left as the file has them and are shown greyed out; the write is atomic (temp file + rename) and keeps the file's permissions (`0600` when new); defaults such as `covers: true` stay out of the file unless it already named them. Everything then applies without a restart: the Radarr/Sonarr/SABnzbd clients are re-pointed (`Reconfigure`, guarded by a mutex), the connection indicators, add-form defaults and options are refreshed, the library and calendar reload, the Downloads interval, notifications, bell and poster style are switched live. `q` and `?` are typed text in this view (`F9` opens the help). - **Config view (F6):** a form for every setting of the config file, in four sections (Radarr, Sonarr, SABnzbd, Interface) plus Test connections / Save / Revert. The fields start from the settings in use; API keys are masked (a checkbox shows them). `Test connections` builds temporary clients from the typed values and reports each service. `Save` validates like startup does (URLs, non-empty keys, refresh 1–3600 s), then writes the file from the file's own contents plus the edits (`config.LoadFile`), so values that only come from `ARR_TUI_*` environment variables are left as the file has them and are shown greyed out; the write is atomic (temp file + rename) and keeps the file's permissions (`0600` when new); defaults such as `covers: true` stay out of the file unless it already named them. Everything then applies without a restart: the Radarr/Sonarr/SABnzbd clients are re-pointed (`Reconfigure`, guarded by a mutex), the connection indicators, add-form defaults and options are refreshed, the library and calendar reload, the Downloads interval, notifications, bell and poster style are switched live. `q` and `?` are typed text in this view (`F9` opens the help).
- **Notifications and log (F6):** feedback about actions (added, deleted, grabbed, failures) appears as popups in the bottom right that fade away (errors stay longer). Everything is also kept in the Log view; only connection changes of the background polling are logged, not every failed poll. - **Notifications and log (F7):** feedback about actions (added, deleted, grabbed, failures) appears as popups in the bottom right that fade away (errors stay longer). Everything is also kept in the Log view; only connection changes of the background polling are logged, not every failed poll.
### 4.2 v0.2 (done, M8) ### 4.2 v0.2 (done, M8)
@@ -101,7 +101,7 @@ Layout sketch (Library view; the other views follow the same frame):
└────────────────────────────────────────────────────────────────────┘ └────────────────────────────────────────────────────────────────────┘
``` ```
Popups for action feedback appear in the bottom right and fade away; the Log view (F6) keeps the history. Popups for action feedback appear in the bottom right and fade away; the Log view (F7) keeps the history.
tview primitives: `Pages` (views and stacked overlays), `Flex` (layout), `InputField` (search), `List`/`Table` (results, queues, library), `TextView` (details, log), `Form` (add dialog), `Modal` (confirmations). Popups are drawn by a wrapper around the root primitive. tview primitives: `Pages` (views and stacked overlays), `Flex` (layout), `InputField` (search), `List`/`Table` (results, queues, library), `TextView` (details, log), `Form` (add dialog), `Modal` (confirmations). Popups are drawn by a wrapper around the root primitive.
@@ -109,7 +109,7 @@ Keybindings (the status bar shows the ones that apply to the current view):
| Key | Action | | Key | Action |
|---|---| |---|---|
| `F1-F7` | Switch view (Movies, Series, Library, Downloads, Calendar, Log, Config); also while typing, and from full-screen views. Dialogs block them. | | `F1-F7` | Switch view (Movies, Series, Library, Downloads, Calendar, Config, Log); also while typing, and from full-screen views. Dialogs block them. |
| `Tab` / `Shift+Tab` | Switch panel within the current view (never the view): search box / results, Downloads panels, Library lists | | `Tab` / `Shift+Tab` | Switch panel within the current view (never the view): search box / results, Downloads panels, Library lists |
| `F9` / `?` | Help. `F9` works everywhere; `?` only when no text field has the focus (it is text in search boxes and in the Config view) | | `F9` / `?` | Help. `F9` works everywhere; `?` only when no text field has the focus (it is text in search boxes and in the Config view) |
| `q` / `Ctrl+C` | Quit | | `q` / `Ctrl+C` | Quit |
@@ -205,8 +205,8 @@ The file should be created with mode `0600`; warn if it is more permissive. API
- [x] **M6** — Interactive release search (movies, then series seasons/episodes) and grab. - [x] **M6** — Interactive release search (movies, then series seasons/episodes) and grab.
- [x] **M7** — Polish: help screen (`?`/F9), per-service connection indicators, README, Makefile release builds, `--version`. - [x] **M7** — Polish: help screen (`?`/F9), per-service connection indicators, README, Makefile release builds, `--version`.
- [x] **M8** — Library view (movies/series, filters, text filter, monitor toggle, automatic search) and series drill-down (seasons/episodes, monitoring, search, release search). - [x] **M8** — Library view (movies/series, filters, text filter, monitor toggle, automatic search) and series drill-down (seasons/episodes, monitoring, search, release search).
- [x] **M9** — Popup notifications, Log view (F6), context-sensitive key hints in the status bar. - [x] **M9** — Popup notifications, Log view (F7), context-sensitive key hints in the status bar.
- [x] **M10** — Download completion notifications, remove from library, calendar view (F5; the Log moves to F6). Multiple instances per service are out of scope. - [x] **M10** — Download completion notifications, remove from library, calendar view (F5; the Log moves to F7, after the Config view on F6). Multiple instances per service are out of scope.
- [ ] **M11+** — ideas: more library actions (edit quality profile, root folder), history of grabs per title. - [ ] **M11+** — ideas: more library actions (edit quality profile, root folder), history of grabs per title.
## 10. Open Questions ## 10. Open Questions
+4 -4
View File
@@ -96,7 +96,7 @@ type overlay struct {
page string page string
focus tview.Primitive focus tview.Primitive
hints string hints string
full bool // full-screen view (can be left with F1-F6), as opposed to a dialog full bool // full-screen view (can be left with F1-F7), as opposed to a dialog
close func() // optional cleanup when the overlay is removed close func() // optional cleanup when the overlay is removed
} }
@@ -159,8 +159,8 @@ func New(cfg *config.Config) *App {
{key: '3', name: "Library", body: library.root, onShow: library.activate, hints: libraryHints}, {key: '3', name: "Library", body: library.root, onShow: library.activate, hints: libraryHints},
{key: '4', name: "Downloads", body: downloads.root, onShow: downloads.activate, onHide: downloads.deactivate, hints: downloads.hints}, {key: '4', name: "Downloads", body: downloads.root, onShow: downloads.activate, onHide: downloads.deactivate, hints: downloads.hints},
{key: '5', name: "Calendar", body: calendar.root, onShow: calendar.activate, hints: calendarHints}, {key: '5', name: "Calendar", body: calendar.root, onShow: calendar.activate, hints: calendarHints},
{key: '6', name: "Log", body: a.logs.root, onShow: a.logs.onShow, hints: logHints}, {key: '6', name: "Config", body: settings.root, onShow: settings.activate, hints: settingsHints, captureKeys: true},
{key: '7', name: "Config", body: settings.root, onShow: settings.activate, hints: settingsHints, captureKeys: true}, {key: '7', name: "Log", body: a.logs.root, onShow: a.logs.onShow, hints: logHints},
} }
for i, v := range a.views { for i, v := range a.views {
a.pages.AddPage(v.name, v.body, true, i == 0) a.pages.AddPage(v.name, v.body, true, i == 0)
@@ -502,7 +502,7 @@ func (a *App) handleKey(ev *tcell.EventKey) *tcell.EventKey {
return ev return ev
} }
// viewShortcut returns the view index for F1-F6, or -1. // viewShortcut returns the view index for F1-F7, or -1.
func (a *App) viewShortcut(ev *tcell.EventKey) int { func (a *App) viewShortcut(ev *tcell.EventKey) int {
if ev.Key() >= tcell.KeyF1 && ev.Key() <= tcell.KeyF12 { if ev.Key() >= tcell.KeyF1 && ev.Key() <= tcell.KeyF12 {
return int(ev.Key() - tcell.KeyF1) return int(ev.Key() - tcell.KeyF1)
+5 -5
View File
@@ -64,11 +64,7 @@ const helpText = `[yellow]Global[-]
t retry a failed download (history) t retry a failed download (history)
r refresh now r refresh now
[yellow]Log (F6)[-] [yellow]Config (F6)[-]
Popups fade away by themselves; everything they said is kept here.
↑↓, PgUp/PgDn scroll G follow new entries c clear
[yellow]Config (F7)[-]
Edit the settings of the config file: service addresses and API keys, add-form Edit the settings of the config file: service addresses and API keys, add-form
defaults, refresh interval, posters, notifications. defaults, refresh interval, posters, notifications.
↑↓ move, Tab next section, Space toggles, Enter presses a button ↑↓ move, Tab next section, Space toggles, Enter presses a button
@@ -76,6 +72,10 @@ const helpText = `[yellow]Global[-]
Save writes the file and applies everything at once; Revert discards edits Save writes the file and applies everything at once; Revert discards edits
Letters such as q and ? are typed here; F9 opens this help Letters such as q and ? are typed here; F9 opens this help
[yellow]Log (F7)[-]
Popups fade away by themselves; everything they said is kept here.
↑↓, PgUp/PgDn scroll G follow new entries c clear
[yellow]Connections[-] [yellow]Connections[-]
` `