diff --git a/tidalapi/playlist.py b/tidalapi/playlist.py index 259e983..6ba7684 100644 --- a/tidalapi/playlist.py +++ b/tidalapi/playlist.py @@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, List, Optional, Sequence, Union, cast from tidalapi.exceptions import ObjectNotFound, TooManyRequests -from tidalapi.types import JsonObj +from tidalapi.types import ItemOrder, JsonObj, OrderDirection from tidalapi.user import LoggedInUser if TYPE_CHECKING: @@ -159,14 +159,30 @@ def parse_factory(self, json_obj: JsonObj) -> "Playlist": self.parse(json_obj) return copy.copy(self.factory()) - def tracks(self, limit: Optional[int] = None, offset: int = 0) -> List["Track"]: + def tracks( + self, + limit: Optional[int] = None, + offset: int = 0, + order: Optional[ItemOrder] = None, + order_direction: Optional[OrderDirection] = None, + ) -> List["Track"]: """Gets the playlists' tracks from TIDAL. :param limit: The amount of items you want returned. :param offset: The index of the first item you want included. + :param order: Optional; A :class:`ItemOrder` describing the ordering type when returning the playlist tracks. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A list of :class:`Tracks <.Track>` """ - params = {"limit": limit, "offset": offset} + params = { + "limit": limit, + "offset": offset, + } + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value + request = self.request.request( "GET", self._base_url % self.id + "/tracks", params=params ) @@ -177,14 +193,27 @@ def tracks(self, limit: Optional[int] = None, offset: int = 0) -> List["Track"]: ) ) - def items(self, limit: int = 100, offset: int = 0) -> List[Union["Track", "Video"]]: + def items( + self, + limit: int = 100, + offset: int = 0, + order: Optional[ItemOrder] = None, + order_direction: Optional[OrderDirection] = None, + ) -> List[Union["Track", "Video"]]: """Fetches up to the first 100 items, including tracks and videos. :param limit: The amount of items you want, up to 100. :param offset: The index of the first item you want returned + :param order: Optional; A :class:`ItemOrder` describing the ordering type when returning the playlist items. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A list of :class:`Tracks<.Track>` and :class:`Videos<.Video>` """ params = {"limit": limit, "offset": offset} + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value + request = self.request.request( "GET", self._base_url % self.id + "/items", params=params ) diff --git a/tidalapi/types.py b/tidalapi/types.py index e37a394..50b4711 100644 --- a/tidalapi/types.py +++ b/tidalapi/types.py @@ -1,5 +1,49 @@ # Copyright (C) 2023- The Tidalapi Developers +from enum import Enum from typing import Any, Dict JsonObj = Dict[str, Any] + + +class AlbumOrder(Enum): + Artist = "ARTIST" + DateAdded = "DATE" + Name = "NAME" + ReleaseDate = "RELEASE_DATE" + + +class ArtistOrder(Enum): + DateAdded = "DATE" + Name = "NAME" + + +class ItemOrder(Enum): + Album = "ALBUM" + Artist = "ARTIST" + Date = "DATE" + Index = "INDEX" + Length = "LENGTH" + Name = "NAME" + + +class MixOrder(Enum): + DateAdded = "DATE" + MixType = "MIX_TYPE" + Name = "NAME" + + +class PlaylistOrder(Enum): + DateCreated = "DATE" + Name = "NAME" + + +class VideoOrder(Enum): + Artist = "ARTIST" + DateAdded = "DATE" + Name = "NAME" + + +class OrderDirection(Enum): + Ascending = "ASC" + Descending = "DESC" diff --git a/tidalapi/user.py b/tidalapi/user.py index a9924ed..9d09fac 100644 --- a/tidalapi/user.py +++ b/tidalapi/user.py @@ -27,7 +27,16 @@ from urllib.parse import urljoin from tidalapi.exceptions import ObjectNotFound -from tidalapi.types import JsonObj +from tidalapi.types import ( + AlbumOrder, + ArtistOrder, + ItemOrder, + JsonObj, + MixOrder, + OrderDirection, + PlaylistOrder, + VideoOrder, +) if TYPE_CHECKING: from tidalapi.album import Album @@ -448,12 +457,27 @@ def remove_folders_playlists(self, trns: [str], type: str = "folder") -> bool: params=params, ).ok - def artists(self, limit: Optional[int] = None, offset: int = 0) -> List["Artist"]: + def artists( + self, + limit: Optional[int] = None, + offset: int = 0, + order: Optional[ArtistOrder] = None, + order_direction: Optional[OrderDirection] = None, + ) -> List["Artist"]: """Get the users favorite artists. + :param limit: Optional; The amount of artists you want returned. + :param offset: The index of the first artist you want included. + :param order: Optional; A :class:`ArtistOrder` describing the ordering type when returning the user favorite artists. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A :class:`list` of :class:`~tidalapi.artist.Artist` objects containing the favorite artists. """ params = {"limit": limit, "offset": offset} + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value + return cast( List["Artist"], self.requests.map_request( @@ -463,12 +487,27 @@ def artists(self, limit: Optional[int] = None, offset: int = 0) -> List["Artist" ), ) - def albums(self, limit: Optional[int] = None, offset: int = 0) -> List["Album"]: + def albums( + self, + limit: Optional[int] = None, + offset: int = 0, + order: Optional[AlbumOrder] = None, + order_direction: Optional[OrderDirection] = None, + ) -> List["Album"]: """Get the users favorite albums. + :param limit: Optional; The amount of albums you want returned. + :param offset: The index of the first album you want included. + :param order: Optional; A :class:`AlbumOrder` describing the ordering type when returning the user favorite albums. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A :class:`list` of :class:`~tidalapi.album.Album` objects containing the favorite albums. """ params = {"limit": limit, "offset": offset} + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value + return cast( List["Album"], self.requests.map_request( @@ -477,13 +516,26 @@ def albums(self, limit: Optional[int] = None, offset: int = 0) -> List["Album"]: ) def playlists( - self, limit: Optional[int] = None, offset: int = 0 + self, + limit: Optional[int] = None, + offset: int = 0, + order: Optional[PlaylistOrder] = None, + order_direction: Optional[OrderDirection] = None, ) -> List["Playlist"]: """Get the users favorite playlists. + :param limit: Optional; The amount of playlists you want returned. + :param offset: The index of the first playlist you want included. + :param order: Optional; A :class:`PlaylistOrder` describing the ordering type when returning the user favorite playlists. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A :class:`list` :class:`~tidalapi.playlist.Playlist` objects containing the favorite playlists. """ params = {"limit": limit, "offset": offset} + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value + return cast( List["Playlist"], self.requests.map_request( @@ -497,23 +549,22 @@ def tracks( self, limit: Optional[int] = None, offset: int = 0, - order: str = "NAME", - order_direction: str = "ASC", + order: Optional[ItemOrder] = None, + order_direction: Optional[OrderDirection] = None, ) -> List["Track"]: """Get the users favorite tracks. :param limit: Optional; The amount of items you want returned. :param offset: The index of the first item you want included. - :param order: A :class:`str` describing the ordering type when returning the user favorite tracks. eg.: "NAME, "DATE" - :param order_direction: A :class:`str` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" + :param order: Optional; A :class:`ItemOrder` describing the ordering type when returning the user favorite tracks. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A :class:`list` of :class:`~tidalapi.media.Track` objects containing all of the favorite tracks. """ - params = { - "limit": limit, - "offset": offset, - "order": order, - "orderDirection": order_direction, - } + params = {"limit": limit, "offset": offset} + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value return cast( List["Track"], @@ -522,24 +573,57 @@ def tracks( ), ) - def videos(self) -> List["Video"]: + def videos( + self, + limit: Optional[int] = None, + offset: int = 0, + order: Optional[VideoOrder] = None, + order_direction: Optional[OrderDirection] = None, + ) -> List["Video"]: """Get the users favorite videos. + :param limit: Optional; The amount of videos you want returned. + :param offset: The index of the first video you want included. + :param order: Optional; A :class:`VideoOrder` describing the ordering type when returning the user favorite videos. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A :class:`list` of :class:`~tidalapi.media.Video` objects containing all the favorite videos """ + params = {"limit": limit, "offset": offset} + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value + return cast( List["Video"], - self.requests.get_items( - f"{self.base_url}/videos", parse=self.session.parse_media + self.requests.map_request( + f"{self.base_url}/videos", + params=params, + parse=self.session.parse_media, ), ) - def mixes(self, limit: Optional[int] = 50, offset: int = 0) -> List["MixV2"]: + def mixes( + self, + limit: Optional[int] = 50, + offset: int = 0, + order: Optional[MixOrder] = None, + order_direction: Optional[OrderDirection] = None, + ) -> List["MixV2"]: """Get the users favorite mixes & radio. + :param limit: Optional; The amount of mixes you want returned. + :param offset: The index of the first mix you want included. + :param order: Optional; A :class:`MixOrder` describing the ordering type when returning the user favorite mixes. eg.: "NAME, "DATE" + :param order_direction: Optional; A :class:`OrderDirection` describing the ordering direction when sorting by `order`. eg.: "ASC", "DESC" :return: A :class:`list` of :class:`~tidalapi.media.Mix` objects containing the user favourite mixes & radio """ params = {"limit": limit, "offset": offset} + if order: + params["order"] = order.value + if order_direction: + params["orderDirection"] = order_direction.value + return cast( List["MixV2"], self.requests.map_request(