// The catalog matcher, against the real import that exposed it: a 258-row // playlist where 41 rows read "not in catalog" while plainly being in it. // Every case below is a pairing taken from that run. import { test } from "node:test"; import assert from "node:assert/strict"; import { splitVersion, qualifierClass, primaryArtist, bandCore, pickCatalogMatch, catalogQueries, findCatalogTrack, pickCrossScript, } from "../../src/lib/catalogMatch.js"; const track = (artist, title, duration_secs, rank = 500_000) => ({ id: 1, artist, title, duration_secs, rank, }); test("version wording is split off, not thrown away", () => { assert.deepEqual(splitVersion("Bohemian Rhapsody - Remastered 2011"), { base: "Bohemian Rhapsody", qualifier: "Remastered 2011", }); assert.deepEqual(splitVersion("Lola (2020 Stereo Remaster)"), { base: "Lola", qualifier: "2020 Stereo Remaster", }); assert.deepEqual(splitVersion("グッドバイ -album version-"), { base: "グッドバイ", qualifier: "album version", }); assert.deepEqual(splitVersion("Here's to you (feat. Joan Baez)"), { base: "Here's to you", qualifier: "feat. Joan Baez", }); // A hyphen inside a word is part of the name, never a qualifier. assert.deepEqual(splitVersion("A-Punk"), { base: "A-Punk", qualifier: "" }); // A dash-separated title that names no version keeps its shape. assert.deepEqual(splitVersion("Sunday Bloody Sunday - Live"), { base: "Sunday Bloody Sunday", qualifier: "Live", }); assert.deepEqual(splitVersion("Detroit Rock City"), { base: "Detroit Rock City", qualifier: "", }); }); test("qualifiers are classed by whether they change the recording", () => { assert.equal(qualifierClass(""), "none"); assert.equal(qualifierClass("2011 Remaster"), "edition"); assert.equal(qualifierClass("Remastered 2011"), "edition"); assert.equal(qualifierClass("2020 Stereo Remaster"), "edition"); assert.equal(qualifierClass("feat. Joan Baez"), "edition"); assert.equal(qualifierClass("Samurai Breaks Remix"), "identity"); assert.equal(qualifierClass("Acoustic"), "identity"); assert.equal(qualifierClass("Live"), "identity"); assert.equal(qualifierClass("Karaoke Version"), "identity"); }); test("the same master worded differently now matches", () => { // The headline failure: Spotify's wording vs Deezer's. const hit = pickCatalogMatch( [track("Queen", "Bohemian Rhapsody (2011 Remaster)", 358)], { artist: "Queen", title: "Bohemian Rhapsody - Remastered 2011", duration_secs: 354 }, ); assert.equal(hit?.title, "Bohemian Rhapsody (2011 Remaster)"); assert.ok( pickCatalogMatch([track("The Kinks", "Lola (Stereo Remastered 2020)", 241)], { artist: "The Kinks", title: "Lola (2020 Stereo Remaster)", duration_secs: 241, }), ); // A plain catalog title answering a remastered request, and vice versa. assert.ok( pickCatalogMatch([track("David Bowie", "Suffragette City", 206)], { artist: "David Bowie", title: "Suffragette City - 2012 Remastered Version", duration_secs: 206, }), ); }); test("artist wording: ampersands and comma-credited guests", () => { assert.ok( pickCatalogMatch([track("Joan Jett and the Blackhearts", "Bad Reputation", 170)], { artist: "Joan Jett & the Blackhearts", title: "Bad Reputation", duration_secs: 170, }), ); assert.ok( pickCatalogMatch([track("Ennio Morricone", "Here's to You", 190)], { artist: "Ennio Morricone, Joan Baez", title: "Here's to you (feat. Joan Baez)", duration_secs: 188, }), ); assert.ok( pickCatalogMatch([track("King Krule", "Seagirl", 202)], { artist: "King Krule, Raveena", title: "Seagirl", duration_secs: 202, }), ); assert.equal(primaryArtist("Ennio Morricone, Joan Baez"), "Ennio Morricone"); // "and" is part of the act's name, never a credit separator. assert.equal(primaryArtist("Joan Jett and the Blackhearts"), "Joan Jett and the Blackhearts"); // Deezer files the STUDIO cut under the shorter credit and gives the // live takes the full band name; both must reach the same record. assert.ok( pickCatalogMatch([track("Joan Jett", "Bad Reputation", 169)], { artist: "Joan Jett & the Blackhearts", title: "Bad Reputation", duration_secs: 170, }), ); assert.equal(bandCore("Joan Jett and the Blackhearts"), "joan jett"); // A bare word is never a backing band. assert.equal(bandCore("Queen Latifah"), "queen latifah"); assert.equal( pickCatalogMatch([track("Queen Latifah", "U.N.I.T.Y.", 200)], { artist: "Queen", title: "U.N.I.T.Y.", duration_secs: 200, }), null, ); }); test("a different PERFORMANCE still never answers for the original", () => { // The DJ-set lesson: a remix must not match the track it samples. assert.equal( pickCatalogMatch([track("Rebound X", "Rhythm 'N' Gash", 240)], { artist: "Rebound X", title: "Rhythm 'N' Gash (Samurai Breaks Remix)", duration_secs: 240, }), null, ); // Nor the reverse: asking for the original must not get the remix. assert.equal( pickCatalogMatch([track("Rebound X", "Rhythm 'N' Gash (Samurai Breaks Remix)", 240)], { artist: "Rebound X", title: "Rhythm 'N' Gash", duration_secs: 240, }), null, ); // The acoustic/live re-recordings Deezer offered for Bad Reputation. assert.equal( pickCatalogMatch( [ track("Joan Jett and the Blackhearts", "Bad Reputation (Acoustic)", 160), track("Joan Jett and the Blackhearts", "Bad Reputation (Live)", 131), ], { artist: "Joan Jett & the Blackhearts", title: "Bad Reputation", duration_secs: 170 }, ), null, ); }); test("covers, karaoke and namesakes are still refused", () => { // What Deezer's plain search actually returned for A-Punk. assert.equal( pickCatalogMatch( [ track("Midium", "A-Punk (Vampire Weekend cover)", 139), track("Zoom Karaoke", "A-Punk (Originally By Vampire Weekend) [Karaoke Version]", 133), ], { artist: "Vampire Weekend", title: "A-Punk", duration_secs: 137 }, ), null, ); // A short name inside a longer one is a coincidence, not a match. assert.equal( pickCatalogMatch([track("Fleetwood Mac", "Go Your Own Way", 223)], { artist: "Fleetwood Mac", title: "Go", duration_secs: 223, }), null, ); }); test("a badly disagreeing duration disqualifies a different cut", () => { // The single edit Deezer offered against the album track. assert.equal( pickCatalogMatch([track("Eagles", "Lyin' Eyes (Single Version; 2018 Remaster)", 255)], { artist: "Eagles", title: "Lyin' Eyes - 2013 Remaster", duration_secs: 381, }), null, ); // With no duration known, the same pairing is allowed — nothing // contradicts it, and a name match is all there is. assert.ok( pickCatalogMatch([track("Eagles", "Lyin' Eyes (Single Version; 2018 Remaster)", 255)], { artist: "Eagles", title: "Lyin' Eyes - 2013 Remaster", duration_secs: null, }), ); }); test("the closest cut wins when several versions qualify", () => { const hit = pickCatalogMatch( [ track("Queen", "Bohemian Rhapsody (2011 Remaster)", 358, 900_000), track("Queen", "Bohemian Rhapsody", 367, 950_000), ], { artist: "Queen", title: "Bohemian Rhapsody - Remastered 2011", duration_secs: 354 }, ); assert.equal(hit?.title, "Bohemian Rhapsody (2011 Remaster)"); }); test("the query ladder asks precisely before asking bluntly", () => { assert.deepEqual( catalogQueries({ artist: "Eagles", title: "Take It Easy - 2013 Remaster" }), [ 'artist:"Eagles" track:"Take It Easy"', 'artist:"Eagles" track:"Take It Easy - 2013 Remaster"', "Eagles Take It Easy", ], ); // Comma-credited guests are dropped from the query's artist. assert.equal( catalogQueries({ artist: "King Krule, Raveena", title: "Seagirl" })[0], 'artist:"King Krule" track:"Seagirl"', ); }); test("the ladder stops at the first rung that answers", async () => { const asked = []; const hit = await findCatalogTrack( async (query) => { asked.push(query); // Mirrors the measured reality: the precise query finds it, the // plain one would have returned nothing. return query.startsWith("artist:") ? [track("Vashti Bunyan", "Diamond Day", 107)] : []; }, { artist: "Vashti Bunyan", title: "Diamond Day", duration_secs: 107 }, ); assert.equal(hit?.title, "Diamond Day"); assert.equal(asked.length, 1); }); test("a romanized catalog entry matches by duration, strictly", () => { const want = { artist: "toe", title: "孤独の発明", duration_secs: 203 }; // The real pairing: Deezer files the track romanized. assert.ok(pickCrossScript([track("toe", "Kodokunohatsumei", 203)], want)); // Two near-length candidates → ambiguous → null. assert.equal( pickCrossScript( [track("toe", "Kodokunohatsumei", 203), track("toe", "Two Moons", 204)], want, ), null, ); // No duration on the row → no anchor → null. assert.equal( pickCrossScript([track("toe", "Kodokunohatsumei", 203)], { ...want, duration_secs: null }), null, ); // A Latin-titled row never takes this path. assert.equal( pickCrossScript([track("toe", "Loneliness Will Shine", 356)], { artist: "toe", title: "Loneliness Will Shine", duration_secs: 356, }), null, ); }); test("the artist shelf is the last rung and answers what search cannot", async () => { const asked = { search: 0, shelf: 0 }; const hit = await findCatalogTrack( async () => { asked.search += 1; return []; // the search index has never heard of it }, { artist: "Mock Orange", title: "End of the World", duration_secs: null }, async () => { asked.shelf += 1; // What the supplemented artist page carries. return [track("Mock Orange", "End of the World", 262)]; }, ); assert.equal(hit?.title, "End of the World"); assert.ok(asked.search >= 2); assert.equal(asked.shelf, 1); }); test("nothing matching still returns null after every rung", async () => { const asked = []; const hit = await findCatalogTrack( async (query) => { asked.push(query); return [track("Someone Else", "A Different Song", 200)]; }, { artist: "Mock Orange", title: "End of the World", duration_secs: 210 }, ); assert.equal(hit, null); // Two rungs, not three: this title carries no version wording, so the // base-name query and the full-title query are the same string. assert.equal(asked.length, 2); });