diff --git a/docs/source/yandex_music.artist.artist_albums.rst b/docs/source/yandex_music.artist.artist_albums.rst new file mode 100644 index 0000000..c734d47 --- /dev/null +++ b/docs/source/yandex_music.artist.artist_albums.rst @@ -0,0 +1,7 @@ +yandex_music.ArtistAlbums +========================= + +.. autoclass:: yandex_music.ArtistAlbums + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/yandex_music.artist.rst b/docs/source/yandex_music.artist.rst index 483b4be..63446e8 100644 --- a/docs/source/yandex_music.artist.rst +++ b/docs/source/yandex_music.artist.rst @@ -11,4 +11,5 @@ yandex_music.artist.description yandex_music.artist.brief_info yandex_music.artist.artist_tracks + yandex_music.artist.artist_albums yandex_music.artist.pager diff --git a/tests/test_artist_albums.py b/tests/test_artist_albums.py new file mode 100644 index 0000000..5b86469 --- /dev/null +++ b/tests/test_artist_albums.py @@ -0,0 +1,39 @@ +import pytest + +from yandex_music import ArtistAlbums + + +@pytest.fixture(scope='class') +def artist_albums(album, pager): + return ArtistAlbums([album], pager) + + +class TestArtistAlbums: + def test_expected_values(self, artist_albums, album, pager): + assert artist_albums.albums == [album] + assert artist_albums.pager == pager + + def test_de_json_required(self, client, album, pager): + json_dict = {'albums': [album.to_dict()], 'pager': pager.to_dict()} + artist_albums = ArtistAlbums.de_json(json_dict, client) + + assert artist_albums.albums == [album] + assert artist_albums.pager == pager + + def test_de_json_all(self, client, album, pager): + json_dict = {'albums': [album.to_dict()], 'pager': pager.to_dict()} + artist_albums = ArtistAlbums.de_json(json_dict, client) + + assert artist_albums.albums == [album] + assert artist_albums.pager == pager + + def test_equality(self, album, pager): + a = ArtistAlbums([album], pager) + b = ArtistAlbums([], pager) + c = ArtistAlbums([album], pager) + + assert a != b + assert hash(a) != hash(b) + assert a is not b + + assert a == c diff --git a/yandex_music/__init__.py b/yandex_music/__init__.py index f216bcb..a81b5b5 100644 --- a/yandex_music/__init__.py +++ b/yandex_music/__init__.py @@ -19,11 +19,11 @@ from .album.label import Label from .album.track_position import TrackPosition from .artist.artist import Artist from .artist.artist_tracks import ArtistTracks +from .artist.artist_albums import ArtistAlbums from .artist.brief_info import BriefInfo from .artist.counts import Counts from .artist.description import Description from .artist.link import Link -from .artist.pager import Pager from .artist.ratings import Ratings from .artist.vinyl import Vinyl @@ -94,6 +94,7 @@ from .supplement.supplement import Supplement from .supplement.lyrics import Lyrics from .supplement.video_supplement import VideoSupplement +from .pager import Pager from .cover import Cover from .experiments import Experiments from .invocation_info import InvocationInfo @@ -112,4 +113,4 @@ __all__ = ['YandexMusicObject', 'Client', 'Account', 'PassportPhone', 'Invocatio 'PersonalPlaylistsData', 'Promotion', 'Landing', 'Chart', 'ChartItem', 'PlayContext', 'Title', 'Genre', 'Icon', 'Images', 'Id', 'Station', 'Dashboard', 'RotorSettings', 'AdParams', 'Restrictions', 'Value', 'Enum', 'DiscreteScale', 'StationResult', 'Sequence', 'StationTracksResult', 'BriefInfo', 'Description', 'PlaylistId', - 'Vinyl', 'Supplement', 'Lyrics', 'VideoSupplement', 'ArtistTracks', 'Pager'] + 'Vinyl', 'Supplement', 'Lyrics', 'VideoSupplement', 'ArtistTracks', 'Pager', 'ArtistAlbums'] diff --git a/yandex_music/artist/artist.py b/yandex_music/artist/artist.py index 53ffe1d..852cad2 100644 --- a/yandex_music/artist/artist.py +++ b/yandex_music/artist/artist.py @@ -95,6 +95,13 @@ class Artist(YandexMusicObject): """ return self.client.artists_tracks(self.id, page, page_size, *args, **kwargs) + def get_albums(self, page=0, page_size=20, sort_by='year', *args, **kwargs): + """Сокращение для:: + + client.artists_direct_albums(artist.id, page, page_size, sort_by, *args, **kwargs) + """ + return self.client.artists_direct_albums(self.id, page, page_size, sort_by, *args, **kwargs) + @classmethod def de_json(cls, data, client): if not data: @@ -129,3 +136,5 @@ class Artist(YandexMusicObject): downloadOpImage = download_op_image #: Псевдоним для :attr:`get_tracks` getTracks = get_tracks + #: Псевдоним для :attr:`get_albums` + getAlbums = get_albums diff --git a/yandex_music/artist/artist_albums.py b/yandex_music/artist/artist_albums.py new file mode 100644 index 0000000..be6c9c3 --- /dev/null +++ b/yandex_music/artist/artist_albums.py @@ -0,0 +1,52 @@ +from yandex_music import YandexMusicObject + + +class ArtistAlbums(YandexMusicObject): + """Класс представляющий страницу списка альбомов артиста. + + Attributes: + albums (:obj:`list` из :obj:`yandex_music.Album`): Список альбомов артиста. + pager (:obj:`yandex_music.Pager`): Объект класса :class:`yandex_music.Pager` представляющий пагинатор. + client (:obj:`yandex_music.Client`): Объект класса :class:`yandex_music.Client` представляющий клиент Yandex + Music. + + Args: + albums (:obj:`list` из :obj:`yandex_music.Album`): Список альбомов артиста. + pager (:obj:`yandex_music.Pager`): Объект класса :class:`yandex_music.Pager` представляющий пагинатор. + client (:obj:`yandex_music.Client`, optional): Объект класса :class:`yandex_music.Client` представляющий клиент + Yandex Music. + **kwargs: Произвольные ключевые аргументы полученные от API. + """ + + def __init__(self, + albums, + pager, + client=None, + **kwargs): + self.albums = albums + self.pager = pager + + self.client = client + self._id_attrs = (self.pager, self.albums) + + @classmethod + def de_json(cls, data, client): + """Десериализация объекта. + + Args: + data (:obj:`dict`): Поля и значения десериализуемого объекта. + client (:obj:`yandex_music.Client`): Объект класса :class:`yandex_music.Client` представляющий клиент Yandex + Music. + + Returns: + :obj:`yandex_music.ArtistAlbums`: Объект класса :class:`yandex_music.ArtistAlbums`. + """ + if not data: + return None + + data = super(ArtistAlbums, cls).de_json(data, client) + from yandex_music import Album, Pager + data['albums'] = Album.de_list(data.get('albums'), client) + data['pager'] = Pager.de_json(data.get('pager'), client) + + return cls(client=client, **data) diff --git a/yandex_music/client.py b/yandex_music/client.py index 8d0f9b4..282cd05 100644 --- a/yandex_music/client.py +++ b/yandex_music/client.py @@ -4,7 +4,8 @@ from datetime import datetime from yandex_music import YandexMusicObject, Status, Settings, PermissionAlerts, Experiments, Artist, Album, Playlist, \ TracksList, Track, AlbumsLikes, ArtistsLikes, PlaylistsLikes, Feed, PromoCodeStatus, DownloadInfo, Search, \ - Suggestions, Landing, Genre, Dashboard, StationResult, StationTracksResult, BriefInfo, Supplement, ArtistTracks + Suggestions, Landing, Genre, Dashboard, StationResult, StationTracksResult, BriefInfo, Supplement, ArtistTracks, \ + ArtistAlbums from yandex_music.utils.request import Request from yandex_music.utils.difference import Difference from yandex_music.exceptions import InvalidToken @@ -25,7 +26,6 @@ de_list_likes = { 'playlist': PlaylistsLikes.de_list, } - logging.getLogger(__name__).addHandler(logging.NullHandler()) @@ -906,7 +906,10 @@ class Client(YandexMusicObject): Returns: :obj:`yandex_music.ArtistsTracks`: Объекта класса :class:`yandex_music.ArtistsTracks` - представляющий страницу списка треков артиста + представляющий страницу списка треков артиста, иначе :obj:`None`. + + Raises: + :class:`yandex_music.YandexMusicError` """ url = f'{self.base_url}/artists/{artist_id}/tracks' @@ -920,6 +923,42 @@ class Client(YandexMusicObject): return ArtistTracks.de_json(result, self) + @log + def artists_direct_albums(self, artist_id: str or int, page=0, page_size=20, sort_by='year', + timeout=None, *args, **kwargs): + """Получение альбомов артиста. + + Известные значения для sort_by: year, rating. + + Args: + artist_id (:obj:`str` | :obj:`int`): Уникальный идентификатор артиста. + page (:obj:`int`, optional): Номер страницы. + page_size (:obj:`int`, optional): Количество альбомов на странице. + sort_by (:obj:`str`, optional): Параметр для сортировки. + timeout (:obj:`int` | :obj:`float`, optional): Если это значение указано, используется как время ожидания + ответа от сервера вместо указанного при создании пула. + **kwargs (:obj:`dict`, optional): Произвольные аргументы (будут переданы в запрос). + + Returns: + :obj:`yandex_music.ArtistAlbums`: Объекта класса :class:`yandex_music.ArtistsTracks` + представляющий страницу списка альбомов артиста, иначе :obj:`None`. + + Raises: + :class:`yandex_music.YandexMusicError` + """ + + url = f'{self.base_url}/artists/{artist_id}/direct-albums' + + params = { + 'sort-by': sort_by, + 'page': page, + 'page-size': page_size + } + + result = self._request.get(url, params, timeout=timeout, *args, **kwargs) + + return ArtistAlbums.de_json(result, self) + def _like_action(self, object_type: str, ids: str or int or list, remove: bool = False, user_id: str or int = None, timeout=None, *args, **kwargs): if user_id is None: @@ -1140,6 +1179,8 @@ class Client(YandexMusicObject): artistsBriefInfo = artists_brief_info #: Псевдоним для :attr:`artists_tracks` artistsTracks = artists_tracks + #: Псевдоним для :attr:`artists_direct_albums` + artistsDirectAlbums = artists_direct_albums #: Псевдоним для :attr:`users_likes_tracks_add` usersLikesTracksAdd = users_likes_tracks_add #: Псевдоним для :attr:`users_likes_tracks_remove` diff --git a/yandex_music/artist/pager.py b/yandex_music/pager.py similarity index 100% rename from yandex_music/artist/pager.py rename to yandex_music/pager.py