Files
Media-Server-Setup/about/index.html

170 lines
11 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Vanguard Media</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
:root{--bg:#141414;--fg:#e6e6e6;--mut:#9a9a9a;--acc:#3d8bfd;--ok:#2ecc71;--box:#1f1f1f;--line:#2e2e2e}
html,body{margin:0;background:var(--bg);color:var(--fg);font:15px/1.5 system-ui,sans-serif}
main{max-width:860px;margin:0 auto;padding:28px 16px 48px}
header{display:flex;align-items:baseline;gap:14px;flex-wrap:wrap;margin-bottom:6px}
h1{font-size:26px;margin:0}.who{color:var(--mut)}.who b{color:var(--fg)}
.pills{margin:6px 0 22px}.pill{display:inline-block;background:#2a2a2a;border-radius:999px;padding:2px 10px;font-size:12px;margin:0 6px 6px 0;color:#bbb}
section{background:var(--box);border:1px solid var(--line);border-radius:14px;padding:18px 20px;margin-bottom:16px}
section h2{margin:0 0 4px;font-size:17px}section .lead{color:var(--mut);margin:0 0 12px}
.links{display:grid;grid-template-columns:repeat(auto-fill,minmax(240px,1fr));gap:10px;margin:10px 0}
a.card{display:block;background:#262626;border:1px solid #333;border-radius:10px;padding:12px 14px;color:var(--fg);text-decoration:none}
a.card:hover{border-color:var(--acc)}a.card b{display:block;margin-bottom:2px}a.card span{color:var(--mut);font-size:13px}
details{margin-top:8px}summary{cursor:pointer;color:var(--mut);font-size:13px}
ol,ul{margin:8px 0 0;padding-left:20px}li{margin:4px 0}code{font-family:ui-monospace,monospace;background:#121212;padding:1px 6px;border-radius:5px}
.hidden{display:none}footer{color:var(--mut);font-size:13px;margin-top:20px}footer a{color:var(--mut)}
</style>
</head>
<body>
<main>
<header><h1>Vanguard Media</h1><div class="who">signed in as <b id="who">…</b></div></header>
<div class="pills" id="pills"></div>
<section id="s-everyone">
<h2>Watch</h2>
<p class="lead">Everything here uses your Discord login. One sign-in covers all of it.</p>
<div class="links">
<a class="card" id="l-watch" href="#"><b>Recordings &amp; clips</b><span>Jellyfin — by streamer, by day/week/month</span></a>
<a class="card" id="l-live" href="#"><b>Live now</b><span>every active stream in one page, audio follows the window you click</span></a>
<a class="card" href="/clips/"><b>Send your game clips</b><span>pair your PC once; clips upload themselves</span></a>
<a class="card" href="/logout"><b>Sign out</b><span>ends the Discord session for all Vanguard sites</span></a>
</div>
<details><summary>How watching works</summary>
<ul>
<li>Jellyfin: each streamer is a show. This week's recordings sit under weekday seasons, older ones roll into week, month and year. Nothing moves; it is only re-labelled.</li>
<li>Live: windows open as people go live and close when they stop. Click a window to hear it; the speaker button pins audio on; the slider is per window.</li>
<li>Clips: install Syncthing on your gaming PC, paste its Device ID on the clips page, accept the folder it offers. Only video files are pulled.</li>
</ul>
</details>
</section>
<section id="s-streamers" class="hidden">
<h2>Stream</h2>
<p class="lead">You are in <code>streamers</code>: you can publish under your own name. No passwords, no stream keys to keep.</p>
<div class="links">
<a class="card" href="/dock/"><b>OBS dock</b><span>title → Go Live; Dump tonight; manual setup</span></a>
<a class="card" id="l-golive" href="#"><b>Go Live from the browser</b><span>Windows Chrome: share the game window, no OBS</span></a>
</div>
<details><summary>OBS setup (once)</summary>
<ol>
<li>OBS → Tools → WebSocket Server Settings → enable, set a password.</li>
<li>OBS → Docks → Custom Browser Docks → add <code id="dockurl">…/dock/</code>; log in with Discord inside the dock.</li>
<li>Dock → Settings: OBS WebSocket password (the rest is prefilled). Optional title prefix/suffix (<code>{date}</code> = today).</li>
<li>Dock → Timecode band → <b>Add band + clock source</b> while not streaming (gives editors a frame-accurate timecode).</li>
<li>Per stream: type a title, <b>Go Live</b>. The dock mints a 12-hour token and sets your stream key itself.</li>
</ol>
</details>
<details><summary>Rules worth knowing</summary>
<ul>
<li>Everything streamed is recorded and visible to editors and members. <b>Dump tonight</b> throws a night away (3-day undo by an admin).</li>
<li>Titles: letters, digits, <code>_ . -</code>; no double underscore; the dock shows the final name as you type.</li>
<li>Browser Go Live needs Windows + Chrome/Edge 141+ for window audio and the GPU encoder; on Linux use OBS.</li>
</ul>
</details>
</section>
<section id="s-editors" class="hidden">
<h2>Edit</h2>
<p class="lead">You are in <code>editors</code>: read streams and clips, write finals.</p>
<div class="links">
<a class="card" href="/"><b>Browse &amp; download</b><span>copyparty — scrub in the browser, download originals, zip folders</span></a>
<a class="card" href="/finals/"><b>Upload finals</b><span>the only folder editors can write to</span></a>
</div>
<details><summary>Multicam &amp; timecode</summary>
<ul>
<li>Every stream file has a timecode track (time of day, Eastern) and a <code>.json</code> sidecar with the exact capture time, source (<code>strip</code> = frame-accurate from the overscan band, <code>arrival</code> = coarse), drift and gaps.</li>
<li>Multicam: sync by timecode, cross-check with voice audio. Export at the game resolution (2560×1440 / 1920×1080) — that drops the thin band at the bottom.</li>
<li>Files are H.264 MP4, constant frame rate, index up front. Streams are published a few minutes after they end.</li>
<li>No WebDAV (Discord-only login). Select files/folders and use copyparty's zip/tar download.</li>
</ul>
</details>
</section>
<section id="s-mediaadmins" class="hidden">
<h2>Media admin</h2>
<p class="lead">You are in <code>media-admins</code>: full rights on every folder, trash, Syncthing, dump anyone's night.</p>
<div class="links">
<a class="card" href="/trash/"><b>Trash</b><span>dumped nights, purged after 3 days</span></a>
<a class="card" href="/sync/"><b>Syncthing</b><span>device pairing, folder states</span></a>
<a class="card" href="/whoami"><b>Who am I</b><span>identity headers as the apps see them</span></a>
</div>
<details><summary>Admin notes</summary>
<ul>
<li>Group changes in Authentik apply on the next login: <a href="/logout">sign out</a> and back in.</li>
<li>Dump anyone's night: the dock's Dump works on your own; for others use the API with <code>{"user":"name"}</code> or ask the owner.</li>
<li>New gamer: they self-serve on <a href="/clips/">/clips/</a>; you only need to watch Syncthing accept the device.</li>
</ul>
</details>
</section>
<section id="s-git" class="hidden">
<h2>Code</h2>
<p class="lead">You are in <code>git-users</code>.</p>
<div class="links">
<a class="card" id="l-git" href="#"><b>Gitea</b><span>repos, issues, CI — sign in with authentik</span></a>
</div>
<details><summary>Notes</summary>
<ul><li>SSH remotes use port 2222: <code id="gitssh">ssh://git@…:2222/org/repo.git</code>. Add your key under Settings → SSH keys.</li>
<li>The stack's own repo is <code>techy/Media-Server-Setup</code>.</li></ul>
</details>
</section>
<section id="s-bot" class="hidden">
<h2>Bot</h2>
<p class="lead">You are in <code>bot-users</code>.</p>
<div class="links"><a class="card" id="l-bot" href="#"><b>Bot web UI</b><span>Discord bot control panel</span></a></div>
</section>
<section id="s-admins" class="hidden">
<h2>Administration</h2>
<p class="lead">You are in <code>admins</code> or <code>authentik Admins</code>.</p>
<div class="links">
<a class="card" id="l-auth" href="#"><b>Authentik admin</b><span>users, groups, Discord source, policies</span></a>
<a class="card" id="l-jfadmin" href="#"><b>Jellyfin dashboard</b><span>libraries, plugin, scheduled tasks</span></a>
<a class="card" id="l-gitadmin" href="#"><b>Gitea site admin</b><span>auth sources, runners</span></a>
</div>
<details><summary>Where things live</summary>
<ul>
<li>Server: <code>~/vanguard-stream</code> on the box; <code>STATUS.md</code> = what runs / who does what / what's unfinished; <code>README.md</code> = how.</li>
<li>Change hostnames, bot token: <code>./configure.py</code>. Plugin updates: <code>./installJellyfinPlugin.sh</code>. Portal: <code>./deployLive.sh</code> (dev box).</li>
<li>Streamers = Authentik group <code>streamers</code>; editors = <code>editors</code>; everything follows Discord roles via the roles policy.</li>
</ul>
</details>
</section>
<footer>Vanguard Media · <a href="/about/">/about</a> · <a href="/logout">sign out</a></footer>
</main>
<script>
const $ = id => document.getElementById(id);
const host = location.hostname, base = host.replace(/^[^.]+\./, '');
const sub = s => `https://${s}.${base}`;
$('l-watch').href = sub('watch'); $('l-live').href = sub('live'); $('l-golive').href = sub('live') + '/#golive';
$('l-git').href = sub('git'); $('l-bot').href = sub('bot'); $('l-auth').href = sub('auth') + '/if/admin/';
$('l-jfadmin').href = sub('watch') + '/web/#/dashboard'; $('l-gitadmin').href = sub('git') + '/-/admin';
$('dockurl').textContent = location.origin + '/dock/'; $('gitssh').textContent = `ssh://git@${'git.' + base}:2222/org/repo.git`;
(async () => {
try {
const r = await fetch('/me', {credentials:'same-origin'}); const d = await r.json(); if (!r.ok) throw new Error(d.error || r.status);
$('who').textContent = d.name && d.name !== d.user ? `${d.name} (${d.user})` : d.user;
$('pills').innerHTML = d.groups.map(g => `<span class="pill">${g}</span>`).join('') || '<span class="pill">no groups yet — ask an admin for a role</span>';
const has = g => d.groups.includes(g);
const show = (id, on) => $(id).classList.toggle('hidden', !on);
const isAdmin = has('admins') || has('authentik Admins');
show('s-streamers', has('streamers') || isAdmin);
show('s-editors', has('editors') || has('media-admins') || isAdmin);
show('s-mediaadmins', has('media-admins') || isAdmin);
show('s-git', has('git-users') || has('git-admins') || isAdmin);
show('s-bot', has('bot-users') || isAdmin);
show('s-admins', isAdmin);
} catch (e) { $('who').textContent = 'unknown (' + e.message + ')'; }
})();
</script>
</body>
</html>