I wrote some code the other day in my repo spotify_to_tidal like below. It would be good to either incorporate a similar API upstream, or to expose a cleaner way for clients to do this without relying on internal implementation details like ._base_url and .request. My concern is that there will be a lot of maintenance work on my side to keep this code working in subsequent releases of this repo
async def _get_all_chunks(url, session, parser, params={}):
"""
Helper function to get all items from a Tidal endpoint in parallel
The main library doesn't provide the total number of items or expose the raw json, so use this wrapper instead
"""
def _make_request(offset: int=0):
new_params = params
new_params['offset'] = offset
return session.request.map_request(url, params=new_params)
first_chunk_raw = _make_request()
limit = first_chunk_raw['limit']
total = first_chunk_raw['totalNumberOfItems']
items = session.request.map_json(first_chunk_raw, parse=parser)
if len(items) < total:
offsets = [limit * n for n in range(1, math.ceil(total/limit))]
extra_results = await atqdm.gather(
*[asyncio.to_thread(lambda offset: session.request.map_json(_make_request(offset), parse=parser), offset) for offset in offsets],
desc="Fetching additional data chunks"
)
for extra_result in extra_results:
items.extend(extra_result)
return items
async def get_all_favorites(favorites: tidalapi.Favorites, order: str = "NAME", order_direction: str = "ASC", chunk_size: int=100) -> List[tidalapi.Track]:
""" Get all favorites from Tidal playlist in chunks """
params = {
"limit": chunk_size,
"order": order,
"orderDirection": order_direction,
}
return await _get_all_chunks(f"{favorites.base_url}/tracks", session=favorites.session, parser=favorites.session.parse_track, params=params)
async def get_all_playlists(user: tidalapi.User, chunk_size: int=10) -> List[tidalapi.Playlist]:
""" Get all user playlists from Tidal in chunks """
print(f"Loading playlists from Tidal user")
params = {
"limit": chunk_size,
}
return await _get_all_chunks(f"users/{user.id}/playlists", session=user.session, parser=user.playlist.parse_factory, params=params)
async def get_all_playlist_tracks(playlist: tidalapi.Playlist, chunk_size: int=20) -> List[tidalapi.Track]:
""" Get all tracks from Tidal playlist in chunks """
params = {
"limit": chunk_size,
}
print(f"Loading tracks from Tidal playlist '{playlist.name}'")
return await _get_all_chunks(f"{playlist._base_url%playlist.id}/tracks", session=playlist.session, parser=playlist.session.parse_track, params=params)
I wrote some code the other day in my repo spotify_to_tidal like below. It would be good to either incorporate a similar API upstream, or to expose a cleaner way for clients to do this without relying on internal implementation details like
._base_url
and.request
. My concern is that there will be a lot of maintenance work on my side to keep this code working in subsequent releases of this repo