コミット
2ef2e5d533
|
@ -10,3 +10,5 @@
|
|||
yandex_music.playlist.playlist
|
||||
yandex_music.playlist.case_forms
|
||||
yandex_music.playlist.playlist_id
|
||||
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:
|
|
@ -77,3 +77,4 @@ from .test_shot_type import TestShotType
|
|||
from .test_shot_data import TestShotData
|
||||
from .test_shot import TestShot
|
||||
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, \
|
||||
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
|
||||
RenewableRemainder, ChartInfoMenuItem, ChartInfoMenu, ChartInfo, Tag
|
||||
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,7 +17,7 @@ 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
|
||||
TestRenewableRemainder, TestChartInfoMenuItem, TestChartInfo, TestTag
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
|
@ -137,6 +137,11 @@ def client():
|
|||
return Client()
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def tag():
|
||||
return Tag(TestTag.id_, TestTag.value, TestTag.name, TestTag.og_description)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def track_with_ads(track):
|
||||
return TrackWithAds(TestTrackWithAds.type, track)
|
||||
|
|
|
@ -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.play_counter import PlayCounter
|
||||
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 import Playlist
|
||||
|
||||
|
@ -123,4 +125,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']
|
||||
'ChartInfoMenuItem', 'Tag', 'TagResult']
|
||||
|
|
|
@ -4,9 +4,9 @@ from datetime import datetime
|
|||
from typing import Callable, Dict, List, Optional, Union
|
||||
|
||||
from yandex_music import Album, Artist, ArtistAlbums, ArtistTracks, BriefInfo, Dashboard, DownloadInfo, Experiments, \
|
||||
Feed, Genre, Landing, Like, PermissionAlerts, Playlist, PromoCodeStatus, Search, Settings, ShotEvent, SimilarTracks, \
|
||||
StationResult, StationTracksResult, Status, Suggestions, Supplement, Track, TracksList, UserSettings, \
|
||||
YandexMusicObject, ChartInfo
|
||||
Feed, Genre, Landing, Like, PermissionAlerts, Playlist, PromoCodeStatus, Search, Settings, ShotEvent, Supplement, \
|
||||
StationResult, StationTracksResult, Status, Suggestions, SimilarTracks, Track, TracksList, UserSettings, \
|
||||
YandexMusicObject, ChartInfo, TagResult
|
||||
from yandex_music.exceptions import Captcha, InvalidToken
|
||||
from yandex_music.utils.difference import Difference
|
||||
from yandex_music.utils.request import Request
|
||||
|
@ -491,6 +491,35 @@ class Client(YandexMusicObject):
|
|||
|
||||
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
|
||||
def tracks_download_info(self, track_id: Union[str, int], get_direct_links: bool = False,
|
||||
timeout: Union[int, float] = None, *args, **kwargs) -> List[DownloadInfo]:
|
||||
|
|
|
@ -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)
|
読み込み中…
新しいイシューから参照