fix(download): stop wrong album/cover from same-titled tracks; add MusicBrainz fallback

Root cause: deezer pickTrackMatch fell back to a blind title-only match, grabbing a
same-titled song by a completely different artist (e.g. 'Memories' by Rab Noakes for
'☆NoAki☆') and applying its album/cover/year. The download's clean fallback existed
but was never reached because the lookup almost always returned *something*.

Stufe A — deezer.js: the title-only fallback now REQUIRES an artist correspondence
(equal, or one name contained in the other after normalization). No match → {} →
the existing clean fallback finally runs (album_artist = song artist, album =
'Singles', cover = source thumbnail, year/genre untouched). Test that encoded the old
blind behaviour replaced; NoAki + loose-match regression tests added.

Stufe B — musicbrainz.js: a rate-limited (~1/s, User-Agent) MusicBrainz recording
lookup with the SAME artist discipline + Cover Art Archive cover. trackmeta.js is the
single resolver (Deezer → MusicBrainz → clean fallback); the three single-track call
sites use it (album batch stays Deezer-only to avoid MB rate-limit slowdowns).

Unit-tested (17/17) + live-verified: NoAki→clean fallback, real track→Deezer, MB finds
real albums when Deezer misses. Backend-only; no frontend/Android change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
HoneyandClaude Opus 4.8 committed 2026-08-12 01:51:29 +02:00
1 parent 16f76a4236
commit 6d084a7b7a
6 files changed
+200 -9

No files matched your search

+15 -4
View File
@@ -65,10 +65,21 @@ test('pickTrackMatch: strict match on artist + title', () => {
assert.equal(m, results[1]);
});
test('pickTrackMatch: title-only fallback for non-Japanese when artist differs', () => {
const results = [{ title: 'Levitating', artist: { name: 'Some Cover Act' } }];
const m = dz.pickTrackMatch(results, 'Dua Lipa', 'Levitating');
assert.equal(m, results[0]); // ASCII title → title-only fallback allowed
test('pickTrackMatch: NO match when the artist is completely different (no wrong album)', () => {
// Regression: "☆NoAki☆ – Memories" used to grab a same-titled song by an unrelated artist and
// apply its album/cover/year. A wholly different artist must now return null → clean fallback.
const results = [
{ title: 'Memories', artist: { name: 'Rab Noakes' } },
{ title: 'Memories', artist: { name: 'Maroon 5' } },
];
assert.equal(dz.pickTrackMatch(results, '☆NoAki☆', 'Memories'), null);
assert.equal(dz.pickTrackMatch(results, 'Some Cover Act', 'Levitating'), null);
});
test('pickTrackMatch: loose artist match — one name contained in the other', () => {
const results = [{ title: 'Flower Dance', artist: { name: 'DJ Okawari' } }];
const m = dz.pickTrackMatch(results, 'Okawari', 'Flower Dance');
assert.equal(m, results[0]); // "okawari" ⊂ "djokawari" → accepted
});
test('pickTrackMatch: NO title-only fallback for Japanese titles', () => {