// Dev-only mock library data, for exercising the Library UI on a machine // without a populated music library. Inert unless explicitly enabled by // setting localStorage.mockLibrary = "1" in the webview (then reload); // remove the key to go back to real backend data. const ARTISTS = ["Aphex Twin","Boards of Canada","Caribou","Daft Punk","Eno Brian","Four Tet","Grimes","Holly Herndon","Jon Hopkins","Kraftwerk","LCD Soundsystem","Moderat","Nils Frahm","Oneohtrix","Portishead","Radiohead","Squarepusher","Tycho","Underworld","Vangelis","Wilco","Yello","Zero 7","Air","Bonobo","Burial","Clark","Deadmau5","Emancipator","Floating Points","Gold Panda","Helios","Kiasmos","Lorn","Moby","Nujabes","Ott","Plaid","Rival Consoles","Shpongle"]; // Titles vary by slot so the Library's classifier has something real to file: // a live set, demos, a remix record and a collection appear per artist cycle, // and a few rows have NO art_path so the generated artwork can be judged. const TITLE_SHAPES = [ (a, j) => `Album ${j + 1} of ${a}`, (a) => `Live at the Roundhouse`, (a) => `Four-Track Demos`, (a) => `Remixes 2001`, (a) => `Singles Collection`, ]; const albums = []; let aid = 1; for (let i = 0; i < ARTISTS.length; i++) { const n = 2 + (i % 4); // 2-5 albums per artist for (let j = 0; j < n; j++) { const shape = j < 2 ? TITLE_SHAPES[0] : TITLE_SHAPES[(i + j) % TITLE_SHAPES.length]; albums.push({ id: aid, artist: ARTISTS[i], title: shape(ARTISTS[i], j), year: 1995 + ((i + j) % 30), track_count: j === 2 && i % 5 === 0 ? 3 : 8 + ((i + j) % 7), art_path: (i + j) % 4 === 3 ? null : `mock://art/${aid}`, artist_art_path: `mock://artist/${i}`, added_at: 1700000000 + i * 86400 * 9 + j * 86400 * 40, path: `C:\\mock\\${i}\\${j}`, }); aid++; } } // Per-album file aggregates, the same shape library_album_stats returns. // Deterministic variety: a third FLAC 16/44.1, a few 24/96, the rest MP3. function statsFor(a) { const kind = a.id % 7; const flac = kind === 0 || kind === 3 || kind === 5; const hires = kind === 5; const perTrack = flac ? (hires ? 120e6 : 38e6) : 9e6; return { album_id: a.id, secs: a.track_count * (170 + (a.id % 90)), bytes: Math.round(a.track_count * perTrack), avg_kbps: flac ? (hires ? 2400 : 900) + (a.id % 120) : 192 + (a.id % 4) * 32, bit_depth: flac ? (hires ? 24 : 16) : null, sample_rate: flac ? (hires ? 96000 : 44100) : null, formats: [flac ? "flac" : "mp3"], last_played_at: a.id % 3 === 0 ? null : 1723000000 - (a.id % 40) * 86400, }; } function svgArt(hue, label) { const s = `` + `` + `${label}`; return "data:image/svg+xml;base64," + btoa(s); } function tracksFor(albumId) { const album = albums.find((a) => a.id === albumId); const artist = album?.artist ?? "?"; const s = album ? statsFor(album) : null; const ext = s?.formats[0] ?? "mp3"; const n = album?.track_count ?? 10; return Array.from({ length: n }, (_, k) => ({ id: albumId * 100 + k, album_id: albumId, title: `Track ${k + 1}`, artist, track_no: k + 1, duration_secs: 120 + ((albumId + k) % 9) * 23, bitrate_kbps: s?.avg_kbps ?? 320, bit_depth: s?.bit_depth ?? null, sample_rate: s?.sample_rate ?? null, size: Math.round((s?.bytes ?? 40e6) / n), path: `C:\\mock\\t${albumId}-${k}.${ext}`, })); } const enabled = (() => { try { return localStorage.getItem("mockLibrary") === "1"; } catch { return false; } })(); /** Returns a Promise for mocked commands, or undefined to pass through. */ export function mockInvoke(cmd, args) { if (!enabled) return undefined; if (cmd === "library_albums") return Promise.resolve(albums); if (cmd === "library_album_stats") return Promise.resolve(albums.map(statsFor)); if (cmd === "followed_artists") return Promise.resolve([]); if (cmd === "recent_albums") return Promise.resolve([]); if (cmd === "album_tracks") return new Promise((r) => setTimeout(() => r(tracksFor(args.albumId)), 60)); if (cmd === "album_art") { const m = /(\d+)$/.exec(args.path || ""); const num = m ? +m[1] : 0; return Promise.resolve(svgArt((num * 47) % 360, String.fromCharCode(65 + (num % 26)))); } if (cmd === "list_playlists") return Promise.resolve([]); return undefined; }