/** * SFV checksum lists: one `name CRC32` per line, `;` comments. Scene * releases (music in particular) post one with every album; it names every * file that belongs to it. */ export interface SfvEntry { name: string crc: string } export function parseSfv(text: string): SfvEntry[] { const entries: SfvEntry[] = [] for (const raw of text.split(/\r?\n/)) { const line = raw.trim() if (!line || line.startsWith(';')) continue const match = /^(.+?)\s+([0-9a-f]{8})$/i.exec(line) if (match) entries.push({ name: match[1].replace(/^"|"$/g, '').split(/[\\/]/).pop()!, crc: match[2].toLowerCase() }) } return entries } /** * The album name an SFV gives a release: its stem without the leading * track number scene groups put on the playlist/SFV/cover files * (`00-artist-album-web-2026-grp.sfv` → `artist-album-web-2026-grp`). */ export function sfvReleaseName(sfvName: string): string { return sfvName.replace(/\.sfv$/i, '').replace(/^0{1,3}-/, '') }