fix(backend): remove album suffix from YTM search query

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 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Sonnet 4.6 committed 2026-06-21 13:50:37 +02:00
1 parent fa4c954ab9
commit d5b088a658
1 file changed
+2 -18
+2 -18
View File
@@ -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)}&params=${YTM_SONGS_PARAM}`;
const expectedAudio = path.join(dir, `${fileBase}.${CONFIG.audioFmt}`);
const hasAudio = () => fs.existsSync(expectedAudio);