mirror of
https://github.com/narrrl/pl8list-rewind.git
synced 2026-11-03 16:41:26 +01:00
The first visit shows a welcome screen where one tap starts a guest session; sign-in moves below it. Guests see a "sign in" pill, are asked once to sign in after five likes or a first follow, and need two taps to forget themselves. Drops are found in the waveform and marked on it; "drop" and the d key jump a bar before the next one. Long and dj-mix fades start on a bar once the beat is locked. Radio sheets can be shared as /?r=handle. The audio features now follow the bar, gaps before drops and the wobble rate, and a new flare pass draws loops round the drop on each kick, with a setting under visuals.
327 lines
20 KiB
HTML
327 lines
20 KiB
HTML
<!doctype html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||
<title>pl8list rewind</title>
|
||
<meta name="description" content="Endless riddim from pl8list. Like it, and it comes back.">
|
||
<meta name="theme-color" content="#000000">
|
||
<meta name="mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-capable" content="yes">
|
||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||
<meta name="apple-mobile-web-app-title" content="rewind">
|
||
<link rel="manifest" href="/manifest.webmanifest">
|
||
<link rel="icon" href="/icons/icon.svg" type="image/svg+xml">
|
||
<link rel="apple-touch-icon" href="/icons/apple-touch-icon.png">
|
||
<!-- Everything, hls.js included, is bundled and served by us: no visitor address
|
||
goes to a CDN or to pl8list. -->
|
||
<script type="module" src="/src/main.ts"></script>
|
||
</head>
|
||
<body>
|
||
<!-- Shared icons, referenced with <use href="#i-…">. -->
|
||
<svg class="sprite" aria-hidden="true">
|
||
<symbol id="i-heart" viewBox="0 0 24 24"><path fill="currentColor" d="M12 21s-7.5-4.6-10-9.3C.4 8.4 2.3 4.5 6 4.5c2.2 0 3.6 1.2 6 3.6 2.4-2.4 3.8-3.6 6-3.6 3.7 0 5.6 3.9 4 7.2C19.5 16.4 12 21 12 21z"/></symbol>
|
||
<symbol id="i-x" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" d="M6 6l12 12M18 6 6 18"/></symbol>
|
||
<symbol id="i-share" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M12 3v12M7 8l5-5 5 5M5 13v6a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2v-6"/></symbol>
|
||
<symbol id="i-open" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M7 17 17 7M9 7h8v8"/></symbol>
|
||
<symbol id="i-down" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" d="M12 4v16M6 14l6 6 6-6"/></symbol>
|
||
<symbol id="i-play" viewBox="0 0 24 24"><path fill="currentColor" d="M8 5.5v13a1 1 0 0 0 1.5.86l10.5-6.5a1 1 0 0 0 0-1.72L9.5 4.64A1 1 0 0 0 8 5.5z"/></symbol>
|
||
<symbol id="i-vol" viewBox="0 0 24 24"><path fill="currentColor" d="M4 9h4l5-4.5v15L8 15H4z"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M16.5 8.5a5 5 0 0 1 0 7M19 6a8.5 8.5 0 0 1 0 12"/></symbol>
|
||
<symbol id="i-mute" viewBox="0 0 24 24"><path fill="currentColor" d="M4 9h4l5-4.5v15L8 15H4z"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M16.5 9.5l5 5M21.5 9.5l-5 5"/></symbol>
|
||
<symbol id="i-rewind" viewBox="0 0 24 24"><circle cx="12" cy="12" r="10" fill="none" stroke="currentColor" stroke-width="2"/><path fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" d="M14.27 7.54A5 5 0 1 0 16.76 13.55"/><path fill="currentColor" d="M17.66 10.79l1.13 4.26-4.56-1.48z"/><circle cx="12" cy="12" r="1.3" fill="currentColor"/></symbol>
|
||
<symbol id="i-sliders" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M4 7h9M17 7h3M4 17h3M11 17h9"/><circle cx="15" cy="7" r="2.2" fill="none" stroke="currentColor" stroke-width="2"/><circle cx="9" cy="17" r="2.2" fill="none" stroke="currentColor" stroke-width="2"/></symbol>
|
||
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="8.5" fill="none" stroke="currentColor" stroke-width="2"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M12 7.5V12l3 2"/></symbol>
|
||
<symbol id="i-plus" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" d="M12 5v14M5 12h14"/></symbol>
|
||
<symbol id="i-check" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" d="M5 12.5l4.5 4.5L19 7.5"/></symbol>
|
||
<symbol id="i-radio" viewBox="0 0 24 24"><circle cx="12" cy="12" r="2.2" fill="currentColor"/><path fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" d="M8.5 8.5a5 5 0 0 0 0 7M15.5 8.5a5 5 0 0 1 0 7M5.6 5.6a9 9 0 0 0 0 12.8M18.4 5.6a9 9 0 0 1 0 12.8"/></symbol>
|
||
<symbol id="i-comment" viewBox="0 0 24 24"><path fill="none" stroke="currentColor" stroke-width="2" stroke-linejoin="round" d="M4.5 5.5h15v10h-8l-4.5 3.5v-3.5h-2.5z"/></symbol>
|
||
<symbol id="i-pause" viewBox="0 0 24 24"><path fill="currentColor" d="M7 4.5h3.5v15H7zM13.5 4.5H17v15h-3.5z"/></symbol>
|
||
</svg>
|
||
|
||
<header id="bar" hidden>
|
||
<span class="logo"><svg aria-hidden="true"><use href="#i-rewind"/></svg><span class="logo-pl8">pl8list </span><b>rewind</b></span>
|
||
<nav id="mode-tabs" aria-label="feed">
|
||
<button type="button" data-mode="classic">for you</button>
|
||
<button type="button" data-mode="riddim">riddim</button>
|
||
<button type="button" data-mode="fresh">fresh</button>
|
||
<button type="button" data-mode="deep">deep cuts</button>
|
||
</nav>
|
||
<button id="mode-chip" type="button" title="back to your feed" hidden>
|
||
<span class="chip-avatar" aria-hidden="true"></span><span class="chip-label"></span><span aria-hidden="true">×</span>
|
||
</button>
|
||
<div class="bar-end">
|
||
<div id="volume" hidden>
|
||
<button id="mute-btn" type="button" class="icon-btn" title="mute (m)" aria-label="mute" aria-pressed="false"><svg><use href="#i-vol"/></svg></button>
|
||
<input id="volume-slider" type="range" min="0" max="1" step="0.01" aria-label="volume">
|
||
</div>
|
||
<button id="history-btn" type="button" class="icon-btn" title="history (h)" aria-label="history" aria-controls="history"><svg><use href="#i-clock"/></svg></button>
|
||
<button id="likes-btn" type="button" class="icon-btn" title="likes" aria-label="likes" aria-controls="likes"><svg><use href="#i-heart"/></svg></button>
|
||
<button id="filters-btn" type="button" class="icon-btn" title="filters and settings" aria-label="filters and settings" aria-controls="filters"><svg><use href="#i-sliders"/></svg></button>
|
||
<button id="account-btn" type="button" class="avatar-btn" title="account" aria-label="account" aria-controls="account"></button>
|
||
</div>
|
||
</header>
|
||
|
||
<div id="login" hidden>
|
||
<div class="login-box">
|
||
<h1><svg class="login-mark" aria-hidden="true"><use href="#i-rewind"/></svg>pl8list <b>rewind</b></h1>
|
||
<p class="tagline">endless riddim from pl8list. like it, and it comes back.</p>
|
||
<p class="or">sign in with pl8list to bring your follows and likes along. What you did as a guest comes with you.</p>
|
||
<form id="email-form">
|
||
<label for="email">sign in with your pl8list email</label>
|
||
<input id="email" type="email" name="email" autocomplete="email" required placeholder="you@example.com">
|
||
<button type="submit">send code</button>
|
||
</form>
|
||
<form id="code-form" hidden>
|
||
<label for="code">pl8list sent a 6-digit code to <span id="sent-to"></span></label>
|
||
<input id="code" name="code" inputmode="numeric" autocomplete="one-time-code" pattern="[0-9]{6}"
|
||
maxlength="6" required placeholder="123456">
|
||
<label class="check">
|
||
<input type="checkbox" id="connect" name="connect">
|
||
<span>stay connected to pl8list on this device
|
||
<small>keeps your feed and library in sync, and saves what you like and follow here to
|
||
your pl8list library. Your pl8list login is stored encrypted with a key only this browser
|
||
holds. Turn it off any time under your account.</small></span>
|
||
</label>
|
||
<button type="submit">sign in</button>
|
||
<div class="login-links">
|
||
<button type="button" id="resend" class="link">resend code</button>
|
||
<button type="button" id="restart" class="link">use another email</button>
|
||
</div>
|
||
</form>
|
||
<button type="button" id="login-cancel" class="link">cancel, keep listening</button>
|
||
<p id="login-error" role="alert"></p>
|
||
<p class="fineprint">
|
||
This site is not affiliated with pl8list. Your email and code
|
||
go to pl8list, which signs this server in for you. Unless you choose to stay connected, we use
|
||
that pl8list login once to read your feed and library, then log it out; it is never stored. We
|
||
keep your pl8list handle, the artists you follow and what you play and like.
|
||
</p>
|
||
<p class="fineprint legal-links">
|
||
<a href="/datenschutz">Datenschutz / privacy</a> · <a href="/impressum">Impressum</a>
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<form id="filters" aria-labelledby="filters-title">
|
||
<h2 id="filters-title">filters and settings</h2>
|
||
<fieldset>
|
||
<legend>filters</legend>
|
||
<label class="switch"><input type="checkbox" name="free"> <span>free downloads only</span></label>
|
||
<div class="bpm">
|
||
<div class="bpm-head"><span>bpm</span><output id="bpm-out">any</output></div>
|
||
<div class="range2">
|
||
<input type="range" name="bpm_min" min="60" max="200" step="1" value="60" aria-label="lowest bpm">
|
||
<input type="range" name="bpm_max" min="60" max="200" step="1" value="200" aria-label="highest bpm">
|
||
</div>
|
||
<div class="presets">
|
||
<button type="button" data-bpm="60-200">any</button>
|
||
<button type="button" data-bpm="138-142">140</button>
|
||
<button type="button" data-bpm="148-152">150</button>
|
||
<button type="button" data-bpm="165-178">170</button>
|
||
</div>
|
||
</div>
|
||
<div class="sheet-actions">
|
||
<button type="submit" class="primary">apply filters</button>
|
||
<button type="button" id="filters-clear" class="link">clear</button>
|
||
</div>
|
||
</fieldset>
|
||
<fieldset class="modes">
|
||
<legend>visuals</legend>
|
||
<label><input type="radio" name="visuals" value="liquid"> liquid</label>
|
||
<label><input type="radio" name="visuals" value="simple"> simple</label>
|
||
</fieldset>
|
||
<fieldset class="modes" id="flares-setting">
|
||
<legend>solar flares <small>on the liquid drop</small></legend>
|
||
<label title="on for riddim, tearout and 140 tracks"><input type="radio" name="flares" value="auto"> auto</label>
|
||
<label><input type="radio" name="flares" value="on"> on</label>
|
||
<label><input type="radio" name="flares" value="off"> off</label>
|
||
</fieldset>
|
||
<fieldset class="modes">
|
||
<legend>crossfade</legend>
|
||
<label><input type="radio" name="crossfade" value="0"> cut</label>
|
||
<label><input type="radio" name="crossfade" value="0.9"> short</label>
|
||
<label><input type="radio" name="crossfade" value="4"> long</label>
|
||
<label><input type="radio" name="crossfade" value="8"> dj mix</label>
|
||
</fieldset>
|
||
<label class="switch"><input type="checkbox" name="bass"> <span>bass boost</span></label>
|
||
<fieldset class="modes">
|
||
<legend>sleep timer <span id="sleep-left"></span></legend>
|
||
<label><input type="radio" name="sleep" value="off"> off</label>
|
||
<label><input type="radio" name="sleep" value="15"> 15 min</label>
|
||
<label><input type="radio" name="sleep" value="30"> 30 min</label>
|
||
<label><input type="radio" name="sleep" value="60"> 1 h</label>
|
||
<label><input type="radio" name="sleep" value="end"> end of track</label>
|
||
</fieldset>
|
||
<button type="button" id="help-open-settings" class="link">gestures and shortcuts</button>
|
||
</form>
|
||
|
||
<aside id="likes" aria-labelledby="likes-title">
|
||
<h2 id="likes-title">likes</h2>
|
||
<div class="sheet-tools">
|
||
<input id="likes-search" type="search" placeholder="search your likes" aria-label="search your likes" autocomplete="off">
|
||
<label class="switch small"><input type="checkbox" id="likes-shuffle"> <span>shuffle</span></label>
|
||
<button type="button" id="likes-play" class="primary"><svg><use href="#i-play"/></svg> play</button>
|
||
</div>
|
||
<ol id="likes-list" class="track-list"></ol>
|
||
</aside>
|
||
|
||
<aside id="history" aria-labelledby="history-title">
|
||
<h2 id="history-title">played lately</h2>
|
||
<p class="fineprint">kept on this device only.</p>
|
||
<ol id="history-list" class="track-list"></ol>
|
||
<button type="button" id="history-clear" class="link">clear history</button>
|
||
</aside>
|
||
|
||
<aside id="account" aria-labelledby="account-handle">
|
||
<h2 id="account-handle"></h2>
|
||
<p id="stats"></p>
|
||
<section id="sync" aria-labelledby="sync-title">
|
||
<h3 id="sync-title">pl8list sync</h3>
|
||
<p id="sync-status"></p>
|
||
<button type="button" id="sync-btn">resync with pl8list</button>
|
||
<button type="button" id="disconnect-btn" class="link" hidden>stop staying connected on this device</button>
|
||
</section>
|
||
<button type="button" id="logout-btn">sign out</button>
|
||
<button type="button" id="logout-all-btn" class="link">sign out on all devices</button>
|
||
<button type="button" id="help-open" class="link">gestures and shortcuts</button>
|
||
<a href="/account/export" download>download my data</a>
|
||
<button type="button" id="delete-open" class="link danger">delete account…</button>
|
||
<form id="delete-form" hidden>
|
||
<label for="delete-confirm">This deletes your likes and listening history here, right away.
|
||
Your pl8list account is not touched. Type <b id="delete-handle"></b> to confirm.</label>
|
||
<input id="delete-confirm" name="confirm" autocomplete="off" required>
|
||
<button type="submit" class="danger">delete my account</button>
|
||
</form>
|
||
<p class="fineprint legal-links">
|
||
<a href="/datenschutz">Datenschutz / privacy</a> · <a href="/impressum">Impressum</a>
|
||
</p>
|
||
</aside>
|
||
|
||
<main id="feed"></main>
|
||
<p id="feed-status" role="status" hidden></p>
|
||
|
||
<div id="start" hidden>
|
||
<h1 class="start-logo"><svg aria-hidden="true"><use href="#i-rewind"/></svg>pl8list <b>rewind</b></h1>
|
||
<button type="button" class="start-play" aria-label="start playing"><svg><use href="#i-play"/></svg></button>
|
||
<p class="start-track"></p>
|
||
<p class="start-hint">tap anywhere to start · no account needed</p>
|
||
<div class="start-welcome">
|
||
<button type="button" id="start-signin" class="link">or sign in with pl8list</button>
|
||
<p class="fineprint">Not affiliated with pl8list. Without an account we keep what you play, like and
|
||
follow under a random cookie, to pick tracks for you; "forget me" in the account menu deletes it.
|
||
<a href="/datenschutz">Datenschutz / privacy</a> · <a href="/impressum">Impressum</a></p>
|
||
</div>
|
||
</div>
|
||
|
||
<button type="button" id="up-next" hidden>
|
||
<span class="up-next-avatar" aria-hidden="true"></span>
|
||
<span class="up-next-text"><small>up next</small><span class="up-next-title"></span></span>
|
||
<svg aria-hidden="true"><use href="#i-down"/></svg>
|
||
</button>
|
||
|
||
<!-- Artist radio: who the radio is built around, and who is next to them. -->
|
||
<div id="station" hidden>
|
||
<section class="station-box" role="dialog" aria-modal="true" aria-labelledby="station-name">
|
||
<button type="button" id="station-back" class="link" hidden></button>
|
||
<button type="button" id="station-close" class="icon-btn" aria-label="close"><svg><use href="#i-x"/></svg></button>
|
||
<div class="station-head">
|
||
<div class="station-avatar"><span class="initial"></span></div>
|
||
<div>
|
||
<p class="station-kicker">artist radio</p>
|
||
<h2 id="station-name"></h2>
|
||
<p id="station-sub"></p>
|
||
<div id="station-tags" class="chips"></div>
|
||
</div>
|
||
</div>
|
||
<h3>around them</h3>
|
||
<ol id="station-neighbours"></ol>
|
||
<p id="station-exploring" hidden>finding related artists…</p>
|
||
<button type="button" id="station-start" class="primary"><svg><use href="#i-play"/></svg> start radio</button>
|
||
<button type="button" id="station-share" class="link">share this radio</button>
|
||
</section>
|
||
</div>
|
||
|
||
<div id="radio-end" hidden>
|
||
<p></p>
|
||
<button type="button" id="radio-end-feed">back to your feed</button>
|
||
<button type="button" id="radio-end-next" class="primary"></button>
|
||
</div>
|
||
|
||
<div id="help" aria-labelledby="help-title">
|
||
<div class="help-box">
|
||
<h2 id="help-title">controls</h2>
|
||
<dl class="touch-only">
|
||
<dt>tap</dt><dd>play / pause</dd>
|
||
<dt>double-tap</dt><dd>like</dd>
|
||
<dt>swipe up / down</dt><dd>next / previous</dd>
|
||
<dt>drag waveform</dt><dd>seek</dd>
|
||
</dl>
|
||
<dl class="pointer-only">
|
||
<dt>click · space</dt><dd>play / pause</dd>
|
||
<dt>double-click · l</dt><dd>like</dd>
|
||
<dt>↓ j · ↑ k · wheel</dt><dd>next / previous</dd>
|
||
<dt>← →</dt><dd>seek 10 s</dd>
|
||
<dt>f</dt><dd>follow artist</dd>
|
||
<dt>r</dt><dd>artist radio</dd>
|
||
<dt>x</dt><dd>not for me</dd>
|
||
<dt>s</dt><dd>share</dd>
|
||
<dt>v</dt><dd>liquid / simple visuals</dd>
|
||
<dt>z</dt><dd>zen: just the drop</dd>
|
||
<dt>c</dt><dd>filters and settings</dd>
|
||
<dt>h</dt><dd>history</dd>
|
||
<dt>0–9 · , .</dt><dd>jump to 0–90 % · seek 5 s</dd>
|
||
<dt>d</dt><dd>jump to the next drop (the marks on the waveform)</dd>
|
||
<dt>m · + −</dt><dd>mute · volume</dd>
|
||
<dt>?</dt><dd>this help</dd>
|
||
</dl>
|
||
<p>Drag the liquid artwork sideways to spin it. On riddim the solar flares round it follow the
|
||
beat: a loop on each kick, the same crown every bar, a break on each snare. Lock-screen and
|
||
headphone buttons work too.</p>
|
||
<p class="pointer-only fineprint">Keys like r or x doing something else, such as reloading or
|
||
closing the tab? A vim-keys browser extension (Vimium and the like) takes them first:
|
||
turn it off for this site.</p>
|
||
<button type="button" id="help-close">got it</button>
|
||
</div>
|
||
</div>
|
||
|
||
<div id="toast" role="status" aria-live="polite"></div>
|
||
|
||
<template id="card-tpl">
|
||
<section class="card">
|
||
<div class="bg"></div>
|
||
<div class="glow"></div>
|
||
<div class="content">
|
||
<div class="art">
|
||
<span class="initial"></span>
|
||
<span class="paused-badge"><svg><use href="#i-play"/></svg></span>
|
||
<span class="spinner"></span>
|
||
</div>
|
||
<p class="why"></p>
|
||
<h1 class="title"></h1>
|
||
<div class="byline">
|
||
<span class="artist-avatar" aria-hidden="true"></span>
|
||
<a class="artist" target="_blank" rel="noopener"></a>
|
||
<button type="button" class="follow pill" title="follow artist (f)"><svg><use href="#i-plus"/></svg><span>follow</span></button>
|
||
<button type="button" class="radio pill" title="more like this artist (r)"><svg><use href="#i-radio"/></svg><span>radio</span></button>
|
||
</div>
|
||
<div class="chips"></div>
|
||
<p class="desc"></p>
|
||
<div class="wave-wrap">
|
||
<canvas class="wave"></canvas>
|
||
<span class="wave-tip"></span>
|
||
</div>
|
||
<div class="time"><span class="cur">0:00</span><button type="button" class="to-drop" title="jump to the drop (d)">drop <svg><use href="#i-down"/></svg></button><span class="counts"></span><span class="dur"></span></div>
|
||
</div>
|
||
<nav class="actions">
|
||
<button type="button" class="act like" title="like (l)" aria-label="like"><span class="ring"><svg><use href="#i-heart"/></svg></span><span class="n saves"></span></button>
|
||
<button type="button" class="act dislike" title="not for me (x)" aria-label="not for me"><span class="ring"><svg><use href="#i-x"/></svg></span><span class="n">nope</span></button>
|
||
<button type="button" class="act share" title="share (s)" aria-label="share"><span class="ring"><svg><use href="#i-share"/></svg></span><span class="n">share</span></button>
|
||
<a class="act open" target="_blank" rel="noopener" title="open on pl8list" aria-label="open on pl8list"><span class="ring"><svg><use href="#i-comment"/></svg></span><span class="n comments"></span></a>
|
||
<button type="button" class="act next" title="next (j)" aria-label="next"><span class="ring"><svg><use href="#i-down"/></svg></span><span class="n">next</span></button>
|
||
</nav>
|
||
</section>
|
||
</template>
|
||
|
||
</body>
|
||
</html>
|