"""Round 46 — Identify Track stops giving up when no database knows the song. Two real failures from trav's library drove this. "B. Clem - Zuuso [1025657891]" fingerprinted fine and returned *zero* AcoustID results — the track is underground, so it is in no database at all, and no amount of cleverness can look up what does not exist. But its filename said exactly what it was, which is how trav knew. And "Snowfall (Live At The Alhambra_1961)" matched, yet proposed a 2002 reissue year and ranked a compilation above the album the filename named, because nothing compared the results against what the file already said. So the file itself is now evidence: it seeds a proposal when the lookup finds nothing, and it ranks the lookup's results when it finds several. """ import pytest from lintunes.fingerprint import ( IdentifyCandidate, candidate_from_filename, hint_for, parse_lookup, ) from lintunes.filename_tags import ( leading_track_number, parse_filename, split_artist_title, strip_download_id, strip_noise, year_in, ) class _Track: def __init__(self, name="", artist="", album="", location=""): self.track_id = 1 self.name = name self.artist = artist self.album = album self.location = location UNKNOWN = "/m/Unknown Artist/Unknown Album/" class TestStrippingDownloadIds: @pytest.mark.parametrize("stem, expected", [ ("B. Clem - Zuuso [1025657891]", "B. Clem - Zuuso"), ("Stardust-321895497", "Stardust"), ("Cold Draft-WC7gK2kgyTQ", "Cold Draft"), ("Self Esteem [EtNZnhxWLHo]", "Self Esteem"), ("Caught Up in the Rapture [Oz-b86LZ21c]", "Caught Up in the Rapture"), ]) def test_yt_dlp_ids_are_removed(self, stem, expected): assert strip_download_id(stem) == expected def test_a_real_word_is_not_mistaken_for_a_youtube_id(self): """"Underground" is 11 characters too — length alone can't decide.""" assert strip_download_id("Cold Draft-Underground") == \ "Cold Draft-Underground" def test_a_year_is_not_mistaken_for_a_numeric_id(self): assert strip_download_id("Cross Country Tour 1958-1961") == \ "Cross Country Tour 1958-1961" class TestStrippingNoise: @pytest.mark.parametrize("text", [ "Dance II (Official Video)", "Dance II (Official Music Video)", "Dance II (Official Lyric Video)", "Dance II [HD]", "Dance II (Audio)", ]) def test_decorations_go(self, text): assert strip_noise(text) == "Dance II" def test_a_real_parenthetical_stays(self): assert strip_noise("Take Off (ASOT 1159)") == "Take Off (ASOT 1159)" class TestSplittingAndNumbering: def test_artist_title_split(self): assert split_artist_title("B. Clem - Zuuso") == ("B. Clem", "Zuuso") def test_hyphen_inside_a_word_is_not_a_separator(self): assert split_artist_title("350-440-DialTone") == \ (None, "350-440-DialTone") def test_a_repeated_uploader_collapses(self): assert split_artist_title("Sean Dream - Sean Dream - tomorrow111") == \ ("Sean Dream", "tomorrow111") def test_leading_track_and_disc_numbers(self): assert leading_track_number("1-04 Sitting Back") == \ ("Sitting Back", 4, 1) assert leading_track_number("02 nashville cats") == \ ("nashville cats", 2, None) def test_a_number_that_is_the_whole_title_is_kept(self): assert leading_track_number("1979") == ("1979", None, None) class TestYearMining: def test_a_single_year_is_read(self): assert year_in("Snowfall (Live At The Alhambra_1961)") == 1961 def test_a_range_is_refused(self): """"1958-62" and "1958-1961" name a span, not a release year.""" assert year_in("Cross Country Tour 1958-1961") is None def test_no_year_is_none(self): assert year_in("Zuuso") is None class TestFilenameProposal: def test_the_zuuso_case(self): """The track that started this: fingerprinted fine, matched nothing, and its name said exactly what trav already knew it was.""" track = _Track(name="B. Clem - Zuuso [1025657891]", location=UNKNOWN + "B. Clem - Zuuso [1025657891].mp3") candidate = candidate_from_filename(track) assert candidate.source == "filename" assert candidate.fields() == {"name": "Zuuso", "artist": "B. Clem"} def test_apostrophes_come_back(self): track = _Track(location=UNKNOWN + "cehryl - That_s So Sick! [738273660].mp3") assert candidate_from_filename(track).name == "That's So Sick!" def test_the_folder_tree_fills_what_the_name_omits(self): track = _Track(location="/m/Onra/Long Distance/1-04 Sitting Back.mp3") fields = candidate_from_filename(track).fields() assert fields["artist"] == "Onra" assert fields["album"] == "Long Distance" assert fields["name"] == "Sitting Back" assert fields["track_number"] == 4 def test_placeholder_folders_are_not_treated_as_tags(self): track = _Track(location=UNKNOWN + "blurf.mp3") fields = candidate_from_filename(track).fields() assert "artist" not in fields and "album" not in fields def test_a_track_with_no_file_proposes_nothing(self): assert candidate_from_filename(_Track()) is None def _payload(*recordings, score=0.9): return {"status": "ok", "results": [{"score": score, "recordings": list(recordings)}]} def _recording(title, duration=None, groups=()): rec = {"title": title, "artists": [{"name": "The Band"}], "releasegroups": list(groups)} if duration is not None: rec["duration"] = duration return rec def _group(title, year, type_="Album", secondary=None): return {"title": title, "type": type_, "secondarytypes": list(secondary or []), "releases": [{"date": {"year": year} if year else {}}]} class TestRankingAgainstTheFile: def test_the_album_the_filename_names_wins(self): payload = _payload(_recording("Snowfall", groups=[ _group("Some Other Record", 1970), _group("Ahmad Jamal's Alhambra", 2002, secondary=["Live"]), ])) hint = "Snowfall (Live At The Alhambra_1961)" assert parse_lookup(payload, hint=hint)[0].album == \ "Ahmad Jamal's Alhambra" def test_a_live_album_is_no_longer_demoted(self): """Live is what a live album *is*; only compilations get pushed down.""" payload = _payload(_recording("Snowfall", groups=[ _group("Greatest Hits", 1990, secondary=["Compilation"]), _group("The Live Album", 1995, secondary=["Live"]), ])) assert parse_lookup(payload)[0].album == "The Live Album" def test_duration_picks_the_right_take(self): """Two recordings of one song; only the length tells them apart.""" payload = _payload( _recording("Snowfall", duration=155.0, groups=[_group("The Long Take", 2000)]), _recording("Snowfall", duration=150.3, groups=[_group("The Short Take", 2000)]), ) assert parse_lookup(payload, duration=150)[0].album == "The Short Take" def test_a_year_in_the_filename_beats_a_reissue_date(self): """MusicBrainz often has only the CD reissue dated, with the original pressing undated — so the file's own 1961 is the better evidence.""" payload = _payload(_recording("Snowfall", groups=[ _group("Ahmad Jamal's Alhambra", 2002)])) hint = "Snowfall (Live At The Alhambra_1961)" assert parse_lookup(payload, hint=hint)[0].year == 1961 def test_a_later_filename_year_never_overrides_an_earlier_one(self): payload = _payload(_recording("Song", groups=[_group("Album", 1967)])) assert parse_lookup(payload, hint="Song (remaster 1999)")[0].year == 1967 def test_hint_never_invents_a_candidate(self): assert parse_lookup({"status": "ok", "results": []}, hint="anything at all") == [] class TestHint: def test_hint_gathers_tags_and_filename(self): track = _Track(name="Snowfall", artist="Ahmad Jamal", location=UNKNOWN + "Snowfall (Live At The Alhambra_1961).mp3") hint = hint_for(track) assert "Snowfall" in hint and "Ahmad Jamal" in hint and "1961" in hint class TestDialogLabelsAGuessHonestly: def test_filename_candidates_say_where_they_came_from(self, qapp): from lintunes.gui.identify_dialog import IdentifyDialog track = _Track(name="B. Clem - Zuuso [1025657891]") guess = IdentifyCandidate(score=0.0, source="filename", name="Zuuso", artist="B. Clem") dialog = IdentifyDialog(track, [guess]) assert "file's name" in dialog._header.text().lower() # No fabricated confidence percentage for something nothing matched. assert "%" not in dialog._header.text() assert "From the filename" in dialog._combo.itemText(0) def test_acoustid_candidates_still_quote_confidence(self, qapp): from lintunes.gui.identify_dialog import IdentifyDialog candidate = IdentifyCandidate(score=0.98, name="Snowfall") dialog = IdentifyDialog(_Track(name="x"), [candidate]) assert "98%" in dialog._header.text()