From c49ff4bac1edddf9ef2056433166f19ba3942b5b Mon Sep 17 00:00:00 2001 From: Speng Reb Date: Thu, 21 May 2026 14:14:47 +0200 Subject: [PATCH] Fix bug where force start did not force starting the show --- src/shows.js | 106 +++++++++++++++++++++++++++++++---- templates/channeloptions.pug | 12 ++-- www/js/ui.js | 6 +- 3 files changed, 103 insertions(+), 21 deletions(-) diff --git a/src/shows.js b/src/shows.js index 03914b57..b7d0d3fe 100644 --- a/src/shows.js +++ b/src/shows.js @@ -2,6 +2,7 @@ const LOGGER = require('@calzoneman/jsli')('shows'); const util = require('./utilities'); const showDB = require('./database/shows'); const Server = require('./server'); +const InfoGetter = require('./get-info'); function makeSystemProxy(name) { const rank = 5; @@ -43,7 +44,90 @@ function normalizePlaylist(rawPlaylist) { .filter(item => item.id && item.type); } -function applyShowToChannel(chan, show) { +function queueShowEntry(plmod, proxy, entry, idx) { + return new Promise((resolve, reject) => { + let data = { + id: entry.id, + type: entry.type, + pos: idx === 0 && entry.pos === 'next' ? 'next' : 'end', + title: false, + link: util.formatLink(entry.id, entry.type, null), + temp: false, + shouldAddToLibrary: true, + queueby: proxy.getName(), + duration: undefined, + maxlength: 0 + }; + + InfoGetter.getMedia(entry.id, entry.type, (err, media) => { + if (err) { + reject(new Error(String(err))); + return; + } + + if (Array.isArray(media)) { + let list = media.slice(); + if (data.pos === 'next') { + list = list.reverse(); + if (plmod.items.length === 0 && list.length > 0) { + list.unshift(list.pop()); + } + } + + if (list.length === 0) { + reject(new Error(`Show item resolved to an empty playlist: ${entry.type}:${entry.id}`)); + return; + } + + let firstUid = null; + let pending = list.length; + let failed = false; + list.forEach((video) => { + const beforeUid = plmod._nextuid; + const itemData = Object.assign({}, data, { + id: video.id, + type: video.type, + link: util.formatLink(video.id, video.type, video.meta || null) + }); + + plmod._addItem(video, itemData, proxy, () => { + if (failed) { + return; + } + + if (plmod._nextuid === beforeUid) { + failed = true; + reject(new Error(`Failed to add show list item: ${entry.type}:${entry.id}`)); + return; + } + + if (firstUid === null) { + firstUid = beforeUid; + } + + pending -= 1; + if (pending === 0) { + resolve(firstUid); + } + }); + }); + return; + } + + const beforeUid = plmod._nextuid; + plmod._addItem(media, data, proxy, () => { + if (plmod._nextuid === beforeUid) { + reject(new Error(`Failed to add show item: ${entry.type}:${entry.id}`)); + return; + } + + resolve(beforeUid); + }); + }); + }); +} + +async function applyShowToChannel(chan, show) { const playlist = normalizePlaylist(show.playlist); if (playlist.length === 0) { throw new Error('Show playlist is empty'); @@ -62,18 +146,16 @@ function applyShowToChannel(chan, show) { plmod.handleClear(proxy); } - playlist.forEach((entry, idx) => { - plmod.handleQueue(proxy, { - id: entry.id, - type: entry.type, - pos: idx === 0 && entry.pos === 'next' ? 'next' : 'end' - }); - }); + const addedUids = []; + for (let i = 0; i < playlist.length; i++) { + const uid = await queueShowEntry(plmod, proxy, playlist[i], i); + addedUids.push(uid); + } if (show.start_playback) { - const first = plmod.items.first; - if (first) { - plmod.handleJumpTo(proxy, first.uid); + const firstShowUid = addedUids[0]; + if (typeof firstShowUid === 'number') { + plmod.handleJumpTo(proxy, firstShowUid); } } } @@ -85,7 +167,7 @@ async function runShow(show) { } const chan = server.getChannel(show.channel_name); - applyShowToChannel(chan, show); + await applyShowToChannel(chan, show); } async function pollAndRunDueShows() { diff --git a/templates/channeloptions.pug b/templates/channeloptions.pug index 0a51f608..adc523c8 100644 --- a/templates/channeloptions.pug +++ b/templates/channeloptions.pug @@ -284,17 +284,17 @@ mixin shows option(value="append") Append to queue option(value="replace") Replace queue .form-group - label.control-label.col-sm-3(for="cs-shows-conflict-mode") Conflict Mode - .col-sm-9 - select#cs-shows-conflict-mode.form-control - option(value="force") Force run - option(value="skip") Skip if queue not empty + .col-sm-9.col-sm-offset-3 + .checkbox + label(for="cs-shows-conflict-skip") + input#cs-shows-conflict-skip(type="checkbox") + | Skip show if queue is not empty .form-group .col-sm-9.col-sm-offset-3 .checkbox label(for="cs-shows-start-playback") input#cs-shows-start-playback(type="checkbox") - | Start playback immediately + | Skip current playback and start this show's first item immediately .form-group label.control-label.col-sm-3(for="cs-shows-mediaurl") Show Playlist .col-sm-9 diff --git a/www/js/ui.js b/www/js/ui.js index f68520d1..c524c3ca 100644 --- a/www/js/ui.js +++ b/www/js/ui.js @@ -1472,7 +1472,7 @@ var CSTShows = (function () { timezone: timezone, recurrence: $('#cs-shows-recurrence').val(), fill_mode: $('#cs-shows-fill-mode').val(), - conflict_mode: $('#cs-shows-conflict-mode').val(), + conflict_mode: $('#cs-shows-conflict-skip').prop('checked') ? 'skip' : 'force', start_playback: $('#cs-shows-start-playback').prop('checked'), playlist: draftPlaylist.map(function (item) { return { id: item.id, type: item.type, pos: item.pos || 'end' }; @@ -1496,7 +1496,7 @@ var CSTShows = (function () { $('#cs-shows-timezone').val(detectedTz); $('#cs-shows-recurrence').val('none'); $('#cs-shows-fill-mode').val('append'); - $('#cs-shows-conflict-mode').val('force'); + $('#cs-shows-conflict-skip').prop('checked', false); $('#cs-shows-start-playback').prop('checked', false); $('#cs-shows-mediaurl').val(''); draftPlaylist = []; @@ -1515,7 +1515,7 @@ var CSTShows = (function () { $('#cs-shows-timezone').val(showTz); $('#cs-shows-recurrence').val(show.recurrence || 'none'); $('#cs-shows-fill-mode').val(show.fill_mode || 'append'); - $('#cs-shows-conflict-mode').val(show.conflict_mode || 'force'); + $('#cs-shows-conflict-skip').prop('checked', (show.conflict_mode || 'force') === 'skip'); $('#cs-shows-start-playback').prop('checked', !!show.start_playback); draftPlaylist = (show.playlist || []).map(function (item) { return {