Release 1.5.3
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// Render the slide at the requested index within the active set.
|
||||
function renderSlideAtIndex(sourceSlides, targetIndex) {
|
||||
async function renderSlideAtIndex(sourceSlides, targetIndex) {
|
||||
const availableSlides = Array.isArray(sourceSlides) ? sourceSlides : [];
|
||||
if (!availableSlides.length) {
|
||||
renderEmpty(slides.length ? 'No slides are scheduled for this time.' : 'No slides assigned to this screen yet.');
|
||||
@@ -11,18 +11,52 @@ function renderSlideAtIndex(sourceSlides, targetIndex) {
|
||||
if (!Number.isFinite(normalizedIndex) || normalizedIndex < 0 || normalizedIndex >= availableSlides.length) {
|
||||
}
|
||||
|
||||
const slide = availableSlides[normalizedIndex];
|
||||
var slideCount = availableSlides.length;
|
||||
var currentIndex = normalizedIndex;
|
||||
var slide = null;
|
||||
var attempts = 0;
|
||||
var renderRequestId = ++slideRenderRequestId;
|
||||
|
||||
while (attempts < slideCount) {
|
||||
slide = availableSlides[currentIndex];
|
||||
if (!slide) {
|
||||
break;
|
||||
}
|
||||
if (currentPlaylistSkipUnavailableRtmp && typeof probeRtmpSlideAvailability === 'function') {
|
||||
var isAvailable = await probeRtmpSlideAvailability(slide);
|
||||
if (!isAvailable) {
|
||||
if (renderRequestId !== slideRenderRequestId) {
|
||||
return false;
|
||||
}
|
||||
currentIndex = (currentIndex + 1) % slideCount;
|
||||
attempts += 1;
|
||||
slide = null;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (renderRequestId !== slideRenderRequestId) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!slide) {
|
||||
if (currentPlaylistSkipUnavailableRtmp) {
|
||||
renderEmpty(slides.length ? 'No RTMP slides are currently available.' : 'No slides assigned to this screen yet.');
|
||||
lastRenderedViewKey = getCurrentRenderKey(availableSlides);
|
||||
scheduleRefreshRetry();
|
||||
return false;
|
||||
}
|
||||
renderEmpty(slides.length ? 'No slides are scheduled for this time.' : 'No slides assigned to this screen yet.');
|
||||
return false;
|
||||
}
|
||||
|
||||
index = normalizedIndex;
|
||||
index = currentIndex;
|
||||
var markup = buildSlideMarkup(slide);
|
||||
renderSlideMarkup(markup, currentPlaylistFadeBetweenSlides);
|
||||
sendCommandState(slide);
|
||||
if (!isPaused) {
|
||||
scheduleSlideAdvance(Math.max(1, Number(slide.duration_seconds || 10)) * 1000);
|
||||
scheduleSlideAdvance(getSlideHoldDelay(Math.max(1, Number(slide.duration_seconds || 10)) * 1000));
|
||||
}
|
||||
lastRenderedViewKey = getCurrentRenderKey(availableSlides);
|
||||
return true;
|
||||
@@ -36,6 +70,7 @@ function applyPendingPlaylistUpdate() {
|
||||
slides = pendingPlaylistUpdate.slides;
|
||||
currentPlaylistSignature = pendingPlaylistUpdate.signature;
|
||||
currentPlaylistFadeBetweenSlides = pendingPlaylistUpdate.fadeBetweenSlides;
|
||||
currentPlaylistSkipUnavailableRtmp = Boolean(pendingPlaylistUpdate.skipUnavailableRtmp);
|
||||
pendingPlaylistUpdate = null;
|
||||
clearActiveSlidesCache();
|
||||
slideMarkupCache = Object.create(null);
|
||||
@@ -53,18 +88,45 @@ function showCurrent() {
|
||||
applyPendingPlaylistUpdate();
|
||||
const activeSlides = getCurrentActiveSlides();
|
||||
syncWebpagePreloads(activeSlides, index);
|
||||
if (typeof syncRtmpPreloads === 'function') {
|
||||
syncRtmpPreloads(activeSlides, index);
|
||||
if (typeof syncRtmpWarmups === 'function') {
|
||||
syncRtmpWarmups(activeSlides, index);
|
||||
}
|
||||
if (!activeSlides.length) {
|
||||
renderEmpty(slides.length ? 'No slides are scheduled for this time.' : 'No slides assigned to this screen yet.');
|
||||
lastRenderedViewKey = getCurrentRenderKey(activeSlides);
|
||||
return;
|
||||
}
|
||||
renderSlideAtIndex(activeSlides, index);
|
||||
void renderSlideAtIndex(activeSlides, index);
|
||||
lastRenderedViewKey = getCurrentRenderKey(activeSlides);
|
||||
}
|
||||
|
||||
// Skip the current slide when an RTMP feed is unavailable and the playlist asks for it.
|
||||
function handleRtmpPlaybackFailure(message, options) {
|
||||
if (!currentPlaylistSkipUnavailableRtmp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var silent = Boolean(options && options.silent);
|
||||
const activeSlides = getCurrentActiveSlides();
|
||||
if (!activeSlides.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
clearSlideTimer();
|
||||
if (!silent) {
|
||||
logDebug('Skipping RTMP slide because the stream is unavailable.', String(message || ''), 'error');
|
||||
}
|
||||
|
||||
const nextIndex = (Number(index || 0) + 1) % activeSlides.length;
|
||||
window.setTimeout(function () {
|
||||
if (!getCurrentActiveSlides().length) {
|
||||
return;
|
||||
}
|
||||
void renderSlideAtIndex(getCurrentActiveSlides(), nextIndex);
|
||||
}, 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fetch the latest playlist and queue any updates.
|
||||
function refresh() {
|
||||
var request = new XMLHttpRequest();
|
||||
@@ -85,7 +147,7 @@ function refresh() {
|
||||
markRefreshHealthy();
|
||||
setOfflineBannerVisible(false);
|
||||
if (lastRenderedSlide && getCurrentActiveSlides().length < 2) {
|
||||
scheduleSlideAdvance(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000);
|
||||
scheduleSlideAdvance(getSlideHoldDelay(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000));
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -105,10 +167,12 @@ function refresh() {
|
||||
const nextSignature = getPlaylistRevision(data);
|
||||
const nextSlides = Array.isArray(data.slides) ? data.slides.map(normalizeSlide) : [];
|
||||
const nextFadeBetweenSlides = Boolean(data && data.playlist && data.playlist.fade_between_slides);
|
||||
const nextSkipUnavailableRtmp = Boolean(data && data.playlist && data.playlist.skip_unavailable_rtmp);
|
||||
savePlaylistSnapshot({
|
||||
slides: nextSlides,
|
||||
signature: nextSignature,
|
||||
fadeBetweenSlides: nextFadeBetweenSlides,
|
||||
skipUnavailableRtmp: nextSkipUnavailableRtmp,
|
||||
etag: responseEtag
|
||||
});
|
||||
markRefreshHealthy();
|
||||
@@ -121,6 +185,7 @@ function refresh() {
|
||||
slides = nextSlides;
|
||||
currentPlaylistSignature = nextSignature;
|
||||
currentPlaylistFadeBetweenSlides = nextFadeBetweenSlides;
|
||||
currentPlaylistSkipUnavailableRtmp = nextSkipUnavailableRtmp;
|
||||
index = 0;
|
||||
showCurrent();
|
||||
sendCommandState(lastRenderedSlide);
|
||||
@@ -128,18 +193,19 @@ function refresh() {
|
||||
}
|
||||
if (nextSignature === currentPlaylistSignature || (pendingPlaylistUpdate && nextSignature === pendingPlaylistUpdate.signature)) {
|
||||
if (currentActiveSlides.length < 2 && lastRenderedSlide) {
|
||||
scheduleSlideAdvance(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000);
|
||||
scheduleSlideAdvance(getSlideHoldDelay(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000));
|
||||
}
|
||||
return;
|
||||
}
|
||||
syncWebpagePreloads(getActiveSlidesFrom(nextSlides), index);
|
||||
if (typeof syncRtmpPreloads === 'function') {
|
||||
syncRtmpPreloads(getActiveSlidesFrom(nextSlides), index);
|
||||
if (typeof syncRtmpWarmups === 'function') {
|
||||
syncRtmpWarmups(getActiveSlidesFrom(nextSlides), index);
|
||||
}
|
||||
if (currentActiveSlides.length < 2) {
|
||||
slides = nextSlides;
|
||||
currentPlaylistSignature = nextSignature;
|
||||
currentPlaylistFadeBetweenSlides = nextFadeBetweenSlides;
|
||||
currentPlaylistSkipUnavailableRtmp = nextSkipUnavailableRtmp;
|
||||
pendingPlaylistUpdate = null;
|
||||
index = 0;
|
||||
showCurrent();
|
||||
@@ -149,7 +215,8 @@ function refresh() {
|
||||
pendingPlaylistUpdate = {
|
||||
slides: nextSlides,
|
||||
signature: nextSignature,
|
||||
fadeBetweenSlides: nextFadeBetweenSlides
|
||||
fadeBetweenSlides: nextFadeBetweenSlides,
|
||||
skipUnavailableRtmp: nextSkipUnavailableRtmp
|
||||
};
|
||||
logDebug('Playlist update detected; applying on next slide transition.');
|
||||
} catch (_error) {
|
||||
@@ -171,7 +238,7 @@ function refresh() {
|
||||
setOfflineBannerVisible(true);
|
||||
scheduleRefreshRetry();
|
||||
if (lastRenderedSlide && getCurrentActiveSlides().length < 2) {
|
||||
scheduleSlideAdvance(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000);
|
||||
scheduleSlideAdvance(getSlideHoldDelay(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000));
|
||||
}
|
||||
};
|
||||
request.ontimeout = function () {
|
||||
@@ -183,7 +250,7 @@ function refresh() {
|
||||
setOfflineBannerVisible(true);
|
||||
scheduleRefreshRetry();
|
||||
if (lastRenderedSlide && getCurrentActiveSlides().length < 2) {
|
||||
scheduleSlideAdvance(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000);
|
||||
scheduleSlideAdvance(getSlideHoldDelay(Math.max(1, Number(lastRenderedSlide.duration_seconds || 10)) * 1000));
|
||||
}
|
||||
};
|
||||
request.send();
|
||||
|
||||
Reference in New Issue
Block a user