Merge branch 'development' into pull/325
このコミットが含まれているのは:
コミット
65d1584b79
|
@ -0,0 +1,7 @@
|
||||||
|
yandex_music.ChartInfo
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. autoclass:: yandex_music.ChartInfo
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
|
@ -0,0 +1,7 @@
|
||||||
|
yandex_music.ChartInfoMenu
|
||||||
|
==========================
|
||||||
|
|
||||||
|
.. autoclass:: yandex_music.ChartInfoMenu
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
|
@ -0,0 +1,7 @@
|
||||||
|
yandex_music.ChartInfoMenuItem
|
||||||
|
==============================
|
||||||
|
|
||||||
|
.. autoclass:: yandex_music.ChartInfoMenuItem
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
|
@ -15,3 +15,6 @@
|
||||||
yandex_music.landing.personal_playlists_data
|
yandex_music.landing.personal_playlists_data
|
||||||
yandex_music.landing.promotion
|
yandex_music.landing.promotion
|
||||||
yandex_music.landing.block
|
yandex_music.landing.block
|
||||||
|
yandex_music.landing.chart_info
|
||||||
|
yandex_music.landing.chart_info_menu
|
||||||
|
yandex_music.landing.chart_info_menu_item
|
||||||
|
|
|
@ -11,3 +11,5 @@
|
||||||
yandex_music.playlist.case_forms
|
yandex_music.playlist.case_forms
|
||||||
yandex_music.playlist.playlist_id
|
yandex_music.playlist.playlist_id
|
||||||
yandex_music.playlist.playlist_recommendations
|
yandex_music.playlist.playlist_recommendations
|
||||||
|
yandex_music.playlist.tag_result
|
||||||
|
yandex_music.playlist.tag
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
yandex_music.Tag
|
||||||
|
================
|
||||||
|
|
||||||
|
.. autoclass:: yandex_music.Tag
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
|
@ -0,0 +1,7 @@
|
||||||
|
yandex_music.TagResult
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. autoclass:: yandex_music.TagResult
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
|
@ -17,6 +17,9 @@ from .test_description import TestDescription
|
||||||
from .test_discrete_scale import TestDiscreteScale
|
from .test_discrete_scale import TestDiscreteScale
|
||||||
from .test_enum import TestEnum
|
from .test_enum import TestEnum
|
||||||
from .test_event import TestEvent
|
from .test_event import TestEvent
|
||||||
|
from .test_chart_info_menu_item import TestChartInfoMenuItem
|
||||||
|
from .test_chart_info_menu import TestChartInfoMenu
|
||||||
|
from .test_chart_info import TestChartInfo
|
||||||
from .test_generated_playlist import TestGeneratedPlaylist
|
from .test_generated_playlist import TestGeneratedPlaylist
|
||||||
from .test_genre import TestGenre
|
from .test_genre import TestGenre
|
||||||
from .test_icon import TestIcon
|
from .test_icon import TestIcon
|
||||||
|
@ -74,3 +77,4 @@ from .test_shot_type import TestShotType
|
||||||
from .test_shot_data import TestShotData
|
from .test_shot_data import TestShotData
|
||||||
from .test_shot import TestShot
|
from .test_shot import TestShot
|
||||||
from .test_renewable_remainder import TestRenewableRemainder
|
from .test_renewable_remainder import TestRenewableRemainder
|
||||||
|
from .test_tag import TestTag
|
||||||
|
|
|
@ -7,7 +7,7 @@ from yandex_music import Counts, TrackId, CaseForms, Ratings, Icon, Album, Lyric
|
||||||
PersonalPlaylistsData, RotorSettings, TrackShortOld, PlayContextsData, Status, Settings, StationResult, Enum, \
|
PersonalPlaylistsData, RotorSettings, TrackShortOld, PlayContextsData, Status, Settings, StationResult, Enum, \
|
||||||
TrackWithAds, VideoSupplement, ArtistEvent, ChartItem, Event, AlbumEvent, Day, PlayContext, Plus, Title, Label, \
|
TrackWithAds, VideoSupplement, ArtistEvent, ChartItem, Event, AlbumEvent, Day, PlayContext, Plus, Title, Label, \
|
||||||
GeneratedPlaylist, Video, Vinyl, SearchResult, BlockEntity, Block, PlaylistAbsence, ShotType, ShotData, Shot, \
|
GeneratedPlaylist, Video, Vinyl, SearchResult, BlockEntity, Block, PlaylistAbsence, ShotType, ShotData, Shot, \
|
||||||
RenewableRemainder
|
RenewableRemainder, ChartInfoMenuItem, ChartInfoMenu, ChartInfo, Tag
|
||||||
from . import TestCounts, TestTrackId, TestCaseForms, TestRatings, TestIcon, TestAlbum, TestLyrics, \
|
from . import TestCounts, TestTrackId, TestCaseForms, TestRatings, TestIcon, TestAlbum, TestLyrics, \
|
||||||
TestTrack, TestInvocationInfo, TestPlaylist, TestAutoRenewable, TestStation, TestNormalization, TestMajor, \
|
TestTrack, TestInvocationInfo, TestPlaylist, TestAutoRenewable, TestStation, TestNormalization, TestMajor, \
|
||||||
TestTrackPosition, TestBest, TestChart, TestPermissions, TestPlus, TestProduct, TestCover, TestPlayCounter, \
|
TestTrackPosition, TestBest, TestChart, TestPermissions, TestPlus, TestProduct, TestCover, TestPlayCounter, \
|
||||||
|
@ -17,7 +17,7 @@ from . import TestCounts, TestTrackId, TestCaseForms, TestRatings, TestIcon, Tes
|
||||||
TestTrackShortOld, TestPager, TestStatus, TestSettings, TestStationResult, TestLabel, TestTrackWithAds, \
|
TestTrackShortOld, TestPager, TestStatus, TestSettings, TestStationResult, TestLabel, TestTrackWithAds, \
|
||||||
TestVideoSupplement, TestEvent, TestDay, TestPlayContext, TestGeneratedPlaylist, TestVideo, TestVinyl, \
|
TestVideoSupplement, TestEvent, TestDay, TestPlayContext, TestGeneratedPlaylist, TestVideo, TestVinyl, \
|
||||||
TestSearchResult, TestBlockEntity, TestBlock, TestPlaylistAbsence, TestShot, TestShotData, TestShotType, \
|
TestSearchResult, TestBlockEntity, TestBlock, TestPlaylistAbsence, TestShot, TestShotData, TestShotType, \
|
||||||
TestRenewableRemainder
|
TestRenewableRemainder, TestChartInfoMenuItem, TestChartInfo, TestTag
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
|
@ -137,6 +137,11 @@ def client():
|
||||||
return Client()
|
return Client()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def tag():
|
||||||
|
return Tag(TestTag.id_, TestTag.value, TestTag.name, TestTag.og_description)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def track_with_ads(track):
|
def track_with_ads(track):
|
||||||
return TrackWithAds(TestTrackWithAds.type, track)
|
return TrackWithAds(TestTrackWithAds.type, track)
|
||||||
|
@ -423,6 +428,22 @@ def event(track, artist_event, album_event):
|
||||||
[album_event], TestEvent.message, TestEvent.device, TestEvent.tracks_count)
|
[album_event], TestEvent.message, TestEvent.device, TestEvent.tracks_count)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def chart_info_menu_item():
|
||||||
|
return ChartInfoMenuItem(TestChartInfoMenuItem.title, TestChartInfoMenuItem.url, TestChartInfoMenuItem.selected)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def chart_info_menu(chart_info_menu_item):
|
||||||
|
return ChartInfoMenu([chart_info_menu_item])
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='session')
|
||||||
|
def chart_info(playlist, chart_info_menu):
|
||||||
|
return ChartInfo(TestChartInfo.id, TestChartInfo.type, TestChartInfo.type_for_from, TestChartInfo.title,
|
||||||
|
chart_info_menu, playlist, TestChartInfo.chart_description)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='session')
|
@pytest.fixture(scope='session')
|
||||||
def track_id():
|
def track_id():
|
||||||
return TrackId(TestTrackId.id, TestTrackId.album_id)
|
return TrackId(TestTrackId.id, TestTrackId.album_id)
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
from yandex_music import ChartInfo
|
||||||
|
|
||||||
|
|
||||||
|
class TestChartInfo:
|
||||||
|
id = 'KpXst7X4'
|
||||||
|
type = 'chart'
|
||||||
|
type_for_from = 'chart'
|
||||||
|
title = 'Треки, популярные на Яндекс.Музыке прямо сейчас'
|
||||||
|
chart_description = 'Слушателей за день'
|
||||||
|
|
||||||
|
def test_expected_values(self, chart_info, chart_info_menu, playlist):
|
||||||
|
assert chart_info.id == self.id
|
||||||
|
assert chart_info.type == self.type
|
||||||
|
assert chart_info.type_for_from == self.type_for_from
|
||||||
|
assert chart_info.title == self.title
|
||||||
|
assert chart_info.chart == playlist
|
||||||
|
assert chart_info.menu == chart_info_menu
|
||||||
|
|
||||||
|
def test_de_json_none(self, client):
|
||||||
|
assert ChartInfo.de_json({}, client) is None
|
||||||
|
|
||||||
|
def test_de_json_required(self, playlist, chart_info_menu, client):
|
||||||
|
json_dict = {
|
||||||
|
'id_': self.id,
|
||||||
|
'type_': self.type,
|
||||||
|
'type_for_from': self.type_for_from,
|
||||||
|
'title': self.title,
|
||||||
|
'chart_description': self.chart_description,
|
||||||
|
'menu': chart_info_menu.to_dict(),
|
||||||
|
'chart': playlist.to_dict()
|
||||||
|
}
|
||||||
|
|
||||||
|
chart_info = ChartInfo.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert chart_info.id == self.id
|
||||||
|
assert chart_info.type == self.type
|
||||||
|
assert chart_info.type_for_from == self.type_for_from
|
||||||
|
assert chart_info.title == self.title
|
||||||
|
assert chart_info.chart_description == self.chart_description
|
||||||
|
|
||||||
|
def test_de_json_all(self, client, playlist, chart_info_menu):
|
||||||
|
json_dict = {
|
||||||
|
'id_': self.id,
|
||||||
|
'type_': self.type,
|
||||||
|
'type_for_from': self.type_for_from,
|
||||||
|
'title': self.title,
|
||||||
|
'chart_description': self.chart_description,
|
||||||
|
'menu': chart_info_menu.to_dict(),
|
||||||
|
'chart': playlist.to_dict()
|
||||||
|
}
|
||||||
|
|
||||||
|
chart_info = ChartInfo.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert chart_info.id == self.id
|
||||||
|
assert chart_info.type == self.type
|
||||||
|
assert chart_info.type_for_from == self.type_for_from
|
||||||
|
assert chart_info.title == self.title
|
||||||
|
assert chart_info.chart_description == self.chart_description
|
||||||
|
assert chart_info.menu == chart_info_menu
|
||||||
|
assert chart_info.chart == playlist
|
||||||
|
|
||||||
|
def test_equality(self, playlist, chart_info_menu):
|
||||||
|
a = ChartInfo(self.id, self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu,
|
||||||
|
playlist)
|
||||||
|
b = ChartInfo("no_id", self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu,
|
||||||
|
playlist)
|
||||||
|
c = ChartInfo(self.id, self.type, self.type_for_from, self.title, self.chart_description, chart_info_menu,
|
||||||
|
playlist)
|
||||||
|
|
||||||
|
assert a != b
|
||||||
|
assert hash(a) != hash(b)
|
||||||
|
assert a is not b
|
||||||
|
|
||||||
|
assert a == c
|
|
@ -0,0 +1,29 @@
|
||||||
|
from yandex_music import ChartInfoMenu, ChartInfoMenuItem
|
||||||
|
|
||||||
|
|
||||||
|
class TestChartInfoMenu:
|
||||||
|
def test_expected_values(self, chart_info_menu, chart_info_menu_item):
|
||||||
|
assert chart_info_menu.items == [chart_info_menu_item]
|
||||||
|
|
||||||
|
def test_de_json_none(self, client):
|
||||||
|
assert ChartInfoMenu.de_json({}, client) is None
|
||||||
|
|
||||||
|
def test_de_json_required(self, chart_info_menu_item, client):
|
||||||
|
json_dict = {
|
||||||
|
'items': [chart_info_menu_item.to_dict()],
|
||||||
|
}
|
||||||
|
|
||||||
|
chart_info_menu = ChartInfoMenu.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert chart_info_menu.items == [chart_info_menu_item]
|
||||||
|
|
||||||
|
def test_equality(self, chart_info_menu_item):
|
||||||
|
a = ChartInfoMenu([chart_info_menu_item])
|
||||||
|
b = ChartInfoMenu([ChartInfoMenuItem("tt", "no_url")])
|
||||||
|
c = ChartInfoMenu([chart_info_menu_item])
|
||||||
|
|
||||||
|
assert a != b
|
||||||
|
assert hash(a) != hash(b)
|
||||||
|
assert a is not b
|
||||||
|
|
||||||
|
assert a == c
|
|
@ -0,0 +1,50 @@
|
||||||
|
from yandex_music import ChartInfoMenuItem
|
||||||
|
|
||||||
|
|
||||||
|
class TestChartInfoMenuItem:
|
||||||
|
title = 'Россия'
|
||||||
|
url = 'russia'
|
||||||
|
selected = True
|
||||||
|
|
||||||
|
def test_expected_values(self, chart_info_menu_item):
|
||||||
|
assert chart_info_menu_item.title == self.title
|
||||||
|
assert chart_info_menu_item.url == self.url
|
||||||
|
assert chart_info_menu_item.selected == self.selected
|
||||||
|
|
||||||
|
def test_de_json_none(self, client):
|
||||||
|
assert ChartInfoMenuItem.de_json({}, client) is None
|
||||||
|
|
||||||
|
def test_de_json_required(self, client):
|
||||||
|
json_dict = {
|
||||||
|
'title': self.title,
|
||||||
|
'url': self.url,
|
||||||
|
}
|
||||||
|
|
||||||
|
chart_info_menu_item = ChartInfoMenuItem.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert chart_info_menu_item.title == self.title
|
||||||
|
assert chart_info_menu_item.url == self.url
|
||||||
|
|
||||||
|
def test_de_json_all(self, client):
|
||||||
|
json_dict = {
|
||||||
|
'title': self.title,
|
||||||
|
'url': self.url,
|
||||||
|
'selected': self.selected,
|
||||||
|
}
|
||||||
|
|
||||||
|
chart_info_menu_item = ChartInfoMenuItem.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert chart_info_menu_item.title == self.title
|
||||||
|
assert chart_info_menu_item.url == self.url
|
||||||
|
assert chart_info_menu_item.selected == self.selected
|
||||||
|
|
||||||
|
def test_equality(self):
|
||||||
|
a = ChartInfoMenuItem(self.title, self.url, self.selected)
|
||||||
|
b = ChartInfoMenuItem(self.title, "no_url", self.selected)
|
||||||
|
c = ChartInfoMenuItem(self.title, self.url, self.selected)
|
||||||
|
|
||||||
|
assert a != b
|
||||||
|
assert hash(a) != hash(b)
|
||||||
|
assert a is not b
|
||||||
|
|
||||||
|
assert a == c
|
|
@ -0,0 +1,47 @@
|
||||||
|
from yandex_music import Tag
|
||||||
|
|
||||||
|
|
||||||
|
class TestTag:
|
||||||
|
id_ = '5795ce8f77d30f7fda41bca0'
|
||||||
|
value = 'вечные хиты'
|
||||||
|
name = 'Вечные хиты'
|
||||||
|
og_description = ''
|
||||||
|
|
||||||
|
def test_expected_values(self, tag):
|
||||||
|
assert tag.id == self.id_
|
||||||
|
assert tag.value == self.value
|
||||||
|
assert tag.name == self.name
|
||||||
|
assert tag.og_description == self.og_description
|
||||||
|
|
||||||
|
def test_de_json_none(self, client):
|
||||||
|
assert Tag.de_json({}, client) is None
|
||||||
|
|
||||||
|
def test_de_json_required(self, client):
|
||||||
|
json_dict = {'id_': self.id_, 'value': self.value, 'name': self.name, 'og_description': self.og_description}
|
||||||
|
tag = Tag.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert tag.id == self.id_
|
||||||
|
assert tag.value == self.value
|
||||||
|
assert tag.name == self.name
|
||||||
|
assert tag.og_description == self.og_description
|
||||||
|
|
||||||
|
def test_de_json_all(self, client):
|
||||||
|
json_dict = {'id_': self.id_, 'value': self.value, 'name': self.name, 'og_description': self.og_description}
|
||||||
|
tag = Tag.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert tag.id == self.id_
|
||||||
|
assert tag.value == self.value
|
||||||
|
assert tag.name == self.name
|
||||||
|
assert tag.og_description == self.og_description
|
||||||
|
|
||||||
|
def test_equality(self):
|
||||||
|
a = Tag(self.id_, self.value, self.name, self.og_description)
|
||||||
|
b = Tag('10b300', self.value, self.name, self.og_description)
|
||||||
|
c = Tag(self.id_, self.value, '', self.og_description)
|
||||||
|
d = Tag(self.id_, self.value, self.name, self.og_description)
|
||||||
|
|
||||||
|
assert a != b != c
|
||||||
|
assert hash(a) != hash(b) != hash(c)
|
||||||
|
assert a is not b is not c
|
||||||
|
|
||||||
|
assert a == d
|
|
@ -0,0 +1,42 @@
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from yandex_music import TagResult
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='class')
|
||||||
|
def tag_result(tag, playlist_id):
|
||||||
|
return TagResult(tag, [playlist_id])
|
||||||
|
|
||||||
|
|
||||||
|
class TestTagResult:
|
||||||
|
def test_expected_values(self, tag_result, tag, playlist_id):
|
||||||
|
assert tag_result.tag == tag
|
||||||
|
assert tag_result.ids == [playlist_id]
|
||||||
|
|
||||||
|
def test_de_json_none(self, client):
|
||||||
|
assert TagResult.de_json({}, client) is None
|
||||||
|
|
||||||
|
def test_de_json_required(self, client, tag, playlist_id):
|
||||||
|
json_dict = {'tag': tag.to_dict(), 'ids': [playlist_id.to_dict()]}
|
||||||
|
tag_result = TagResult.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert tag_result.tag == tag
|
||||||
|
assert tag_result.ids == [playlist_id]
|
||||||
|
|
||||||
|
def test_de_json_all(self, client, tag, playlist_id):
|
||||||
|
json_dict = {'tag': tag.to_dict(), 'ids': [playlist_id.to_dict()]}
|
||||||
|
tag_result = TagResult.de_json(json_dict, client)
|
||||||
|
|
||||||
|
assert tag_result.tag == tag
|
||||||
|
assert tag_result.ids == [playlist_id]
|
||||||
|
|
||||||
|
def test_equality(self, tag, playlist_id):
|
||||||
|
a = TagResult(tag, [playlist_id])
|
||||||
|
b = TagResult(tag, [])
|
||||||
|
c = TagResult(tag, [playlist_id])
|
||||||
|
|
||||||
|
assert a != b
|
||||||
|
assert hash(a) != hash(b)
|
||||||
|
assert a is not b
|
||||||
|
|
||||||
|
assert a == c
|
|
@ -34,6 +34,8 @@ from .playlist.made_for import MadeFor
|
||||||
from .playlist.user import User
|
from .playlist.user import User
|
||||||
from .playlist.play_counter import PlayCounter
|
from .playlist.play_counter import PlayCounter
|
||||||
from .playlist.playlist_id import PlaylistId
|
from .playlist.playlist_id import PlaylistId
|
||||||
|
from .playlist.tag import Tag
|
||||||
|
from .playlist.tag_result import TagResult
|
||||||
from .playlist.playlist_absence import PlaylistAbsence
|
from .playlist.playlist_absence import PlaylistAbsence
|
||||||
from .playlist.playlist import Playlist
|
from .playlist.playlist import Playlist
|
||||||
from .playlist.playlist_recommendation import PlaylistRecommendations
|
from .playlist.playlist_recommendation import PlaylistRecommendations
|
||||||
|
@ -74,6 +76,9 @@ from .landing.promotion import Promotion
|
||||||
from .landing.block_entity import BlockEntity
|
from .landing.block_entity import BlockEntity
|
||||||
from .landing.landing import Landing
|
from .landing.landing import Landing
|
||||||
from .landing.block import Block
|
from .landing.block import Block
|
||||||
|
from .landing.chart_info_menu_item import ChartInfoMenuItem
|
||||||
|
from .landing.chart_info_menu import ChartInfoMenu
|
||||||
|
from .landing.chart_info import ChartInfo
|
||||||
from .landing.track_id import TrackId
|
from .landing.track_id import TrackId
|
||||||
from .landing.chart import Chart
|
from .landing.chart import Chart
|
||||||
from .landing.play_contexts_data import PlayContextsData
|
from .landing.play_contexts_data import PlayContextsData
|
||||||
|
@ -120,4 +125,5 @@ __all__ = ['YandexMusicObject', 'Client', 'Account', 'PassportPhone', 'Invocatio
|
||||||
'Dashboard', 'RotorSettings', 'AdParams', 'Restrictions', 'Value', 'Enum', 'DiscreteScale', 'StationResult',
|
'Dashboard', 'RotorSettings', 'AdParams', 'Restrictions', 'Value', 'Enum', 'DiscreteScale', 'StationResult',
|
||||||
'Sequence', 'StationTracksResult', 'BriefInfo', 'Description', 'PlaylistId', 'Vinyl', 'Supplement', 'Lyrics',
|
'Sequence', 'StationTracksResult', 'BriefInfo', 'Description', 'PlaylistId', 'Vinyl', 'Supplement', 'Lyrics',
|
||||||
'VideoSupplement', 'ArtistTracks', 'Pager', 'ArtistAlbums', 'PlaylistAbsence', 'Shot', 'ShotEvent',
|
'VideoSupplement', 'ArtistTracks', 'Pager', 'ArtistAlbums', 'PlaylistAbsence', 'Shot', 'ShotEvent',
|
||||||
'ShotType', 'ShotData', 'SimilarTracks', 'UserSettings', 'RenewableRemainder', 'PlaylistRecommendations']
|
'ShotType', 'ShotData', 'SimilarTracks', 'UserSettings', 'RenewableRemainder', 'ChartInfo', 'ChartInfoMenu',
|
||||||
|
'ChartInfoMenuItem', 'Tag', 'TagResult', 'PlaylistRecommendations']
|
||||||
|
|
|
@ -4,9 +4,9 @@ from datetime import datetime
|
||||||
from typing import Callable, Dict, List, Optional, Union
|
from typing import Callable, Dict, List, Optional, Union
|
||||||
|
|
||||||
from yandex_music import Album, Artist, ArtistAlbums, ArtistTracks, BriefInfo, Dashboard, DownloadInfo, Experiments, \
|
from yandex_music import Album, Artist, ArtistAlbums, ArtistTracks, BriefInfo, Dashboard, DownloadInfo, Experiments, \
|
||||||
Feed, Genre, Landing, Like, PermissionAlerts, Playlist, PromoCodeStatus, Search, Settings, ShotEvent, SimilarTracks, \
|
Feed, Genre, Landing, Like, PermissionAlerts, Playlist, PromoCodeStatus, Search, Settings, ShotEvent, Supplement, \
|
||||||
StationResult, StationTracksResult, Status, Suggestions, Supplement, Track, TracksList, UserSettings, \
|
StationResult, StationTracksResult, Status, Suggestions, SimilarTracks, Track, TracksList, UserSettings, \
|
||||||
YandexMusicObject, PlaylistRecommendations
|
YandexMusicObject, ChartInfo, TagResult, PlaylistRecommendations
|
||||||
from yandex_music.exceptions import Captcha, InvalidToken
|
from yandex_music.exceptions import Captcha, InvalidToken
|
||||||
from yandex_music.utils.difference import Difference
|
from yandex_music.utils.difference import Difference
|
||||||
from yandex_music.utils.request import Request
|
from yandex_music.utils.request import Request
|
||||||
|
@ -439,6 +439,36 @@ class Client(YandexMusicObject):
|
||||||
|
|
||||||
return Landing.de_json(result, self)
|
return Landing.de_json(result, self)
|
||||||
|
|
||||||
|
@log
|
||||||
|
def chart(self, chart_option: str = '', timeout: Union[int, float] = None, *args, **kwargs) -> Optional[ChartInfo]:
|
||||||
|
"""Получение чарта.
|
||||||
|
|
||||||
|
Note:
|
||||||
|
`chart_option` - это постфикс к запросу из поля `menu` чарта.
|
||||||
|
Например, на сайте можно выбрать глобальный (world) чарт или российский (russia).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chart_option (:obj:`str` optional): Параметры чарта.
|
||||||
|
timeout (:obj:`int` | :obj:`float`, optional): Если это значение указано, используется как время ожидания
|
||||||
|
ответа от сервера вместо указанного при создании пула.
|
||||||
|
**kwargs (:obj:`dict`, optional): Произвольные аргументы (будут переданы в запрос).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`yandex_music.ChartInfo`: Чарт.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`yandex_music.exceptions.YandexMusicError`: Базовое исключение библиотеки.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = f'{self.base_url}/landing3/chart'
|
||||||
|
|
||||||
|
if chart_option:
|
||||||
|
url = f'{url}/{chart_option}'
|
||||||
|
|
||||||
|
result = self._request.get(url, timeout=timeout, *args, **kwargs)
|
||||||
|
|
||||||
|
return ChartInfo.de_json(result, self)
|
||||||
|
|
||||||
@log
|
@log
|
||||||
def genres(self, timeout: Union[int, float] = None, *args, **kwargs) -> List[Genre]:
|
def genres(self, timeout: Union[int, float] = None, *args, **kwargs) -> List[Genre]:
|
||||||
"""Получение жанров музыки.
|
"""Получение жанров музыки.
|
||||||
|
@ -461,6 +491,35 @@ class Client(YandexMusicObject):
|
||||||
|
|
||||||
return Genre.de_list(result, self)
|
return Genre.de_list(result, self)
|
||||||
|
|
||||||
|
@log
|
||||||
|
def tags(self, tag_id: str, timeout: Union[int, float] = None, *args, **kwargs) -> Optional[TagResult]:
|
||||||
|
"""Получение тега (подборки).
|
||||||
|
|
||||||
|
Note:
|
||||||
|
Теги есть в `MixLink` у `Landing`, а также плейлистов в `.tags`.
|
||||||
|
|
||||||
|
У `MixLink` есть `URL`, но `tag_id` только его последняя часть.
|
||||||
|
Например, `/tag/belarus/`. `Tag` - `belarus`.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag_id (:obj:`str`): Уникальный идентификатор тега.
|
||||||
|
timeout (:obj:`int` | :obj:`float`, optional): Если это значение указано, используется как время ожидания
|
||||||
|
ответа от сервера вместо указанного при создании пула.
|
||||||
|
**kwargs (:obj:`dict`, optional): Произвольные аргументы (будут переданы в запрос).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`list` из :obj:`yandex_music.Genre` | :obj:`None`: Жанры музыки или :obj:`None`.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`yandex_music.exceptions.YandexMusicError`: Базовое исключение библиотеки.
|
||||||
|
"""
|
||||||
|
|
||||||
|
url = f'{self.base_url}/tags/{tag_id}/playlist-ids'
|
||||||
|
|
||||||
|
result = self._request.get(url, timeout=timeout, *args, **kwargs)
|
||||||
|
|
||||||
|
return TagResult.de_json(result, self)
|
||||||
|
|
||||||
@log
|
@log
|
||||||
def tracks_download_info(self, track_id: Union[str, int], get_direct_links: bool = False,
|
def tracks_download_info(self, track_id: Union[str, int], get_direct_links: bool = False,
|
||||||
timeout: Union[int, float] = None, *args, **kwargs) -> List[DownloadInfo]:
|
timeout: Union[int, float] = None, *args, **kwargs) -> List[DownloadInfo]:
|
||||||
|
@ -1448,7 +1507,7 @@ class Client(YandexMusicObject):
|
||||||
Note:
|
Note:
|
||||||
Типы объектов: `track` - трек, `artist` - исполнитель, `playlist` - плейлист, `album` - альбом.
|
Типы объектов: `track` - трек, `artist` - исполнитель, `playlist` - плейлист, `album` - альбом.
|
||||||
|
|
||||||
Идентификатор плейлиста указывается в формате `playlist_id:owner_id`. Где `playlist_id` - идентификатор
|
Идентификатор плейлиста указывается в формате `owner_id:playlist_id`. Где `playlist_id` - идентификатор
|
||||||
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1581,7 +1640,7 @@ class Client(YandexMusicObject):
|
||||||
"""Поставить отметку "Мне нравится" плейлисту/плейлистам.
|
"""Поставить отметку "Мне нравится" плейлисту/плейлистам.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
Идентификатор плейлиста указывается в формате `playlist_id:owner_id`. Где `playlist_id` - идентификатор
|
Идентификатор плейлиста указывается в формате `owner_id:playlist_id`. Где `playlist_id` - идентификатор
|
||||||
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1608,7 +1667,7 @@ class Client(YandexMusicObject):
|
||||||
"""Снять отметку "Мне нравится" у плейлиста/плейлистов.
|
"""Снять отметку "Мне нравится" у плейлиста/плейлистов.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
Идентификатор плейлиста указывается в формате `playlist_id:owner_id`. Где `playlist_id` - идентификатор
|
Идентификатор плейлиста указывается в формате `owner_id:playlist_id`. Где `playlist_id` - идентификатор
|
||||||
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1772,7 +1831,7 @@ class Client(YandexMusicObject):
|
||||||
"""Получение плейлиста/плейлистов.
|
"""Получение плейлиста/плейлистов.
|
||||||
|
|
||||||
Note:
|
Note:
|
||||||
Идентификатор плейлиста указывается в формате `playlist_id:owner_id`. Где `playlist_id` - идентификатор
|
Идентификатор плейлиста указывается в формате `owner_id:playlist_id`. Где `playlist_id` - идентификатор
|
||||||
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
плейлиста, `owner_id` - уникальный идентификатор владельца плейлиста.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -1915,7 +1974,7 @@ class Client(YandexMusicObject):
|
||||||
@log
|
@log
|
||||||
def users_likes_playlists(self, user_id: Union[str, int] = None, timeout: Union[int, float] = None,
|
def users_likes_playlists(self, user_id: Union[str, int] = None, timeout: Union[int, float] = None,
|
||||||
*args, **kwargs) -> List[Like]:
|
*args, **kwargs) -> List[Like]:
|
||||||
"""Получение артистов с отметкой "Мне нравится".
|
"""Получение плейлистов с отметкой "Мне нравится".
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
user_id (:obj:`str` | :obj:`int`, optional): Уникальный идентификатор пользователя. Если не указан
|
user_id (:obj:`str` | :obj:`int`, optional): Уникальный идентификатор пользователя. Если не указан
|
||||||
|
|
|
@ -0,0 +1,72 @@
|
||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from yandex_music import YandexMusicObject, Playlist, ChartInfoMenu
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from yandex_music import Client
|
||||||
|
|
||||||
|
|
||||||
|
class ChartInfo(YandexMusicObject):
|
||||||
|
"""Класс, представляющий чарт.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
id (:obj:`str`): Уникальный идентификатор блока.
|
||||||
|
type (:obj:`str`): Тип блока.
|
||||||
|
type_for_from (:obj:`str`): Откуда получен блок (как к нему пришли).
|
||||||
|
title (:obj:`str`): Заголовок.
|
||||||
|
menu (:obj:`yandex_music.ChartInfoMenu` | :obj:`None`): Меню TODO.
|
||||||
|
chart (:obj:`yandex_music.Playlist` | :obj:`None`): Плейлист.
|
||||||
|
chart_description (:obj:`str`): Описание.
|
||||||
|
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id_ (:obj:`str`): Уникальный идентификатор блока.
|
||||||
|
type_ (:obj:`str`): Тип блока.
|
||||||
|
type_for_from (:obj:`str`): Откуда получен блок (как к нему пришли).
|
||||||
|
title (:obj:`str`): Заголовок.
|
||||||
|
menu (:obj:`yandex_music.ChartInfoMenu`, optional): Меню TODO.
|
||||||
|
chart (:obj:`yandex_music.Playlist`, optional): Плейлист.
|
||||||
|
chart_description (:obj:`str`, optional): Описание.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
id_: str,
|
||||||
|
type_: str,
|
||||||
|
type_for_from: str,
|
||||||
|
title: str,
|
||||||
|
menu: Optional['ChartInfoMenu'],
|
||||||
|
chart: Optional['Playlist'],
|
||||||
|
chart_description: Optional[str] = None,
|
||||||
|
client: Optional['Client'] = None):
|
||||||
|
self.id = id_
|
||||||
|
self.type = type_
|
||||||
|
self.type_for_from = type_for_from
|
||||||
|
self.title = title
|
||||||
|
|
||||||
|
self.menu = menu
|
||||||
|
self.chart = chart
|
||||||
|
self.chart_description = chart_description
|
||||||
|
|
||||||
|
self.client = client
|
||||||
|
self._id_attrs = (id_,)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(cls, data: dict, client: 'Client') -> Optional['ChartInfo']:
|
||||||
|
"""Десериализация объекта.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (:obj:`dict`): Поля и значения десериализуемого объекта.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`yandex_music.ChartInfo`: Чарт.
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = super(ChartInfo, cls).de_json(data, client)
|
||||||
|
data['chart'] = Playlist.de_json(data.get('chart'), client)
|
||||||
|
data['menu'] = ChartInfoMenu.de_json(data.get('menu'), client)
|
||||||
|
|
||||||
|
return cls(client=client, **data)
|
|
@ -0,0 +1,44 @@
|
||||||
|
from typing import TYPE_CHECKING, List, Optional
|
||||||
|
|
||||||
|
from yandex_music import YandexMusicObject, ChartInfoMenuItem
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from yandex_music import Client
|
||||||
|
|
||||||
|
|
||||||
|
class ChartInfoMenu(YandexMusicObject):
|
||||||
|
"""Класс, представляющий меню чарта.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
items (:obj:`list` из :obj:`yandex_music.ChartInfoMenuItem`): Список элементов меню.
|
||||||
|
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
items (:obj:`list` из :obj:`yandex_music.ChartInfoMenuItem`): Список элементов меню.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, items: List['ChartInfoMenuItem'], client: Optional['Client'] = None):
|
||||||
|
self.items = items
|
||||||
|
|
||||||
|
self.client = client
|
||||||
|
self._id_attrs = (self.items, )
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(cls, data: dict, client: 'Client') -> Optional['ChartInfoMenu']:
|
||||||
|
"""Десериализация объекта.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (:obj:`dict`): Поля и значения десериализуемого объекта.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`yandex_music.ChartInfoMenu`: Меню чарта.
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = super(ChartInfoMenu, cls).de_json(data, client)
|
||||||
|
data['items'] = ChartInfoMenuItem.de_list(data.get('items'), client)
|
||||||
|
|
||||||
|
return cls(client=client, **data)
|
|
@ -0,0 +1,65 @@
|
||||||
|
from typing import TYPE_CHECKING, Optional, List
|
||||||
|
|
||||||
|
from yandex_music import YandexMusicObject
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from yandex_music import Client
|
||||||
|
|
||||||
|
|
||||||
|
class ChartInfoMenuItem(YandexMusicObject):
|
||||||
|
"""Класс, представляющий элемент меню чарта.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
title (:obj:`str`): Заголовок.
|
||||||
|
url (:obj:`str`): Постфикс для запроса чарта.
|
||||||
|
selected (:obj:`bool` | :obj:`None`): Текущий ли элемент.
|
||||||
|
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
title (:obj:`str`): Заголовок.
|
||||||
|
url (:obj:`str`): Постфикс для запроса чарта.
|
||||||
|
selected (:obj:`bool`, optional): Текущий ли элемент.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, title: str, url: str, selected: Optional[bool] = None, client: Optional['Client'] = None):
|
||||||
|
self.title = title
|
||||||
|
self.url = url
|
||||||
|
self.selected = selected
|
||||||
|
|
||||||
|
self.client = client
|
||||||
|
self._id_attrs = (url, selected)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(cls, data: dict, client: 'Client') -> Optional['ChartInfoMenuItem']:
|
||||||
|
"""Десериализация объекта.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (:obj:`dict`): Поля и значения десериализуемого объекта.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`yandex_music.ChartInfoMenuItem`: Элемент меню.
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = super(ChartInfoMenuItem, cls).de_json(data, client)
|
||||||
|
|
||||||
|
return cls(client=client, **data)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_list(cls, data: list, client: 'Client') -> List['ChartInfoMenuItem']:
|
||||||
|
"""Десериализация списка объектов.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (:obj:`list`): Список словарей с полями и значениями десериализуемого объекта.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`list` из :obj:`yandex_music.ChartInfoMenuItem`: Список элементов меню чарта.
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return []
|
||||||
|
|
||||||
|
return [cls.de_json(item, client) for item in data]
|
|
@ -0,0 +1,61 @@
|
||||||
|
from typing import TYPE_CHECKING, Optional
|
||||||
|
|
||||||
|
from yandex_music import YandexMusicObject
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from yandex_music import Client
|
||||||
|
|
||||||
|
|
||||||
|
class Tag(YandexMusicObject):
|
||||||
|
"""Класс, представляющий тег (подборку).
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
id (:obj:`str`): Уникальный идентификатор тега.
|
||||||
|
value (:obj:`str`): Значение тега (название в lower case).
|
||||||
|
name (:obj:`str`): Название тега (отображаемое).
|
||||||
|
og_description (:obj:`str`): Описание тега для OpenGraph.
|
||||||
|
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
id (:obj:`str`): Уникальный идентификатор тега.
|
||||||
|
value (:obj:`str`): Значение тега (название в lower case).
|
||||||
|
name (:obj:`str`): Название тега (отображаемое).
|
||||||
|
og_description (:obj:`str`): Описание тега для OpenGraph.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
**kwargs: Произвольные ключевые аргументы полученные от API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
id_: str,
|
||||||
|
value: str,
|
||||||
|
name: str,
|
||||||
|
og_description: str,
|
||||||
|
client: Optional['Client'] = None,
|
||||||
|
**kwargs) -> None:
|
||||||
|
super().handle_unknown_kwargs(self, **kwargs)
|
||||||
|
|
||||||
|
self.id = id_
|
||||||
|
self.value = value
|
||||||
|
self.name = name
|
||||||
|
self.og_description = og_description
|
||||||
|
|
||||||
|
self.client = client
|
||||||
|
self._id_attrs = (self.id, )
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(cls, data: dict, client: 'Client') -> Optional['Tag']:
|
||||||
|
"""Десериализация объекта.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (:obj:`dict`): Поля и значения десериализуемого объекта.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`yandex_music.Tag`: Тег.
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = super(Tag, cls).de_json(data, client)
|
||||||
|
|
||||||
|
return cls(client=client, **data)
|
|
@ -0,0 +1,56 @@
|
||||||
|
from typing import TYPE_CHECKING, Optional, List
|
||||||
|
|
||||||
|
from yandex_music import YandexMusicObject
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from yandex_music import Client, PlaylistId
|
||||||
|
|
||||||
|
|
||||||
|
class TagResult(YandexMusicObject):
|
||||||
|
"""Класс, представляющий тег и его плейлисты.
|
||||||
|
|
||||||
|
Attributes:
|
||||||
|
tag (:obj:`yandex_music.Tag`): Тег.
|
||||||
|
ids (:obj:`list` из :obj:`yandex_music.PlaylistId`): Уникальные идентификаторы плейлистов тега.
|
||||||
|
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
tag (:obj:`yandex_music.Tag`): Тег.
|
||||||
|
ids (:obj:`list` из :obj:`yandex_music.PlaylistId`): Уникальные идентификаторы плейлистов тега.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
**kwargs: Произвольные ключевые аргументы полученные от API.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
tag: str,
|
||||||
|
ids: List['PlaylistId'],
|
||||||
|
client: Optional['Client'] = None,
|
||||||
|
**kwargs) -> None:
|
||||||
|
super().handle_unknown_kwargs(self, **kwargs)
|
||||||
|
|
||||||
|
self.tag = tag
|
||||||
|
self.ids = ids
|
||||||
|
|
||||||
|
self.client = client
|
||||||
|
self._id_attrs = (self.tag, self.ids)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def de_json(cls, data: dict, client: 'Client') -> Optional['TagResult']:
|
||||||
|
"""Десериализация объекта.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (:obj:`dict`): Поля и значения десериализуемого объекта.
|
||||||
|
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
:obj:`yandex_music.TagResult`: Тег и его плейлисты.
|
||||||
|
"""
|
||||||
|
if not data:
|
||||||
|
return None
|
||||||
|
|
||||||
|
data = super(TagResult, cls).de_json(data, client)
|
||||||
|
from yandex_music import Tag, PlaylistId
|
||||||
|
data['tag'] = Tag.de_json(data.get('tag'), client)
|
||||||
|
data['ids'] = PlaylistId.de_list(data.get('ids'), client)
|
||||||
|
|
||||||
|
return cls(client=client, **data)
|
読み込み中…
新しいイシューから参照