Save worktree changes

This commit is contained in:
2026-07-25 02:29:19 +01:00
parent 8d3b7d557b
commit db9d718cd8
170 changed files with 11719 additions and 3414 deletions
+227
View File
@@ -0,0 +1,227 @@
function renderRtmpRegion(region, regionContent) {
var url = String(regionContent.value || '').trim();
var disableAudio = regionContent.disable_audio === undefined ? true : Boolean(regionContent.disable_audio);
if (!url) {
return '<div class="template-region rtmp" style="' + region.baseStyle + '"><div class="template-region-placeholder">RTMP stream</div></div>';
}
return '<div class="template-region rtmp" style="' + region.baseStyle + '"><video class="template-region-rtmp-video" data-rtmp-source="' + escapeHtml(url) + '" data-rtmp-disable-audio="' + (disableAudio ? '1' : '0') + '" autoplay playsinline preload="auto" tabindex="-1" disablepictureinpicture></video><div class="template-region-placeholder template-region-rtmp-placeholder">Loading RTMP stream...</div></div>';
}
function getRtmpSessionUrl(sourceUrl, disableAudio) {
return '/api/rtmp/session?source=' + encodeURIComponent(sourceUrl) + '&disableAudio=' + (disableAudio ? '1' : '0');
}
var rtmpPreloadSignature = '';
function getRtmpPreloadSlides(sourceSlides, targetIndex) {
var availableSlides = Array.isArray(sourceSlides) ? sourceSlides : [];
if (!availableSlides.length) {
return [];
}
var normalizedIndex = Number(targetIndex || 0);
if (!Number.isFinite(normalizedIndex) || normalizedIndex < 0 || normalizedIndex >= availableSlides.length) {
normalizedIndex = 0;
}
var preloadSlides = [];
var currentSlide = availableSlides[normalizedIndex];
var nextSlide = availableSlides[normalizedIndex + 1];
if (currentSlide) {
preloadSlides.push(currentSlide);
}
if (nextSlide && nextSlide !== currentSlide) {
preloadSlides.push(nextSlide);
}
return preloadSlides;
}
function getRtmpPreloadEntries(sourceSlides) {
var entries = [];
var seen = Object.create(null);
(Array.isArray(sourceSlides) ? sourceSlides : []).forEach(function (slide) {
var content = slide && slide.content ? slide.content : {};
var regions = slide && slide.template && Array.isArray(slide.template.regions) ? slide.template.regions : [];
regions.forEach(function (region) {
if (region.region_type !== 'rtmp') {
return;
}
var regionContent = content[region.region_key] || {};
var url = String(regionContent.value || '').trim();
if (!url) {
return;
}
var disableAudio = regionContent.disable_audio === undefined ? true : Boolean(regionContent.disable_audio);
var key = url + '\n' + (disableAudio ? '1' : '0');
if (seen[key]) {
return;
}
seen[key] = true;
entries.push({
url: url,
disableAudio: disableAudio
});
});
});
return entries;
}
function syncRtmpPreloads(sourceSlides, targetIndex) {
var entries = getRtmpPreloadEntries(getRtmpPreloadSlides(sourceSlides, targetIndex));
var signature = entries.map(function (entry) {
return entry.url + '\n' + (entry.disableAudio ? '1' : '0');
}).join('\n');
if (signature === rtmpPreloadSignature) {
return;
}
rtmpPreloadSignature = signature;
if (!entries.length) {
return;
}
entries.forEach(function (entry) {
fetch(getRtmpSessionUrl(entry.url, entry.disableAudio), {
credentials: 'same-origin'
}).catch(function () {
return null;
});
});
}
function syncRtmpRegions(root) {
if (!root) {
return;
}
var videos = root.querySelectorAll('video[data-rtmp-source]');
Array.prototype.forEach.call(videos, function (video) {
if (!video || video.dataset.rtmpInitialized === '1') {
return;
}
var sourceUrl = String(video.dataset.rtmpSource || '').trim();
var disableAudio = String(video.dataset.rtmpDisableAudio || '1') !== '0';
var region = video.parentNode;
var placeholder = region ? region.querySelector('.template-region-rtmp-placeholder') : null;
if (!sourceUrl) {
if (placeholder) {
placeholder.textContent = 'RTMP stream';
}
return;
}
video.dataset.rtmpInitialized = '1';
video.muted = disableAudio;
video.controls = false;
video.playsInline = true;
video.autoplay = true;
var markReady = function () {
if (placeholder) {
placeholder.style.display = 'none';
}
};
var tryPlay = function () {
if (video && typeof video.play === 'function') {
video.play().catch(function () {
return null;
});
}
};
video.addEventListener('canplay', markReady, { once: true });
video.addEventListener('playing', markReady, { once: true });
fetch(getRtmpSessionUrl(sourceUrl, disableAudio), {
credentials: 'same-origin'
}).then(function (response) {
if (!response.ok) {
throw new Error('Unable to initialize RTMP stream.');
}
return response.json();
}).then(function (payload) {
var playlistUrl = payload && payload.playlistUrl ? String(payload.playlistUrl).trim() : '';
if (!playlistUrl) {
throw new Error('RTMP playlist URL was not returned.');
}
if (window.Hls && window.Hls.isSupported && window.Hls.isSupported()) {
var hls = new window.Hls({
enableWorker: true,
lowLatencyMode: true,
liveSyncDurationCount: 4,
liveMaxLatencyDurationCount: 8,
maxBufferLength: 20,
maxLiveSyncPlaybackRate: 1,
backBufferLength: 30
});
video.__rtmpHls = hls;
hls.attachMedia(video);
hls.on(window.Hls.Events.MEDIA_ATTACHED, function () {
hls.loadSource(playlistUrl);
});
hls.on(window.Hls.Events.MANIFEST_PARSED, function () {
tryPlay();
});
hls.on(window.Hls.Events.ERROR, function (_event, data) {
if (data && data.fatal) {
try {
hls.destroy();
} catch (_error) {
// ignore cleanup errors
}
video.__rtmpHls = null;
if (placeholder) {
placeholder.style.display = 'flex';
placeholder.textContent = 'RTMP playback failed.';
}
}
});
return;
}
if (video.canPlayType && video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = playlistUrl;
tryPlay();
return;
}
if (placeholder) {
placeholder.style.display = 'flex';
placeholder.textContent = 'RTMP playback is not supported in this browser.';
}
}).catch(function (_error) {
if (placeholder) {
placeholder.style.display = 'flex';
placeholder.textContent = 'Unable to load RTMP stream.';
}
});
});
}
function destroyRtmpRegions(root) {
if (!root) {
return;
}
var videos = root.querySelectorAll('video[data-rtmp-source]');
Array.prototype.forEach.call(videos, function (video) {
if (video.__rtmpHls) {
try {
video.__rtmpHls.destroy();
} catch (_error) {
// ignore cleanup errors
}
video.__rtmpHls = null;
}
});
}