The browser side of the song index: index.astro embeds loadSongs() as JSON in #jev-songs, and the REPL reads it back from the page.
The song the home page opens on: selected on the jev panel, loaded into the editor, and played once audio is allowed (see useReplContext).
11export const featuredSongId = 'jev/lightning-in-a-bottle';
The song this page opens on: a song's own page (/songs/<theme>/<song>/) names it in a jev-song meta tag (ReplPage.astro); the home page opens on the featured song.
A listener's song link (/?listener=<id>) opens on that song instead, fetched from the Worker when the editor starts (useReplContext).
The song in the editor, as the song browser, the radio and "is it art?" see it: set when a song is loaded, and read against the editor's code, so an edited song still counts as that song.
44let playingId = null; 45const playingListeners = new Set(); 46export const nowPlaying = { 47 subscribe(listener) { 48 playingListeners.add(listener); 49 return () => playingListeners.delete(listener); 50 }, 51 get: () => playingId, 52 set(id) { 53 playingId = id; 54 for (const listener of playingListeners) listener(); 55 }, 56};
Songs are arranged with masks that count cycles from 0, so they must start
from stopped: the scheduler's stop() resets the cycle count, pause() does not.
A song picked here plays live: a performance being replayed ends
(performance.mjs). Only the site's own songs: a listener's has no code
(listeners.mjs) and plays in the sandbox (sandbox.mjs, playListenerSong).
A listener's song (listeners.mjs): its code into the editor as foreign,
so it is evaluated only in the sandbox (sandbox.mjs), and, with play,
played there. With replay, a recorded performance's id: the sandbox's
jev()s play that take and ask Jev nothing, still in the sandbox (the
frame arms it; sandbox.mjs's armSandboxReplay). Resolves to { replaying:
{ changed } } when it replays, or { error } when that take could not be
loaded (Jev then plays the song live), else {}.
80export async function loadListenerSong(editor, song, { play = false, replay = null } = {}) { 81 if (!editor || !song.foreignCode) return {}; 82 endReplay(); 83 let replaying = null; 84 let error; 85 if (replay) { 86 try { 87 const performance = await fetchPerformance(replay); 88 if (performance.song !== song.id) throw new Error(`that take is of ${performance.song}`); 89 replaying = { jevs: performance.jevs, changed: performance.codeHash !== (await codeHash(song.foreignCode)) }; 90 } catch (e) { 91 error = e.message; 92 } 93 } 94 showSong(song); 95 nowPlaying.set(song.id); 96 await editor.stop(); 97 // `code`: the song as written, so the recorder knows an edited one (JevPerformance.jsx) 98 showForeign(editor, song.foreignCode, { song: { title: song.title, author: song.author, id: song.id, code: song.foreignCode } }); 99 armSandboxReplay(song.id, replaying); 100 if (play) await playInSandbox(song.foreignCode); 101 return replaying ? { replaying: { changed: replaying.changed } } : error ? { error } : {}; 102}
A song's shareable address. Picking a song puts it in the address bar (keeping the query, e.g. ?session=, but not a replayed ?performance=, which that song does not play) and the tab title, so the link to copy is always the song that is playing. A listener's song has no page of its own (the site is built before it exists): its address is the home page with ?listener=<id>.
110export const songPath = (song) => `/songs/${song.id}/`; 111export function showSong(song) { 112 document.title = `${song.title} - ${siteName}`; 113 try { 114 const query = new URLSearchParams(location.search); 115 query.delete(PERFORMANCE_PARAM); 116 query.delete(LISTENER_PARAM); 117 if (song.listenerId) query.set(LISTENER_PARAM, song.listenerId); 118 const search = query.size ? `?${query}` : ''; 119 history.replaceState(history.state, '', (song.listenerId ? '/' : songPath(song)) + search); 120 } catch { 121 // an embedded or sandboxed page may refuse; the song still plays 122 } 123}
Whether the song the page opens on plays by itself. Never on a reload: the PWA's "update" reloads the page, and a song the visitor had stopped must not start again on their next click. A song's own page is a link to that song, so it plays whenever it is opened; the home page's featured song plays once per tab (and the tools mark it played to keep it quiet).
130const AUTOPLAYED = 'jevstrudel.autoplayed'; 131const reloaded = () => performance.getEntriesByType?.('navigation')[0]?.type === 'reload'; 132export function takeAutoplay() { 133 if (reloaded()) return false; 134 if (songPageId()) return true; 135 try { 136 if (sessionStorage.getItem(AUTOPLAYED)) return false; 137 sessionStorage.setItem(AUTOPLAYED, '1'); 138 } catch { 139 // no storage: play, as a first visit would 140 } 141 return true; 142}