From a6c0c709fdac37a07a9282b57c9c250cf89fae16 Mon Sep 17 00:00:00 2001 From: Il`ya Semyonov Date: Sun, 14 Jun 2020 22:11:38 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D1=8B=20=D0=BD=D0=BE=D0=B2=D1=8B=D0=B5=20=D0=BA=D0=BB?= =?UTF-8?q?=D0=B0=D1=81=D1=81=D1=8B:=20Brand,=20Contest,=20OpenGraphData.?= =?UTF-8?q?=20=D0=9F=D0=BE=D0=BB=D1=8F=20contest,=20dummy=5Fdescription,?= =?UTF-8?q?=20dummy=5Fpage=5Fdescription,=20dummy=5Fcover,=20dummy=5Frollo?= =?UTF-8?q?ver=5Fcover,=20og=5Fdata,=20branding=20=D0=BA=D0=BB=D0=B0=D1=81?= =?UTF-8?q?=D1=81=D1=83=20Playlist.=20=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D0=B0=20=D0=B8=D0=BD=D1=84=D0=BE=D1=80=D0=BC=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8E=20=D0=BF=D0=BE=20=D0=BF=D0=BE=D0=B2=D0=BE?= =?UTF-8?q?=D0=B4=D1=83=20=D0=B7=D0=B0=D0=BF=D1=83=D1=81=D0=BA=D0=B0=20?= =?UTF-8?q?=D0=BF=D0=BE=D1=82=D0=BE=D0=BA=D0=B0=20=D0=BF=D0=BE=20=D1=82?= =?UTF-8?q?=D1=80=D0=B5=D0=BA=D1=83,=20=D0=BF=D0=BB=D0=B5=D0=B9=D0=BB?= =?UTF-8?q?=D0=B8=D1=81=D1=82=D1=83=20=D0=B8=20=D1=82.=D0=B4.=20=D0=94?= =?UTF-8?q?=D0=BE=D0=BA=D1=83=D0=BC=D0=B5=D0=BD=D1=82=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F=20=D0=B8=20=D1=82=D0=B5=D1=81=D1=82=D1=8B=20=D0=BA=20?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2=D1=8B=D0=BC=20=D0=BF=D0=BE=D0=BB=D1=8F=D0=BC?= =?UTF-8?q?,=20=D0=BA=D0=BB=D0=B0=D1=81=D1=81=D0=B0=D0=BC=20#339?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/source/yandex_music.playlist.brand.rst | 7 ++ docs/source/yandex_music.playlist.contest.rst | 7 ++ .../yandex_music.playlist.open_graph_data.rst | 7 ++ docs/source/yandex_music.playlist.rst | 3 + tests/__init__.py | 3 + tests/conftest.py | 40 +++++++--- tests/test_brand.py | 67 ++++++++++++++++ tests/test_contest.py | 49 ++++++++++++ tests/test_open_graph_data.py | 41 ++++++++++ tests/test_playlist.py | 27 ++++++- yandex_music/__init__.py | 5 +- yandex_music/client.py | 3 + yandex_music/playlist/brand.py | 76 +++++++++++++++++++ yandex_music/playlist/contest.py | 68 +++++++++++++++++ yandex_music/playlist/open_graph_data.py | 59 ++++++++++++++ yandex_music/playlist/playlist.py | 41 +++++++++- 16 files changed, 487 insertions(+), 16 deletions(-) create mode 100644 docs/source/yandex_music.playlist.brand.rst create mode 100644 docs/source/yandex_music.playlist.contest.rst create mode 100644 docs/source/yandex_music.playlist.open_graph_data.rst create mode 100644 tests/test_brand.py create mode 100644 tests/test_contest.py create mode 100644 tests/test_open_graph_data.py create mode 100644 yandex_music/playlist/brand.py create mode 100644 yandex_music/playlist/contest.py create mode 100644 yandex_music/playlist/open_graph_data.py diff --git a/docs/source/yandex_music.playlist.brand.rst b/docs/source/yandex_music.playlist.brand.rst new file mode 100644 index 0000000..c748dc1 --- /dev/null +++ b/docs/source/yandex_music.playlist.brand.rst @@ -0,0 +1,7 @@ +yandex_music.Brand +================== + +.. autoclass:: yandex_music.Brand + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/yandex_music.playlist.contest.rst b/docs/source/yandex_music.playlist.contest.rst new file mode 100644 index 0000000..3b16caf --- /dev/null +++ b/docs/source/yandex_music.playlist.contest.rst @@ -0,0 +1,7 @@ +yandex_music.Contest +==================== + +.. autoclass:: yandex_music.Contest + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/yandex_music.playlist.open_graph_data.rst b/docs/source/yandex_music.playlist.open_graph_data.rst new file mode 100644 index 0000000..fa9ff85 --- /dev/null +++ b/docs/source/yandex_music.playlist.open_graph_data.rst @@ -0,0 +1,7 @@ +yandex_music.OpenGraphData +========================== + +.. autoclass:: yandex_music.OpenGraphData + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/source/yandex_music.playlist.rst b/docs/source/yandex_music.playlist.rst index be53013..17cbd01 100644 --- a/docs/source/yandex_music.playlist.rst +++ b/docs/source/yandex_music.playlist.rst @@ -13,3 +13,6 @@ yandex_music.playlist.playlist_recommendations yandex_music.playlist.tag_result yandex_music.playlist.tag + yandex_music.playlist.contest + yandex_music.playlist.open_graph_data + yandex_music.playlist.brand diff --git a/tests/__init__.py b/tests/__init__.py index d600652..3ec6282 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -87,3 +87,6 @@ from .test_non_auto_renewable import TestNonAutoRenewable from .test_poetry_lover_match import TestPoetryLoverMatch from .test_deactivation import TestDeactivation from .test_operator import TestOperator +from .test_contest import TestContest +from .test_open_graph_data import TestOpenGraphData +from .test_brand import TestBrand diff --git a/tests/conftest.py b/tests/conftest.py index 95fad8c..19a55d7 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -8,7 +8,8 @@ from yandex_music import Account, AdParams, Album, AlbumEvent, Artist, ArtistEve PlaylistId, Plus, Price, Product, Promotion, Ratings, RenewableRemainder, Restrictions, RotorSettings, \ SearchResult, Sequence, Settings, Shot, ShotData, ShotType, Station, StationResult, Status, Subscription, Tag, \ Title, Track, TrackId, TrackPosition, TrackShort, TrackShortOld, TrackWithAds, User, Value, Video, \ - VideoSupplement, Vinyl, StationData, AlertButton, Alert, NonAutoRenewable, PoetryLoverMatch, Deactivation, Operator + VideoSupplement, Vinyl, StationData, AlertButton, Alert, NonAutoRenewable, PoetryLoverMatch, Deactivation, \ + Operator, Contest, OpenGraphData, Brand from . import TestAccount, TestAdParams, TestAlbum, TestArtist, TestAutoRenewable, TestBest, TestBlock, \ TestBlockEntity, TestCaseForms, TestChart, TestChartInfo, TestChartInfoMenuItem, TestCounts, TestCover, TestDay, \ TestDescription, TestDiscreteScale, TestEnum, TestEvent, TestGeneratedPlaylist, TestIcon, TestId, TestImages, \ @@ -20,7 +21,7 @@ from . import TestAccount, TestAdParams, TestAlbum, TestArtist, TestAutoRenewabl TestTag, TestTitle, TestTrack, TestTrackId, TestTrackPosition, TestTrackShort, TestTrackShortOld, \ TestTrackWithAds, TestUser, TestValue, TestVideo, TestVideoSupplement, TestVinyl, TestArtistEvent, \ TestStationData, TestAlertButton, TestAlert, TestNonAutoRenewable, TestPoetryLoverMatch, TestDeactivation, \ - TestOperator + TestOperator, TestContest, TestOpenGraphData, TestBrand @pytest.fixture(scope='session') @@ -133,7 +134,8 @@ def album_without_nested_albums(album_factory, artist_without_tracks, track_with @pytest.fixture(scope='session') -def playlist_factory(user, cover, made_for, track_short, play_counter, playlist_absence, artist, track_id): +def playlist_factory(user, cover, made_for, track_short, play_counter, playlist_absence, + artist, track_id, contest, open_graph_data, brand): class PlaylistFactory: def get(self, similar_playlists, last_owner_playlists): return Playlist(user, cover, made_for, play_counter, playlist_absence, TestPlaylist.uid, TestPlaylist.kind, @@ -142,13 +144,14 @@ def playlist_factory(user, cover, made_for, track_short, play_counter, playlist_ TestPlaylist.url_part, TestPlaylist.created, TestPlaylist.modified, TestPlaylist.available, TestPlaylist.is_banner, TestPlaylist.is_premiere, TestPlaylist.duration_ms, TestPlaylist.og_image, TestPlaylist.og_title, - TestPlaylist.og_description, TestPlaylist.image, cover, TestPlaylist.background_color, - TestPlaylist.text_color, TestPlaylist.id_for_from, TestPlaylist.metrika_id, - TestPlaylist.coauthors, [artist], [track_id], [track_short], TestPlaylist.prerolls, - TestPlaylist.likes_count, similar_playlists, last_owner_playlists, - TestPlaylist.generated_playlist_type, TestPlaylist.animated_cover_uri, - TestPlaylist.ever_played, TestPlaylist.description, TestPlaylist.description_formatted, - TestPlaylist.is_for_from, TestPlaylist.regions) + TestPlaylist.og_description, TestPlaylist.image, cover, contest, + TestPlaylist.background_color, TestPlaylist.text_color, TestPlaylist.id_for_from, + TestPlaylist.dummy_description, TestPlaylist.dummy_page_description, cover, cover, + open_graph_data, brand, TestPlaylist.metrika_id, TestPlaylist.coauthors, [artist], + [track_id], [track_short], TestPlaylist.prerolls, TestPlaylist.likes_count, + similar_playlists, last_owner_playlists, TestPlaylist.generated_playlist_type, + TestPlaylist.animated_cover_uri, TestPlaylist.ever_played, TestPlaylist.description, + TestPlaylist.description_formatted, TestPlaylist.is_for_from, TestPlaylist.regions) return PlaylistFactory() @@ -179,6 +182,12 @@ def tag(): return Tag(TestTag.id_, TestTag.value, TestTag.name, TestTag.og_description, TestTag.og_image) +@pytest.fixture(scope='session') +def brand(): + return Brand(TestBrand.image, TestBrand.background, TestBrand.reference, TestBrand.pixels, + TestBrand.theme, TestBrand.playlist_theme, TestBrand.button) + + @pytest.fixture(scope='session') def track_with_ads(track): return TrackWithAds(TestTrackWithAds.type, track) @@ -240,6 +249,11 @@ def cover(): TestCover.prefix, TestCover.error) +@pytest.fixture(scope='session') +def open_graph_data(cover): + return OpenGraphData(TestOpenGraphData.title, TestOpenGraphData.description, cover) + + @pytest.fixture(scope='session') def meta_data(): return MetaData(TestMetaData.album, TestMetaData.volume, TestMetaData.year, TestMetaData.number, TestMetaData.genre) @@ -475,6 +489,12 @@ def playlist_id(): return PlaylistId(TestPlaylistId.uid, TestPlaylistId.kind) +@pytest.fixture(scope='session') +def contest(): + return Contest(TestContest.contest_id, TestContest.status, TestContest.can_edit, + TestContest.sent, TestContest.withdrawn) + + @pytest.fixture(scope='session') def label(): return Label(TestLabel.id, TestLabel.name) diff --git a/tests/test_brand.py b/tests/test_brand.py new file mode 100644 index 0000000..22433f9 --- /dev/null +++ b/tests/test_brand.py @@ -0,0 +1,67 @@ +from yandex_music import Brand + + +class TestBrand: + image = 'https://avatars.mds.yandex.net/get-music-misc/2419084/img.5dbb0478e482b01822a89af8/%%' + background = '#2A2A2A' + reference = 'yandexmusic://post/5c94a7bf433f8221feac3fa6' + pixels = [ + 'http://ads6.adfox.ru/256152/event?hash=84862c423eb&rand=eo=hdxqd&pr=deyq&p1=bwzel', + 'http://banners.adfox.ru/transparent.gif' + ] + theme = 'dark' + playlist_theme = '' + button = 'Больше подкастов' + + def test_expected_values(self, brand): + assert brand.image == self.image + assert brand.background == self.background + assert brand.reference == self.reference + assert brand.pixels == self.pixels + assert brand.theme == self.theme + assert brand.playlist_theme == self.playlist_theme + assert brand.button == self.button + + def test_de_json_none(self, client): + assert Brand.de_json({}, client) is None + + def test_de_json_required(self, client): + json_dict = {'image': self.image, 'background': self.background, 'reference': self.reference, + 'pixels': self.pixels, 'theme': self.theme, 'playlist_theme': self.playlist_theme, + 'button': self.button} + brand = Brand.de_json(json_dict, client) + + assert brand.image == self.image + assert brand.background == self.background + assert brand.reference == self.reference + assert brand.pixels == self.pixels + assert brand.theme == self.theme + assert brand.playlist_theme == self.playlist_theme + assert brand.button == self.button + + def test_de_json_all(self, client): + json_dict = {'image': self.image, 'background': self.background, 'reference': self.reference, + 'pixels': self.pixels, 'theme': self.theme, 'playlist_theme': self.playlist_theme, + 'button': self.button} + brand = Brand.de_json(json_dict, client) + + assert brand.image == self.image + assert brand.background == self.background + assert brand.reference == self.reference + assert brand.pixels == self.pixels + assert brand.theme == self.theme + assert brand.playlist_theme == self.playlist_theme + assert brand.button == self.button + + def test_equality(self): + a = Brand(self.image, self.background, self.reference, self.pixels, + self.theme, self.playlist_theme, self.button) + b = Brand('', self.background, self.reference, ['link'], self.theme, self.playlist_theme, self.button) + c = Brand(self.image, self.background, self.reference, self.pixels, + self.theme, self.playlist_theme, self.button) + + assert a != b + assert hash(a) != hash(b) + assert a is not b + + assert a == c diff --git a/tests/test_contest.py b/tests/test_contest.py new file mode 100644 index 0000000..4757005 --- /dev/null +++ b/tests/test_contest.py @@ -0,0 +1,49 @@ +from yandex_music import Contest + + +class TestContest: + contest_id = 'disco_contest' + status = 'withdrew-moderator' + can_edit = True + sent = '2019-10-22T09:41:54+00:00' + withdrawn = '2019-10-23T07:02:03+00:00' + + def test_expected_values(self, contest): + assert contest.contest_id == self.contest_id + assert contest.status == self.status + assert contest.can_edit == self.can_edit + assert contest.sent == self.sent + assert contest.withdrawn == self.withdrawn + + def test_de_json_none(self, client): + assert Contest.de_json({}, client) is None + + def test_de_json_required(self, client): + json_dict = {'contest_id': self.contest_id, 'status': self.status, 'can_edit': self.can_edit} + contest = Contest.de_json(json_dict, client) + + assert contest.contest_id == self.contest_id + assert contest.status == self.status + assert contest.can_edit == self.can_edit + + def test_de_json_all(self, client): + json_dict = {'contest_id': self.contest_id, 'status': self.status, 'can_edit': self.can_edit, + 'sent': self.sent, 'withdrawn': self.withdrawn} + contest = Contest.de_json(json_dict, client) + + assert contest.contest_id == self.contest_id + assert contest.status == self.status + assert contest.can_edit == self.can_edit + assert contest.sent == self.sent + assert contest.withdrawn == self.withdrawn + + def test_equality(self): + a = Contest(self.contest_id, self.status, self.can_edit) + b = Contest('', self.status, self.can_edit) + c = Contest(self.contest_id, self.status, self.can_edit) + + assert a != b + assert hash(a) != hash(b) + assert a is not b + + assert a == c diff --git a/tests/test_open_graph_data.py b/tests/test_open_graph_data.py new file mode 100644 index 0000000..4103580 --- /dev/null +++ b/tests/test_open_graph_data.py @@ -0,0 +1,41 @@ +from yandex_music import OpenGraphData + + +class TestOpenGraphData: + title = 'Подкасты недели' + description = 'Чтобы собрать для вас этот плейлист, мы должны узнать вас ' \ + 'чуточку поближе. Заходите на Музыку и слушайте больше!' + + def test_expected_values(self, open_graph_data, cover): + assert open_graph_data.title == self.title + assert open_graph_data.description == self.description + + def test_de_json_none(self, client): + assert OpenGraphData.de_json({}, client) is None + + def test_de_json_required(self, client, cover): + json_dict = {'title': self.title, 'description': self.description, 'image': cover.to_dict()} + open_graph_data = OpenGraphData.de_json(json_dict, client) + + assert open_graph_data.title == self.title + assert open_graph_data.description == self.description + assert open_graph_data.image == cover + + def test_de_json_all(self, client, cover): + json_dict = {'title': self.title, 'description': self.description, 'image': cover.to_dict()} + open_graph_data = OpenGraphData.de_json(json_dict, client) + + assert open_graph_data.title == self.title + assert open_graph_data.description == self.description + assert open_graph_data.image == cover + + def test_equality(self, cover): + a = OpenGraphData(self.title, self.description, cover) + b = OpenGraphData('', self.description, cover) + c = OpenGraphData(self.title, self.description, cover) + + assert a != b + assert hash(a) != hash(b) + assert a is not b + + assert a == c diff --git a/tests/test_playlist.py b/tests/test_playlist.py index 908adb6..b7d335f 100644 --- a/tests/test_playlist.py +++ b/tests/test_playlist.py @@ -25,6 +25,9 @@ class TestPlaylist: background_color = '' text_color = '' id_for_from = 'playlist_of_the_day' + dummy_description = 'Слушайте интересные подкасты, чтобы мы могли узнать вас получше и\\xa0собрать этот плейлист' + dummy_page_description = 'Чтобы собрать для вас этот плейлист, мы должны узнать ' \ + 'вас чуточку поближе. Слушайте больше!' metrika_id = 666666 coauthors = [1130000003905541] prerolls = [] @@ -38,7 +41,7 @@ class TestPlaylist: regions = None def test_expected_values(self, playlist, user, cover, made_for, track_short, play_counter, playlist_absence, - playlist_without_nested_playlists, artist, track_id): + playlist_without_nested_playlists, artist, track_id, contest, open_graph_data, brand): assert playlist.owner == user assert playlist.uid == self.uid assert playlist.kind == self.kind @@ -65,9 +68,16 @@ class TestPlaylist: assert playlist.og_description == self.og_description assert playlist.image == self.image assert playlist.cover_without_text == cover + assert playlist.contest == contest assert playlist.background_color == self.background_color assert playlist.text_color == self.text_color assert playlist.id_for_from == self.id_for_from + assert playlist.dummy_description == self.dummy_description + assert playlist.dummy_page_description == self.dummy_page_description + assert playlist.dummy_cover == cover + assert playlist.dummy_rollover_cover == cover + assert playlist.og_data == open_graph_data + assert playlist.branding == brand assert playlist.metrika_id == self.metrika_id assert playlist.coauthors == self.coauthors assert playlist.top_artist == [artist] @@ -103,7 +113,7 @@ class TestPlaylist: assert playlist.playlist_absence == playlist_absence def test_de_json_all(self, client, user, cover, made_for, track_short, play_counter, playlist_absence, - playlist_without_nested_playlists, artist, track_id): + playlist_without_nested_playlists, artist, track_id, contest, open_graph_data, brand): json_dict = {'owner': user.to_dict(), 'uid': self.uid, 'kind': self.kind, 'title': self.title, 'track_count': self.track_count, 'cover': cover.to_dict(), 'made_for': made_for.to_dict(), 'play_counter': play_counter.to_dict(), 'playlist_absence': playlist_absence.to_dict(), @@ -121,7 +131,11 @@ class TestPlaylist: 'similar_playlists': [playlist_without_nested_playlists.to_dict()], 'last_owner_playlists': [playlist_without_nested_playlists.to_dict()], 'og_description': self.og_description, 'top_artist': [artist.to_dict()], - 'recent_tracks': [track_id.to_dict()], 'metrika_id': self.metrika_id} + 'recent_tracks': [track_id.to_dict()], 'metrika_id': self.metrika_id, + 'contest': contest.to_dict(), 'dummy_description': self.dummy_description, + 'dummy_page_description': self.dummy_page_description, 'dummy_cover': cover.to_dict(), + 'dummy_rollover_cover': cover.to_dict(), 'og_data': open_graph_data.to_dict(), + 'branding': brand.to_dict()} playlist = Playlist.de_json(json_dict, client) assert playlist.owner == user @@ -150,9 +164,16 @@ class TestPlaylist: assert playlist.og_description == self.og_description assert playlist.image == self.image assert playlist.cover_without_text == cover + assert playlist.contest == contest assert playlist.background_color == self.background_color assert playlist.text_color == self.text_color assert playlist.id_for_from == self.id_for_from + assert playlist.dummy_description == self.dummy_description + assert playlist.dummy_page_description == self.dummy_page_description + assert playlist.dummy_cover == cover + assert playlist.dummy_rollover_cover == cover + assert playlist.og_data == open_graph_data + assert playlist.branding == brand assert playlist.metrika_id == self.metrika_id assert playlist.coauthors == self.coauthors assert playlist.top_artist == [artist] diff --git a/yandex_music/__init__.py b/yandex_music/__init__.py index 11bbb85..1cb669b 100644 --- a/yandex_music/__init__.py +++ b/yandex_music/__init__.py @@ -37,6 +37,9 @@ from .artist.vinyl import Vinyl from .playlist.case_forms import CaseForms from .playlist.made_for import MadeFor from .playlist.user import User +from .playlist.contest import Contest +from .playlist.open_graph_data import OpenGraphData +from .playlist.brand import Brand from .playlist.play_counter import PlayCounter from .playlist.playlist_id import PlaylistId from .playlist.tag import Tag @@ -138,4 +141,4 @@ __all__ = ['YandexMusicObject', 'Client', 'Account', 'PassportPhone', 'Invocatio 'ShotType', 'ShotData', 'SimilarTracks', 'UserSettings', 'RenewableRemainder', 'ChartInfo', 'ChartInfoMenu', 'ChartInfoMenuItem', 'Tag', 'TagResult', 'PlaylistRecommendations', 'LandingList', 'MetaData', 'LicenceTextPart', 'StationData', 'AlertButton', 'Alert', 'NonAutoRenewable', 'PoetryLoverMatch', - 'Operator', 'Deactivation'] + 'Operator', 'Deactivation', 'Contest', 'OpenGraphData', 'Brand'] diff --git a/yandex_music/client.py b/yandex_music/client.py index 28f35fa..f1ab12c 100644 --- a/yandex_music/client.py +++ b/yandex_music/client.py @@ -1456,6 +1456,9 @@ class Client(YandexMusicObject): """Получение цепочки треков определённой станции. Note: + Запуск потока по сущности сервиса осуществляется через станцию `:`. + Например, станцией для запуска потока по треку будет `track:1234`. + Для продолжения цепочки треков необходимо: 1. Передавать `ID` трека, что был до этого (первый в цепочки). diff --git a/yandex_music/playlist/brand.py b/yandex_music/playlist/brand.py new file mode 100644 index 0000000..43f7c2d --- /dev/null +++ b/yandex_music/playlist/brand.py @@ -0,0 +1,76 @@ +from typing import TYPE_CHECKING, Optional, List + +from yandex_music import YandexMusicObject + +if TYPE_CHECKING: + from yandex_music import Client + + +class Brand(YandexMusicObject): + """Класс, представляющий бренд плейлиста. + + Note: + Отслеживание просмотров на сторонник сервисах бренда, рекомендация следующего контента. + + Attributes: + image (:obj:`str`): Ссылка на изображение. + background (:obj:`str`): Цвет заднего фона. + reference (:obj:`str`): URI ссылка на содержимое. + pixels (:obj:`list` из :obj:`str`): Ссылки на gif изображения для отслеживания просмотров (web beacon). + theme (:obj:`str`): Тема оформления. + playlist_theme (:obj:`str`): Тема плейлиста TODO. + button (:obj:`str`): Текст кнопки. + client (:obj:`yandex_music.Client`): Клиент Yandex Music. + + Args: + image (:obj:`str`): Ссылка на изображение. + background (:obj:`str`): Цвет заднего фона. + reference (:obj:`str`): URI ссылка на содержимое. + pixels (:obj:`list` из :obj:`str`): Ссылки на gif изображения для отслеживания просмотров (web beacon). + theme (:obj:`str`): Тема оформления. + playlist_theme (:obj:`str`): Тема плейлиста TODO. + button (:obj:`str`): Текст кнопки. + client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. + **kwargs: Произвольные ключевые аргументы полученные от API. + """ + + def __init__(self, + image: str, + background: str, + reference: str, + pixels: List[str], + theme: str, + playlist_theme: str, + button: str, + client: Optional['Client'] = None, + **kwargs) -> None: + self.image = image + self.background = background + self.reference = reference + self.pixels = pixels + self.theme = theme + self.playlist_theme = playlist_theme + self.button = button + + self.client = client + self._id_attrs = (self.image, self.reference, self.pixels) + + super().handle_unknown_kwargs(self, **kwargs) + + @classmethod + def de_json(cls, data: dict, client: 'Client') -> Optional['Brand']: + """Десериализация объекта. + + Args: + data (:obj:`dict`): Поля и значения десериализуемого объекта. + client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. + + Returns: + :obj:`yandex_music.Brand`: Бренд плейлиста. + """ + if not data: + return None + + data = super(Brand, cls).de_json(data, client) + + return cls(client=client, **data) diff --git a/yandex_music/playlist/contest.py b/yandex_music/playlist/contest.py new file mode 100644 index 0000000..3dbb590 --- /dev/null +++ b/yandex_music/playlist/contest.py @@ -0,0 +1,68 @@ +from typing import TYPE_CHECKING, Optional + +from yandex_music import YandexMusicObject + +if TYPE_CHECKING: + from yandex_music import Client + + +class Contest(YandexMusicObject): + """Класс, представляющий контест TODO. + + Note: + Известные значения поля `status`: `editing`, `withdrew-moderator`. + + Attributes: + contest_id (:obj:`str`): Уникальный идентификатор. + status (:obj:`str`): Статус. + can_edit (:obj:`bool`): Разрешено ли редактирование. + sent (:obj:`str`): Дата отправки. + withdrawn (:obj:`str`): Дата вывода (окончания). + client (:obj:`yandex_music.Client`): Клиент Yandex Music. + + Args: + contest_id (:obj:`str`): Уникальный идентификатор. + status (:obj:`str`): Статус. + can_edit (:obj:`bool`): Разрешено ли редактирование. + sent (:obj:`str`, optional): Дата отправки. + withdrawn (:obj:`str`, optional): Дата вывода (окончания). + client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. + **kwargs: Произвольные ключевые аргументы полученные от API. + """ + + def __init__(self, + contest_id: str, + status: str, + can_edit: bool, + sent: Optional[str] = None, + withdrawn: Optional[str] = None, + client: Optional['Client'] = None, + **kwargs) -> None: + self.contest_id = contest_id + self.status = status + self.can_edit = can_edit + self.sent = sent + self.withdrawn = withdrawn + + self.client = client + self._id_attrs = (self.contest_id, self.status) + + super().handle_unknown_kwargs(self, **kwargs) + + @classmethod + def de_json(cls, data: dict, client: 'Client') -> Optional['Contest']: + """Десериализация объекта. + + Args: + data (:obj:`dict`): Поля и значения десериализуемого объекта. + client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. + + Returns: + :obj:`yandex_music.Contest`: Контест. + """ + if not data: + return None + + data = super(Contest, cls).de_json(data, client) + + return cls(client=client, **data) diff --git a/yandex_music/playlist/open_graph_data.py b/yandex_music/playlist/open_graph_data.py new file mode 100644 index 0000000..c67833d --- /dev/null +++ b/yandex_music/playlist/open_graph_data.py @@ -0,0 +1,59 @@ +from typing import TYPE_CHECKING, Optional, List + +from yandex_music import YandexMusicObject + +if TYPE_CHECKING: + from yandex_music import Client, Cover + + +class OpenGraphData(YandexMusicObject): + """Класс, представляющий данные для Open Graph. + + Attributes: + title (:obj:`str`): Заголовок. + description (:obj:`str`): Описание. + image (:obj:`yandex_music.Cover`): Изображение. + client (:obj:`yandex_music.Client`): Клиент Yandex Music. + + Args: + title (:obj:`str`): Заголовок. + description (:obj:`str`): Описание. + image (:obj:`yandex_music.Cover`): Изображение. + client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. + **kwargs: Произвольные ключевые аргументы полученные от API. + """ + + def __init__(self, + title: str, + description: str, + image: 'Cover', + client: Optional['Client'] = None, + **kwargs) -> None: + self.title = title + self.description = description + self.image = image + + self.client = client + self._id_attrs = (self.title, self.description, self.image) + + super().handle_unknown_kwargs(self, **kwargs) + + @classmethod + def de_json(cls, data: dict, client: 'Client') -> Optional['OpenGraphData']: + """Десериализация объекта. + + Args: + data (:obj:`dict`): Поля и значения десериализуемого объекта. + client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. + + Returns: + :obj:`yandex_music.OpenGraphData`: Данные для Open Graph. + """ + if not data: + return None + + data = super(OpenGraphData, cls).de_json(data, client) + from yandex_music import Cover + data['image'] = Cover.de_json(data.get('image'), client) + + return cls(client=client, **data) diff --git a/yandex_music/playlist/playlist.py b/yandex_music/playlist/playlist.py index f0b6201..c019f3a 100644 --- a/yandex_music/playlist/playlist.py +++ b/yandex_music/playlist/playlist.py @@ -4,13 +4,16 @@ from yandex_music import YandexMusicObject if TYPE_CHECKING: from yandex_music import Client, User, Cover, MadeFor, TrackShort, PlaylistAbsence, PlayCounter,\ - PlaylistRecommendations, Artist, TrackId + PlaylistRecommendations, Artist, TrackId, Contest, OpenGraphData, Brand class Playlist(YandexMusicObject): """Класс, представляющий плейлист. Note: + Под полями с заглушками понимаются поля, которые доступны у умных плейлистов тогда, когда у сервиса мало + данных для генерации плейлиста. + Известные значения `visibility`: `public` - публичный плейлист, `private` - приватный плейлист. Известные значения `generated_playlist_type`: `playlistOfTheDay` - Плейлист дня, `recentTracks` - Премьера, @@ -44,9 +47,16 @@ class Playlist(YandexMusicObject): og_description (:obj:`str`, optional): Описание Open Graph. image (:obj:`str`): Изображение TODO. cover_without_text (:obj:`yandex_music.Cover`): Обложка без текста. + contest (:obj:`yandex_music.Contest`): Контест TODO. background_color (:obj:`str`): Цвет заднего фона TODO. text_color (:obj:`str`): Цвет текста TODO. id_for_from (:obj:`str`): Откуда пришло событие (уникальный идентификатор объекта) TODO. + dummy_description (:obj:`str`): Описание-заглушка плейлиста. + dummy_page_description (:obj:`str`): Описание-заглушка страницы. + dummy_cover (:obj:`str`): Обложка-заглушка. + dummy_rollover_cover (:obj:`str`): Обложка-заглушка TODO. + og_data (:obj:`yandex_music.OpenGraphData`): Данные для OpenGraph. + branding (:obj:`yandex_music.Brand`): Бренд. metrika_id (:obj:`int`): Уникальный идентификатор счётчика на Яндекс.Метрика. coauthors (:obj:`list` из :obj:`int`): Перечень ID аккаунтов соавторов плейлиста. top_artist (:obj:`list` из :obj:`yandex_music.Artist`): Топ артистов TODO. @@ -93,9 +103,16 @@ class Playlist(YandexMusicObject): og_description (:obj:`str`, optional): Описание Open Graph. image (:obj:`str`, optional): Изображение TODO. cover_without_text (:obj:`yandex_music.Cover`, optional): Обложка без текста. + contest (:obj:`yandex_music.Contest`, optional): Контест TODO. background_color (:obj:`str`, optional): Цвет заднего фона TODO. text_color (:obj:`str`, optional): Цвет текста TODO. id_for_from (:obj:`str`, optional): Откуда пришло событие (уникальный идентификатор объекта) TODO. + dummy_description (:obj:`str`, optional): Описание-заглушка плейлиста. + dummy_page_description (:obj:`str`, optional): Описание-заглушка страницы. + dummy_cover (:obj:`str`, optional): Обложка-заглушка. + dummy_rollover_cover (:obj:`str`, optional): Обложка-заглушка TODO. + og_data (:obj:`yandex_music.OpenGraphData`, optional): Данные для OpenGraph. + branding (:obj:`yandex_music.Brand`): Бренд. metrika_id (:obj:`int`, optional): Уникальный идентификатор счётчика на Яндекс.Метрика. coauthors (:obj:`list` из :obj:`int`, optional): Перечень ID аккаунтов соавторов плейлиста. top_artist (:obj:`list` из :obj:`yandex_music.Artist`, optional): Топ артистов TODO. @@ -144,9 +161,16 @@ class Playlist(YandexMusicObject): og_description: Optional[str] = None, image: Optional[str] = None, cover_without_text: Optional['Cover'] = None, + contest: Optional['Contest'] = None, background_color: Optional[str] = None, text_color: Optional[str] = None, id_for_from: Optional[str] = None, + dummy_description: Optional[str] = None, + dummy_page_description: Optional[str] = None, + dummy_cover: Optional['Cover'] = None, + dummy_rollover_cover: Optional['Cover'] = None, + og_data: Optional['OpenGraphData'] = None, + branding: Optional['Brand'] = None, metrika_id: Optional[int] = None, coauthors: List[int] = None, top_artist: List['Artist'] = None, @@ -191,9 +215,16 @@ class Playlist(YandexMusicObject): self.og_description = og_description self.image = image self.cover_without_text = cover_without_text + self.contest = contest self.background_color = background_color self.text_color = text_color self.id_for_from = id_for_from + self.dummy_description = dummy_description + self.dummy_page_description = dummy_page_description + self.dummy_cover = dummy_cover + self.dummy_rollover_cover = dummy_rollover_cover + self.og_data = og_data + self.branding = branding self.metrika_id = metrika_id self.coauthors = coauthors self.top_artist = top_artist @@ -294,7 +325,8 @@ class Playlist(YandexMusicObject): return None data = super(Playlist, cls).de_json(data, client) - from yandex_music import User, MadeFor, Cover, PlayCounter, TrackShort, PlaylistAbsence, Artist, TrackId + from yandex_music import User, MadeFor, Cover, PlayCounter, TrackShort, \ + PlaylistAbsence, Artist, TrackId, Contest, OpenGraphData, Brand data['owner'] = User.de_json(data.get('owner'), client) data['cover'] = Cover.de_json(data.get('cover'), client) data['cover_without_text'] = Cover.de_json(data.get('cover_without_text'), client) @@ -303,6 +335,11 @@ class Playlist(YandexMusicObject): data['recent_tracks'] = TrackId.de_list(data.get('recent_tracks'), client) data['play_counter'] = PlayCounter.de_json(data.get('play_counter'), client) data['top_artist'] = Artist.de_list(data.get('top_artist'), client) + data['contest'] = Contest.de_json(data.get('contest'), client) + data['og_data'] = OpenGraphData.de_json(data.get('og_data'), client) + data['dummy_cover'] = Cover.de_json(data.get('dummy_cover'), client) + data['dummy_rollover_cover'] = Cover.de_json(data.get('dummy_rollover_cover'), client) + data['branding'] = Brand.de_json(data.get('branding'), client) data['similar_playlists'] = Playlist.de_list(data.get('similar_playlists'), client) data['last_owner_playlists'] = Playlist.de_list(data.get('last_owner_playlists'), client)