From d5b088a65838662faa52670df88f45ce48ebceb4 Mon Sep 17 00:00:00 2001 From: Honey Date: Sun, 21 Jun 2026 13:50:37 +0200 Subject: [PATCH] fix(backend): remove album suffix from YTM search query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Album words ("KAGUYA Music", "OST" etc.) appended to the search query caused wrong or no results — "Kei Haneoka 確信 KAGUYA Music" would miss tracks the plain "Kei Haneoka 確信" query finds immediately. Artist + cleanTitle is sufficient for both JP and Western tracks. Co-Authored-By: Claude Sonnet 4.6 --- backend/lib/ytdlp.js | 20 ++------------------ 1 file changed, 2 insertions(+), 18 deletions(-) diff --git a/backend/lib/ytdlp.js b/backend/lib/ytdlp.js index 47a748f..a81f2f0 100644 --- a/backend/lib/ytdlp.js +++ b/backend/lib/ytdlp.js @@ -127,26 +127,10 @@ async function downloadTrack({ jobId, artist, rawArtist, albumArtist, title, alb const artistChannelPart = (artistFirstWord.length >= 3 && !JP_RE.test(artistFirstWord)) ? ` & channel ~= (?i)${escRe(artistFirstWord)}` : ''; - // When the title is Japanese (keywords stripped to nothing) OR when we have an album that - // provides better search context, include the album's first two words in the search query. - // This helps YTM rank the official OST/album track above fan covers and romaji-subtitle uploads. - // Only use album words that are ASCII (romaji/English) — Japanese album words don't help YTM ranking. - const hasJpTitle = JP_RE.test(title); - const GENERIC_ALBUM_WORDS = new Set(['single', 'ep', 'album', 'soundtrack', 'ost', 'edition', 'remaster', 'remastered', 'deluxe', 'bonus', 'version', 'live']); - const titleWordSet = new Set(title.toLowerCase().split(/\s+/)); - const albumWords = (album && album !== 'Singles' && album !== 'Unknown') - ? album.split(/\s+/) - .filter(w => /^[A-Za-z0-9]/.test(w) && !titleWordSet.has(w.toLowerCase()) && !GENERIC_ALBUM_WORDS.has(w.toLowerCase())) - .slice(0, 2).join(' ') - : ''; - // Only append album words for Japanese titles where title keywords are stripped to nothing. - // For Western tracks, artist + title + duration matching is sufficient (matches spotdl behaviour). - const albumQuerySuffix = hasJpTitle && albumWords ? ' ' + albumWords : ''; - // Use a space (not " - ") between artist and title: this matches how users type // in the YTM search box and ranks the exact official track first. A dash skews // YTM ranking toward a same-named artist's full discography. - const query = `${ytmArtist} ${searchTitle}${albumQuerySuffix}`; + const query = `${ytmArtist} ${searchTitle}`; const baseArgs = [ '--extract-audio', @@ -195,7 +179,7 @@ async function downloadTrack({ jobId, artist, rawArtist, albumArtist, title, alb // for normal tracks; for ambiguous artist names yt-dlp's search may still not surface the // exact official track (a known extractor limitation — use the direct link in that case). const YTM_SONGS_PARAM = 'EgWKAQIIAWoKEAkQBRAKEAMQBA%3D%3D'; - const ytmQuery = `${rawArtist || mainArtist} ${searchTitle}${albumQuerySuffix}`; + const ytmQuery = `${rawArtist || mainArtist} ${searchTitle}`; const ytmUrl = `https://music.youtube.com/search?q=${encodeURIComponent(ytmQuery)}¶ms=${YTM_SONGS_PARAM}`; const expectedAudio = path.join(dir, `${fileBase}.${CONFIG.audioFmt}`); const hasAudio = () => fs.existsSync(expectedAudio);