Stop replacing working FAAB thumbs with Gracenote URLs that 404, and only enrich highlights after verifying EventImages exist.
98 lines
3.2 KiB
TypeScript
98 lines
3.2 KiB
TypeScript
/**
|
|
* Category backdrop fallbacks when an event has no real cover art.
|
|
* Served from /assets/event-fallbacks/{sport}.jpg on master-api.
|
|
*/
|
|
|
|
import { isChannelLogoUrl, isLiveChannelThumb, type EnrichableEvent } from "./ziggo-epg-art";
|
|
|
|
const FALLBACK_FILE: Record<string, string> = {
|
|
football: "football.jpg",
|
|
racing: "racing.jpg",
|
|
tennis: "tennis.jpg",
|
|
golf: "golf.jpg",
|
|
darts: "darts.jpg",
|
|
snooker: "snooker.jpg",
|
|
basketball: "basketball.jpg",
|
|
waterpolo: "waterpolo.jpg",
|
|
sailing: "sailing.jpg",
|
|
hockey: "hockey.jpg",
|
|
cycling: "cycling.jpg",
|
|
other: "other.jpg",
|
|
};
|
|
|
|
export function fallbackFilenameForSport(sport: string | null | undefined): string {
|
|
const s = (sport || "other").toLowerCase();
|
|
return FALLBACK_FILE[s] ?? FALLBACK_FILE.other;
|
|
}
|
|
|
|
export function eventFallbackUrl(publicBase: string, sport: string | null | undefined): string {
|
|
const base = publicBase.replace(/\/+$/, "");
|
|
return `${base}/assets/event-fallbacks/${fallbackFilenameForSport(sport)}`;
|
|
}
|
|
|
|
export function isCategoryFallbackUrl(url: string | null | undefined): boolean {
|
|
if (!url) return false;
|
|
return /\/assets\/event-fallbacks\/[a-z]+\.jpg(\?|$)/i.test(url);
|
|
}
|
|
|
|
/** True when landscape is missing or only a channel logo (not usable cover). */
|
|
export function needsCategoryFallback(e: {
|
|
name?: string | null;
|
|
imageLandscape?: string | null;
|
|
images?: string[];
|
|
}): boolean {
|
|
const land = e.imageLandscape;
|
|
if (!land) return true;
|
|
// FAAB live channel thumbs are real card art — keep them.
|
|
// Highlights/replays with a live snap are wrong sport; treat as weak.
|
|
if (isLiveChannelThumb(land)) {
|
|
return /\b(samenvatting|hoogtepunten|highlights?|herhaling|replay)\b/i.test(
|
|
e.name ?? ""
|
|
);
|
|
}
|
|
if (isChannelLogoUrl(land)) return true;
|
|
if (isCategoryFallbackUrl(land)) return false;
|
|
// Already has real art
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Fill empty/weak covers with sport-category backdrops and preserve channel logos in logoUrl.
|
|
*/
|
|
export function applyCategoryFallbacks<T extends EnrichableEvent & { provider?: string; sportBucket?: string }>(
|
|
events: T[],
|
|
publicBase: string
|
|
): T[] {
|
|
if (!publicBase) return events;
|
|
return events.map((e) => {
|
|
if (!needsCategoryFallback(e)) {
|
|
// Still ensure logoUrl when we only have channel logo in images
|
|
if (!e.logoUrl) {
|
|
const logo = e.images.find((u) => isChannelLogoUrl(u));
|
|
if (logo) return { ...e, logoUrl: logo };
|
|
}
|
|
return e;
|
|
}
|
|
|
|
const fallback = eventFallbackUrl(publicBase, e.sportBucket);
|
|
const logoFromImages = e.images.find((u) => isChannelLogoUrl(u) && !isLiveChannelThumb(u));
|
|
const logoFromLandscape =
|
|
e.imageLandscape && isChannelLogoUrl(e.imageLandscape) ? e.imageLandscape : null;
|
|
const logoUrl = e.logoUrl || logoFromLandscape || logoFromImages || null;
|
|
|
|
const cleaned = e.images.filter(
|
|
(u) => !isLiveChannelThumb(u) && !isCategoryFallbackUrl(u)
|
|
);
|
|
const images = [fallback, ...cleaned.filter((u) => u !== fallback)];
|
|
|
|
return {
|
|
...e,
|
|
imageLandscape: fallback,
|
|
imageBackdrop: e.imageBackdrop && !isLiveChannelThumb(e.imageBackdrop) && !isChannelLogoUrl(e.imageBackdrop)
|
|
? e.imageBackdrop
|
|
: fallback,
|
|
logoUrl,
|
|
images,
|
|
};
|
|
});
|
|
}
|