Skip to content

added paginator to spotify client #506

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 55 additions & 1 deletion src/spotifyaio/spotify.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import asyncio
from dataclasses import dataclass
from importlib import metadata
from typing import TYPE_CHECKING, Any, Callable, Self
from typing import TYPE_CHECKING, Any, Callable, Self, Generator

from aiohttp import ClientSession
from aiohttp.hdrs import METH_DELETE, METH_GET, METH_POST, METH_PUT
Expand Down Expand Up @@ -159,6 +159,60 @@ async def _delete(
"""Handle a DELETE request to Spotify."""
return await self._request(METH_DELETE, uri, data=data, params=params)

async def _paginator(
self,
endpoint: str,
params: dict[str, Any] = None,
max_items: int = None,
limit: int = 48,
sub_layer: str = None,
) -> Generator[list[dict], None, None]:
"""Get items from a pagination api endpoint

Args:
- endpoint(str): The api endpoint to call
- params(dict[str, Any], optional): Parameters to send with
each requests
- max_items(int, optional): The maximum number of items to
retrieve across all requests. If None, retrieves all
items
- limit(int, optional): The limit of items to retrieve per
call. Defaults to 48
- sub_layer(str, optional): a sub layer that contains the
actual list of items

Returns:
- list[dict]: the list of dictionary items corresponding to
the items of a pagination endpoint
"""
total = max_items
params = {} if params is None else params
params["offset"] = 0
params["limit"] = limit
item_count = 0

while total is None or item_count < total:

result = await self._get(endpoint, params)
result = orjson.loads(result)

if sub_layer is not None:
result = result[sub_layer]

if total is None or result["total"] < total:
total = result["total"]

items = result["items"]
delta = total - (item_count + len(items))

if delta < 0:
items = items[:delta]

yield [x for x in items if x is not None]

item_count += len(items)
params["offset"] = item_count

async def get_album(self, album_id: str) -> Album:
"""Get album."""
identifier = get_identifier(album_id)
Expand Down
Loading