815 lines
26 KiB
Plaintext
815 lines
26 KiB
Plaintext
<!DOCTYPE html>
|
|
<html lang="de" class="dark">
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>FOLX Music Television — Live | Volksmusik & Schlager</title>
|
|
|
|
<!-- SEO -->
|
|
<meta name="description" content="FOLX TV Live Stream. Oberkrainer, Bayrische und Zillertaler Musik rund um die Uhr. Volksmusik & Schlager Fernsehsender Nr. 1 in DE, AT und CH." />
|
|
<meta name="keywords" content="Volksmusik, Schlager, Folx TV Live, Folx Music Television, Oberkrainer, Bayrische Musik, Zillertaler Musik, Live Stream, Musiksender, Alpenmusik, Volksmusik Live" />
|
|
<meta name="robots" content="index, follow" />
|
|
<link rel="canonical" href="https://folx.live/" />
|
|
|
|
<!-- Open Graph -->
|
|
<meta property="og:title" content="FOLX Music Television — Live" />
|
|
<meta property="og:description" content="24/7 Volksmusik & Schlager Live-Stream. Oberkrainer, Bayrische und Zillertaler Musik." />
|
|
<meta property="og:type" content="video.other" />
|
|
<meta property="og:site_name" content="FOLX Music Television" />
|
|
<meta property="og:url" content="https://folx.live/" />
|
|
<meta property="og:image" content="https://folx.live/brand/folx-with-tagline-neg.png" />
|
|
<meta property="og:image:width" content="1241" />
|
|
<meta property="og:image:height" content="875" />
|
|
<meta property="og:locale" content="de_DE" />
|
|
|
|
<!-- Twitter -->
|
|
<meta name="twitter:card" content="summary_large_image" />
|
|
<meta name="twitter:title" content="FOLX Music Television — Live" />
|
|
<meta name="twitter:description" content="24/7 Volksmusik & Schlager Live-Stream." />
|
|
<meta name="twitter:image" content="https://folx.live/brand/folx-with-tagline-neg.png" />
|
|
|
|
<!-- Favicon -->
|
|
<link rel="icon" type="image/png" href="/brand/folx-full-poz.png" />
|
|
<link rel="apple-touch-icon" href="/brand/folx-full-poz.png" />
|
|
|
|
<!-- Fonts: Druk (Archivo Black proxy) for display + Inter for body -->
|
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
<link href="https://fonts.googleapis.com/css2?family=Archivo+Black&family=Archivo:wght@400;500;600;700;800;900&display=swap" rel="stylesheet" />
|
|
|
|
<style>
|
|
:root {
|
|
--folx-magenta: #dc1c4c;
|
|
--folx-magenta-bright: #ff2e63;
|
|
--folx-magenta-deep: #9d0f32;
|
|
--bg-0: #000000;
|
|
--bg-1: #0a0a0a;
|
|
--bg-2: #141414;
|
|
--bg-3: #1e1e1e;
|
|
--border: #2a2a2a;
|
|
--text: #f5f5f5;
|
|
--text-muted: #888888;
|
|
--text-faint: #555555;
|
|
}
|
|
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
html, body {
|
|
background: var(--bg-0);
|
|
color: var(--text);
|
|
font-family: 'Archivo', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
font-weight: 500;
|
|
-webkit-font-smoothing: antialiased;
|
|
line-height: 1.5;
|
|
overflow-x: hidden;
|
|
}
|
|
|
|
/* ======================= NAVIGATION ======================= */
|
|
.topnav {
|
|
position: sticky;
|
|
top: 0;
|
|
z-index: 50;
|
|
background: rgba(0, 0, 0, 0.92);
|
|
backdrop-filter: blur(12px);
|
|
-webkit-backdrop-filter: blur(12px);
|
|
border-bottom: 1px solid var(--border);
|
|
}
|
|
.topnav-inner {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 12px 24px;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 16px;
|
|
min-height: 70px;
|
|
}
|
|
.brand {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 14px;
|
|
color: inherit;
|
|
text-decoration: none;
|
|
}
|
|
.brand-logo {
|
|
height: 48px;
|
|
width: auto;
|
|
display: block;
|
|
}
|
|
@media (max-width: 520px) {
|
|
.brand-logo { height: 36px; }
|
|
.topnav-inner { padding: 10px 16px; min-height: 56px; }
|
|
}
|
|
.brand-sep {
|
|
width: 1px;
|
|
height: 24px;
|
|
background: var(--border);
|
|
}
|
|
.brand-tagline {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 11px;
|
|
letter-spacing: 0.22em;
|
|
color: var(--text-muted);
|
|
text-transform: uppercase;
|
|
}
|
|
.live-pill {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 6px 10px 6px 8px;
|
|
border-radius: 3px;
|
|
background: var(--folx-magenta);
|
|
color: white;
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 11px;
|
|
letter-spacing: 0.18em;
|
|
text-transform: uppercase;
|
|
}
|
|
.live-dot {
|
|
display: inline-block;
|
|
width: 7px;
|
|
height: 7px;
|
|
border-radius: 50%;
|
|
background: white;
|
|
animation: livePulse 1.6s infinite;
|
|
}
|
|
@keyframes livePulse {
|
|
0%, 100% { opacity: 1; transform: scale(1); }
|
|
50% { opacity: 0.4; transform: scale(0.85); }
|
|
}
|
|
|
|
/* ======================= HERO PLAYER ======================= */
|
|
.hero {
|
|
padding: 12px 24px 24px;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
.hero-header {
|
|
margin: 6px 0 14px;
|
|
display: flex;
|
|
align-items: baseline;
|
|
justify-content: space-between;
|
|
flex-wrap: wrap;
|
|
gap: 14px;
|
|
}
|
|
.hero-title {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: clamp(28px, 4vw, 52px);
|
|
line-height: 0.95;
|
|
letter-spacing: -0.02em;
|
|
text-transform: uppercase;
|
|
}
|
|
.hero-title .accent { color: var(--folx-magenta); }
|
|
.hero-meta {
|
|
font-size: 13px;
|
|
color: var(--text-muted);
|
|
letter-spacing: 0.08em;
|
|
text-transform: uppercase;
|
|
}
|
|
.hero-meta .dot {
|
|
color: var(--folx-magenta);
|
|
padding: 0 8px;
|
|
}
|
|
|
|
/* Player wrapper — always 16:9 */
|
|
.player-frame {
|
|
position: relative;
|
|
width: 100%;
|
|
aspect-ratio: 16 / 9;
|
|
background: #000;
|
|
border: 1px solid var(--border);
|
|
overflow: hidden;
|
|
}
|
|
.player-frame video {
|
|
position: absolute;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
background: #000;
|
|
object-fit: contain;
|
|
display: block;
|
|
}
|
|
|
|
/* Overlay layer for the controls + GO LIVE pill */
|
|
.player-overlay {
|
|
position: absolute;
|
|
inset: 0;
|
|
pointer-events: none;
|
|
z-index: 3;
|
|
background: linear-gradient(180deg, rgba(0,0,0,0.4) 0%, rgba(0,0,0,0) 18%, rgba(0,0,0,0) 70%, rgba(0,0,0,0.55) 100%);
|
|
opacity: 0;
|
|
transition: opacity 0.25s;
|
|
}
|
|
.player-frame:hover .player-overlay,
|
|
.player-frame:focus-within .player-overlay,
|
|
.player-frame.touched .player-overlay {
|
|
opacity: 1;
|
|
}
|
|
.player-controls {
|
|
position: absolute;
|
|
bottom: 14px;
|
|
right: 14px;
|
|
display: flex;
|
|
gap: 6px;
|
|
pointer-events: auto;
|
|
}
|
|
.pctl {
|
|
background: rgba(0, 0, 0, 0.7);
|
|
backdrop-filter: blur(8px);
|
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
color: white;
|
|
width: 42px;
|
|
height: 42px;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 16px;
|
|
transition: all 0.15s;
|
|
padding: 0;
|
|
}
|
|
.pctl:hover {
|
|
background: var(--folx-magenta);
|
|
border-color: var(--folx-magenta);
|
|
}
|
|
.pctl {
|
|
background: rgba(0, 0, 0, 0.7);
|
|
backdrop-filter: blur(8px);
|
|
border: 1px solid rgba(255, 255, 255, 0.15);
|
|
color: white;
|
|
width: 42px;
|
|
height: 42px;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
font-size: 16px;
|
|
transition: all 0.15s;
|
|
padding: 0;
|
|
}
|
|
.pctl:hover {
|
|
background: var(--folx-magenta);
|
|
border-color: var(--folx-magenta);
|
|
}
|
|
|
|
/* Status & loading */
|
|
.player-msg {
|
|
position: absolute;
|
|
inset: 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
color: var(--text-muted);
|
|
font-size: 14px;
|
|
letter-spacing: 0.05em;
|
|
pointer-events: none;
|
|
z-index: 2;
|
|
opacity: 0;
|
|
transition: opacity 0.3s;
|
|
background: rgba(0,0,0,0.4);
|
|
}
|
|
.player-msg.visible { opacity: 1; }
|
|
.spinner {
|
|
width: 30px;
|
|
height: 30px;
|
|
border: 2px solid var(--border);
|
|
border-top-color: var(--folx-magenta);
|
|
border-radius: 50%;
|
|
animation: spin 0.8s linear infinite;
|
|
}
|
|
@keyframes spin { to { transform: rotate(360deg); } }
|
|
|
|
/* ======================= SECTIONS ======================= */
|
|
section {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
padding: 48px 24px;
|
|
}
|
|
|
|
/* Feature row */
|
|
.features {
|
|
display: grid;
|
|
grid-template-columns: repeat(4, 1fr);
|
|
gap: 2px;
|
|
background: var(--border);
|
|
border: 1px solid var(--border);
|
|
}
|
|
.feature {
|
|
background: var(--bg-1);
|
|
padding: 28px 24px;
|
|
}
|
|
.feature-num {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 11px;
|
|
color: var(--folx-magenta);
|
|
letter-spacing: 0.2em;
|
|
margin-bottom: 14px;
|
|
}
|
|
.feature-title {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 20px;
|
|
letter-spacing: -0.01em;
|
|
margin-bottom: 8px;
|
|
text-transform: uppercase;
|
|
}
|
|
.feature-desc {
|
|
color: var(--text-muted);
|
|
font-size: 14px;
|
|
line-height: 1.55;
|
|
}
|
|
|
|
/* Programm section — editorial list */
|
|
.section-label {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 12px;
|
|
letter-spacing: 0.24em;
|
|
color: var(--folx-magenta);
|
|
text-transform: uppercase;
|
|
margin-bottom: 10px;
|
|
}
|
|
.section-head {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: clamp(28px, 4vw, 48px);
|
|
line-height: 1;
|
|
letter-spacing: -0.02em;
|
|
margin-bottom: 8px;
|
|
text-transform: uppercase;
|
|
}
|
|
.section-intro {
|
|
max-width: 720px;
|
|
color: var(--text-muted);
|
|
font-size: 15px;
|
|
line-height: 1.65;
|
|
margin-bottom: 40px;
|
|
}
|
|
|
|
/* Info blocks (3-column under "Was läuft bei FOLX") */
|
|
.info-blocks {
|
|
display: grid;
|
|
grid-template-columns: repeat(3, 1fr);
|
|
gap: 2px;
|
|
background: var(--border);
|
|
border: 1px solid var(--border);
|
|
margin-top: 32px;
|
|
}
|
|
.info-block {
|
|
background: var(--bg-1);
|
|
padding: 32px 28px;
|
|
}
|
|
.info-num {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 11px;
|
|
color: var(--folx-magenta);
|
|
letter-spacing: 0.2em;
|
|
margin-bottom: 14px;
|
|
}
|
|
.info-title {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 18px;
|
|
letter-spacing: -0.01em;
|
|
margin-bottom: 8px;
|
|
text-transform: uppercase;
|
|
}
|
|
.info-desc {
|
|
color: var(--text-muted);
|
|
font-size: 14.5px;
|
|
line-height: 1.55;
|
|
}
|
|
|
|
/* Footer */
|
|
footer {
|
|
border-top: 1px solid var(--border);
|
|
padding: 48px 24px 32px;
|
|
margin-top: 32px;
|
|
}
|
|
.footer-inner {
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
display: grid;
|
|
grid-template-columns: 2fr 1.2fr 1.4fr 1.2fr;
|
|
gap: 40px;
|
|
}
|
|
.foot-label {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 11px;
|
|
color: var(--folx-magenta);
|
|
letter-spacing: 0.22em;
|
|
text-transform: uppercase;
|
|
margin-bottom: 14px;
|
|
}
|
|
.foot-title {
|
|
font-family: 'Archivo Black', sans-serif;
|
|
font-size: 20px;
|
|
text-transform: uppercase;
|
|
margin-bottom: 6px;
|
|
}
|
|
.foot-text {
|
|
color: var(--text-muted);
|
|
font-size: 13.5px;
|
|
line-height: 1.65;
|
|
}
|
|
.foot-text a {
|
|
color: var(--text);
|
|
text-decoration: none;
|
|
border-bottom: 1px solid var(--text-faint);
|
|
transition: border-color 0.15s;
|
|
}
|
|
.foot-text a:hover { border-color: var(--folx-magenta); }
|
|
.foot-socials {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0;
|
|
}
|
|
.foot-socials a {
|
|
border-bottom: none;
|
|
padding: 0;
|
|
display: inline-block;
|
|
width: fit-content;
|
|
line-height: 1.65;
|
|
}
|
|
.foot-socials a:hover { color: var(--folx-magenta); }
|
|
.foot-divider {
|
|
display: block;
|
|
width: 24px;
|
|
height: 1px;
|
|
background: var(--border);
|
|
margin: 10px 0 6px;
|
|
}
|
|
.foot-copy {
|
|
max-width: 1400px;
|
|
margin: 32px auto 0;
|
|
padding-top: 24px;
|
|
border-top: 1px solid var(--border);
|
|
display: flex;
|
|
justify-content: space-between;
|
|
color: var(--text-faint);
|
|
font-size: 12px;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
.foot-mark {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
}
|
|
.foot-mark img {
|
|
height: 18px;
|
|
width: auto;
|
|
opacity: 0.65;
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 900px) {
|
|
.features { grid-template-columns: repeat(2, 1fr); }
|
|
.info-blocks { grid-template-columns: 1fr; }
|
|
.footer-inner { grid-template-columns: 1fr; gap: 32px; }
|
|
.foot-copy { flex-direction: column; gap: 12px; }
|
|
}
|
|
@media (max-width: 520px) {
|
|
.features { grid-template-columns: 1fr; }
|
|
.brand-tagline, .brand-sep { display: none; }
|
|
.hero { padding: 16px; }
|
|
section { padding: 32px 16px; }
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
|
|
<nav class="topnav">
|
|
<div class="topnav-inner">
|
|
<a href="/" class="brand">
|
|
<img src="/brand/folx-logo-transparent.png?v=2" alt="FOLX Music Television" class="brand-logo" />
|
|
</a>
|
|
<span class="live-pill">
|
|
<span class="live-dot"></span>
|
|
Jetzt live
|
|
</span>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="hero">
|
|
<div class="hero-header">
|
|
<h1 class="hero-title">
|
|
Volksmusik<br/>
|
|
<span class="accent">Rund um die Uhr.</span>
|
|
</h1>
|
|
<div class="hero-meta">
|
|
<span>24 / 7 Live</span>
|
|
<span class="dot">•</span>
|
|
<span>HD</span>
|
|
<span class="dot">•</span>
|
|
<span>DE · AT · CH</span>
|
|
<span class="dot">•</span>
|
|
<span>Worldwide</span>
|
|
</div>
|
|
</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>
|
|
</div>
|
|
</main>
|
|
|
|
<section>
|
|
<div class="features">
|
|
<div class="feature">
|
|
<div class="feature-num">01</div>
|
|
<div class="feature-title">Oberkrainer</div>
|
|
<div class="feature-desc">Die Wurzeln der alpenländischen Volksmusik — Polka, Walzer und unvergessliche Klänge der Oberkrainer-Tradition.</div>
|
|
</div>
|
|
<div class="feature">
|
|
<div class="feature-num">02</div>
|
|
<div class="feature-title">Bayrisch</div>
|
|
<div class="feature-desc">Bayerische und österreichische Volksmusik in ihrer ganzen Vielfalt — von der Blaskapelle bis zum Alpenrock.</div>
|
|
</div>
|
|
<div class="feature">
|
|
<div class="feature-num">03</div>
|
|
<div class="feature-title">Zillertaler</div>
|
|
<div class="feature-desc">Pure alpine Lebensfreude aus dem Herzen der Tiroler Berge — Ländler, Polka und Tiroler Klassiker.</div>
|
|
</div>
|
|
<div class="feature">
|
|
<div class="feature-num">04</div>
|
|
<div class="feature-title">Schlager</div>
|
|
<div class="feature-desc">Vom Klassiker bis zum Sommerhit — die größten Schlagerstars und neuen Talente aus DE, AT und CH.</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section>
|
|
<div class="section-label">Über FOLX</div>
|
|
<h2 class="section-head">Was läuft bei FOLX</h2>
|
|
<p class="section-intro">
|
|
FOLX Music Television ist der private Fernsehsender für Volksmusik, Schlager und alpine Klänge
|
|
in Deutschland, Österreich und der Schweiz. Wir senden das Beste aus der volkstümlichen
|
|
Musikszene — von Andreas Gabalier bis Helene Fischer, von Andrea Berg bis zu den jungen
|
|
Talenten der Alpen.
|
|
</p>
|
|
<p class="section-intro">
|
|
Zwischen den Musikvideos bieten wir Tele-Shopping mit ausgewählten Produkten sowie Berichte
|
|
aus der Volksmusik- und Schlagerszene. Kein festes Programm — einfach die Musik, die Sie
|
|
lieben, jederzeit.
|
|
</p>
|
|
|
|
<div class="info-blocks">
|
|
<div class="info-block">
|
|
<div class="info-num">A</div>
|
|
<div class="info-title">Musik</div>
|
|
<div class="info-desc">Das Beste aus Volksmusik & Schlagerszene — Oberkrainer, Bayrisch, Zillertaler und mehr.</div>
|
|
</div>
|
|
<div class="info-block">
|
|
<div class="info-num">B</div>
|
|
<div class="info-title">Tele-Shopping</div>
|
|
<div class="info-desc">Premium Produkte aus dem Sortiment von Genius TV — Innovation, Qualität und das Beste für Ihren Alltag.</div>
|
|
</div>
|
|
<div class="info-block">
|
|
<div class="info-num">C</div>
|
|
<div class="info-title">Rund um die Uhr</div>
|
|
<div class="info-desc">24 Stunden Live — weltweit empfangbar über folx.live.</div>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<footer>
|
|
<div class="footer-inner">
|
|
<div>
|
|
<div class="foot-label">Sender</div>
|
|
<div class="foot-title">FOLX Music Television</div>
|
|
<div class="foot-text">
|
|
Der private Fernsehsender für Musikvideos und Entertainment aus der Volksmusik-
|
|
und Schlagerszene in Deutschland, Österreich und der Schweiz.
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="foot-label">Herausgeber</div>
|
|
<div class="foot-text">
|
|
BoldFrame Productions d.o.o.<br/>
|
|
Maribor, Slowenien
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="foot-label">Kontakt</div>
|
|
<div class="foot-text">
|
|
PRIME TIME Consulting GmbH<br/>
|
|
Sigmaringer Str. 10<br/>
|
|
72379 Hechingen · Deutschland<br/><br/>
|
|
<a href="tel:+491725675800">+49 172 5675800</a><br/>
|
|
<a href="mailto:office@folx.tv">office@folx.tv</a>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<div class="foot-label">Folgt uns</div>
|
|
<div class="foot-text foot-socials">
|
|
<a href="https://www.facebook.com/folxtv/" target="_blank" rel="noopener">Facebook</a>
|
|
<a href="https://www.instagram.com/folxtv/" target="_blank" rel="noopener">Instagram</a>
|
|
<a href="https://www.youtube.com/@folxmtv" target="_blank" rel="noopener">YouTube</a>
|
|
<a href="https://www.tiktok.com/@folx.tv" target="_blank" rel="noopener">TikTok</a>
|
|
<span class="foot-divider"></span>
|
|
<a href="https://folx.tv">folx.tv</a> — Nachrichten & Videos
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="foot-copy">
|
|
<div class="foot-mark">
|
|
<img src="/brand/folx-wordmark-transparent.png" alt="FOLX" />
|
|
<span>© <%= new Date().getFullYear() %> FOLX Music Television</span>
|
|
</div>
|
|
<div>Jederzeit, überall — folx.live</div>
|
|
</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, () => {
|
|
try {
|
|
if (hls.levels && hls.levels.length) {
|
|
hls.levels.forEach((lvl) => {
|
|
if (lvl.height && lvl.height <= 480) {
|
|
lvl.enabled = false;
|
|
}
|
|
});
|
|
}
|
|
} catch (e) {}
|
|
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>
|