Files
site/webamp.html
T

47 lines
3.2 KiB
HTML

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>g*ndora · winamp</title>
<link rel="icon" href="favicon.svg">
<style>
html,body{margin:0;height:100%;background:#0b0b0e;color:#ededf0;font:13px ui-monospace,Menlo,Consolas,monospace}
#note{position:fixed;left:50%;top:50%;transform:translate(-50%,-50%);text-align:center;color:#8a8a96;line-height:1.7;max-width:420px;padding:0 16px}
#note a{color:#ededf0}
#bar{position:fixed;left:0;right:0;bottom:0;display:flex;gap:14px;justify-content:center;padding:10px;font-size:11px;letter-spacing:.18em;color:#8a8a96}
#bar a{color:#8a8a96;text-decoration:none}#bar a:hover{color:#ededf0}
#app{position:fixed;inset:0}
</style>
</head>
<body>
<div id="app"></div>
<div id="note">loading…</div>
<div id="bar"><a href="/">◂ G*NDORA</a><span id="count"></span></div>
<script type="module">
/* g*ndora's library in Winamp. The tracks come from this origin's IndexedDB (dev.gandora.lol has its own library:
play a station here first, or open a shared tape). Milkdrop runs Butterchurn's presets on the real audio. */
import Webamp from "https://unpkg.com/webamp@2.3.1/built/webamp.butterchurn-bundle.min.mjs";
const note = document.getElementById("note");
function open() { return new Promise((ok, no) => { const r = indexedDB.open("gandora", 3); r.onupgradeneeded = () => { const d = r.result; for (const s of ["tracks", "stations", "tapes"]) if (!d.objectStoreNames.contains(s)) d.createObjectStore(s, { keyPath: "id" }); }; r.onsuccess = () => ok(r.result); r.onerror = () => no(r.error); }); }
async function all(store) { const d = await open(); return new Promise((ok, no) => { const r = d.transaction(store).objectStore(store).getAll(); r.onsuccess = () => ok(r.result); r.onerror = () => no(r.error); }); }
try {
const [tracks, stations] = await Promise.all([all("tracks"), all("stations")]);
const byStation = Object.fromEntries(stations.map((s) => [s.id, s.name || s.seed]));
const rows = tracks.filter((t) => t.blob && t.spec && !t.spec.break).sort((a, b) => (b.kept - a.kept) || (b.made - a.made));
document.getElementById("count").textContent = rows.length ? `${rows.length} TRACKS · KEPT FIRST` : "";
if (!rows.length) { note.innerHTML = 'nothing in this library yet.<br>this is <b>dev.gandora.lol</b>, which keeps its own library: <a href="/">play a station here</a> first, then come back.'; }
else note.remove();
const initialTracks = rows.map((t) => ({ blob: t.blob, metaData: { title: t.spec.title, artist: byStation[t.spec.stationId] || t.spec.seed || "g*ndora" }, duration: t.spec.seconds || 120 }));
const webamp = new Webamp({
initialTracks,
windowLayout: { main: { position: { top: 0, left: 0 } }, equalizer: { position: { top: 116, left: 0 } }, playlist: { position: { top: 232, left: 0 }, size: { extraHeight: 4, extraWidth: 0 } }, milkdrop: { position: { top: 0, left: 275 }, size: { extraHeight: 12, extraWidth: 7 } } },
enableHotkeys: true,
});
await webamp.renderWhenReady(document.getElementById("app"));
webamp.onClose(() => { location.href = "/"; });
} catch (e) { note.textContent = "winamp could not start: " + e.message; }
</script>
</body>
</html>