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.case_forms
yandex_music.playlist.playlist_id
yandex_music.playlist.playlist_recommendations
yandex_music.playlist.tag_result
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.playlist_absence import PlaylistAbsence
from .playlist.playlist import Playlist
from .playlist.playlist_recommendation import PlaylistRecommendations
from .shot.shot_type import ShotType
from .shot.shot_data import ShotData
@ -125,4 +126,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']
'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, \
Feed, Genre, Landing, Like, PermissionAlerts, Playlist, PromoCodeStatus, Search, Settings, ShotEvent, Supplement, \
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.utils.difference import Difference
from yandex_music.utils.request import Request
@ -823,6 +823,33 @@ class Client(YandexMusicObject):
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
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]:
@ -2134,6 +2161,10 @@ class Client(YandexMusicObject):
generateTokenByUsernameAndPassword = generate_token_by_username_and_password
#: Псевдоним для :attr:`account_status`
accountStatus = account_status
#: Псевдоним для :attr:`account_settings`
accountSettings = account_settings
#: Псевдоним для :attr:`account_settings_set`
accountSettingsSet = account_settings_set
#: Псевдоним для :attr:`permission_alerts`
permissionAlerts = permission_alerts
#: Псевдоним для :attr:`account_experiments`
@ -2154,8 +2185,12 @@ class Client(YandexMusicObject):
albumsWithTracks = albums_with_tracks
#: Псевдоним для :attr:`search_suggest`
searchSuggest = search_suggest
#: Псевдоним для :attr:`users_settings`
usersSettings = users_settings
#: Псевдоним для :attr:`users_playlists`
usersPlaylists = users_playlists
#: Псевдоним для :attr:`users_playlists_recommendations`
usersPlaylistsRecommendations = users_playlists_recommendations
#: Псевдоним для :attr:`users_playlists_create`
usersPlaylistsCreate = users_playlists_create
#: Псевдоним для :attr:`users_playlists_delete`

ファイルの表示

@ -3,7 +3,8 @@ from typing import TYPE_CHECKING, Optional, List
from yandex_music import YandexMusicObject
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):
@ -168,6 +169,13 @@ class Playlist(YandexMusicObject):
def playlist_id(self) -> str:
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:
"""Загрузка анимированной обложки.
@ -263,6 +271,8 @@ class Playlist(YandexMusicObject):
isMine = is_mine
#: Псевдоним для :attr:`playlist_id`
playlistId = playlist_id
#: Псевдоним для :attr:`get_recommendations`
getRecommendations = get_recommendations
#: Псевдоним для :attr:`download_animated_cover`
downloadAnimatedCover = download_animated_cover
#: Псевдоним для :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)