mirror of
https://github.com/streamyfin/streamyfin.git
synced 2026-06-28 00:30:30 +01:00
feat(appearance): episode images for Next Up & Continue Watching
- Fix black episode thumbnails in the Next Up / Continue Watching rows: build the parent Thumb URL from the matched ParentThumbItemId + ParentThumbImageTag pair, instead of pairing ParentBackdropItemId with the thumb tag (different parent -> 404 -> black). Fixed on mobile (ContinueWatchingPoster) and TV (TVPosterCard, TVHeroCarousel). - Add a "Use episode images for Next Up & Continue Watching" setting (default off = series image, matching Jellyfin), wired into the home rows on mobile and TV. - Add helper descriptions under the Appearance settings rows.
This commit is contained in:
@@ -70,6 +70,9 @@ export interface TVPosterCardProps {
|
||||
|
||||
/** Custom image URL getter - if not provided, uses smart URL logic */
|
||||
imageUrlGetter?: (item: BaseItemDto) => string | undefined;
|
||||
|
||||
/** For horizontal episodes, prefer the episode's own image over the series thumb */
|
||||
preferEpisodeImage?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -106,6 +109,7 @@ export const TVPosterCard: React.FC<TVPosterCardProps> = ({
|
||||
glowColor = "white",
|
||||
scaleAmount = 1.05,
|
||||
imageUrlGetter,
|
||||
preferEpisodeImage = false,
|
||||
}) => {
|
||||
const { t } = useTranslation();
|
||||
const api = useAtomValue(apiAtom);
|
||||
@@ -138,9 +142,14 @@ export const TVPosterCard: React.FC<TVPosterCardProps> = ({
|
||||
if (orientation === "horizontal") {
|
||||
// Episode: prefer series thumb image for consistent look (like hero section)
|
||||
if (item.Type === "Episode") {
|
||||
// First try parent/series thumb (horizontal series artwork)
|
||||
if (item.ParentBackdropItemId && item.ParentThumbImageTag) {
|
||||
return `${api.basePath}/Items/${item.ParentBackdropItemId}/Images/Thumb?fillHeight=700&quality=80&tag=${item.ParentThumbImageTag}`;
|
||||
// Opt-in: use the episode's own image instead of the series thumb.
|
||||
if (preferEpisodeImage && item.ImageTags?.Primary) {
|
||||
return `${api.basePath}/Items/${item.Id}/Images/Primary?fillHeight=600&quality=80&tag=${item.ImageTags.Primary}`;
|
||||
}
|
||||
// First try parent/series thumb (horizontal series artwork).
|
||||
// Matched pair: ParentThumbItemId owns the Thumb tag, not ParentBackdropItemId.
|
||||
if (item.ParentThumbItemId && item.ParentThumbImageTag) {
|
||||
return `${api.basePath}/Items/${item.ParentThumbItemId}/Images/Thumb?fillHeight=700&quality=80&tag=${item.ParentThumbImageTag}`;
|
||||
}
|
||||
// Fall back to episode's own primary image
|
||||
if (item.ImageTags?.Primary) {
|
||||
@@ -172,7 +181,7 @@ export const TVPosterCard: React.FC<TVPosterCardProps> = ({
|
||||
item,
|
||||
width: width * 2, // 2x for quality on large screens
|
||||
});
|
||||
}, [api, item, orientation, width, imageUrlGetter]);
|
||||
}, [api, item, orientation, width, imageUrlGetter, preferEpisodeImage]);
|
||||
|
||||
// Progress calculation
|
||||
const progress = useMemo(() => {
|
||||
|
||||
Reference in New Issue
Block a user