From 96a1c8b7b81e1a916d25d0a566b93d01edafa13f Mon Sep 17 00:00:00 2001 From: Broque Thomas <26755000+Nezreka@users.noreply.github.com> Date: Sat, 16 May 2026 16:21:12 -0700 Subject: [PATCH] Enrich Amazon album track durations via search results MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- core/amazon_client.py | 18 +++++++++++++++++- tests/tools/test_amazon_client.py | 24 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/core/amazon_client.py b/core/amazon_client.py index 9b000372..c566f4c4 100644 --- a/core/amazon_client.py +++ b/core/amazon_client.py @@ -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 "", diff --git a/tests/tools/test_amazon_client.py b/tests/tools/test_amazon_client.py index d869c5d1..cc758371 100644 --- a/tests/tools/test_amazon_client.py +++ b/tests/tools/test_amazon_client.py @@ -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)