Enrich Amazon album track durations via search results

media_from_asin returns no duration data. get_album_tracks now does one
search_raw call using the album name + primary artist from stream tags,
filters hits by albumAsin == requested asin, and builds a duration_map
(track asin → duration_ms). Search failures are swallowed — duration_ms
falls back to 0 so the existing behaviour is preserved on error.

2 new tests: duration populated when search returns matching hit; duration
stays 0 when search endpoint returns an error.
This commit is contained in:
Broque Thomas 2026-05-16 16:21:12 -07:00
parent c2fcef45c2
commit 96a1c8b7b8
2 changed files with 41 additions and 1 deletions

View file

@ -501,12 +501,28 @@ class AmazonClient:
streams = self.media_from_asin(asin)
except AmazonClientError:
return None
# media_from_asin has no duration — enrich from search results which do.
duration_map: Dict[str, int] = {} # track asin → duration_ms
if streams:
album_name = _strip_edition(streams[0].album)
artist_name = _primary_artist(streams[0].artist)
try:
search_items = self.search_raw(
f"{album_name} {artist_name}", types="track,album"
)
for item in search_items:
if item.album_asin == asin and item.duration_seconds:
duration_map[item.asin] = item.duration_seconds * 1000
except Exception:
pass
items = [
{
"id": s.asin,
"name": _strip_edition(s.title),
"artists": [{"name": _primary_artist(s.artist), "id": ""}],
"duration_ms": 0,
"duration_ms": duration_map.get(s.asin, 0),
"track_number": s.track_number,
"disc_number": s.disc_number,
"release_date": s.date or "",

View file

@ -844,6 +844,30 @@ class TestGetAlbumTracks:
assert item["track_number"] == 3
assert item["disc_number"] == 1
def test_duration_enriched_from_search(self):
search_resp = {
"results": [{"hits": [
{"document": {
"asin": "B09XYZ1234", "__type": "track",
"title": "Not Like Us", "artistName": "Kendrick Lamar",
"albumAsin": "B09XYZ1234", "duration": 217,
}},
]}]
}
client = _make_client({
"amazon-music/media-from-asin": [MEDIA_RESPONSE_FLAC],
"amazon-music/search": search_resp,
})
with patch("core.amazon_client._rate_limit"):
result = client.get_album_tracks("B09XYZ1234")
assert result["items"][0]["duration_ms"] == 217_000
def test_duration_zero_when_search_fails(self):
client = _make_client({"amazon-music/media-from-asin": [MEDIA_RESPONSE_FLAC]})
with patch("core.amazon_client._rate_limit"):
result = client.get_album_tracks("B09XYZ1234")
assert result["items"][0]["duration_ms"] == 0
def test_returns_none_on_api_error(self):
client = _make_client()
client.session.get.return_value = _mock_response({}, 500)