Добавлен новый класс 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
このコミットが含まれているのは:
コミット
0240eb6cb9
|
@ -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.major
|
||||
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_renewable_remainder import TestRenewableRemainder
|
||||
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, \
|
||||
TrackWithAds, VideoSupplement, ArtistEvent, ChartItem, Event, AlbumEvent, Day, PlayContext, Plus, Title, Label, \
|
||||
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, \
|
||||
TestTrack, TestInvocationInfo, TestPlaylist, TestAutoRenewable, TestStation, TestNormalization, TestMajor, \
|
||||
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, \
|
||||
TestVideoSupplement, TestEvent, TestDay, TestPlayContext, TestGeneratedPlaylist, TestVideo, TestVinyl, \
|
||||
TestSearchResult, TestBlockEntity, TestBlock, TestPlaylistAbsence, TestShot, TestShotData, TestShotType, \
|
||||
TestRenewableRemainder, TestChartInfoMenuItem, TestChartInfo, TestTag
|
||||
TestRenewableRemainder, TestChartInfoMenuItem, TestChartInfo, TestTag, TestMetaData
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def artist_factory(cover, counts, ratings, link, description):
|
||||
class ArtistFactory:
|
||||
def get(self, popular_tracks):
|
||||
return Artist(TestArtist.id, TestArtist.reason, TestArtist.name, cover, TestArtist.various,
|
||||
TestArtist.composer, TestArtist.genres, TestArtist.og_image, TestArtist.op_image,
|
||||
TestArtist.no_pictures_from_search, counts, TestArtist.available, ratings, [link],
|
||||
TestArtist.tickets_available, TestArtist.likes_count, popular_tracks, TestArtist.regions,
|
||||
TestArtist.decomposed, TestArtist.full_names, description, TestArtist.countries,
|
||||
TestArtist.en_wikipedia_link, TestArtist.db_aliases, TestArtist.aliases, TestArtist.init_date,
|
||||
TestArtist.end_date)
|
||||
return Artist(TestArtist.id, TestArtist.error, TestArtist.reason, TestArtist.name, cover,
|
||||
TestArtist.various, TestArtist.composer, TestArtist.genres, TestArtist.og_image,
|
||||
TestArtist.op_image, TestArtist.no_pictures_from_search, counts, TestArtist.available,
|
||||
ratings, [link], TestArtist.tickets_available, TestArtist.likes_count, popular_tracks,
|
||||
TestArtist.regions, TestArtist.decomposed, TestArtist.full_names, description,
|
||||
TestArtist.countries, TestArtist.en_wikipedia_link, TestArtist.db_aliases, TestArtist.aliases,
|
||||
TestArtist.init_date, TestArtist.end_date)
|
||||
|
||||
return ArtistFactory()
|
||||
|
||||
|
@ -46,14 +46,16 @@ def artist_without_tracks(artist_factory):
|
|||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def track_factory(major, normalization):
|
||||
def track_factory(major, normalization, user, meta_data):
|
||||
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,
|
||||
TestTrack.available_for_premium_users, TestTrack.lyrics_available, TestTrack.best,
|
||||
TestTrack.real_id, TestTrack.og_image, TestTrack.type, TestTrack.cover_uri, major,
|
||||
TestTrack.duration_ms, TestTrack.storage_dir, TestTrack.file_size, normalization,
|
||||
TestTrack.error, TestTrack.regions, TestTrack.available_as_rbt, TestTrack.content_warning,
|
||||
TestTrack.duration_ms, TestTrack.storage_dir, TestTrack.file_size, track_without_nested_tracks,
|
||||
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.version, TestTrack.remember_position)
|
||||
|
||||
|
@ -61,8 +63,8 @@ def track_factory(major, normalization):
|
|||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def track(track_factory, artist, album):
|
||||
return track_factory.get([artist], [album])
|
||||
def track(track_factory, artist, album, track_without_nested_tracks):
|
||||
return track_factory.get([artist], [album], track_without_nested_tracks)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
|
@ -80,6 +82,11 @@ def track_without_artists_and_albums(track_factory):
|
|||
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')
|
||||
def album_factory(label, track_position):
|
||||
class AlbumFactory:
|
||||
|
@ -207,7 +214,13 @@ def icon():
|
|||
@pytest.fixture(scope='session')
|
||||
def cover():
|
||||
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')
|
||||
|
@ -361,7 +374,8 @@ def renewable_remainder():
|
|||
|
||||
@pytest.fixture(scope='session')
|
||||
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')
|
||||
|
|
|
@ -3,6 +3,7 @@ from yandex_music import Artist
|
|||
|
||||
class TestArtist:
|
||||
id = 10987
|
||||
error = 'not-found'
|
||||
reason = 'not-found'
|
||||
name = 'Elvis Presley'
|
||||
various = False
|
||||
|
@ -26,6 +27,7 @@ class TestArtist:
|
|||
|
||||
def test_expected_values(self, artist, cover, counts, ratings, link, track_without_artists_and_albums, description):
|
||||
assert artist.id == self.id
|
||||
assert artist.error == self.error
|
||||
assert artist.reason == self.reason
|
||||
assert artist.name == self.name
|
||||
assert artist.various == self.various
|
||||
|
@ -66,7 +68,7 @@ class TestArtist:
|
|||
assert artist.id == self.id
|
||||
|
||||
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(),
|
||||
'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(),
|
||||
|
@ -80,6 +82,7 @@ class TestArtist:
|
|||
artist = Artist.de_json(json_dict, client)
|
||||
|
||||
assert artist.id == self.id
|
||||
assert artist.error == self.error
|
||||
assert artist.reason == self.reason
|
||||
assert artist.name == self.name
|
||||
assert artist.various == self.various
|
||||
|
|
|
@ -10,6 +10,8 @@ class TestCover:
|
|||
custom = True
|
||||
is_custom = True
|
||||
prefix = None
|
||||
copyright_name = 'ТАСС'
|
||||
copyright_cline = 'imago stock&people'
|
||||
error = None
|
||||
|
||||
def test_expected_values(self, cover):
|
||||
|
@ -20,6 +22,8 @@ class TestCover:
|
|||
assert cover.version == self.version
|
||||
assert cover.custom == self.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.error == self.error
|
||||
|
||||
|
@ -36,7 +40,8 @@ class TestCover:
|
|||
def test_de_json_all(self, client):
|
||||
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,
|
||||
'error': self.error}
|
||||
'error': self.error, 'copyright_name': self.copyright_name,
|
||||
'copyright_cline': self.copyright_cline}
|
||||
cover = Cover.de_json(json_dict, client)
|
||||
|
||||
assert cover.type == self.type
|
||||
|
@ -46,6 +51,8 @@ class TestCover:
|
|||
assert cover.version == self.version
|
||||
assert cover.custom == self.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.error == self.error
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ from yandex_music import DownloadInfo
|
|||
@pytest.fixture(scope='class')
|
||||
def download_info():
|
||||
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:
|
||||
|
@ -16,6 +16,7 @@ class TestDownloadInfo:
|
|||
preview = False
|
||||
download_info_url = 'https://storage.mds.yandex.net/file-download-info/136146_d158926e.14534319.6.10994777/320' \
|
||||
'?sign=8caf5ea72c946d4753f15298e4033b961c7acb1bb4db48eb5e6b59621e387d64&ts=5dc4a6f2 '
|
||||
direct = False
|
||||
|
||||
def test_expected_values(self, download_info):
|
||||
assert download_info.codec == self.codec
|
||||
|
@ -23,6 +24,7 @@ class TestDownloadInfo:
|
|||
assert download_info.gain == self.gain
|
||||
assert download_info.preview == self.preview
|
||||
assert download_info.download_info_url == self.download_info_url
|
||||
assert download_info.direct == self.direct
|
||||
|
||||
def test_de_json_none(self, client):
|
||||
assert DownloadInfo.de_json({}, client) is None
|
||||
|
@ -32,7 +34,7 @@ class TestDownloadInfo:
|
|||
|
||||
def test_de_json_required(self, client):
|
||||
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)
|
||||
|
||||
assert download_info.codec == self.codec
|
||||
|
@ -40,10 +42,11 @@ class TestDownloadInfo:
|
|||
assert download_info.gain == self.gain
|
||||
assert download_info.preview == self.preview
|
||||
assert download_info.download_info_url == self.download_info_url
|
||||
assert download_info.direct == self.direct
|
||||
|
||||
def test_de_json_all(self, client):
|
||||
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)
|
||||
|
||||
assert download_info.codec == self.codec
|
||||
|
@ -51,11 +54,12 @@ class TestDownloadInfo:
|
|||
assert download_info.gain == self.gain
|
||||
assert download_info.preview == self.preview
|
||||
assert download_info.download_info_url == self.download_info_url
|
||||
assert download_info.direct == self.direct
|
||||
|
||||
def test_equality(self):
|
||||
a = DownloadInfo(self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url)
|
||||
b = DownloadInfo(self.codec, 128, self.gain, True, self.download_info_url)
|
||||
c = 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, True)
|
||||
c = DownloadInfo(self.codec, self.bitrate_in_kbps, self.gain, self.preview, self.download_info_url, self.direct)
|
||||
|
||||
assert a != b
|
||||
assert hash(a) != hash(b)
|
||||
|
|
|
@ -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'
|
||||
file_size = 6036792
|
||||
error = None
|
||||
can_publish = False
|
||||
state = 'playable'
|
||||
desired_visibility = 'private'
|
||||
filename = 'Ты не так плох.mp3'
|
||||
regions = None
|
||||
available_as_rbt = None
|
||||
content_warning = None
|
||||
|
@ -25,7 +29,8 @@ class TestTrack:
|
|||
version = 'Radio Edit'
|
||||
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.title == self.title
|
||||
assert track.available == self.available
|
||||
|
@ -42,8 +47,11 @@ class TestTrack:
|
|||
assert track.duration_ms == self.duration_ms
|
||||
assert track.storage_dir == self.storage_dir
|
||||
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.error == self.error
|
||||
assert track.meta_data == meta_data
|
||||
assert track.regions == self.regions
|
||||
assert track.available_as_rbt == self.available_as_rbt
|
||||
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.version == self.version
|
||||
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):
|
||||
assert Track.de_json({}, client) is None
|
||||
|
@ -65,7 +78,8 @@ class TestTrack:
|
|||
|
||||
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,
|
||||
'available_for_premium_users': self.available_for_premium_users,
|
||||
'artists': [artist.to_dict()], 'albums': [album.to_dict()],
|
||||
|
@ -77,7 +91,10 @@ class TestTrack:
|
|||
'content_warning': self.content_warning, 'explicit': self.explicit,
|
||||
'preview_duration_ms': self.preview_duration_ms, 'version': self.version,
|
||||
'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)
|
||||
|
||||
assert track.id == self.id
|
||||
|
@ -96,8 +113,11 @@ class TestTrack:
|
|||
assert track.duration_ms == self.duration_ms
|
||||
assert track.storage_dir == self.storage_dir
|
||||
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.error == self.error
|
||||
assert track.meta_data == meta_data
|
||||
assert track.regions == self.regions
|
||||
assert track.available_as_rbt == self.available_as_rbt
|
||||
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.version == self.version
|
||||
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):
|
||||
a = Track(self.id)
|
||||
|
|
|
@ -5,6 +5,8 @@ class TestUser:
|
|||
uid = 503646255
|
||||
login = 'yamusic-daily'
|
||||
name = 'yamusic-daily'
|
||||
display_name = 'Ilya (Marshal)'
|
||||
full_name = 'Илья'
|
||||
sex = 'unknown'
|
||||
verified = False
|
||||
|
||||
|
@ -12,6 +14,8 @@ class TestUser:
|
|||
assert user.uid == self.uid
|
||||
assert user.login == self.login
|
||||
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.verified == self.verified
|
||||
|
||||
|
@ -19,31 +23,29 @@ class TestUser:
|
|||
assert User.de_json({}, client) is None
|
||||
|
||||
def test_de_json_required(self, client):
|
||||
json_dict = {'uid': self.uid, 'login': self.login, 'name': self.name, 'sex': self.sex,
|
||||
'verified': self.verified}
|
||||
json_dict = {'uid': self.uid, 'login': self.login}
|
||||
user = User.de_json(json_dict, client)
|
||||
|
||||
assert user.uid == self.uid
|
||||
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):
|
||||
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)
|
||||
|
||||
assert user.uid == self.uid
|
||||
assert user.login == self.login
|
||||
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.verified == self.verified
|
||||
|
||||
def test_equality(self):
|
||||
a = User(self.uid, self.login, self.name, self.sex, self.verified)
|
||||
b = User(1, self.login, self.name, self.sex, self.verified)
|
||||
c = User(self.uid, self.login, '', self.sex, self.verified)
|
||||
a = User(self.uid, self.login)
|
||||
b = User(1, self.login)
|
||||
c = User(self.uid, self.login)
|
||||
|
||||
assert a != b
|
||||
assert hash(a) != hash(b)
|
||||
|
|
|
@ -47,6 +47,7 @@ from .shot.shot_event import ShotEvent
|
|||
|
||||
from .tracks_list import TracksList
|
||||
from .track.major import Major
|
||||
from .track.meta_data import MetaData
|
||||
from .track.normalization import Normalization
|
||||
from .track.track import Track
|
||||
from .track.tracks_similar import SimilarTracks
|
||||
|
@ -127,4 +128,4 @@ __all__ = ['YandexMusicObject', 'Client', 'Account', 'PassportPhone', 'Invocatio
|
|||
'Sequence', 'StationTracksResult', 'BriefInfo', 'Description', 'PlaylistId', 'Vinyl', 'Supplement', 'Lyrics',
|
||||
'VideoSupplement', 'ArtistTracks', 'Pager', 'ArtistAlbums', 'PlaylistAbsence', 'Shot', 'ShotEvent',
|
||||
'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:
|
||||
id (:obj:`int`): Уникальный идентификатор.
|
||||
error (:obj:`str`): Сообщение об ошибке с объяснением почему не вернуло исполнителя.
|
||||
reason (:obj:`str`): Причина отсутствия исполнителя (сообщение об ошибке).
|
||||
name (:obj:`str`): Название.
|
||||
cover (:obj:`yandex_music.Cover` | :obj:`None`): Обложка.
|
||||
|
@ -41,6 +42,7 @@ class Artist(YandexMusicObject):
|
|||
|
||||
Args:
|
||||
id_ (:obj:`int`): Уникальный идентификатор.
|
||||
error (:obj:`str`, optional): Сообщение об ошибке с объяснением почему не вернуло исполнителя.
|
||||
reason (:obj:`str`, optional): Причина отсутствия исполнителя (сообщение об ошибке).
|
||||
name (:obj:`str`, optional): Название.
|
||||
cover (:obj:`yandex_music.Cover`, optional): Обложка.
|
||||
|
@ -73,6 +75,7 @@ class Artist(YandexMusicObject):
|
|||
|
||||
def __init__(self,
|
||||
id_: int,
|
||||
error: Optional[str] = None,
|
||||
reason: Optional[str] = None,
|
||||
name: Optional[str] = None,
|
||||
cover: Optional['Cover'] = None,
|
||||
|
@ -103,6 +106,7 @@ class Artist(YandexMusicObject):
|
|||
**kwargs) -> None:
|
||||
self.id = id_
|
||||
|
||||
self.error = error
|
||||
self.reason = reason
|
||||
self.name = name
|
||||
self.cover = cover
|
||||
|
|
|
@ -49,7 +49,7 @@ class Client(YandexMusicObject):
|
|||
uid аккаунта для отправки запроса. Так же в большинстве методов придётся передавать `uid` явно.
|
||||
|
||||
Attributes:
|
||||
logger (:obj:`logging.Logger`): Объект логера.
|
||||
logger (:obj:`logging.Logger`): Объект логгера.
|
||||
token (:obj:`str`): Уникальный ключ для аутентификации.
|
||||
base_url (:obj:`str`): Ссылка на API 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,
|
||||
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.token = token
|
||||
|
||||
|
@ -133,7 +133,7 @@ class Client(YandexMusicObject):
|
|||
|
||||
@classmethod
|
||||
def from_token(cls, token: str, *args, **kwargs) -> 'Client':
|
||||
"""Инициализция клиента по токену.
|
||||
"""Инициализация клиента по токену.
|
||||
|
||||
Note:
|
||||
Ничем не отличается от `Client(token)`. Так исторически сложилось.
|
||||
|
|
|
@ -18,6 +18,8 @@ class Cover(YandexMusicObject):
|
|||
is_custom (:obj:`bool`): Является ли обложка пользовательской.
|
||||
custom (:obj:`bool`): Является ли обложка пользовательской.
|
||||
prefix (:obj:`str`): Уникальный идентификатор.
|
||||
copyright_name (:obj:`str`): Название владельца авторским правом.
|
||||
copyright_cline (:obj:`str`): Владелец прав на музыку (автор текста и т.д.), а не её записи.
|
||||
error (:obj:`str`): Сообщение об ошибке.
|
||||
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||
|
||||
|
@ -30,6 +32,8 @@ class Cover(YandexMusicObject):
|
|||
is_custom (:obj:`bool`, optional): Является ли обложка пользовательской.
|
||||
custom (:obj:`bool`, optional): Является ли обложка пользовательской.
|
||||
prefix (:obj:`str`, optional): Уникальный идентификатор.
|
||||
copyright_name (:obj:`str`, optional): Название владельца авторским правом.
|
||||
copyright_cline (:obj:`str`, optional): Владелец прав на музыку (автор текста и т.д.), а не её записи.
|
||||
error (:obj:`str`, optional): Сообщение об ошибке.
|
||||
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||
**kwargs: Произвольные ключевые аргументы полученные от API.
|
||||
|
@ -43,6 +47,8 @@ class Cover(YandexMusicObject):
|
|||
version: Optional[str] = None,
|
||||
custom: Optional[bool] = None,
|
||||
is_custom: Optional[bool] = None,
|
||||
copyright_name: Optional[str] = None,
|
||||
copyright_cline: Optional[str] = None,
|
||||
prefix: Optional[str] = None,
|
||||
error: Optional[str] = None,
|
||||
client: Optional['Client'] = None,
|
||||
|
@ -55,6 +61,8 @@ class Cover(YandexMusicObject):
|
|||
self.version = version
|
||||
self.custom = custom
|
||||
self.is_custom = is_custom
|
||||
self.copyright_name = copyright_name
|
||||
self.copyright_cline = copyright_cline
|
||||
self.error = error
|
||||
|
||||
self.client = client
|
||||
|
|
|
@ -19,6 +19,7 @@ class DownloadInfo(YandexMusicObject):
|
|||
gain (:obj:`bool`): Усиление TODO.
|
||||
preview (:obj:`bool`): Предварительный просмотр TODO.
|
||||
download_info_url (:obj:`str`): Ссылка на XML документ содержащий данные для загрузки трека.
|
||||
direct (:obj:`bool`): Прямая ли ссылка.
|
||||
direct_link (:obj:`str`): Прямая ссылка на загрузку. Доступна после получения ссылки.
|
||||
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||
|
||||
|
@ -28,6 +29,7 @@ class DownloadInfo(YandexMusicObject):
|
|||
gain (:obj:`bool`): Усиление TODO.
|
||||
preview (:obj:`bool`): Предварительный просмотр TODO.
|
||||
download_info_url (:obj:`str`): Ссылка на XML документ содержащий данные для загрузки трека.
|
||||
direct (:obj:`bool`): Прямая ли ссылка.
|
||||
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||
**kwargs: Произвольные ключевые аргументы полученные от API.
|
||||
"""
|
||||
|
@ -38,6 +40,7 @@ class DownloadInfo(YandexMusicObject):
|
|||
gain: bool,
|
||||
preview: bool,
|
||||
download_info_url: str,
|
||||
direct: bool,
|
||||
client: Optional['Client'] = None,
|
||||
**kwargs):
|
||||
self.codec = codec
|
||||
|
@ -45,6 +48,7 @@ class DownloadInfo(YandexMusicObject):
|
|||
self.gain = gain
|
||||
self.preview = preview
|
||||
self.download_info_url = download_info_url
|
||||
self.direct = direct
|
||||
|
||||
self.direct_link = None
|
||||
|
||||
|
|
|
@ -9,10 +9,19 @@ if TYPE_CHECKING:
|
|||
class User(YandexMusicObject):
|
||||
"""Класс, представляющий пользователя.
|
||||
|
||||
Note:
|
||||
Когда данный класс используется в `MadeFor` и `Playlist, то доступны все поля кроме `display_name` и
|
||||
`full_name`.
|
||||
|
||||
При наличии экземпляра класса в `user_info` у `Track` (у самозагруженных треков) доступны только `uid`,
|
||||
'`login`, 'display_name` и `full_name`.
|
||||
|
||||
Attributes:
|
||||
uid (:obj:`int`): Идентификатор пользователя.
|
||||
login (:obj:`str`): Логин пользователя.
|
||||
name (:obj:`str`): Имя пользователя.
|
||||
display_name (:obj:`str`, optional): Отображаемое пользователя.
|
||||
full_name (:obj:`str`, optional): Полное имя пользователя.
|
||||
sex (:obj:`str`): Пол пользователя.
|
||||
verified (:obj:`bool`): Участвует ли пользователь в генерации плейлистов дня и т.д., и т.п.
|
||||
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
|
||||
|
@ -20,9 +29,11 @@ class User(YandexMusicObject):
|
|||
Args:
|
||||
uid (:obj:`int`): Идентификатор пользователя.
|
||||
login (:obj:`str`): Логин пользователя.
|
||||
name (:obj:`str`): Имя пользователя.
|
||||
sex (:obj:`str`): Пол пользователя.
|
||||
verified (:obj:`bool`): Участвует ли пользователь в генерации плейлистов дня и т.д., и т.п.
|
||||
name (:obj:`str`, optional): Имя пользователя.
|
||||
display_name (:obj:`str`, optional): Отображаемое пользователя.
|
||||
full_name (:obj:`str`, optional): Полное имя пользователя.
|
||||
sex (:obj:`str`, optional): Пол пользователя.
|
||||
verified (:obj:`bool`, optional): Участвует ли пользователь в генерации плейлистов дня и т.д., и т.п.
|
||||
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
|
||||
**kwargs: Произвольные ключевые аргументы полученные от API.
|
||||
"""
|
||||
|
@ -30,14 +41,19 @@ class User(YandexMusicObject):
|
|||
def __init__(self,
|
||||
uid: int,
|
||||
login: str,
|
||||
name: str,
|
||||
sex: str,
|
||||
verified: bool,
|
||||
name: Optional[str] = None,
|
||||
display_name: Optional[str] = None,
|
||||
full_name: Optional[str] = None,
|
||||
sex: Optional[str] = None,
|
||||
verified: Optional[bool] = None,
|
||||
client: Optional['Client'] = None,
|
||||
**kwargs) -> None:
|
||||
self.uid = uid
|
||||
self.login = login
|
||||
|
||||
self.name = name
|
||||
self.display_name = display_name
|
||||
self.full_name = full_name
|
||||
self.sex = sex
|
||||
self.verified = verified
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
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):
|
||||
|
@ -15,6 +15,9 @@ class Track(YandexMusicObject):
|
|||
|
||||
Известные значения поля `type`: `music`.
|
||||
|
||||
Поля `can_publish`, `state`, `desired_visibility`, `filename`, `user_info` доступны только у треков что были
|
||||
загружены пользователем.
|
||||
|
||||
Attributes:
|
||||
id (:obj:`int` | :obj:`str`): Уникальный идентификатор.
|
||||
title (:obj:`str`): Название.
|
||||
|
@ -32,8 +35,16 @@ class Track(YandexMusicObject):
|
|||
duration_ms (:obj:`int`): Длительность трека в миллисекундах.
|
||||
storage_dir (:obj:`str`): В какой папке на сервере хранится файл 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`): Значения для нормализации трека.
|
||||
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.
|
||||
available_as_rbt (:obj:`bool`): TODO.
|
||||
content_warning (:obj:`str`): Тип откровенного контента.
|
||||
|
@ -62,8 +73,16 @@ class Track(YandexMusicObject):
|
|||
duration_ms (:obj:`int`, optional): Длительность трека в миллисекундах.
|
||||
storage_dir (:obj:`str`, 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): Значения для нормализации трека.
|
||||
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.
|
||||
available_as_rbt (:obj:`bool`, optional): TODO.
|
||||
content_warning (:obj:`str`, optional): Тип откровенного контента.
|
||||
|
@ -93,8 +112,16 @@ class Track(YandexMusicObject):
|
|||
duration_ms: Optional[int] = None,
|
||||
storage_dir: Optional[str] = None,
|
||||
file_size: Optional[int] = None,
|
||||
substituted: Optional['Track'] = None,
|
||||
matched_track: Optional['Track'] = None,
|
||||
normalization: Optional['Normalization'] = 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,
|
||||
available_as_rbt: Optional[bool] = None,
|
||||
content_warning: Optional[str] = None,
|
||||
|
@ -122,8 +149,16 @@ class Track(YandexMusicObject):
|
|||
self.duration_ms = duration_ms
|
||||
self.storage_dir = storage_dir
|
||||
self.file_size = file_size
|
||||
self.substituted = substituted
|
||||
self.matched_track = matched_track
|
||||
self.normalization = normalization
|
||||
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.available_as_rbt = available_as_rbt
|
||||
self.content_warning = content_warning
|
||||
|
@ -238,11 +273,15 @@ class Track(YandexMusicObject):
|
|||
return None
|
||||
|
||||
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['artists'] = Artist.de_list(data.get('artists'), client)
|
||||
data['normalization'] = Normalization.de_json(data.get('normalization'), 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)
|
||||
|
||||
|
@ -260,11 +299,7 @@ class Track(YandexMusicObject):
|
|||
if not data:
|
||||
return []
|
||||
|
||||
tracks = list()
|
||||
for track in data:
|
||||
tracks.append(cls.de_json(track, client))
|
||||
|
||||
return tracks
|
||||
return [cls.de_json(track, client) for track in data]
|
||||
|
||||
# camelCase псевдонимы
|
||||
|
||||
|
|
読み込み中…
新しいイシューから参照