fix: survive an album with two monitored releases
Build and publish container / build (pull_request) Successful in 8m11s
Build and publish container / build (pull_request) Successful in 8m11s
Fetching every album in one unfiltered request avoided Lidarr's unguarded per-artist path, but not the exception underneath it. Every album endpoint maps through AlbumResource.ToResource, which selects the release with SingleOrDefault(x => x.Monitored). An album with two monitored releases makes that throw -- "Sequence contains more than one element" -- and the bulk call loses the entire library to one bad row. Keep the unfiltered call as the first attempt, since it is a single request and is still the only path that skips albums whose artist metadata is missing. When it fails, fall back to one request per artist. That cannot dodge the exception either, but it confines the loss to whichever artist owns the offending album and names them, which is the only practical way to find it in a large library. Album failures are counted separately from artist failures because they do not mean the same thing. Tracks come from a different endpoint with a different mapper, so an artist whose albums cannot be fetched still gets indexed and still matches; it is the cull that cannot run. The report distinguishes the two rather than lumping them into one warning that overstates the damage.
This commit is contained in:
@@ -503,8 +503,7 @@ def test_matching_is_redone_when_new_scrobbles_arrive(tmp_path):
|
||||
|
||||
|
||||
def test_albums_come_from_the_unfiltered_endpoint(tmp_path):
|
||||
"""`?artistId=` is Lidarr's unguarded path and 500s on data it cannot
|
||||
hydrate; the unfiltered one skips such albums instead."""
|
||||
"""One request, and the only path that skips albums it cannot hydrate."""
|
||||
api = FakeLidarr(LIBRARY)
|
||||
store = store_at(tmp_path)
|
||||
|
||||
@@ -515,6 +514,33 @@ def test_albums_come_from_the_unfiltered_endpoint(tmp_path):
|
||||
assert store.scalar("SELECT COUNT(*) FROM lidarr_album") == 3
|
||||
|
||||
|
||||
def test_a_bad_album_falls_back_to_asking_per_artist(tmp_path):
|
||||
"""An album with two monitored releases throws in the resource mapper, so
|
||||
the bulk call dies wholesale. Per artist, only its owner is lost."""
|
||||
# The bulk call fails because artist 2 owns the offending album.
|
||||
api = FakeLidarr(LIBRARY, fail=[("album", 0), ("album", 2)])
|
||||
store = store_at(tmp_path)
|
||||
|
||||
music_curator.index_library(music_curator.Lidarr("http://lidarr", "key", transport=api), store)
|
||||
|
||||
assert store.scalar("SELECT COUNT(*) FROM lidarr_album WHERE artist_id = 2") == 0
|
||||
# The other two artists keep their albums.
|
||||
assert store.scalar("SELECT COUNT(*) FROM lidarr_album") == 2
|
||||
assert store.get_state("index_albums_skipped") == "1"
|
||||
|
||||
|
||||
def test_a_bad_album_does_not_cost_that_artist_their_tracks(tmp_path):
|
||||
"""Tracks come from a different endpoint with a different mapper, so
|
||||
matching survives an album Lidarr cannot serialise."""
|
||||
api = FakeLidarr(LIBRARY, fail=[("album", 0), ("album", 2)])
|
||||
store = store_at(tmp_path)
|
||||
|
||||
music_curator.index_library(music_curator.Lidarr("http://lidarr", "key", transport=api), store)
|
||||
|
||||
assert store.scalar("SELECT COUNT(*) FROM lidarr_track WHERE artist_id = 2") == 1
|
||||
assert store.get_state("index_skipped") == "0"
|
||||
|
||||
|
||||
def test_an_artist_lidarr_cannot_serve_does_not_kill_the_index(tmp_path):
|
||||
# Artist 2 is AC/DC in LIBRARY; its track lookup fails.
|
||||
api = FakeLidarr(LIBRARY, fail=[("track", 2)])
|
||||
|
||||
Reference in New Issue
Block a user