Prefer unique Gracenote art for Ziggo events over shared FAAB channel thumbs.

Keep FAAB live thumbs only when EventImages is missing or 404 so cards stay filled without looking identical.
This commit is contained in:
Jos Vooges | STH 2026-09-24 02:11:36 +02:00
parent ff7ad3ddda
commit 035ec9dc98
3 changed files with 14 additions and 19 deletions

View file

@ -106,7 +106,7 @@ async function main() {
return {
status: "ok",
service: "master-api",
version: "1.0.6-ziggo-faab-art",
version: "1.0.7-ziggo-gracenote",
lastVodPlay: getLastVodPlay(),
};
});

View file

@ -28,13 +28,13 @@ assert(!isZiggoSportChannel("ESPN"), "espn");
assert(isReplayOrHighlightTitle("Moto3 BWIN Grand Prix of Austria (samenvatting)"), "samenvatting");
assert(
!needsZiggoArtEnrichment({
needsZiggoArtEnrichment({
name: "ATP 250: Chengdu Open",
channel: "Ziggo Sport 1",
imageLandscape: "https://zst1-akm-cdn-triple.akamaized.net/live/zs1/thumb.jpg?scale=640",
images: [],
}),
"keep FAAB live thumb for normal events"
"enrich live thumb (per-channel snap → try Gracenote)"
);
assert(
needsZiggoArtEnrichment({

View file

@ -1,11 +1,10 @@
/**
* Enrich Ziggo Sport events with real Gracenote art from Ziggo GO EPG
* (epg-service-lite + image-service) when FAAB only has logos or a misleading
* live snap on highlights/replays.
* (epg-service-lite + image-service). FAAB live thumbs are per-channel and look
* identical across events — replace when EventImages probes OK; otherwise keep FAAB.
*
* Match: channel → Ziggo channelId(s) + (time overlap | series family) + title tokens.
* Art: ImagesEPG/EventImages/p{mergedId}_bd_h8_aa.jpg (probed for HTTP 200).
* Keep FAAB live thumbs for normal live/upcoming cards.
*/
const CHANNELS_URL =
@ -80,11 +79,9 @@ export function needsZiggoArtEnrichment(e: {
if (!isZiggoSportChannel(e.channel) && !isZiggoSportChannel(e.network)) return false;
if (!e.imageLandscape && !(e.images?.length)) return true;
if (e.imageLandscape && isChannelLogoUrl(e.imageLandscape)) return true;
// FAAB live thumbs are usable card art for live/upcoming — keep them.
// Only replace for highlights/replays (on-air snap ≠ programme art).
const hasLiveThumb =
isLiveChannelThumb(e.imageLandscape) || (e.images ?? []).some(isLiveChannelThumb);
if (hasLiveThumb) return isReplayOrHighlightTitle(e.name ?? "");
// Live thumbs are per-channel (same snap for every event on ZS1) — always try Gracenote.
if (isLiveChannelThumb(e.imageLandscape)) return true;
if ((e.images ?? []).some(isLiveChannelThumb)) return true;
return false;
}
@ -528,9 +525,9 @@ export type EnrichableEvent = {
};
/**
* Enrich Ziggo Sport rows that lack usable FAAB art (logos / highlight live-snaps)
* with Gracenote EPG art. Live FAAB thumbs are left alone so cards stay filled.
* Soft-fails keep FAAB images when Ziggo GO is down or EventImages 404.
* Prefer unique Gracenote EventImages over FAAB live thumbs (which are identical
* per channel). Only replace when the Gracenote URL probes OK; otherwise keep FAAB
* so cards never go empty. Highlights without art strip live snaps → category fallback.
*/
export async function enrichZiggoGoArt<T extends EnrichableEvent>(events: T[]): Promise<T[]> {
const targets = events.filter(needsZiggoArtEnrichment);
@ -548,10 +545,9 @@ export async function enrichZiggoGoArt<T extends EnrichableEvent>(events: T[]):
const index = await loadZiggoIndex(minMs, maxMs);
/** On miss: strip misleading live snaps for highlights; otherwise keep FAAB as-is. */
/** Miss / 404: keep FAAB live thumb for normal rows; strip only for highlights. */
function fallbackArt(e: T): T {
const highlight = isReplayOrHighlightTitle(e.name);
if (!highlight) return e;
if (!isReplayOrHighlightTitle(e.name)) return e;
const logo =
(index ? channelLogoFallback(index, e.channel, e.network, e.images) : null) ||
e.images.find(isChannelLogoUrl) ||
@ -592,8 +588,7 @@ export async function enrichZiggoGoArt<T extends EnrichableEvent>(events: T[]):
const images = [
arts.landscape,
arts.portrait,
// Keep FAAB live thumbs as client-side fallback (Gracenote may 404 on device)
...e.images,
...e.images.filter((u) => !isLiveChannelThumb(u)),
];
const seen = new Set<string>();
const deduped = images.filter((u) => {