Merge pull request #330 from MarshalX/pull/325

Рекомендуемые треки для плейлиста
このコミットが含まれているのは:
Il'ya 2020-05-14 23:41:58 +03:00 committed by GitHub
コミット e19b206f3d
この署名に対応する既知のキーがデータベースに存在しません
GPGキーID: 4AEE18F83AFDEB23
7個のファイルの変更155行の追加3行の削除

ファイルの表示

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

ファイルの表示

@ -10,5 +10,6 @@
yandex_music.playlist.playlist yandex_music.playlist.playlist
yandex_music.playlist.case_forms yandex_music.playlist.case_forms
yandex_music.playlist.playlist_id yandex_music.playlist.playlist_id
yandex_music.playlist.playlist_recommendations
yandex_music.playlist.tag_result yandex_music.playlist.tag_result
yandex_music.playlist.tag yandex_music.playlist.tag

43
tests/test_playlist_recommendations.py ノーマルファイル
ファイルの表示

@ -0,0 +1,43 @@
import pytest
from yandex_music import PlaylistRecommendations
@pytest.fixture(scope='class')
def playlist_recommendations(track):
return PlaylistRecommendations([track], TestPlaylistRecommendations.batch_id)
class TestPlaylistRecommendations:
batch_id = '1588835234913188-6341822935848536902'
def test_expected_values(self, playlist_recommendations, track):
assert playlist_recommendations.batch_id == self.batch_id
assert playlist_recommendations.tracks == [track]
def test_de_json_none(self, client):
assert PlaylistRecommendations.de_json({}, client) is None
def test_de_json_required(self, client, track):
json_dict = {'tracks': [track.to_dict()]}
playlist_recommendations = PlaylistRecommendations.de_json(json_dict, client)
assert playlist_recommendations.tracks == [track]
def test_de_json_all(self, client, track):
json_dict = {'batch_id': self.batch_id, 'tracks': [track.to_dict()]}
playlist_recommendations = PlaylistRecommendations.de_json(json_dict, client)
assert playlist_recommendations.batch_id == self.batch_id
assert playlist_recommendations.tracks == [track]
def test_equality(self, track):
a = PlaylistRecommendations([track])
b = PlaylistRecommendations([])
c = PlaylistRecommendations([track])
assert a != b
assert hash(a) != hash(b)
assert a is not b
assert a == c

ファイルの表示

@ -38,6 +38,7 @@ from .playlist.tag import Tag
from .playlist.tag_result import TagResult from .playlist.tag_result import TagResult
from .playlist.playlist_absence import PlaylistAbsence from .playlist.playlist_absence import PlaylistAbsence
from .playlist.playlist import Playlist from .playlist.playlist import Playlist
from .playlist.playlist_recommendation import PlaylistRecommendations
from .shot.shot_type import ShotType from .shot.shot_type import ShotType
from .shot.shot_data import ShotData from .shot.shot_data import ShotData
@ -125,4 +126,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'] 'ChartInfoMenuItem', 'Tag', 'TagResult', 'PlaylistRecommendations']

ファイルの表示

@ -6,7 +6,7 @@ from typing import Callable, Dict, List, Optional, Union
from yandex_music import Album, Artist, ArtistAlbums, ArtistTracks, BriefInfo, Dashboard, DownloadInfo, Experiments, \ from yandex_music import Album, Artist, ArtistAlbums, ArtistTracks, BriefInfo, Dashboard, DownloadInfo, Experiments, \
Feed, Genre, Landing, Like, PermissionAlerts, Playlist, PromoCodeStatus, Search, Settings, ShotEvent, Supplement, \ Feed, Genre, Landing, Like, PermissionAlerts, Playlist, PromoCodeStatus, Search, Settings, ShotEvent, Supplement, \
StationResult, StationTracksResult, Status, Suggestions, SimilarTracks, Track, TracksList, UserSettings, \ StationResult, StationTracksResult, Status, Suggestions, SimilarTracks, Track, TracksList, UserSettings, \
YandexMusicObject, ChartInfo, TagResult YandexMusicObject, ChartInfo, TagResult, PlaylistRecommendations
from yandex_music.exceptions import Captcha, InvalidToken from yandex_music.exceptions import Captcha, InvalidToken
from yandex_music.utils.difference import Difference from yandex_music.utils.difference import Difference
from yandex_music.utils.request import Request from yandex_music.utils.request import Request
@ -823,6 +823,33 @@ class Client(YandexMusicObject):
return Playlist.de_json(result, self) return Playlist.de_json(result, self)
@log
def users_playlists_recommendations(self, kind: Union[str, int], user_id: Union[str, int] = None,
timeout: Union[int, float] = None, *args, **kwargs):
"""Получение рекомендаций для плейлиста.
Args:
kind (:obj:`str` | :obj:`int`): Уникальный идентификатор плейлиста.
user_id (:obj:`str` | :obj:`int`): Уникальный идентификатор пользователя владеющим плейлистом.
timeout (:obj:`int` | :obj:`float`, optional): Если это значение указано, используется как время ожидания
ответа от сервера вместо указанного при создании пула.
**kwargs (:obj:`dict`, optional): Произвольные аргументы (будут переданы в запрос).
Returns:
:obj:`yandex_music.PlaylistRecommendations` | :obj:`None`: Рекомендации для плейлиста или :obj:`None`.
Raises:
:class:`yandex_music.exceptions.YandexMusicError`: Базовое исключение библиотеки.
"""
if user_id is None and self.me is not None:
user_id = self.me.account.uid
url = f'{self.base_url}/users/{user_id}/playlists/{kind}/recommendations'
result = self._request.get(url, timeout=timeout, *args, **kwargs)
return PlaylistRecommendations.de_json(result, self)
@log @log
def users_playlists_create(self, title: str, visibility: str = 'public', user_id: Union[str, int] = None, def users_playlists_create(self, title: str, visibility: str = 'public', user_id: Union[str, int] = None,
timeout: Union[int, float] = None, *args, **kwargs) -> Optional[Playlist]: timeout: Union[int, float] = None, *args, **kwargs) -> Optional[Playlist]:
@ -2134,6 +2161,10 @@ class Client(YandexMusicObject):
generateTokenByUsernameAndPassword = generate_token_by_username_and_password generateTokenByUsernameAndPassword = generate_token_by_username_and_password
#: Псевдоним для :attr:`account_status` #: Псевдоним для :attr:`account_status`
accountStatus = account_status accountStatus = account_status
#: Псевдоним для :attr:`account_settings`
accountSettings = account_settings
#: Псевдоним для :attr:`account_settings_set`
accountSettingsSet = account_settings_set
#: Псевдоним для :attr:`permission_alerts` #: Псевдоним для :attr:`permission_alerts`
permissionAlerts = permission_alerts permissionAlerts = permission_alerts
#: Псевдоним для :attr:`account_experiments` #: Псевдоним для :attr:`account_experiments`
@ -2154,8 +2185,12 @@ class Client(YandexMusicObject):
albumsWithTracks = albums_with_tracks albumsWithTracks = albums_with_tracks
#: Псевдоним для :attr:`search_suggest` #: Псевдоним для :attr:`search_suggest`
searchSuggest = search_suggest searchSuggest = search_suggest
#: Псевдоним для :attr:`users_settings`
usersSettings = users_settings
#: Псевдоним для :attr:`users_playlists` #: Псевдоним для :attr:`users_playlists`
usersPlaylists = users_playlists usersPlaylists = users_playlists
#: Псевдоним для :attr:`users_playlists_recommendations`
usersPlaylistsRecommendations = users_playlists_recommendations
#: Псевдоним для :attr:`users_playlists_create` #: Псевдоним для :attr:`users_playlists_create`
usersPlaylistsCreate = users_playlists_create usersPlaylistsCreate = users_playlists_create
#: Псевдоним для :attr:`users_playlists_delete` #: Псевдоним для :attr:`users_playlists_delete`

ファイルの表示

@ -3,7 +3,8 @@ from typing import TYPE_CHECKING, Optional, List
from yandex_music import YandexMusicObject from yandex_music import YandexMusicObject
if TYPE_CHECKING: if TYPE_CHECKING:
from yandex_music import Client, User, Cover, MadeFor, TrackShort, PlaylistAbsence, PlayCounter from yandex_music import Client, User, Cover, MadeFor, TrackShort, PlaylistAbsence, PlayCounter,\
PlaylistRecommendations
class Playlist(YandexMusicObject): class Playlist(YandexMusicObject):
@ -168,6 +169,13 @@ class Playlist(YandexMusicObject):
def playlist_id(self) -> str: def playlist_id(self) -> str:
return f'{self.owner.uid}:{self.kind}' return f'{self.owner.uid}:{self.kind}'
def get_recommendations(self, *args, **kwargs) -> Optional['PlaylistRecommendations']:
"""Сокращение для::
client.users_playlists_recommendations(playlist.kind, playlist.owner.uid, *args, **kwargs)
"""
return self.client.users_playlists_recommendations(self.kind, self.owner.uid, *args, **kwargs)
def download_animated_cover(self, filename: str, size: str = '200x200') -> None: def download_animated_cover(self, filename: str, size: str = '200x200') -> None:
"""Загрузка анимированной обложки. """Загрузка анимированной обложки.
@ -263,6 +271,8 @@ class Playlist(YandexMusicObject):
isMine = is_mine isMine = is_mine
#: Псевдоним для :attr:`playlist_id` #: Псевдоним для :attr:`playlist_id`
playlistId = playlist_id playlistId = playlist_id
#: Псевдоним для :attr:`get_recommendations`
getRecommendations = get_recommendations
#: Псевдоним для :attr:`download_animated_cover` #: Псевдоним для :attr:`download_animated_cover`
downloadAnimatedCover = download_animated_cover downloadAnimatedCover = download_animated_cover
#: Псевдоним для :attr:`download_og_image` #: Псевдоним для :attr:`download_og_image`

ファイルの表示

@ -0,0 +1,55 @@
from typing import TYPE_CHECKING, Optional, List
from yandex_music import YandexMusicObject
if TYPE_CHECKING:
from yandex_music import Client, Track
class PlaylistRecommendations(YandexMusicObject):
"""Класс, представляющий рекомендации для плейлиста.
Attributes:
tracks (:obj:`list` из :obj:`yandex_music.Track`): Список рекомендованных треков.
batch_id (:obj:`str`): Уникальный идентификатор партии треков.
client (:obj:`yandex_music.Client`): Клиент Yandex Music.
Args:
tracks (:obj:`list` из :obj:`yandex_music.Track`): Список рекомендованных треков.
batch_id (:obj:`str`, optional): Уникальный идентификатор партии треков.
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
**kwargs: Произвольные ключевые аргументы полученные от API.
"""
def __init__(self,
tracks: List['Track'],
batch_id: Optional[str] = None,
client: Optional['Client'] = None,
**kwargs) -> None:
super().handle_unknown_kwargs(self, **kwargs)
self.batch_id = batch_id
self.tracks = tracks
self.client = client
self._id_attrs = (self.batch_id, self.tracks)
@classmethod
def de_json(cls, data: dict, client: 'Client') -> Optional['PlaylistRecommendations']:
"""Десериализация объекта.
Args:
data (:obj:`dict`): Поля и значения десериализуемого объекта.
client (:obj:`yandex_music.Client`, optional): Клиент Yandex Music.
Returns:
:obj:`yandex_music.PlaylistRecommendations`: Рекомендации для плейлиста.
"""
if not data:
return None
data = super(PlaylistRecommendations, cls).de_json(data, client)
from yandex_music import Track
data['tracks'] = Track.de_list(data.get('tracks'), client)
return cls(client=client, **data)