Files
arr-tui/internal/ui/configapply.go
T
nilsandClaude Opus 5.5 1056846a48 Keep posters and casts between runs
Posters (the downloaded bytes, per size, 30 days, at most 200 MB) and
casts (people.json, 7 days, at most 2000) are stored in the user's cache
directory (os.UserCacheDir()/arr-tui) and used on the next start before
asking the servers. Expired posters are pruned at startup, casts are
written shortly after new ones arrive and on exit. Tests turn the cache
off.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 10:35:02 +02:00

92 lines
2.8 KiB
Go

package ui
import (
"os"
"time"
"git.stinnesbeck.com/nils/arr-tui/internal/config"
)
// SetConfigSource tells the app which file the settings came from and what that
// file contains, so the Config view can save changes. raw is the file as
// written (see config.LoadFile), not the effective settings.
func (a *App) SetConfigSource(path string, raw *config.Config) {
a.cfgPath, a.cfgFile = path, raw
if a.settings != nil {
a.settings.describe()
}
}
// applyConfig puts new settings into effect without a restart.
func (a *App) applyConfig(c *config.Config) {
old := a.cfg
a.cfg = c
if old.Radarr.Service != c.Radarr.Service || old.Sonarr.Service != c.Sonarr.Service || old.SABnzbd != c.SABnzbd {
a.radarr.Reconfigure(c.Radarr.URL, c.Radarr.APIKey)
a.sonarr.Reconfigure(c.Sonarr.URL, c.Sonarr.APIKey)
a.sab.Reconfigure(c.SABnzbd.URL, c.SABnzbd.APIKey)
a.probeAll() // the indicators, right away
for _, f := range a.reconnect {
f()
}
}
if old.Trakt.ClientID != c.Trakt.ClientID {
a.trakt.Reconfigure(c.Trakt.ClientID)
a.people.failed = map[string]time.Time{} // casts do not depend on the client ID; failures may
for _, p := range a.panes {
p.castKey = "" // ask again the next time a title is shown
}
}
if old.Trakt.ClientID != c.Trakt.ClientID || old.Radarr.Service != c.Radarr.Service || old.Sonarr.Service != c.Sonarr.Service {
for _, v := range a.searches {
v.forgetLists()
}
}
if old.UI.RefreshSeconds != c.UI.RefreshSeconds {
a.downloads.setInterval(time.Duration(c.UI.RefreshSeconds) * time.Second)
}
a.bell = c.UI.Bell
if old.UI.Theme != c.UI.Theme {
a.setTheme(chooseTheme(c.UI.Theme, terminalAnswers()))
}
if c.UI.ShouldNotifyDownloads() != a.notifyDone {
a.setNotifyDownloads(c.UI.ShouldNotifyDownloads())
}
if old.UI.ShowCovers() != c.UI.ShowCovers() || old.UI.CoverStyle != c.UI.CoverStyle {
a.covers = c.UI.ShowCovers()
a.restyleCovers()
}
}
// restyleCovers applies a changed poster style or switch to every detail pane.
func (a *App) restyleCovers() {
blocks, graphics := resolveCovers(a.cfg.UI.CoverStyle, os.Getenv)
if a.gfx != nil {
a.gfx.deleteAll() // the terminal's copies belong to the old images
}
a.coverStyle = blocks
switch {
case graphics && a.gfx == nil:
a.gfx = a.newGraphics()
case !graphics:
a.gfx = nil
}
a.coverCache = newCoverCache() // stored copies depend on the style (their height)
for _, p := range a.panes {
p.cover.style, p.cover.gfx = blocks, a.gfx
p.cover.cells = nil
p.Show(p.detail, p.lastRef) // fetch the poster again for the new style
}
}
// forgetPane drops a detail pane that is no longer shown (a closed drill-down).
func (a *App) forgetPane(d *detailPane) {
for i, p := range a.panes {
if p == d {
a.panes = append(a.panes[:i], a.panes[i+1:]...)
return
}
}
}