Добавлен новый класс MetaData.

Добавлено поле error классу Artist.
Класс User расширен для поддержки поля user_info из Track (поля full_name, display_name).
Добавлены новые поля классу Track: substituted, matched_track, can_publish, state, desired_visibility, filename, user_info, meta_data.
Новые поля класса Cover: copyright_name, copyright_cline.
Добавлено поле direct классу DownloadInfo.
Предупреждения о новых полях включены по умолчанию.
Документация и тесты к новым поля. #339
このコミットが含まれているのは:
Il`ya Semyonov 2020-06-06 17:06:23 +03:00
コミット 0240eb6cb9
18個のファイルの変更285行の追加54行の削除

ファイルの表示

@ -0,0 +1,7 @@
yandex_music.MetaData
=====================
.. autoclass:: yandex_music.MetaData
:members:
:undoc-members:
:show-inheritance:

ファイルの表示

@ -6,3 +6,4 @@
yandex_music.track.normalization yandex_music.track.normalization
yandex_music.track.major yandex_music.track.major
yandex_music.track.track yandex_music.track.track
yandex_music.track.meta_data

ファイルの表示

@ -78,3 +78,4 @@ 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 from .test_tag import TestTag
from .test_meta_data import TestMetaData

ファイルの表示

@ -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, ChartInfoMenuItem, ChartInfoMenu, ChartInfo, Tag RenewableRemainder, ChartInfoMenuItem, ChartInfoMenu, ChartInfo, Tag, MetaData
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,20 +17,20 @@ 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, TestChartInfoMenuItem, TestChartInfo, TestTag TestRenewableRemainder, TestChartInfoMenuItem, TestChartInfo, TestTag, TestMetaData
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def artist_factory(cover, counts, ratings, link, description): def artist_factory(cover, counts, ratings, link, description):
class ArtistFactory: class ArtistFactory:
def get(self, popular_tracks): def get(self, popular_tracks):
return Artist(TestArtist.id, TestArtist.reason, TestArtist.name, cover, TestArtist.various, return Artist(TestArtist.id, TestArtist.error, TestArtist.reason, TestArtist.name, cover,
TestArtist.composer, TestArtist.genres, TestArtist.og_image, TestArtist.op_image, TestArtist.various, TestArtist.composer, TestArtist.genres, TestArtist.og_image,
TestArtist.no_pictures_from_search, counts, TestArtist.available, ratings, [link], TestArtist.op_image, TestArtist.no_pictures_from_search, counts, TestArtist.available,
TestArtist.tickets_available, TestArtist.likes_count, popular_tracks, TestArtist.regions, ratings, [link], TestArtist.tickets_available, TestArtist.likes_count, popular_tracks,
TestArtist.decomposed, TestArtist.full_names, description, TestArtist.countries, TestArtist.regions, TestArtist.decomposed, TestArtist.full_names, description,
TestArtist.en_wikipedia_link, TestArtist.db_aliases, TestArtist.aliases, TestArtist.init_date, TestArtist.countries, TestArtist.en_wikipedia_link, TestArtist.db_aliases, TestArtist.aliases,
TestArtist.end_date) TestArtist.init_date, TestArtist.end_date)
return ArtistFactory() return ArtistFactory()
@ -46,14 +46,16 @@ def artist_without_tracks(artist_factory):
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def track_factory(major, normalization): def track_factory(major, normalization, user, meta_data):
class TrackFactory: class TrackFactory:
def get(self, artists, albums): def get(self, artists, albums, track_without_nested_tracks=None):
return Track(TestTrack.id, TestTrack.title, TestTrack.available, artists, albums, return Track(TestTrack.id, TestTrack.title, TestTrack.available, artists, albums,
TestTrack.available_for_premium_users, TestTrack.lyrics_available, TestTrack.best, TestTrack.available_for_premium_users, TestTrack.lyrics_available, TestTrack.best,
TestTrack.real_id, TestTrack.og_image, TestTrack.type, TestTrack.cover_uri, major, TestTrack.real_id, TestTrack.og_image, TestTrack.type, TestTrack.cover_uri, major,
TestTrack.duration_ms, TestTrack.storage_dir, TestTrack.file_size, normalization, TestTrack.duration_ms, TestTrack.storage_dir, TestTrack.file_size, track_without_nested_tracks,
TestTrack.error, TestTrack.regions, TestTrack.available_as_rbt, TestTrack.content_warning, track_without_nested_tracks, normalization, TestTrack.error, TestTrack.can_publish,
TestTrack.state, TestTrack.desired_visibility, TestTrack.filename, user, meta_data,
TestTrack.regions, TestTrack.available_as_rbt, TestTrack.content_warning,
TestTrack.explicit, TestTrack.preview_duration_ms, TestTrack.available_full_without_permission, TestTrack.explicit, TestTrack.preview_duration_ms, TestTrack.available_full_without_permission,
TestTrack.version, TestTrack.remember_position) TestTrack.version, TestTrack.remember_position)
@ -61,8 +63,8 @@ def track_factory(major, normalization):
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def track(track_factory, artist, album): def track(track_factory, artist, album, track_without_nested_tracks):
return track_factory.get([artist], [album]) return track_factory.get([artist], [album], track_without_nested_tracks)
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
@ -80,6 +82,11 @@ def track_without_artists_and_albums(track_factory):
return track_factory.get([], []) return track_factory.get([], [])
@pytest.fixture(scope='session')
def track_without_nested_tracks(artist, album, track_factory):
return track_factory.get([artist], [album])
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def album_factory(label, track_position): def album_factory(label, track_position):
class AlbumFactory: class AlbumFactory:
@ -207,7 +214,13 @@ def icon():
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def cover(): def cover():
return Cover(TestCover.type, TestCover.uri, TestCover.items_uri, TestCover.dir, TestCover.version, return Cover(TestCover.type, TestCover.uri, TestCover.items_uri, TestCover.dir, TestCover.version,
TestCover.custom, TestCover.is_custom, TestCover.prefix, TestCover.error) TestCover.custom, TestCover.is_custom, TestCover.copyright_name, TestCover.copyright_cline,
TestCover.prefix, TestCover.error)
@pytest.fixture(scope='session')
def meta_data():
return MetaData(TestMetaData.album, TestMetaData.volume, TestMetaData.year)
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
@ -361,7 +374,8 @@ def renewable_remainder():
@pytest.fixture(scope='session') @pytest.fixture(scope='session')
def user(): def user():
return User(TestUser.uid, TestUser.login, TestUser.name, TestUser.sex, TestUser.verified) return User(TestUser.uid, TestUser.login, TestUser.name, TestUser.display_name,
TestUser.full_name, TestUser.sex, TestUser.verified)
@pytest.fixture(scope='session') @pytest.fixture(scope='session')

ファイルの表示

@ -3,6 +3,7 @@ from yandex_music import Artist
class TestArtist: class TestArtist:
id = 10987 id = 10987
error = 'not-found'
reason = 'not-found' reason = 'not-found'
name = 'Elvis Presley' name = 'Elvis Presley'
various = False various = False
@ -26,6 +27,7 @@ class TestArtist:
def test_expected_values(self, artist, cover, counts, ratings, link, track_without_artists_and_albums, description): def test_expected_values(self, artist, cover, counts, ratings, link, track_without_artists_and_albums, description):
assert artist.id == self.id assert artist.id == self.id
assert artist.error == self.error
assert artist.reason == self.reason assert artist.reason == self.reason
assert artist.name == self.name assert artist.name == self.name
assert artist.various == self.various assert artist.various == self.various
@ -66,7 +68,7 @@ class TestArtist:
assert artist.id == self.id assert artist.id == self.id
def test_de_json_all(self, client, cover, counts, ratings, link, track_without_artists, description): def test_de_json_all(self, client, cover, counts, ratings, link, track_without_artists, description):
json_dict = {'id_': self.id, 'reason': self.reason, 'name': self.name, json_dict = {'id_': self.id, 'reason': self.reason, 'error': self.error, 'name': self.name,
'various': self.various, 'composer': self.composer, 'cover': cover.to_dict(), 'various': self.various, 'composer': self.composer, 'cover': cover.to_dict(),
'genres': self.genres, 'op_image': self.op_image, 'og_image': self.og_image, 'genres': self.genres, 'op_image': self.op_image, 'og_image': self.og_image,
'no_pictures_from_search': self.no_pictures_from_search, 'counts': counts.to_dict(), 'no_pictures_from_search': self.no_pictures_from_search, 'counts': counts.to_dict(),
@ -80,6 +82,7 @@ class TestArtist:
artist = Artist.de_json(json_dict, client) artist = Artist.de_json(json_dict, client)
assert artist.id == self.id assert artist.id == self.id
assert artist.error == self.error
assert artist.reason == self.reason assert artist.reason == self.reason
assert artist.name == self.name assert artist.name == self.name
assert artist.various == self.various assert artist.various == self.various

ファイルの表示

@ -10,6 +10,8 @@ class TestCover:
custom = True custom = True
is_custom = True is_custom = True
prefix = None prefix = None
copyright_name = 'ТАСС'
copyright_cline = 'imago stock&people'
error = None error = None
def test_expected_values(self, cover): def test_expected_values(self, cover):
@ -20,6 +22,8 @@ class TestCover:
assert cover.version == self.version assert cover.version == self.version
assert cover.custom == self.custom assert cover.custom == self.custom
assert cover.is_custom == self.is_custom assert cover.is_custom == self.is_custom
assert cover.copyright_name == self.copyright_name
assert cover.copyright_cline == self.copyright_cline
assert cover.prefix == self.prefix assert cover.prefix == self.prefix
assert cover.error == self.error assert cover.error == self.error
@ -36,7 +40,8 @@ class TestCover:
def test_de_json_all(self, client): def test_de_json_all(self, client):
json_dict = {'type_': self.type, 'uri': self.uri, 'items_uri': self.items_uri, 'dir_': self.dir, json_dict = {'type_': self.type, 'uri': self.uri, 'items_uri': self.items_uri, 'dir_': self.dir,
'version': self.version, 'custom': self.custom, 'is_custom': self.is_custom, 'prefix': self.prefix, 'version': self.version, 'custom': self.custom, 'is_custom': self.is_custom, 'prefix': self.prefix,
'error': self.error} 'error': self.error, 'copyright_name': self.copyright_name,
'copyright_cline': self.copyright_cline}
cover = Cover.de_json(json_dict, client) cover = Cover.de_json(json_dict, client)
assert cover.type == self.type assert cover.type == self.type
@ -46,6 +51,8 @@ class TestCover:
assert cover.version == self.version assert cover.version == self.version
assert cover.custom == self.custom assert cover.custom == self.custom
assert cover.is_custom == self.is_custom assert cover.is_custom == self.is_custom
assert cover.copyright_name == self.copyright_name
assert cover.copyright_cline == self.copyright_cline
assert cover.prefix == self.prefix assert cover.prefix == self.prefix
assert cover.error == self.error assert cover.error == self.error

ファイルの表示

@ -6,7 +6,7 @@ from yandex_music import DownloadInfo
@pytest.fixture(scope='class') @pytest.fixture(scope='class')
def download_info(): def download_info():
return DownloadInfo(TestDownloadInfo.codec, TestDownloadInfo.bitrate_in_kbps, TestDownloadInfo.gain, return DownloadInfo(TestDownloadInfo.codec, TestDownloadInfo.bitrate_in_kbps, TestDownloadInfo.gain,
TestDownloadInfo.preview, TestDownloadInfo.download_info_url) TestDownloadInfo.preview, TestDownloadInfo.download_info_url, TestDownloadInfo.direct)
class TestDownloadInfo: class TestDownloadInfo:
@ -16,6 +16,7 @@ class TestDownloadInfo:
preview = False preview = False
download_info_url = 'https://storage.mds.yandex.net/file-download-info/136146_d158926e.14534319.6.10994777/320' \ download_info_url = 'https://storage.mds.yandex.net/file-download-info/136146_d158926e.14534319.6.10994777/320' \
'?sign=8caf5ea72c946d4753f15298e4033b961c7acb1bb4db48eb5e6b59621e387d64&ts=5dc4a6f2 ' '?sign=8caf5ea72c946d4753f15298e4033b961c7acb1bb4db48eb5e6b59621e387d64&ts=5dc4a6f2 '
direct = False
def test_expected_values(self, download_info): def test_expected_values(self, download_info):
assert download_info.codec == self.codec assert download_info.codec == self.codec
@ -23,6 +24,7 @@ class TestDownloadInfo:
assert download_info.gain == self.gain assert download_info.gain == self.gain
assert download_info.preview == self.preview assert download_info.preview == self.preview
assert download_info.download_info_url == self.download_info_url assert download_info.download_info_url == self.download_info_url
assert download_info.direct == self.direct
def test_de_json_none(self, client): def test_de_json_none(self, client):
assert DownloadInfo.de_json({}, client) is None assert DownloadInfo.de_json({}, client) is None
@ -32,7 +34,7 @@ class TestDownloadInfo:
def test_de_json_required(self, client): def test_de_json_required(self, client):
json_dict = {'codec': self.codec, 'bitrate_in_kbps': self.bitrate_in_kbps, 'gain': self.gain, json_dict = {'codec': self.codec, 'bitrate_in_kbps': self.bitrate_in_kbps, 'gain': self.gain,
'preview': self.preview, 'download_info_url': self.download_info_url} 'preview': self.preview, 'download_info_url': self.download_info_url, 'direct': self.direct}
download_info = DownloadInfo.de_json(json_dict, client) download_info = DownloadInfo.de_json(json_dict, client)
assert download_info.codec == self.codec assert download_info.codec == self.codec
@ -40,10 +42,11 @@ class TestDownloadInfo:
assert download_info.gain == self.gain assert download_info.gain == self.gain
assert download_info.preview == self.preview assert download_info.preview == self.preview
assert download_info.download_info_url == self.download_info_url assert download_info.download_info_url == self.download_info_url
assert download_info.direct == self.direct
def test_de_json_all(self, client): def test_de_json_all(self, client):
json_dict = {'codec': self.codec, 'bitrate_in_kbps': self.bitrate_in_kbps, 'gain': self.gain, json_dict = {'codec': self.codec, 'bitrate_in_kbps': self.bitrate_in_kbps, 'gain': self.gain,
'preview': self.preview, 'download_info_url': self.download_info_url} 'preview': self.preview, 'download_info_url': self.download_info_url, 'direct': self.direct}
download_info = DownloadInfo.de_json(json_dict, client) download_info = DownloadInfo.de_json(json_dict, client)
assert download_info.codec == self.codec assert download_info.codec == self.codec
@ -51,11 +54,12 @@ class TestDownloadInfo:
assert download_info.gain == self.gain assert download_info.gain == self.gain
assert download_info.preview == self.preview assert download_info.preview == self.preview
assert download_info.download_info_url == self.download_info_url assert download_info.download_info_url == self.download_info_url
assert download_info.direct == self.direct
def test_equality(self): def test_equality(self):
a = DownloadInfo(self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url) a = DownloadInfo(self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url, self.direct)
b = DownloadInfo(self.codec, 128, self.gain, True, self.download_info_url) b = DownloadInfo(self.codec, 128, self.gain, True, self.download_info_url, True)
c = DownloadInfo(self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url) c = DownloadInfo(self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url, self.direct)
assert a != b assert a != b
assert hash(a) != hash(b) assert hash(a) != hash(b)

42
tests/test_meta_data.py ノーマルファイル
ファイルの表示

@ -0,0 +1,42 @@
from yandex_music import MetaData
class TestMetaData:
album = 'VK Virus Bot'
volume = 1
year = 2018
def test_expected_values(self, meta_data):
assert meta_data.album == self.album
assert meta_data.volume == self.volume
assert meta_data.year == self.year
def test_de_json_none(self, client):
assert MetaData.de_json({}, client) is None
def test_de_json_required(self, client):
json_dict = {'album': self.album, 'volume': self.volume, 'year': self.year}
meta_data = MetaData.de_json(json_dict, client)
assert meta_data.album == self.album
assert meta_data.volume == self.volume
assert meta_data.year == self.year
def test_de_json_all(self, client):
json_dict = {'album': self.album, 'volume': self.volume, 'year': self.year}
meta_data = MetaData.de_json(json_dict, client)
assert meta_data.album == self.album
assert meta_data.volume == self.volume
assert meta_data.year == self.year
def test_equality(self):
a = MetaData(self.album, self.volume, self.year)
b = MetaData(self.album, 0, 2016)
c = MetaData(self.album, self.volume, self.year)
assert a != b
assert hash(a) != hash(b)
assert a is not b
assert a == c

ファイルの表示

@ -16,6 +16,10 @@ class TestTrack:
storage_dir = '51327_109b74ca.36526310.1.609676' storage_dir = '51327_109b74ca.36526310.1.609676'
file_size = 6036792 file_size = 6036792
error = None error = None
can_publish = False
state = 'playable'
desired_visibility = 'private'
filename = 'Ты не так плох.mp3'
regions = None regions = None
available_as_rbt = None available_as_rbt = None
content_warning = None content_warning = None
@ -25,7 +29,8 @@ class TestTrack:
version = 'Radio Edit' version = 'Radio Edit'
remember_position = False remember_position = False
def test_expected_values(self, track, artist, album, major, normalization): def test_expected_values(self, track, artist, album, major, normalization,
track_without_nested_tracks, user, meta_data):
assert track.id == self.id assert track.id == self.id
assert track.title == self.title assert track.title == self.title
assert track.available == self.available assert track.available == self.available
@ -42,8 +47,11 @@ class TestTrack:
assert track.duration_ms == self.duration_ms assert track.duration_ms == self.duration_ms
assert track.storage_dir == self.storage_dir assert track.storage_dir == self.storage_dir
assert track.file_size == self.file_size assert track.file_size == self.file_size
assert track.substituted == track_without_nested_tracks
assert track.matched_track == track_without_nested_tracks
assert track.normalization == normalization assert track.normalization == normalization
assert track.error == self.error assert track.error == self.error
assert track.meta_data == meta_data
assert track.regions == self.regions assert track.regions == self.regions
assert track.available_as_rbt == self.available_as_rbt assert track.available_as_rbt == self.available_as_rbt
assert track.content_warning == self.content_warning assert track.content_warning == self.content_warning
@ -52,6 +60,11 @@ class TestTrack:
assert track.available_full_without_permission == self.available_full_without_permission assert track.available_full_without_permission == self.available_full_without_permission
assert track.version == self.version assert track.version == self.version
assert track.remember_position == self.remember_position assert track.remember_position == self.remember_position
assert track.can_publish == self.can_publish
assert track.state == self.state
assert track.desired_visibility == self.desired_visibility
assert track.filename == self.filename
assert track.user_info == user
def test_de_json_none(self, client): def test_de_json_none(self, client):
assert Track.de_json({}, client) is None assert Track.de_json({}, client) is None
@ -65,7 +78,8 @@ class TestTrack:
assert track.id == self.id assert track.id == self.id
def test_de_json_all(self, client, artist, album, major, normalization): def test_de_json_all(self, client, artist, album, major, normalization,
track_without_nested_tracks, user, meta_data):
json_dict = {'id_': self.id, 'title': self.title, 'available': self.available, json_dict = {'id_': self.id, 'title': self.title, 'available': self.available,
'available_for_premium_users': self.available_for_premium_users, 'available_for_premium_users': self.available_for_premium_users,
'artists': [artist.to_dict()], 'albums': [album.to_dict()], 'artists': [artist.to_dict()], 'albums': [album.to_dict()],
@ -77,7 +91,10 @@ class TestTrack:
'content_warning': self.content_warning, 'explicit': self.explicit, 'content_warning': self.content_warning, 'explicit': self.explicit,
'preview_duration_ms': self.preview_duration_ms, 'version': self.version, 'preview_duration_ms': self.preview_duration_ms, 'version': self.version,
'available_full_without_permission': self.available_full_without_permission, 'available_full_without_permission': self.available_full_without_permission,
'remember_position': self.remember_position} 'remember_position': self.remember_position, 'substituted': track_without_nested_tracks.to_dict(),
'matched_track': track_without_nested_tracks.to_dict(), 'can_publish': self.can_publish,
'state': self.state, 'desired_visibility': self.desired_visibility, 'filename': self.filename,
'user_info': user.to_dict(), 'meta_data': meta_data.to_dict()}
track = Track.de_json(json_dict, client) track = Track.de_json(json_dict, client)
assert track.id == self.id assert track.id == self.id
@ -96,8 +113,11 @@ class TestTrack:
assert track.duration_ms == self.duration_ms assert track.duration_ms == self.duration_ms
assert track.storage_dir == self.storage_dir assert track.storage_dir == self.storage_dir
assert track.file_size == self.file_size assert track.file_size == self.file_size
assert track.substituted == track_without_nested_tracks
assert track.matched_track == track_without_nested_tracks
assert track.normalization == normalization assert track.normalization == normalization
assert track.error == self.error assert track.error == self.error
assert track.meta_data == meta_data
assert track.regions == self.regions assert track.regions == self.regions
assert track.available_as_rbt == self.available_as_rbt assert track.available_as_rbt == self.available_as_rbt
assert track.content_warning == self.content_warning assert track.content_warning == self.content_warning
@ -106,6 +126,11 @@ class TestTrack:
assert track.available_full_without_permission == self.available_full_without_permission assert track.available_full_without_permission == self.available_full_without_permission
assert track.version == self.version assert track.version == self.version
assert track.remember_position == self.remember_position assert track.remember_position == self.remember_position
assert track.can_publish == self.can_publish
assert track.state == self.state
assert track.desired_visibility == self.desired_visibility
assert track.filename == self.filename
assert track.user_info == user
def test_equality(self): def test_equality(self):
a = Track(self.id) a = Track(self.id)

ファイルの表示

@ -5,6 +5,8 @@ class TestUser:
uid = 503646255 uid = 503646255
login = 'yamusic-daily' login = 'yamusic-daily'
name = 'yamusic-daily' name = 'yamusic-daily'
display_name = 'Ilya (Marshal)'
full_name = 'Илья'
sex = 'unknown' sex = 'unknown'
verified = False verified = False
@ -12,6 +14,8 @@ class TestUser:
assert user.uid == self.uid assert user.uid == self.uid
assert user.login == self.login assert user.login == self.login
assert user.name == self.name assert user.name == self.name
assert user.display_name == self.display_name
assert user.full_name == self.full_name
assert user.sex == self.sex assert user.sex == self.sex
assert user.verified == self.verified assert user.verified == self.verified
@ -19,31 +23,29 @@ class TestUser:
assert User.de_json({}, client) is None assert User.de_json({}, client) is None
def test_de_json_required(self, client): def test_de_json_required(self, client):
json_dict = {'uid': self.uid, 'login': self.login, 'name': self.name, 'sex': self.sex, json_dict = {'uid': self.uid, 'login': self.login}
'verified': self.verified}
user = User.de_json(json_dict, client) user = User.de_json(json_dict, client)
assert user.uid == self.uid assert user.uid == self.uid
assert user.login == self.login assert user.login == self.login
assert user.name == self.name
assert user.sex == self.sex
assert user.verified == self.verified
def test_de_json_all(self, client): def test_de_json_all(self, client):
json_dict = {'uid': self.uid, 'login': self.login, 'name': self.name, 'sex': self.sex, json_dict = {'uid': self.uid, 'login': self.login, 'name': self.name, 'sex': self.sex,
'verified': self.verified} 'verified': self.verified, 'display_name': self.display_name, 'full_name': self.full_name}
user = User.de_json(json_dict, client) user = User.de_json(json_dict, client)
assert user.uid == self.uid assert user.uid == self.uid
assert user.login == self.login assert user.login == self.login
assert user.name == self.name assert user.name == self.name
assert user.display_name == self.display_name
assert user.full_name == self.full_name
assert user.sex == self.sex assert user.sex == self.sex
assert user.verified == self.verified assert user.verified == self.verified
def test_equality(self): def test_equality(self):
a = User(self.uid, self.login, self.name, self.sex, self.verified) a = User(self.uid, self.login)
b = User(1, self.login, self.name, self.sex, self.verified) b = User(1, self.login)
c = User(self.uid, self.login, '', self.sex, self.verified) c = User(self.uid, self.login)
assert a != b assert a != b
assert hash(a) != hash(b) assert hash(a) != hash(b)

ファイルの表示

@ -47,6 +47,7 @@ from .shot.shot_event import ShotEvent
from .tracks_list import TracksList from .tracks_list import TracksList
from .track.major import Major from .track.major import Major
from .track.meta_data import MetaData
from .track.normalization import Normalization from .track.normalization import Normalization
from .track.track import Track from .track.track import Track
from .track.tracks_similar import SimilarTracks from .track.tracks_similar import SimilarTracks
@ -127,4 +128,4 @@ __all__ = ['YandexMusicObject', 'Client', 'Account', 'PassportPhone', 'Invocatio
'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', 'ChartInfo', 'ChartInfoMenu', 'ShotType', 'ShotData', 'SimilarTracks', 'UserSettings', 'RenewableRemainder', 'ChartInfo', 'ChartInfoMenu',
'ChartInfoMenuItem', 'Tag', 'TagResult', 'PlaylistRecommendations', 'LandingList'] 'ChartInfoMenuItem', 'Tag', 'TagResult', 'PlaylistRecommendations', 'LandingList', 'MetaData']

ファイルの表示

@ -11,6 +11,7 @@ class Artist(YandexMusicObject):
Attributes: Attributes:
id (:obj:`int`): Уникальный идентификатор. id (:obj:`int`): Уникальный идентификатор.
error (:obj:`str`): Сообщение об ошибке с объяснением почему не вернуло исполнителя.
reason (:obj:`str`): Причина отсутствия исполнителя (сообщение об ошибке). reason (:obj:`str`): Причина отсутствия исполнителя (сообщение об ошибке).
name (:obj:`str`): Название. name (:obj:`str`): Название.
cover (:obj:`yandex_music.Cover` | :obj:`None`): Обложка. cover (:obj:`yandex_music.Cover` | :obj:`None`): Обложка.
@ -41,6 +42,7 @@ class Artist(YandexMusicObject):
Args: Args:
id_ (:obj:`int`): Уникальный идентификатор. id_ (:obj:`int`): Уникальный идентификатор.
error (:obj:`str`, optional): Сообщение об ошибке с объяснением почему не вернуло исполнителя.
reason (:obj:`str`, optional): Причина отсутствия исполнителя (сообщение об ошибке). reason (:obj:`str`, optional): Причина отсутствия исполнителя (сообщение об ошибке).
name (:obj:`str`, optional): Название. name (:obj:`str`, optional): Название.
cover (:obj:`yandex_music.Cover`, optional): Обложка. cover (:obj:`yandex_music.Cover`, optional): Обложка.
@ -73,6 +75,7 @@ class Artist(YandexMusicObject):
def __init__(self, def __init__(self,
id_: int, id_: int,
error: Optional[str] = None,
reason: Optional[str] = None, reason: Optional[str] = None,
name: Optional[str] = None, name: Optional[str] = None,
cover: Optional['Cover'] = None, cover: Optional['Cover'] = None,
@ -103,6 +106,7 @@ class Artist(YandexMusicObject):
**kwargs) -> None: **kwargs) -> None:
self.id = id_ self.id = id_
self.error = error
self.reason = reason self.reason = reason
self.name = name self.name = name
self.cover = cover self.cover = cover

ファイルの表示

@ -49,7 +49,7 @@ class Client(YandexMusicObject):
uid аккаунта для отправки запроса. Так же в большинстве методов придётся передавать `uid` явно. uid аккаунта для отправки запроса. Так же в большинстве методов придётся передавать `uid` явно.
Attributes: Attributes:
logger (:obj:`logging.Logger`): Объект логера. logger (:obj:`logging.Logger`): Объект логгера.
token (:obj:`str`): Уникальный ключ для аутентификации. token (:obj:`str`): Уникальный ключ для аутентификации.
base_url (:obj:`str`): Ссылка на API Yandex Music. base_url (:obj:`str`): Ссылка на API Yandex Music.
oauth_url (:obj:`str`): Ссылка на OAuth Yandex Music. oauth_url (:obj:`str`): Ссылка на OAuth Yandex Music.
@ -67,7 +67,7 @@ class Client(YandexMusicObject):
""" """
def __init__(self, token: str = None, fetch_account_status: bool = True, base_url: str = None, def __init__(self, token: str = None, fetch_account_status: bool = True, base_url: str = None,
oauth_url: str = None, request: Request = None, report_new_fields=False) -> None: oauth_url: str = None, request: Request = None, report_new_fields=True) -> None:
self.logger = logging.getLogger(__name__) self.logger = logging.getLogger(__name__)
self.token = token self.token = token
@ -133,7 +133,7 @@ class Client(YandexMusicObject):
@classmethod @classmethod
def from_token(cls, token: str, *args, **kwargs) -> 'Client': def from_token(cls, token: str, *args, **kwargs) -> 'Client':
"""Инициализция клиента по токену. """Инициализация клиента по токену.
Note: Note:
Ничем не отличается от `Client(token)`. Так исторически сложилось. Ничем не отличается от `Client(token)`. Так исторически сложилось.

ファイルの表示

@ -18,6 +18,8 @@ class Cover(YandexMusicObject):
is_custom (:obj:`bool`): Является ли обложка пользовательской. is_custom (:obj:`bool`): Является ли обложка пользовательской.
custom (:obj:`bool`): Является ли обложка пользовательской. custom (:obj:`bool`): Является ли обложка пользовательской.
prefix (:obj:`str`): Уникальный идентификатор. prefix (:obj:`str`): Уникальный идентификатор.
copyright_name (:obj:`str`): Название владельца авторским правом.
copyright_cline (:obj:`str`): Владелец прав на музыку (автор текста и т.д.), а не её записи.
error (:obj:`str`): Сообщение об ошибке. error (:obj:`str`): Сообщение об ошибке.
client (:obj:`yandex_music.Client`): Клиент Yandex Music. client (:obj:`yandex_music.Client`): Клиент Yandex Music.
@ -30,6 +32,8 @@ class Cover(YandexMusicObject):
is_custom (:obj:`bool`, optional): Является ли обложка пользовательской. is_custom (:obj:`bool`, optional): Является ли обложка пользовательской.
custom (:obj:`bool`, optional): Является ли обложка пользовательской. custom (:obj:`bool`, optional): Является ли обложка пользовательской.
prefix (:obj:`str`, optional): Уникальный идентификатор. prefix (:obj:`str`, optional): Уникальный идентификатор.
copyright_name (:obj:`str`, optional): Название владельца авторским правом.
copyright_cline (:obj:`str`, optional): Владелец прав на музыку (автор текста и т.д.), а не её записи.
error (:obj:`str`, optional): Сообщение об ошибке. error (:obj:`str`, optional): Сообщение об ошибке.
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
**kwargs: Произвольные ключевые аргументы полученные от API. **kwargs: Произвольные ключевые аргументы полученные от API.
@ -43,6 +47,8 @@ class Cover(YandexMusicObject):
version: Optional[str] = None, version: Optional[str] = None,
custom: Optional[bool] = None, custom: Optional[bool] = None,
is_custom: Optional[bool] = None, is_custom: Optional[bool] = None,
copyright_name: Optional[str] = None,
copyright_cline: Optional[str] = None,
prefix: Optional[str] = None, prefix: Optional[str] = None,
error: Optional[str] = None, error: Optional[str] = None,
client: Optional['Client'] = None, client: Optional['Client'] = None,
@ -55,6 +61,8 @@ class Cover(YandexMusicObject):
self.version = version self.version = version
self.custom = custom self.custom = custom
self.is_custom = is_custom self.is_custom = is_custom
self.copyright_name = copyright_name
self.copyright_cline = copyright_cline
self.error = error self.error = error
self.client = client self.client = client

ファイルの表示

@ -19,6 +19,7 @@ class DownloadInfo(YandexMusicObject):
gain (:obj:`bool`): Усиление TODO. gain (:obj:`bool`): Усиление TODO.
preview (:obj:`bool`): Предварительный просмотр TODO. preview (:obj:`bool`): Предварительный просмотр TODO.
download_info_url (:obj:`str`): Ссылка на XML документ содержащий данные для загрузки трека. download_info_url (:obj:`str`): Ссылка на XML документ содержащий данные для загрузки трека.
direct (:obj:`bool`): Прямая ли ссылка.
direct_link (:obj:`str`): Прямая ссылка на загрузку. Доступна после получения ссылки. direct_link (:obj:`str`): Прямая ссылка на загрузку. Доступна после получения ссылки.
client (:obj:`yandex_music.Client`): Клиент Yandex Music. client (:obj:`yandex_music.Client`): Клиент Yandex Music.
@ -28,6 +29,7 @@ class DownloadInfo(YandexMusicObject):
gain (:obj:`bool`): Усиление TODO. gain (:obj:`bool`): Усиление TODO.
preview (:obj:`bool`): Предварительный просмотр TODO. preview (:obj:`bool`): Предварительный просмотр TODO.
download_info_url (:obj:`str`): Ссылка на XML документ содержащий данные для загрузки трека. download_info_url (:obj:`str`): Ссылка на XML документ содержащий данные для загрузки трека.
direct (:obj:`bool`): Прямая ли ссылка.
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
**kwargs: Произвольные ключевые аргументы полученные от API. **kwargs: Произвольные ключевые аргументы полученные от API.
""" """
@ -38,6 +40,7 @@ class DownloadInfo(YandexMusicObject):
gain: bool, gain: bool,
preview: bool, preview: bool,
download_info_url: str, download_info_url: str,
direct: bool,
client: Optional['Client'] = None, client: Optional['Client'] = None,
**kwargs): **kwargs):
self.codec = codec self.codec = codec
@ -45,6 +48,7 @@ class DownloadInfo(YandexMusicObject):
self.gain = gain self.gain = gain
self.preview = preview self.preview = preview
self.download_info_url = download_info_url self.download_info_url = download_info_url
self.direct = direct
self.direct_link = None self.direct_link = None

ファイルの表示

@ -9,10 +9,19 @@ if TYPE_CHECKING:
class User(YandexMusicObject): class User(YandexMusicObject):
"""Класс, представляющий пользователя. """Класс, представляющий пользователя.
Note:
Когда данный класс используется в `MadeFor` и `Playlist, то доступны все поля кроме `display_name` и
`full_name`.
При наличии экземпляра класса в `user_info` у `Track` (у самозагруженных треков) доступны только `uid`,
'`login`, 'display_name` и `full_name`.
Attributes: Attributes:
uid (:obj:`int`): Идентификатор пользователя. uid (:obj:`int`): Идентификатор пользователя.
login (:obj:`str`): Логин пользователя. login (:obj:`str`): Логин пользователя.
name (:obj:`str`): Имя пользователя. name (:obj:`str`): Имя пользователя.
display_name (:obj:`str`, optional): Отображаемое пользователя.
full_name (:obj:`str`, optional): Полное имя пользователя.
sex (:obj:`str`): Пол пользователя. sex (:obj:`str`): Пол пользователя.
verified (:obj:`bool`): Участвует ли пользователь в генерации плейлистов дня и т.д., и т.п. verified (:obj:`bool`): Участвует ли пользователь в генерации плейлистов дня и т.д., и т.п.
client (:obj:`yandex_music.Client`): Клиент Yandex Music. client (:obj:`yandex_music.Client`): Клиент Yandex Music.
@ -20,9 +29,11 @@ class User(YandexMusicObject):
Args: Args:
uid (:obj:`int`): Идентификатор пользователя. uid (:obj:`int`): Идентификатор пользователя.
login (:obj:`str`): Логин пользователя. login (:obj:`str`): Логин пользователя.
name (:obj:`str`): Имя пользователя. name (:obj:`str`, optional): Имя пользователя.
sex (:obj:`str`): Пол пользователя. display_name (:obj:`str`, optional): Отображаемое пользователя.
verified (:obj:`bool`): Участвует ли пользователь в генерации плейлистов дня и т.д., и т.п. full_name (:obj:`str`, optional): Полное имя пользователя.
sex (:obj:`str`, optional): Пол пользователя.
verified (:obj:`bool`, optional): Участвует ли пользователь в генерации плейлистов дня и т.д., и т.п.
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music. client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
**kwargs: Произвольные ключевые аргументы полученные от API. **kwargs: Произвольные ключевые аргументы полученные от API.
""" """
@ -30,14 +41,19 @@ class User(YandexMusicObject):
def __init__(self, def __init__(self,
uid: int, uid: int,
login: str, login: str,
name: str, name: Optional[str] = None,
sex: str, display_name: Optional[str] = None,
verified: bool, full_name: Optional[str] = None,
sex: Optional[str] = None,
verified: Optional[bool] = None,
client: Optional['Client'] = None, client: Optional['Client'] = None,
**kwargs) -> None: **kwargs) -> None:
self.uid = uid self.uid = uid
self.login = login self.login = login
self.name = name self.name = name
self.display_name = display_name
self.full_name = full_name
self.sex = sex self.sex = sex
self.verified = verified self.verified = verified

57
yandex_music/track/meta_data.py ノーマルファイル
ファイルの表示

@ -0,0 +1,57 @@
from typing import TYPE_CHECKING, Optional
from yandex_music import YandexMusicObject
if TYPE_CHECKING:
from yandex_music import Client
class MetaData(YandexMusicObject):
"""Класс, представляющий метаданные трека.
Attributes:
album (:obj:`str`): Название альбома.
volume (:obj:`int`): Диск (раздел).
year (:obj:`int`): Год выхода.
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
Args:
album (:obj:`str`): Название альбома.
volume (:obj:`int`): Диск (раздел).
year (:obj:`int`): Год выхода.
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
**kwargs: Произвольные ключевые аргументы полученные от API.
"""
def __init__(self,
album: str,
volume: int,
year: int,
client: Optional['Client'] = None,
**kwargs) -> None:
self.album = album
self.volume = volume
self.year = year
self.client = client
self._id_attrs = (self.album, self.volume, self.year)
super().handle_unknown_kwargs(self, **kwargs)
@classmethod
def de_json(cls, data: dict, client: 'Client') -> Optional['MetaData']:
"""Десериализация объекта.
Args:
data (:obj:`dict`): Поля и значения десериализуемого объекта.
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
Returns:
:obj:`yandex_music.MetaData`: Метаданные трека
"""
if not data:
return None
data = super(MetaData, cls).de_json(data, client)
return cls(client=client, **data)

ファイルの表示

@ -4,7 +4,7 @@ from yandex_music import YandexMusicObject
from yandex_music.exceptions import InvalidBitrate from yandex_music.exceptions import InvalidBitrate
if TYPE_CHECKING: if TYPE_CHECKING:
from yandex_music import Client, Normalization, Major, Album, Artist, Supplement, DownloadInfo from yandex_music import Client, Normalization, Major, Album, Artist, Supplement, DownloadInfo, User, MetaData
class Track(YandexMusicObject): class Track(YandexMusicObject):
@ -15,6 +15,9 @@ class Track(YandexMusicObject):
Известные значения поля `type`: `music`. Известные значения поля `type`: `music`.
Поля `can_publish`, `state`, `desired_visibility`, `filename`, `user_info` доступны только у треков что были
загружены пользователем.
Attributes: Attributes:
id (:obj:`int` | :obj:`str`): Уникальный идентификатор. id (:obj:`int` | :obj:`str`): Уникальный идентификатор.
title (:obj:`str`): Название. title (:obj:`str`): Название.
@ -32,8 +35,16 @@ class Track(YandexMusicObject):
duration_ms (:obj:`int`): Длительность трека в миллисекундах. duration_ms (:obj:`int`): Длительность трека в миллисекундах.
storage_dir (:obj:`str`): В какой папке на сервере хранится файл TODO. storage_dir (:obj:`str`): В какой папке на сервере хранится файл TODO.
file_size (:obj:`int`): Размер файла. TODO добавить единицу измерения. file_size (:obj:`int`): Размер файла. TODO добавить единицу измерения.
substituted (:obj:`yandex_music.Track`): Замещённый трек.
matched_track (:obj:`yandex_music.Track`): Соответствующий трек TODO.
normalization (:obj:`list` из :obj:`yandex_music.Normalization`): Значения для нормализации трека. normalization (:obj:`list` из :obj:`yandex_music.Normalization`): Значения для нормализации трека.
error (:obj:`str`): Сообщение об ошибке. error (:obj:`str`): Сообщение об ошибке.
can_publish (:obj:`bool`): Может ли быть опубликован.
state (:obj:`str`): Состояние, например, playable.
desired_visibility (:obj:`str`): Видимость трека.
filename (:obj:`str`): Название файла.
user_info (:obj:`yandex_music.User`): Информация о пользователе, который загрузил трек.
meta_data (:obj:`yandex_music.MetaData`): Информация о метаданных трека.
regions (:obj:`list` из :obj:`str`): Регион TODO. regions (:obj:`list` из :obj:`str`): Регион TODO.
available_as_rbt (:obj:`bool`): TODO. available_as_rbt (:obj:`bool`): TODO.
content_warning (:obj:`str`): Тип откровенного контента. content_warning (:obj:`str`): Тип откровенного контента.
@ -62,8 +73,16 @@ class Track(YandexMusicObject):
duration_ms (:obj:`int`, optional): Длительность трека в миллисекундах. duration_ms (:obj:`int`, optional): Длительность трека в миллисекундах.
storage_dir (:obj:`str`, optional): В какой папке на сервере хранится файл TODO. storage_dir (:obj:`str`, optional): В какой папке на сервере хранится файл TODO.
file_size (:obj:`int`, optional): Размер файла. TODO добавить единицу измерения. file_size (:obj:`int`, optional): Размер файла. TODO добавить единицу измерения.
substituted (:obj:`yandex_music.Track`, optional): Замещённый трек.
matched_track (:obj:`yandex_music.Track`, optional): Соответствующий трек TODO.
normalization (:obj:`list` из :obj:`yandex_music.Normalization`, optional): Значения для нормализации трека. normalization (:obj:`list` из :obj:`yandex_music.Normalization`, optional): Значения для нормализации трека.
error (:obj:`str`, optional): Сообщение об ошибке. error (:obj:`str`, optional): Сообщение об ошибке.
can_publish (:obj:`bool`, optional): Может ли быть опубликован.
state (:obj:`str`, optional): Состояние, например, playable.
desired_visibility (:obj:`str`, optional): Видимость трека.
filename (:obj:`str`, optional): Название файла.
user_info (:obj:`yandex_music.User`, optional): Информация о пользователе, который загрузил трек.
meta_data (:obj:`yandex_music.MetaData`, optional): Информация о метаданных трека.
regions (:obj:`list` из :obj:`str`, optional): Регион TODO. regions (:obj:`list` из :obj:`str`, optional): Регион TODO.
available_as_rbt (:obj:`bool`, optional): TODO. available_as_rbt (:obj:`bool`, optional): TODO.
content_warning (:obj:`str`, optional): Тип откровенного контента. content_warning (:obj:`str`, optional): Тип откровенного контента.
@ -93,8 +112,16 @@ class Track(YandexMusicObject):
duration_ms: Optional[int] = None, duration_ms: Optional[int] = None,
storage_dir: Optional[str] = None, storage_dir: Optional[str] = None,
file_size: Optional[int] = None, file_size: Optional[int] = None,
substituted: Optional['Track'] = None,
matched_track: Optional['Track'] = None,
normalization: Optional['Normalization'] = None, normalization: Optional['Normalization'] = None,
error: Optional[str] = None, error: Optional[str] = None,
can_publish: Optional[bool] = None,
state: Optional[str] = None,
desired_visibility: Optional[str] = None,
filename: Optional[str] = None,
user_info: Optional['User'] = None,
meta_data: Optional['MetaData'] = None,
regions: Optional[List[str]] = None, regions: Optional[List[str]] = None,
available_as_rbt: Optional[bool] = None, available_as_rbt: Optional[bool] = None,
content_warning: Optional[str] = None, content_warning: Optional[str] = None,
@ -122,8 +149,16 @@ class Track(YandexMusicObject):
self.duration_ms = duration_ms self.duration_ms = duration_ms
self.storage_dir = storage_dir self.storage_dir = storage_dir
self.file_size = file_size self.file_size = file_size
self.substituted = substituted
self.matched_track = matched_track
self.normalization = normalization self.normalization = normalization
self.error = error self.error = error
self.can_publish = can_publish
self.state = state
self.desired_visibility = desired_visibility
self.filename = filename
self.user_info = user_info
self.meta_data = meta_data
self.regions = regions self.regions = regions
self.available_as_rbt = available_as_rbt self.available_as_rbt = available_as_rbt
self.content_warning = content_warning self.content_warning = content_warning
@ -238,11 +273,15 @@ class Track(YandexMusicObject):
return None return None
data = super(Track, cls).de_json(data, client) data = super(Track, cls).de_json(data, client)
from yandex_music import Normalization, Major, Album, Artist from yandex_music import Normalization, Major, Album, Artist, User, MetaData
data['albums'] = Album.de_list(data.get('albums'), client) data['albums'] = Album.de_list(data.get('albums'), client)
data['artists'] = Artist.de_list(data.get('artists'), client) data['artists'] = Artist.de_list(data.get('artists'), client)
data['normalization'] = Normalization.de_json(data.get('normalization'), client) data['normalization'] = Normalization.de_json(data.get('normalization'), client)
data['major'] = Major.de_json(data.get('major'), client) data['major'] = Major.de_json(data.get('major'), client)
data['substituted'] = Track.de_json(data.get('substituted'), client)
data['matched_track'] = Track.de_json(data.get('matched_track'), client)
data['user_info'] = User.de_json(data.get('user_info'), client)
data['meta_data'] = MetaData.de_json(data.get('meta_data'), client)
return cls(client=client, **data) return cls(client=client, **data)
@ -260,11 +299,7 @@ class Track(YandexMusicObject):
if not data: if not data:
return [] return []
tracks = list() return [cls.de_json(track, client) for track in data]
for track in data:
tracks.append(cls.de_json(track, client))
return tracks
# camelCase псевдонимы # camelCase псевдонимы