diff --git a/backend/lib/metadata.js b/backend/lib/metadata.js index ae0993d..9b36f7a 100644 --- a/backend/lib/metadata.js +++ b/backend/lib/metadata.js @@ -51,13 +51,20 @@ const AUDIO_EXTS = ['mp3', 'flac', 'opus', 'm4a', 'ogg', 'wav']; // Strips release-type suffixes like "- Single", "- EP", "2024" from end of title/stem. const _RELEASE_SUFFIX_RE = /\s*[-–]\s*(?:(?:official\s+)?(?:music\s+)?(?:single|ep|lp|album|ost|soundtrack|remaster(?:ed)?|deluxe(?:\s+edition)?|bonus\s+tracks?|b-?sides?|version|edit)\b.*|(?:20|19)\d{2})\s*$/i; +// Version markers that make a track a DISTINCT recording — brackets containing these must NOT be +// stripped during duplicate detection, or a remix/live/acoustic/instrumental collapses onto the +// base track and gets falsely skipped (e.g. "Therapy (Remix)" was skipped because "Therapy" existed). +const _VERSION_KW = /\b(?:remix|live|acoustic|instrumental|version|vip|flip|bootleg|re-?work|reprise|unplugged|demo|mashup|cover|sped|slowed|nightcore|extended|edit|mix|dub)\b/i; + // Robust duplicate detection: search case-insensitively across all album folders // under the artist folder matching firstArtist, compare normalized title ignoring // release suffixes and track prefixes. Handles DJ OKAWARI vs DJ Okawari, and // "recognize - Single.mp3" vs "recognize.mp3" (drift between runs). function findExistingTrack(musicRoot, firstArtist, cleanTitle) { const norm = s => (s || '').toLowerCase() - .replace(/[\[((][^\]))]*[\]))]/g, '') + // Strip bracketed noise (feat. X, Official Video, Prod. by …) but KEEP version markers + // (Remix/Live/Acoustic/…) so distinct recordings aren't collapsed onto the base track. + .replace(/[\[((]([^\]))]*)[\]))]/g, (m, inner) => _VERSION_KW.test(inner) ? m : '') // Filesystem-sanitized chars (/ \ : * ? " < > |) become "_" on disk — map those AND "_" // to a space so a title tag "Kwik Flip | YTPMV" matches the file "Kwik Flip _ YTPMV". .replace(/[/\\:*?"<>|_]/g, ' ')