From 9458af95fd8275e4a7b83f4e5367827d718f6251 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 30 Jul 2026 22:30:16 -0500 Subject: [PATCH] Show the idle card on a group-synced screen when nothing is scheduled MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Give every item on a sync-group playlist a daypart — "menu boards 06:00-22:00" — and at 22:00 the whole group kept displaying, or looping, whatever had been in-window last. An identical ungrouped screen showed "Nothing scheduled right now" correctly. The group schedule tick filters items by the same scheduleAllows check as solo playback. With everything filtered out the period is zero, so the target is null and the tick simply returned. Nothing else was watching: group members are schedule-driven, so renderContent arms no advanceTimer, and a group-rendered video is created with loop = !!groupSync. Solo playback routes this exact condition into the idle card; group playback had no equivalent, on either player. Both ticks now tear down and show the idle card when the schedule has nothing live, and pick up again when the daypart re-opens. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Uaeo9MvzKoyXuN6ZsbhtkL --- server/player/index.html | 14 +++++++++++++- tizen/js/player.js | 10 +++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/server/player/index.html b/server/player/index.html index 317bbe2..e00a0f8 100644 --- a/server/player/index.html +++ b/server/player/index.html @@ -1720,7 +1720,19 @@ function groupScheduleTick() { if (!groupSync || playlist.length === 0) return; const t = groupScheduleTarget(); - if (!t) return; + if (!t) { + // period === 0 means every item is currently outside its daypart. Solo playback routes the + // same condition into showNothingScheduled(); group playback just returned, so nothing was + // watching — group members are scheduleDriven, so renderContent arms no advanceTimer, and + // a group-rendered video is created with loop = !!groupSync. Out of hours the whole group + // therefore kept displaying (or looping) whatever had been in-window last, while an + // identical ungrouped screen correctly showed the idle card. + if (isPlaying) { + teardownCurrentMedia(); + showNothingScheduled(); + } + return; + } // Double buffer: warm the next clip ~6s before the boundary (once per boundary). if (t.nextIndex !== t.index && t.secToBoundary >= 0 && t.secToBoundary <= 6 && groupPreloadIdx !== t.nextIndex) { groupPreloadNext(t.nextIndex); diff --git a/tizen/js/player.js b/tizen/js/player.js index 0bffe4b..2f0b526 100644 --- a/tizen/js/player.js +++ b/tizen/js/player.js @@ -1323,7 +1323,15 @@ GroupSyncController.prototype.target = function () { }; GroupSyncController.prototype.tick = function () { if (!this.groupId || !this.player.items.length) return; - var t = this.target(); if (!t) return; + // No target means every item is currently outside its daypart. Returning here left the whole + // group displaying (or looping) whatever was in-window last, out of hours — while an identical + // ungrouped screen correctly showed the idle card. Group members are schedule-driven, so no + // renderer arms a timer and nothing else was watching for this. + var t = this.target(); + if (!t) { + if (this.player.hasContentOnScreen()) this.player.nothingScheduled(); + return; + } // Double buffer: warm the next clip ~6s before the boundary (once per boundary). if (t.nextIndex !== t.index && t.secToBoundary >= 0 && t.secToBoundary <= 6) { this.player.preloadVideo(t.nextIndex); // warm next clip (video-only; no-ops otherwise)