Upgrade all outbound Discord surfaces (personal webhooks, bot DMs, server channels, request events) from bare title/description embeds to rich ones: poster thumbnail, overview teaser, TMDB/IMDb/TVDB links, rating and genre fields, content-rating footer, and a clickable title URL. Artwork respects the v1 privacy contract via a new admin poster mode (notifications.discord.poster_mode): "provider" (default) only emits public provider-CDN URLs, "server" additionally presigns locally cached posters from this server's image storage, "off" drops images entirely. Builders never derive artwork URLs themselves; the sender layer resolves PosterURL through System.discordPosterURL. To keep provider-CDN URLs derivable after image caching rewrites poster_path to a local storage key, media_items gains poster_source_path, captured during cacheItemImages, preserved across refreshes that keep the cached poster, and cleared on explicit poster overrides. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
58 lines
2.0 KiB
Go
58 lines
2.0 KiB
Go
package metadata
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/Silo-Server/silo-server/internal/models"
|
|
)
|
|
|
|
type stubImageCacher struct{}
|
|
|
|
func (stubImageCacher) CacheImage(_ context.Context, req CacheImageRequest) (*CacheImageResult, error) {
|
|
return &CacheImageResult{
|
|
BasePath: req.ProviderID + "/" + req.ContentType + "/" + req.ContentID + "/poster",
|
|
Thumbhash: "hash",
|
|
Ext: ".jpg",
|
|
}, nil
|
|
}
|
|
|
|
// Caching rewrites poster_path to a local storage key; the provider-origin
|
|
// path must survive in PosterSourcePath so outbound notification embeds can
|
|
// keep building public provider-CDN URLs.
|
|
func TestCacheItemImagesKeepsPosterSourcePath(t *testing.T) {
|
|
s := &MetadataService{imageCacher: stubImageCacher{}}
|
|
item := &models.MediaItem{
|
|
Type: "series",
|
|
TmdbID: "95396",
|
|
PosterPath: "https://image.tmdb.org/t/p/original/severance.jpg",
|
|
}
|
|
s.cacheItemImages(context.Background(), item, []RemoteImage{
|
|
{URL: item.PosterPath, ProviderID: "tmdb", Type: ImagePoster},
|
|
})
|
|
if item.PosterSourcePath != "https://image.tmdb.org/t/p/original/severance.jpg" {
|
|
t.Fatalf("provider poster path not preserved, got %q", item.PosterSourcePath)
|
|
}
|
|
if item.PosterPath != "tmdb/series/95396/poster/original.jpg" {
|
|
t.Fatalf("poster path not rewritten to cached key, got %q", item.PosterPath)
|
|
}
|
|
}
|
|
|
|
// Already-cached posters (bare storage keys) produce no cache job, so the
|
|
// source path must not be overwritten and the caller's carry-forward applies.
|
|
func TestCacheItemImagesSkipsBareKeys(t *testing.T) {
|
|
s := &MetadataService{imageCacher: stubImageCacher{}}
|
|
item := &models.MediaItem{
|
|
Type: "series",
|
|
TmdbID: "95396",
|
|
PosterPath: "tmdb/series/95396/poster/original.jpg",
|
|
}
|
|
s.cacheItemImages(context.Background(), item, nil)
|
|
if item.PosterSourcePath != "" {
|
|
t.Fatalf("bare key must not produce a source path, got %q", item.PosterSourcePath)
|
|
}
|
|
if item.PosterPath != "tmdb/series/95396/poster/original.jpg" {
|
|
t.Fatalf("bare key must pass through unchanged, got %q", item.PosterPath)
|
|
}
|
|
}
|