Playout: slate fallback, strict ffprobe validation, Prometheus metrics Chat: history on join, DM offline delivery, env-config rate limits, Redis auto-reconnect, heartbeat, ban/mute enforcement, DM metrics Viewer: presence indicators, schedule overlay, public /api/schedule Admin: playlist drag-reorder, schedule overrides CRUD, user actions, inline mod buttons, CSV export, config editor, restart buttons, upload normalization gate, analytics time range nginx: CORS preflight, JSON health, stub_status Docs: test-lab vs production distinction across all configs/docs Infra: Redis maxmemory, CD health IP-agnostic, slate volume mount
65 lines
2.6 KiB
HTML
65 lines
2.6 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
|
|
<head>
|
|
<meta charset="UTF-8" />
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
<title>Linear Void - 24/7 Synchronized Channel</title>
|
|
<link rel="stylesheet" href="/src/style.css" />
|
|
</head>
|
|
|
|
<body class="lv-body">
|
|
<main class="viewer-shell" aria-label="Live player and chat">
|
|
<header class="viewer-header">
|
|
<div class="viewer-brand-group">
|
|
<div class="brand-badge" aria-hidden="true">LV</div>
|
|
<div>
|
|
<h1 class="viewer-title">Linear Void</h1>
|
|
<p class="viewer-subtitle">24/7 Synchronized Channel • Live</p>
|
|
</div>
|
|
</div>
|
|
<button id="chat-toggle" type="button" class="btn btn-secondary chat-toggle-btn" onclick="toggleChatPanel()" aria-controls="chat-panel" aria-expanded="true">Hide Chat</button>
|
|
</header>
|
|
|
|
<section class="viewer-content" aria-label="Live stream and chat layout">
|
|
<section class="player-stage" aria-label="Video stage">
|
|
<video id="player" class="player" controls autoplay muted playsinline></video>
|
|
<div id="now-playing" class="now-playing-overlay" aria-live="polite">
|
|
<span id="np-title">Loading...</span>
|
|
<span id="np-next" class="np-next"></span>
|
|
</div>
|
|
</section>
|
|
|
|
<aside id="chat-panel" class="chat-sidebar" aria-label="Chat panel">
|
|
<header class="chat-header">
|
|
<div class="chat-room-title">
|
|
<span class="chat-live-marker" aria-hidden="true">●</span>
|
|
<span id="room-name">Main Channel</span>
|
|
</div>
|
|
<button type="button" class="btn btn-secondary" onclick="togglePrivateDM()">New DM</button>
|
|
</header>
|
|
|
|
<section id="messages" class="chat-messages" aria-live="polite" aria-label="Message stream"></section>
|
|
|
|
<section id="presence-panel" class="presence-panel" aria-label="Online users">
|
|
<div id="presence-list" class="presence-list"></div>
|
|
</section>
|
|
|
|
<div class="chat-input-area">
|
|
<div class="chat-input-row">
|
|
<label for="message-input" class="sr-only">Message input</label>
|
|
<input id="message-input" type="text" placeholder="Type a message..." class="input" onkeydown="if(event.key === 'Enter') sendMessage()" />
|
|
<button type="button" class="btn btn-primary" onclick="sendMessage()">Send</button>
|
|
</div>
|
|
<p class="chat-note">
|
|
Synced with video • Moderation active
|
|
</p>
|
|
</div>
|
|
</aside>
|
|
</section>
|
|
</main>
|
|
|
|
<script type="module" src="/src/main.ts"></script>
|
|
</body>
|
|
|
|
</html> |