Fetch all Qobuz favorite tracks for discovery

Remove the implicit 500-track cap from Qobuz Favorite Tracks so the Sync page discovers the same number of tracks shown on the playlist card. Keep an explicit limit parameter for callers that want a capped fetch.

Add tests covering the default full-pagination behavior and explicit limit handling.
pull/685/head
Broque Thomas 17 hours ago
parent 3c0b6c6204
commit 9769d8be19

@ -887,11 +887,14 @@ class QobuzClient(DownloadSourcePlugin):
logger.info(f"Retrieved Qobuz playlist '{normalized['name']}' with {len(tracks)} tracks")
return normalized
def get_user_favorite_tracks(self, limit: int = 500) -> List[Dict[str, Any]]:
def get_user_favorite_tracks(self, limit: Optional[int] = None) -> List[Dict[str, Any]]:
"""Fetch the authenticated user's favorited tracks.
Mirrors ``TidalClient.get_collection_tracks`` the Sync page's
Favorite Tracks card pulls from here on click.
Favorite Tracks card pulls from here on click. By default this
fetches the full favorites collection so the card count and the
discovered track list cannot silently diverge. Pass ``limit`` for
explicit capped callers.
"""
if not self.is_authenticated():
logger.warning("Qobuz not authenticated — cannot list favorite tracks")
@ -899,8 +902,11 @@ class QobuzClient(DownloadSourcePlugin):
tracks: List[Dict[str, Any]] = []
offset = 0
while len(tracks) < limit:
page_size = min(self._PLAYLIST_PAGE_SIZE, limit - len(tracks))
while True:
page_size = self._PLAYLIST_PAGE_SIZE if limit is None else min(self._PLAYLIST_PAGE_SIZE, limit - len(tracks))
if page_size <= 0:
break
data = self._api_request('favorite/getUserFavorites', {
'type': 'tracks',
'limit': page_size,
@ -924,6 +930,8 @@ class QobuzClient(DownloadSourcePlugin):
offset += len(items)
if offset >= total or len(items) < page_size:
break
if limit is not None and len(tracks) >= limit:
break
logger.info(f"Retrieved {len(tracks)} Qobuz favorite tracks")
return tracks

@ -331,6 +331,60 @@ def test_get_user_favorite_tracks_paginates(authed_client):
assert tracks[-1]['name'] == 'F129'
def test_get_user_favorite_tracks_fetches_all_by_default(authed_client):
def make_items(start, count):
return [
{'id': start + i, 'title': f'F{start + i}', 'duration': 200,
'performer': {'name': 'Fav Artist'},
'album': {'title': 'Fav Album', 'image': {}}}
for i in range(count)
]
offsets: List[int] = []
def responder(endpoint, params=None):
assert endpoint == 'favorite/getUserFavorites'
offsets.append(params['offset'])
start = params['offset']
remaining = max(0, 625 - start)
return {'tracks': {'items': make_items(start, min(params['limit'], remaining)), 'total': 625}}
_install_api_responder(authed_client, responder)
tracks = authed_client.get_user_favorite_tracks()
assert len(tracks) == 625
assert offsets == [0, 100, 200, 300, 400, 500, 600]
assert tracks[-1]['name'] == 'F624'
def test_get_user_favorite_tracks_honors_explicit_limit(authed_client):
def make_items(start, count):
return [
{'id': start + i, 'title': f'F{start + i}', 'duration': 200,
'performer': {'name': 'Fav Artist'},
'album': {'title': 'Fav Album', 'image': {}}}
for i in range(count)
]
requests: List[Dict[str, Any]] = []
def responder(endpoint, params=None):
assert endpoint == 'favorite/getUserFavorites'
requests.append(dict(params))
start = params['offset']
return {'tracks': {'items': make_items(start, params['limit']), 'total': 625}}
_install_api_responder(authed_client, responder)
tracks = authed_client.get_user_favorite_tracks(limit=150)
assert len(tracks) == 150
assert requests == [
{'type': 'tracks', 'limit': 100, 'offset': 0},
{'type': 'tracks', 'limit': 50, 'offset': 100},
]
assert tracks[-1]['name'] == 'F149'
def test_get_user_favorite_tracks_count_uses_cheap_call(authed_client):
captured: Dict[str, Any] = {}

Loading…
Cancel
Save