Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | import { isSong, type Song } from "shared/lib/uge/types"; export const BACKUP_SONG_KEY = "gbsMusicWeb:song.bck"; export const BACKUP_TIMESTAMP_KEY = "gbsMusicWeb:song.bck.timestamp"; const UINT8_TAG = "__uint8array"; // JSON replacer that converts Uint8Array to a tagged plain object so it can // survive a JSON round-trip without being silently mangled into {0:…, 1:…}. const songReplacer = (_key: string, value: unknown): unknown => { Iif (value instanceof Uint8Array) { return { [UINT8_TAG]: Array.from(value) }; } return value; }; // Paired JSON reviver that reconstructs Uint8Arrays from the tagged form. const songReviver = (_key: string, value: unknown): unknown => { Iif ( value !== null && typeof value === "object" && UINT8_TAG in (value as Record<string, unknown>) ) { return new Uint8Array((value as Record<string, number[]>)[UINT8_TAG]); } return value; }; export const serializeSong = (song: Song): string => JSON.stringify(song, songReplacer); export const deserializeSong = (json: string): Song | null => { try { const data: unknown = JSON.parse(json, songReviver); return isSong(data) ? data : null; } catch { return null; } }; interface BackupInfo { name: string; filename: string; timestamp: number; } /** Returns metadata about the stored backup without fully deserialising the song. */ export const getBackupInfo = (): BackupInfo | null => { try { const json = localStorage.getItem(BACKUP_SONG_KEY); Iif (!json) return null; const parsed = deserializeSong(json); Iif (!parsed) { return null; } const name = parsed.name ?? "Backup"; const filename = parsed.filename ?? "backup.uge"; const rawTimestamp = localStorage.getItem(BACKUP_TIMESTAMP_KEY); const timestamp = rawTimestamp ? parseInt(rawTimestamp, 10) : Date.now(); return { name, filename, timestamp }; } catch { return null; } }; export const clearBackup = (): void => { localStorage.removeItem(BACKUP_SONG_KEY); localStorage.removeItem(BACKUP_TIMESTAMP_KEY); }; |