Posters: fetch TheMovieDB images at the shown size, not the original
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- **Posters of titles not in the library load faster:** they are fetched from TheMovieDB at the
|
||||
size shown (780 pixels wide for real images) instead of the original Radarr names, which is often
|
||||
2000×3000 and over 2 MB: about a tenth of the download and a sixth of the decoding time.
|
||||
- **Real-image posters fill their box in every terminal:** they are scaled to the exact pixel size
|
||||
of their cells before they are sent. Ghostty shows an image that is smaller than its place at its
|
||||
own size, so library posters (Radarr's copy is only 333×500, not 500×750 as assumed in 0.4.0)
|
||||
|
||||
+22
-2
@@ -35,7 +35,7 @@ func (c *Client) Poster(images []Image, inLibrary bool) (key string, fetch func(
|
||||
if err != nil && remote != "" {
|
||||
// The instance has no usable copy (not cached, or behind a login):
|
||||
// use the metadata provider's, as for titles not in the library.
|
||||
if remoteData, remoteErr := FetchURL(ctx, remote); remoteErr == nil {
|
||||
if remoteData, remoteErr := FetchURL(ctx, tmdbSized(remote, large)); remoteErr == nil {
|
||||
return remoteData, nil
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,9 @@ func (c *Client) Poster(images []Image, inLibrary bool) (key string, fetch func(
|
||||
}
|
||||
if img.RemoteURL != "" {
|
||||
remote := img.RemoteURL
|
||||
return remote, func(ctx context.Context, _ bool) ([]byte, error) { return FetchURL(ctx, remote) }, true
|
||||
return remote, func(ctx context.Context, large bool) ([]byte, error) {
|
||||
return FetchURL(ctx, tmdbSized(remote, large))
|
||||
}, true
|
||||
}
|
||||
}
|
||||
return "", nil, false
|
||||
@@ -84,6 +86,24 @@ func (c *Client) localPoster(ctx context.Context, local string, large bool) ([]b
|
||||
return try(local)
|
||||
}
|
||||
|
||||
// tmdbSized asks TheMovieDB for a poster of the size that is shown instead of
|
||||
// the original Radarr hands out (often 2000×3000 and over 2 MB, which takes
|
||||
// longer to download and to decode than everything else together): 780
|
||||
// pixels wide for real images, 342 for block characters. Other URLs are
|
||||
// returned as they are.
|
||||
func tmdbSized(rawURL string, large bool) string {
|
||||
u, err := url.Parse(rawURL)
|
||||
if err != nil || u.Host != "image.tmdb.org" || !strings.HasPrefix(u.Path, "/t/p/original/") {
|
||||
return rawURL
|
||||
}
|
||||
size := "w342"
|
||||
if large {
|
||||
size = "w780"
|
||||
}
|
||||
u.Path = "/t/p/" + size + strings.TrimPrefix(u.Path, "/t/p/original")
|
||||
return u.String()
|
||||
}
|
||||
|
||||
// scaledVariant turns /MediaCover/1/poster.jpg?x into
|
||||
// /MediaCover/1/poster-250.jpg?x (for width 250; Radarr and Sonarr keep 250
|
||||
// and 500).
|
||||
|
||||
@@ -8,6 +8,23 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTMDBSized(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
in string
|
||||
large bool
|
||||
want string
|
||||
}{
|
||||
{"https://image.tmdb.org/t/p/original/abc.jpg", true, "https://image.tmdb.org/t/p/w780/abc.jpg"},
|
||||
{"https://image.tmdb.org/t/p/original/abc.jpg", false, "https://image.tmdb.org/t/p/w342/abc.jpg"},
|
||||
{"https://image.tmdb.org/t/p/w500/abc.jpg", true, "https://image.tmdb.org/t/p/w500/abc.jpg"},
|
||||
{"https://artworks.thetvdb.com/banners/posters/1.jpg", true, "https://artworks.thetvdb.com/banners/posters/1.jpg"},
|
||||
} {
|
||||
if got := tmdbSized(tc.in, tc.large); got != tc.want {
|
||||
t.Errorf("tmdbSized(%q, %v) = %q, want %q", tc.in, tc.large, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestScaledVariant(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
in string
|
||||
|
||||
Reference in New Issue
Block a user