mirror of
https://github.com/dbv111m/musicgrabber.git
synced 2026-10-19 01:31:29 -05:00
Album downloads stop sneaking out to Monochrome behind your back
- resolve_by_isrc now checks Monochrome is enabled. Album imports pass each track's ISRC straight to it and skip the search, so a Soulseek-only setup was still getting albums via MONO. The Queue's rescue search used the same lookup and gets the same fix. - Album mode's strict artist match compared the artist to the result's "channel", which for Soulseek is the username of whoever is sharing the file. Every Soulseek candidate failed; it now checks the artist parsed from the folder path instead. Built by a human with a Soulseek-only user's Radiohead problem and an AI that now knows flacgoblin is not a member of the band.
This commit is contained in:
1 parent
f7574d4347
commit
81e511aa17
6 files changed
+53
-2
No files matched your search
@@ -30,6 +30,7 @@ Housekeeping. The backlog's to-do list, cleared in one sitting, which has never
|
||||
- **The rabbit hole's way out follows you down**: the "Down the rabbit hole" breadcrumb, with Climb out and the jump links, sat above the rows while new rows were added at the bottom, so two hops in it was 3,000px behind you. It now sticks to the top of the screen.
|
||||
- **Monochrome is benched when its downloads die, not just when its search does**: the health check only ran a search, and on 2026-10-04 Monochrome's search answered happily while every download crawled at 12 KB/s and was cut off at 38 seconds, a few hundred KB into a 40 MB FLAC. So Monochrome stayed green, its lossless results kept winning, and every track spent half a minute failing there before JioSaavn or Soulseek stepped in. The check now also pulls the first megabyte of a real FLAC and wants it inside 15 seconds; miss that and Monochrome is parked until it recovers, as it should have been all along.
|
||||
- **No more "FAILED" for tracks that arrived anyway**: each download worker announced its own failure the moment its source fell over, before the automatic fallback had a chance to fetch the track from somewhere else. Four failure pings went out on 2026-10-04 for four tracks that were sitting in the library seconds later. Failures inside a fallback cycle are now held, and one notification goes out only if every source genuinely lets you down.
|
||||
- **Album downloads respect your Search Sources, and Soulseek can finally win one**: two faults, one report. Albums tab imports hand each track's ISRC straight to Monochrome, skipping the search, and that lookup never asked whether Monochrome was switched on, so a Soulseek-only setup still got albums from MONO. `resolve_by_isrc` now returns nothing for a disabled source, which also covers the Queue's rescue search. Meanwhile album mode's strict artist check compared the artist against the result's "channel", which for Soulseek is the username of whoever is sharing the file, so every Soulseek candidate failed with "No strict artist match found". Soulseek results are now checked against the artist read from their folder path. Reported by a Soulseek-only user whose Radiohead albums came back one via Monochrome and one not at all.
|
||||
- **Four em dashes evicted from the UI**: in the acquisition attempt list, "Later succeeded on retry", the cue point hint and the empty playlist placeholder. The ones in regexes that parse pasted input stay, since other people's text has them even if ours does not.
|
||||
|
||||
### Tests
|
||||
|
||||
+8
-1
@@ -237,7 +237,14 @@ def _candidate_channel_matches_expected_artist(candidate: dict, expected_artist:
|
||||
if not expected_norm:
|
||||
return False
|
||||
|
||||
channel_norm = _normalise_candidate_match_text(candidate.get("channel", ""))
|
||||
# A Soulseek "channel" is whoever happens to be sharing the file, and
|
||||
# "xX_flacgoblin_Xx" is rarely Radiohead. The artist read out of their
|
||||
# folder path is the honest equivalent.
|
||||
if candidate.get("source") == "soulseek":
|
||||
channel = candidate.get("artist", "")
|
||||
else:
|
||||
channel = candidate.get("channel", "")
|
||||
channel_norm = _normalise_candidate_match_text(channel)
|
||||
if not channel_norm:
|
||||
return False
|
||||
|
||||
|
||||
@@ -303,7 +303,12 @@ def resolve_by_isrc(isrc: str, artist: str = "", title: str = "") -> dict | None
|
||||
is safer than blindly queueing a recording we could not confirm exists. This
|
||||
differs on purpose from _deezer_search_leg's optimistic "label it and hope"
|
||||
behaviour; here we have a clean fallback waiting, so we use it.
|
||||
|
||||
A disabled source is a None too. The callers skip the search fan-out on a
|
||||
hit, so this is the only place the switch in Settings gets a say.
|
||||
"""
|
||||
if not monochrome_enabled():
|
||||
return None
|
||||
isrc = (isrc or "").strip().upper()
|
||||
if not _isrc_valid(isrc):
|
||||
return None
|
||||
|
||||
@@ -56,6 +56,7 @@ const RELEASE_NOTES = {
|
||||
"Click the Failed number on Stats and you're taken straight to those failed downloads in the Queue, old ones included. Show everything puts the rest back.",
|
||||
"No more \"failed\" notifications for songs that turned up anyway. If one source falls over and another delivers, you won't hear about it; you'll only get a ping when every source has let you down.",
|
||||
"When Monochrome's downloads stall, it now gets benched straight away instead of making every song wait for it to fail first.",
|
||||
"Album downloads now stick to the sources you've switched on. Turned Monochrome off? It stays off, albums included. And if Soulseek is all you use, album tracks from it no longer get turned away for being shared by someone not called Radiohead.",
|
||||
]
|
||||
},
|
||||
]
|
||||
|
||||
@@ -30,6 +30,19 @@ def test_single_import_download_capacity_is_two():
|
||||
assert bulk_import.TRACKS_PER_IMPORT == 2
|
||||
|
||||
|
||||
def test_album_strict_match_reads_soulseek_artist_not_username():
|
||||
"""Album mode rejected every Soulseek result, because the 'channel' is the peer."""
|
||||
from bulk_import import _candidate_channel_matches_expected_artist as matches
|
||||
|
||||
sharer = {"source": "soulseek", "channel": "flacgoblin", "artist": "Radiohead"}
|
||||
namesake = {"source": "soulseek", "channel": "Radiohead", "artist": "Radiohead Tribute Band"}
|
||||
assert matches(sharer, "Radiohead")
|
||||
assert not matches(namesake, "Radiohead")
|
||||
# YouTube still goes by the channel, Topic suffix and all.
|
||||
assert matches({"source": "youtube", "channel": "Radiohead - Topic"}, "Radiohead")
|
||||
assert not matches({"source": "youtube", "channel": "flacgoblin", "artist": "Radiohead"}, "Radiohead")
|
||||
|
||||
|
||||
def test_bulk_imports_list(api, base_url):
|
||||
r = api.get(f"{base_url}/api/bulk-imports", timeout=10)
|
||||
assert r.status_code == 200
|
||||
|
||||
@@ -24,6 +24,13 @@ def _import_monochrome_or_skip():
|
||||
return monochrome
|
||||
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def _monochrome_switched_on(monkeypatch):
|
||||
"""Every test here assumes the source is enabled unless it says otherwise."""
|
||||
monochrome = _import_monochrome_or_skip()
|
||||
monkeypatch.setattr(monochrome, "monochrome_enabled", lambda: True)
|
||||
|
||||
|
||||
# A well-formed ISRC: Radiohead - Creep, reliably in the catalogue.
|
||||
_VALID_ISRC = "GBAYE9200070"
|
||||
|
||||
@@ -141,7 +148,24 @@ def test_transport_failure_returns_none():
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6. The real lookup: a missing title means nothing to search by
|
||||
# 6. Monochrome switched off in Settings -> None, catalogue never asked
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_disabled_source_returns_none_without_lookup(monkeypatch):
|
||||
"""Album imports went to Monochrome with it disabled, through this door."""
|
||||
monochrome = _import_monochrome_or_skip()
|
||||
monkeypatch.setattr(monochrome, "monochrome_enabled", lambda: False)
|
||||
|
||||
with patch.object(monochrome, "_tracks_isrc_lookup",
|
||||
return_value=(_tracks_item(), False)) as mock_lookup:
|
||||
result = monochrome.resolve_by_isrc(_VALID_ISRC, "Radiohead", "Creep")
|
||||
|
||||
assert result is None
|
||||
mock_lookup.assert_not_called()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 7. The real lookup: a missing title means nothing to search by
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def test_no_title_is_a_clean_miss_without_a_search(monkeypatch):
|
||||
|
||||
Reference in new issue
Block a user