import { parseFile } from 'music-metadata'; export interface AudioMetadata { format: { sampleRate?: number; bitsPerSample?: number; duration?: number; bitrate?: number; }; common: { title?: string; artist?: string; album?: string; track?: { no: number | null; of: number | null }; disk?: { no: number | null; of: number | null }; year?: number; date?: string; copyright?: string; barcode?: string; // UPC artists?: string[]; albumartist?: string; }; native?: { tidalUrl?: string; }; } export async function getFlacMetadata(filePath: string): Promise { try { const metadata = await parseFile(filePath); // Extract Tidal URL from native tags if available let tidalUrl: string | undefined; if (metadata.native && metadata.native.vorbis) { const urlTag = metadata.native.vorbis.find(tag => tag.id === 'URL'); if (urlTag) { tidalUrl = String(urlTag.value); } //console.log(metadata.native.vorbis); } return { format: { sampleRate: metadata.format.sampleRate, bitsPerSample: metadata.format.bitsPerSample, duration: metadata.format.duration, bitrate: metadata.format.bitrate, }, common: { title: metadata.common.title, artist: metadata.common.artist, album: metadata.common.album, track: metadata.common.track, disk: metadata.common.disk, year: metadata.common.year, date: metadata.common.date, copyright: metadata.common.copyright, barcode: (metadata.native?.vorbis?.find(tag => tag.id === 'UPC')?.value as string) || metadata.common.barcode, artists: metadata.common.artists, albumartist: metadata.common.albumartist, }, native: { tidalUrl } }; } catch (error) { console.error(`Error parsing metadata for ${filePath}:`, error); throw error; } } export function parseLabel(rawLabel: string): string { let label = rawLabel; const labelCleaners = [ // Remove year and copyright/phonorecord symbols (strict 1900-2099 range) (l: string) => l.replace(/(\(c\)|\(p\)|\u00A9|\u2117)?\s*\b(19|20)\d{2}\b\s*/gi, '').trim(), // Remove leading/trailing copyright and phonorecord symbols (l: string) => l.replace(/^(\(c\)|\(p\)|\u00A9|\u2117|\s)+/gi, '').replace(/(\(c\)|\(p\)|\u00A9|\u2117|\s)+$/gi, '').trim(), // Handle "under exclusive license to" (l: string) => { const match = l.match(/under exclusive license to\s+(.*)/i); return match ? match[1].trim() : l; }, // Handle "exclusively distributed by" (l: string) => { const match = l.match(/exclusively distributed by\s+(.*)/i); return match ? match[1].trim() : l; }, // Handle "sob licença exclusiva de" (Portuguese) (l: string) => { const match = l.match(/sob licen[çc]a exclusiva de\s+(.*)/i); return match ? match[1].trim() : l; }, // Handle "under license to" (non-exclusive) - keep text BEFORE this (l: string) => { const match = l.match(/(.*)\s+under license to/i); return match ? match[1].trim().replace(/,$/, '').trim() : l; }, // Handle ", a division of" (l: string) => { const match = l.match(/(.*), a division of/i); return match ? match[1].trim() : l; } ]; for (const cleaner of labelCleaners) { label = cleaner(label); } // Blank out if it contains "Records DK" if (label.includes("Records DK")) { return ""; } return label; }