Switch to Rok viprime embed widget on main page (test how DVR + native controls behave)

This commit is contained in:
Sebastjan 2026-04-25 17:54:51 +02:00
parent 63679fe786
commit 4caa948d98

View File

@ -506,21 +506,7 @@
</div>
<div class="player-frame" id="playerFrame">
<video id="v" autoplay muted playsinline tabindex="-1"
disablepictureinpicture
controlsList="nodownload nofullscreen noremoteplayback noplaybackrate"></video>
<div class="player-msg visible" id="msg">
<div class="spinner"></div>
<div>Stream wird geladen…</div>
</div>
<div class="player-overlay">
<div class="player-controls">
<button class="pctl" id="btnAudio" aria-label="Ton umschalten" title="Ton umschalten">🔇</button>
<button class="pctl" id="btnFs" aria-label="Vollbild" title="Vollbild">⛶</button>
</div>
</div>
<script src="https://livestream1.viprime.net/embed/stream1_dvr.js"></script>
</div>
</main>
@ -631,177 +617,5 @@
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/hls.js@1.5.17/dist/hls.min.js"></script>
<script>
(function () {
const HLS_URL = <%- JSON.stringify(hlsUrl) %>;
const video = document.getElementById('v');
const msg = document.getElementById('msg');
const playerFrame = document.getElementById('playerFrame');
let hls = null;
function showMsg(html) { msg.innerHTML = html; msg.classList.add('visible'); }
function hideMsg() { msg.classList.remove('visible'); }
function attach() {
try { hls && hls.destroy(); } catch (e) {}
hls = null;
if (video.canPlayType('application/vnd.apple.mpegurl')) {
video.src = HLS_URL;
video.play().catch(() => {});
video.addEventListener('playing', hideMsg, { once: true });
return;
}
if (window.Hls && window.Hls.isSupported()) {
hls = new Hls({
liveDurationInfinity: true,
liveSyncDurationCount: 4,
backBufferLength: 30,
maxBufferLength: 60,
manifestLoadingTimeOut: 10000,
manifestLoadingMaxRetry: 6,
fragLoadingTimeOut: 20000,
fragLoadingMaxRetry: 6,
startLevel: -1,
capLevelToPlayerSize: false,
abrEwmaDefaultEstimate: 3000000,
testBandwidth: true,
abrBandWidthFactor: 0.95,
abrBandWidthUpFactor: 0.7,
});
hls.loadSource(HLS_URL);
hls.attachMedia(video);
hls.on(Hls.Events.MANIFEST_PARSED, () => {
// ABR enabled across ALL variants (1080p / 720p / 480p)
// Rok synced all 3 variants — same MEDIA-SEQUENCE base, encoder restarted.
hideMsg();
video.play().catch(() => setTimeout(() => video.play().catch(() => {}), 200));
});
hls.on(Hls.Events.ERROR, (_e, data) => {
if (!data.fatal) return;
showMsg('<div class="spinner"></div><div>Verbindung wird wiederhergestellt…</div>');
setTimeout(() => { attach(); }, 3000);
});
} else {
showMsg('<div>HLS wird von diesem Browser nicht unterstützt.</div>');
}
}
attach();
// Stall detection
let lastT = 0, stalls = 0;
setInterval(() => {
if (video.paused) { video.play().catch(() => {}); return; }
if (video.currentTime === lastT && !video.seeking) {
stalls++;
if (stalls >= 3) {
stalls = 0;
showMsg('<div class="spinner"></div><div>Verbindung wird wiederhergestellt…</div>');
setTimeout(() => { attach(); }, 500);
}
} else stalls = 0;
lastT = video.currentTime;
}, 5000);
// Live-only mode (Twitch style) — pause is disabled.
// If anything pauses the video, resume immediately AND seek to the live edge.
function seekToLive() {
try {
if (hls && hls.liveSyncPosition) {
video.currentTime = hls.liveSyncPosition;
} else if (video.seekable && video.seekable.length > 0) {
video.currentTime = video.seekable.end(video.seekable.length - 1);
}
} catch (e) {}
}
video.addEventListener('pause', () => {
setTimeout(() => {
seekToLive();
video.play().catch(() => {});
}, 80);
});
// If user seeks back, force forward to live
video.addEventListener('seeked', () => {
if (!hls) return;
if (hls.liveSyncPosition && video.currentTime < hls.liveSyncPosition - 10) {
video.currentTime = hls.liveSyncPosition;
}
});
// Block right-click context menu
video.addEventListener('contextmenu', (e) => e.preventDefault());
video.disablePictureInPicture = true;
video.setAttribute('disablePictureInPicture', 'true');
try { video.disableRemotePlayback = true; } catch (e) {}
// Block keyboard shortcuts that could pause: spacebar, K, Media keys
document.addEventListener('keydown', (e) => {
const tag = (e.target && e.target.tagName) || '';
if (tag === 'INPUT' || tag === 'TEXTAREA') return;
if (e.key === ' ' || e.key === 'Spacebar' || e.code === 'Space' ||
e.key === 'k' || e.key === 'K' ||
e.key === 'MediaPlayPause' || e.key === 'MediaPause') {
e.preventDefault();
if (video.paused) {
seekToLive();
video.play().catch(() => {});
}
}
});
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
seekToLive();
video.play().catch(() => {});
}
});
// Audio toggle (custom button)
const btnAudio = document.getElementById('btnAudio');
const btnFs = document.getElementById('btnFs');
function updateAudio() {
btnAudio.textContent = video.muted ? '🔇' : '🔊';
btnAudio.title = video.muted ? 'Ton einschalten' : 'Stummschalten';
}
updateAudio();
btnAudio.addEventListener('click', (e) => {
e.stopPropagation();
video.muted = !video.muted;
video.volume = 1.0;
updateAudio();
});
// Fullscreen — handle iOS Safari separately
function enterFullscreen() {
if (typeof video.webkitEnterFullscreen === 'function' && !document.fullscreenEnabled) {
try { video.webkitEnterFullscreen(); return; } catch (e) {}
}
if (video.requestFullscreen) { video.requestFullscreen().catch(() => {}); return; }
if (video.webkitRequestFullscreen) { video.webkitRequestFullscreen(); return; }
if (playerFrame.requestFullscreen) { playerFrame.requestFullscreen().catch(() => {}); return; }
if (playerFrame.webkitRequestFullscreen) { playerFrame.webkitRequestFullscreen(); return; }
if (typeof video.webkitEnterFullscreen === 'function') {
try { video.webkitEnterFullscreen(); } catch (e) {}
}
}
function exitFullscreen() {
if (document.exitFullscreen) { document.exitFullscreen().catch(() => {}); return; }
if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); return; }
if (typeof video.webkitExitFullscreen === 'function') { try { video.webkitExitFullscreen(); } catch (e) {} }
}
function isFullscreen() {
return !!(document.fullscreenElement || document.webkitFullscreenElement || video.webkitDisplayingFullscreen);
}
btnFs.addEventListener('click', (e) => {
e.stopPropagation();
if (isFullscreen()) exitFullscreen();
else enterFullscreen();
});
// Tap on video = audio toggle, double = fullscreen
video.addEventListener('click', () => { video.muted = !video.muted; video.volume = 1.0; updateAudio(); });
video.addEventListener('dblclick', (e) => { e.preventDefault(); btnFs.click(); });
})();
</script>
</body>
</html>