diff --git a/backend/lib/ytdlp.js b/backend/lib/ytdlp.js index 937b517..ffafee1 100644 --- a/backend/lib/ytdlp.js +++ b/backend/lib/ytdlp.js @@ -22,7 +22,7 @@ function buildTitleKeywords(title) { return escaped ? [escaped] : []; } const VARIANT_WORDS = new Set(['sped','speedup','slowed','reverb','nightcore','karaoke','parody','remix','cover','acoustic','instrumental']); - const STOPWORDS = new Set(['the','a','an','and','or','of','in','on','at','to','for','feat','ft','with']); + const STOPWORDS = new Set(['the','a','an','and','or','of','in','on','at','to','for','feat','ft','with','single','ep','album','remaster','remastered','deluxe','edition','version','live','bonus']); const MIX_QUALIFIERS = ['radio', 'extended', 'club', 'vip', 'original', 'edit']; const lower = (title || '').toLowerCase(); const strippedTitle = (title || '').replace(/\([^)]*\)/g, '').trim(); @@ -110,8 +110,12 @@ async function downloadTrack({ jobId, artist, rawArtist, albumArtist, title, alb const escRe = s => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); - const variantFilter = buildVariantFilter(title); - const titleKws = buildTitleKeywords(title); + // Strip release-type suffixes Spotify sometimes appends to track/album names + // e.g. "recognize - Single" → "recognize", "Blue Moon - EP" → "Blue Moon" + const searchTitle = title.replace(/\s*[-–]\s*(single|ep|album|remaster(?:ed)?|deluxe(?:\s+edition)?|bonus\s+track)s?\s*$/i, '').trim() || title; + + const variantFilter = buildVariantFilter(searchTitle); + const titleKws = buildTitleKeywords(searchTitle); const variantPart = variantFilter ? ` & ${variantFilter}` : ''; const titleKwPart = titleKws.length ? titleKws.map(k => ` & title ~= (?i)${k}`).join('') : ''; @@ -139,7 +143,7 @@ async function downloadTrack({ jobId, artist, rawArtist, albumArtist, title, alb // For Western tracks, artist + title + duration matching is sufficient (matches spotdl behaviour). const albumQuerySuffix = hasJpTitle && albumWords ? ' ' + albumWords : ''; - const query = `${ytmArtist} - ${title}${albumQuerySuffix}`; + const query = `${ytmArtist} - ${searchTitle}${albumQuerySuffix}`; const baseArgs = [ '--extract-audio',