154 lines
6.3 KiB
JavaScript
154 lines
6.3 KiB
JavaScript
// Video region playback, retry, and source probe helpers.
|
|
|
|
var videoRegionLastGoodSrcCache = Object.create(null);
|
|
var videoRegionProbeStateCache = Object.create(null);
|
|
var videoRegionProbeTimerCache = Object.create(null);
|
|
var VIDEO_REGION_RETRY_DELAY_MS = 5000;
|
|
|
|
function getVideoRegionCacheKey(region) {
|
|
return String(region && (region.regionKey || region.label) || '').trim();
|
|
}
|
|
|
|
function isDirectlyRenderableSource(src) {
|
|
return /^(?:https?:)?\/\//i.test(src) || /^data:/i.test(src) || /^blob:/i.test(src) || /^\/media\//i.test(src);
|
|
}
|
|
|
|
function appendCacheBust(src, cacheBust) {
|
|
var key = String(cacheBust || '').trim();
|
|
var raw = String(src || '').trim();
|
|
if (!raw || !key) {
|
|
return raw;
|
|
}
|
|
return raw + (raw.indexOf('?') === -1 ? '?' : '&') + 'v=' + encodeURIComponent(key);
|
|
}
|
|
|
|
function getVideoSourceAvailability(src) {
|
|
return videoRegionProbeStateCache[String(src || '').trim()] || null;
|
|
}
|
|
|
|
function setVideoSourceAvailability(src, available) {
|
|
var key = String(src || '').trim();
|
|
if (!key) {
|
|
return;
|
|
}
|
|
videoRegionProbeStateCache[key] = {
|
|
available: available === null ? null : Boolean(available),
|
|
checkedAt: Date.now()
|
|
};
|
|
}
|
|
|
|
function logVideoRegionStatus(message, details, level) {
|
|
if (typeof logDebug === 'function') {
|
|
logDebug(message, details || '', level || 'info');
|
|
}
|
|
}
|
|
|
|
function triggerVideoRegionSourceRefresh() {
|
|
if (typeof window.notifyVideoRegionSourceReady === 'function') {
|
|
window.notifyVideoRegionSourceReady();
|
|
return;
|
|
}
|
|
|
|
if (typeof videoRegionRenderVersion === 'number') {
|
|
videoRegionRenderVersion += 1;
|
|
}
|
|
slideMarkupCache = Object.create(null);
|
|
if (typeof showCurrent === 'function' && slides && slides.length) {
|
|
showCurrent();
|
|
}
|
|
}
|
|
|
|
function scheduleVideoSourceProbe(regionKey, src, isRetry) {
|
|
var key = String(src || '').trim();
|
|
if (!regionKey || !key || isDirectlyRenderableSource(key)) {
|
|
if (key) {
|
|
setVideoSourceAvailability(key, true);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (videoRegionProbeTimerCache[key]) {
|
|
return;
|
|
}
|
|
|
|
if (!isRetry) {
|
|
logVideoRegionStatus('Video source changed; probing mirrored file before swapping.', 'region=' + regionKey + ' src=' + key);
|
|
} else {
|
|
logVideoRegionStatus('Video source still unavailable; retrying mirrored file probe.', 'region=' + regionKey + ' src=' + key, 'warn');
|
|
}
|
|
|
|
videoRegionProbeTimerCache[key] = window.setTimeout(function () {
|
|
delete videoRegionProbeTimerCache[key];
|
|
fetch(key, {
|
|
method: 'HEAD',
|
|
cache: 'no-store',
|
|
credentials: 'same-origin'
|
|
}).then(function (response) {
|
|
if (response && response.ok) {
|
|
setVideoSourceAvailability(key, true);
|
|
if (videoRegionLastGoodSrcCache[regionKey] !== key) {
|
|
videoRegionLastGoodSrcCache[regionKey] = key;
|
|
logVideoRegionStatus('Mirrored video is ready; switching to the new source.', 'region=' + regionKey + ' src=' + key);
|
|
triggerVideoRegionSourceRefresh();
|
|
}
|
|
return;
|
|
}
|
|
|
|
setVideoSourceAvailability(key, false);
|
|
logVideoRegionStatus('Mirrored video probe returned unavailable; keeping the old source for now.', 'region=' + regionKey + ' src=' + key, 'warn');
|
|
scheduleVideoSourceProbe(regionKey, key, true);
|
|
}).catch(function () {
|
|
setVideoSourceAvailability(key, false);
|
|
logVideoRegionStatus('Mirrored video probe failed; keeping the old source for now.', 'region=' + regionKey + ' src=' + key, 'warn');
|
|
scheduleVideoSourceProbe(regionKey, key, true);
|
|
});
|
|
}, isRetry ? VIDEO_REGION_RETRY_DELAY_MS : 0);
|
|
}
|
|
|
|
function renderVideoRegion(region, regionContent) {
|
|
var requestedSrc = String(regionContent && regionContent.value || '').trim();
|
|
var requestedSrcVersioned = appendCacheBust(requestedSrc, regionContent && regionContent.cache_bust);
|
|
var regionKey = getVideoRegionCacheKey(region);
|
|
var cachedSrc = regionKey ? String(videoRegionLastGoodSrcCache[regionKey] || '').trim() : '';
|
|
var cachedSrcVersioned = appendCacheBust(cachedSrc, regionContent && regionContent.cache_bust);
|
|
var disableAudio = regionContent && regionContent.disable_audio === undefined ? true : Boolean(regionContent && regionContent.disable_audio);
|
|
|
|
if (!requestedSrc) {
|
|
return '';
|
|
}
|
|
|
|
if (isDirectlyRenderableSource(requestedSrc)) {
|
|
if (regionKey) {
|
|
videoRegionLastGoodSrcCache[regionKey] = requestedSrc;
|
|
}
|
|
setVideoSourceAvailability(requestedSrc, true);
|
|
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(requestedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" data-disable-audio="' + (disableAudio ? '1' : '0') + '" autoplay' + (disableAudio ? ' muted' : '') + ' loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})"></video></div>';
|
|
}
|
|
|
|
var requestedState = getVideoSourceAvailability(requestedSrc);
|
|
var requestedReady = Boolean(requestedState && requestedState.available === true);
|
|
|
|
if (requestedReady) {
|
|
if (regionKey) {
|
|
videoRegionLastGoodSrcCache[regionKey] = requestedSrc;
|
|
}
|
|
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(requestedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" data-disable-audio="' + (disableAudio ? '1' : '0') + '" autoplay' + (disableAudio ? ' muted' : '') + ' loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})"></video></div>';
|
|
}
|
|
|
|
scheduleVideoSourceProbe(regionKey, requestedSrc, false);
|
|
|
|
if (cachedSrc) {
|
|
if (cachedSrc !== requestedSrc) {
|
|
logVideoRegionStatus('Keeping the previous playable video until the new mirrored file finishes transferring.', 'region=' + regionKey + ' old=' + cachedSrc + ' new=' + requestedSrc);
|
|
}
|
|
return '<div class="template-region video" style="' + region.baseStyle + '"><video src="' + escapeHtml(cachedSrcVersioned) + '" title="' + escapeHtml(region.label) + '" data-disable-audio="' + (disableAudio ? '1' : '0') + '" autoplay' + (disableAudio ? ' muted' : '') + ' loop playsinline preload="auto" disablepictureinpicture oncanplay="this.play().catch(function () {})"></video></div>';
|
|
}
|
|
|
|
return '';
|
|
}
|
|
|
|
if (window.pulsePlayerRegionTypes && typeof window.pulsePlayerRegionTypes.register === 'function') {
|
|
window.pulsePlayerRegionTypes.register('video', {
|
|
renderRegion: renderVideoRegion
|
|
});
|
|
} |