From 9b3bcbfa457ba80d18c9d74b22b892c8738bbcf0 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 14 Oct 2026 16:32:46 +0700 Subject: [PATCH 01/13] feat(schedule): model uncovered guide times without inventing an on-air programme --- utils/station-schedule.mjs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/utils/station-schedule.mjs b/utils/station-schedule.mjs index c6283410..805e6a0a 100644 --- a/utils/station-schedule.mjs +++ b/utils/station-schedule.mjs @@ -47,3 +47,33 @@ export const schedulePosition = (programs, nowSeconds, isReference = false) => { scrollIndex: upcomingIndex !== -1 ? upcomingIndex : programs.length - 1, }; }; + +// A missing block of *reference metadata* is not evidence that the radio has +// stopped broadcasting. Show a neutral "programme not listed" time marker, +// rather than attributing the next programme to the current moment. +// Index is where the marker belongs among chronologically ordered programmes. +export const referenceScheduleGap = (programs, nowSeconds) => { + if (!Array.isArray(programs) || !programs.length || !Number.isFinite(nowSeconds)) return null; + for (let index = 0; index < programs.length; index++) { + const next = programs[index]; + if (!Number.isFinite(next?.startTime) || !Number.isFinite(next?.endTime)) return null; + if (next.startTime <= nowSeconds && nowSeconds < next.endTime) return null; + if (nowSeconds < next.startTime) { + const previous = programs[index - 1]; + // Explicit inter-programme gaps and time before the first listed slot. + if (!previous || (Number.isFinite(previous.endTime) && nowSeconds >= previous.endTime)) { + return { + insertIndex: index, + nextTitle: next.title || '', + nextStartTime: next.startTime, + }; + } + return null; + } + } + // Today's published guide has finished. Don't label this as off-air. + const last = programs[programs.length - 1]; + return Number.isFinite(last?.endTime) && nowSeconds >= last.endTime + ? { insertIndex: programs.length, nextTitle: '', nextStartTime: null } + : null; +}; From d31e73d3979a8f566f2bcabb186b0431ad8c48b4 Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 14 Oct 2026 16:33:28 +0700 Subject: [PATCH 02/13] feat(ui): show precise current-time marker and next listed show when broadcaster guide has a gap --- components/player/ScheduleGap.vue | 43 +++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 components/player/ScheduleGap.vue diff --git a/components/player/ScheduleGap.vue b/components/player/ScheduleGap.vue new file mode 100644 index 00000000..0a787606 --- /dev/null +++ b/components/player/ScheduleGap.vue @@ -0,0 +1,43 @@ + + + From 3862971d7ea14383165e56d2e43fe15c821dc5aa Mon Sep 17 00:00:00 2001 From: David Nguyen Date: Wed, 14 Oct 2026 16:34:00 +0700 Subject: [PATCH 03/13] fix(schedule): insert a live time marker in unlisted intervals and auto-center it --- components/player/Queue.vue | 48 ++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/components/player/Queue.vue b/components/player/Queue.vue index 8f891e85..8c5e2567 100644 --- a/components/player/Queue.vue +++ b/components/player/Queue.vue @@ -147,9 +147,14 @@