From 035ec9dc98235773de0234ff071d7a3a2a919f5e Mon Sep 17 00:00:00 2001 From: Jos Vooges | STH Date: Thu, 24 Sep 2026 02:11:36 +0200 Subject: [PATCH] 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. --- apps/master-api/src/app.ts | 2 +- .../src/viewer/ziggo-epg-art.test.ts | 4 +-- apps/master-api/src/viewer/ziggo-epg-art.ts | 27 ++++++++----------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/apps/master-api/src/app.ts b/apps/master-api/src/app.ts index be2ce29..98df2da 100644 --- a/apps/master-api/src/app.ts +++ b/apps/master-api/src/app.ts @@ -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(), }; }); diff --git a/apps/master-api/src/viewer/ziggo-epg-art.test.ts b/apps/master-api/src/viewer/ziggo-epg-art.test.ts index 78ab00c..d2c1b36 100644 --- a/apps/master-api/src/viewer/ziggo-epg-art.test.ts +++ b/apps/master-api/src/viewer/ziggo-epg-art.test.ts @@ -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({ diff --git a/apps/master-api/src/viewer/ziggo-epg-art.ts b/apps/master-api/src/viewer/ziggo-epg-art.ts index da52872..5873a2e 100644 --- a/apps/master-api/src/viewer/ziggo-epg-art.ts +++ b/apps/master-api/src/viewer/ziggo-epg-art.ts @@ -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(events: T[]): Promise { const targets = events.filter(needsZiggoArtEnrichment); @@ -548,10 +545,9 @@ export async function enrichZiggoGoArt(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(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(); const deduped = images.filter((u) => {