Real-image posters: scale to the box's pixel size

Ghostty shows an image smaller than its placement at its own size, so
library posters (Radarr's poster-500 is 333x500, not 500x750) came out
smaller than the 426x640 remote ones. Images are now scaled (bilinear)
to exactly cols*cellWidth x rows*cellHeight pixels before upload, and
library titles use the original poster for real images. The disk cache
stores posters as decoded (JPEG) instead of the possibly large originals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 11:25:45 +02:00
co-authored by Claude Opus 5.5
parent 786e783951
commit 15e97f4582
8 changed files with 100 additions and 25 deletions
+19 -5
View File
@@ -32,11 +32,12 @@ type view struct {
// App is the top-level arr-tui application.
type App struct {
app *tview.Application
theme theme // the colors in use
trakt *trakt.Client // trending, most watched and anticipated lists, casts
people *peopleCache // casts loaded from Trakt
disk *diskCache // posters and casts kept between runs
cellW, cellH int // size of a terminal cell in pixels, 0 if unknown
app *tview.Application
theme theme // the colors in use
trakt *trakt.Client // trending, most watched and anticipated lists, casts
people *peopleCache // casts loaded from Trakt
disk *diskCache // posters and casts kept between runs
// Called (on the UI goroutine) a moment after a release was grabbed.
afterGrab []func()
// The Movies and Series views, to refresh their Trakt lists.
@@ -218,6 +219,7 @@ func New(cfg *config.Config) *App {
s.HideCursor()
a.screen = s
a.cellAspect = cellAspectOf(s)
a.cellW, a.cellH = cellPixelsOf(s)
a.noteWindow(s)
return false
})
@@ -240,6 +242,7 @@ func New(cfg *config.Config) *App {
// helps to find out why a poster is drawn wrongly in some terminal.
func (a *App) newGraphics() *kittyGraphics {
k := newKittyGraphics(a.writeTerminal)
k.cellPixels = func() (int, int) { return a.cellW, a.cellH }
switch v := os.Getenv("ARR_TUI_DEBUG_GFX"); {
case v == "":
case strings.Contains(v, "/"):
@@ -298,6 +301,17 @@ func (a *App) writeTerminal(b []byte) error {
// cellAspectOf measures the height of a terminal cell divided by its width in
// pixels; 2 when the terminal does not report pixel sizes.
// cellPixelsOf returns the size of a terminal cell in pixels, 0, 0 when the
// terminal does not say.
func cellPixelsOf(s tcell.Screen) (w, h int) {
if tty, ok := s.Tty(); ok {
if ws, err := tty.WindowSize(); err == nil && ws.Width > 0 && ws.Height > 0 {
return ws.PixelWidth / ws.Width, ws.PixelHeight / ws.Height
}
}
return 0, 0
}
func cellAspectOf(s tcell.Screen) float64 {
if tty, ok := s.Tty(); ok {
if ws, err := tty.WindowSize(); err == nil {