New supported objects: Station, StationResult, StationTrackResult, Value, Sequence, RotorSettings, Restrictions, Id, Enum, DiscreteScale, DashBoard, AdParams

The following methods are wrapped:
- /rotor/account/status
- /rotor/stations/dashboard
- /rotor/stations/list
- /rotor/station/genre:{genre}/feedback
- /rotor/station/genre:{genre}/info
- /rotor/station/genre:{genre}/tracks
The following fields are now optional: Account[region, passport_phones], Status[cache_limit, subeditor, subeditor_level, plus], Subscription[auto_renewable, can_start_trial, mcdonalds]
Added new fields: Subscription.end, Status[skips_per_hour, station_exists, premium_region], Track..preview_duration_ms
Fixed downloading the cover of the track
このコミットが含まれているのは:
Marshal 2019-06-03 16:16:24 +03:00
コミット 1cd21aae01
19個のファイルの変更501行の追加16行の削除

ファイルの表示

@ -80,6 +80,19 @@ from genre.title import Title
from genre.images import Images
from genre.genre import Genre
from rotor.id import Id
from rotor.value import Value
from rotor.enum import Enum
from rotor.sequence import Sequence
from rotor.discrete_scale import DiscreteScale
from rotor.ad_params import AdParams
from rotor.restrictions import Restrictions
from rotor.rotor_settings import RotorSettings
from rotor.station import Station
from rotor.station_tracks_result import StationTracksResult
from rotor.station_result import StationResult
from rotor.dashboard import Dashboard
__all__ = ['YandexMusicObject', 'Account', 'PassportPhone', 'InvocationInfo', 'Permissions', 'Plus', 'Subscription',
'Status', 'Price', 'Product', 'AutoRenewable', 'Settings', 'PermissionAlerts', 'Experiments', 'Cover',
'Ratings', 'Counts', 'Link', 'Artist', 'User', 'CaseForms', 'MadeFor', 'Label', 'Album', 'PlayCounter',
@ -89,4 +102,5 @@ __all__ = ['YandexMusicObject', 'Account', 'PassportPhone', 'InvocationInfo', 'P
'ArtistSearchResult', 'PlaylistSearchResult', 'TrackSearchResult', 'VideoSearchResult', 'Search',
'Suggestions', 'MixLink', 'BlockEntity', 'Block', 'PlayContextsData', 'TrackId', 'TrackShortOld',
'PersonalPlaylistsData', 'Promotion', 'Landing', 'Chart', 'ChartItem', 'PlayContext', 'Title', 'Genre',
'Icon', 'Images']
'Icon', 'Images', 'Id', 'Station', 'Dashboard', 'RotorSettings', 'AdParams', 'Restrictions', 'Value', 'Enum',
'DiscreteScale', 'StationResult', 'Sequence', 'StationTracksResult']

ファイルの表示

@ -3,7 +3,7 @@ from datetime import datetime
from yandex_music import YandexMusicObject, Status, Settings, PermissionAlerts, Experiments, Artist, Album, Playlist, \
TracksLikes, Track, AlbumsLikes, ArtistsLikes, PlaylistsLikes, Feed, PromoCodeStatus, DownloadInfo, Search, \
Suggestions, Landing, Genre
Suggestions, Landing, Genre, Dashboard, StationResult, StationTracksResult
from yandex_music.utils.request import Request
from yandex_music.utils.difference import Difference
from yandex_music.exceptions import InvalidToken
@ -289,6 +289,74 @@ class Client(YandexMusicObject):
return self.users_playlists_change(kind, diff.to_json(), revision, user_id, timeout, *args, **kwargs)
def rotor_account_status(self, timeout=None, *args, **kwargs):
url = f'{self.base_url}/rotor/account/status'
result = self._request.get(url, timeout=timeout, *args, **kwargs)
return Status.de_json(result, self)
def rotor_stations_dashboard(self, timeout=None, *args, **kwargs):
url = f'{self.base_url}/rotor/stations/dashboard'
result = self._request.get(url, timeout=timeout, *args, **kwargs)
return Dashboard.de_json(result, self)
def rotor_stations_list(self, language: str = 'en', timeout=None, *args, **kwargs):
url = f'{self.base_url}/rotor/stations/list'
result = self._request.get(url, {'language': language}, timeout=timeout, *args, **kwargs)
return StationResult.de_list(result, self)
def rotor_station_genre_feedback(self, genre: str, type_: str, timestamp=None, from_: str = None,
batch_id: str or int = None, track_id: str = None, timeout=None, *args, **kwargs):
if timestamp is None:
timestamp = datetime.now().timestamp()
url = f'{self.base_url}/rotor/station/genre:{genre}/feedback'
params = {}
data = {
'type': type_,
'timestamp': timestamp
}
if batch_id and track_id:
data.update({'trackId': track_id})
params = {'batch-id': batch_id}
if from_:
data.update({'from': from_})
result = self._request.post(url, params=params, json=data, timeout=timeout, *args, **kwargs)
return result == 'ok'
def rotor_station_genre_feedback_radio_started(self, genre: str, from_: str, timestamp=None,
timeout=None, *args, **kwargs):
return self.rotor_station_genre_feedback(genre, 'radioStarted', timestamp, from_, timeout, *args, **kwargs)
def rotor_station_genre_feedback_track_started(self, genre: str, track_id: str, batch_id: str or int,
timestamp=None, timeout=None, *args, **kwargs):
return self.rotor_station_genre_feedback(genre, 'trackStarted', timestamp, track_id=track_id, batch_id=batch_id,
timeout=timeout, *args, **kwargs)
def rotor_station_genre_info(self, genre: str, timeout=None, *args, **kwargs):
url = f'{self.base_url}/rotor/station/genre:{genre}/info'
result = self._request.get(url, timeout=timeout, *args, **kwargs)
return StationResult.de_list(result, self)
def rotor_station_genre_tracks(self, genre: str, timeout=None, *args, **kwargs):
url = f'{self.base_url}/rotor/station/genre:{genre}/tracks'
result = self._request.get(url, timeout=timeout, *args, **kwargs)
return StationTracksResult.de_json(result, self)
def _add_like(self, object_type: str, ids: str or int or list, remove: bool = False, user_id: str or int = None,
timeout=None, *args, **kwargs):
if user_id is None:

35
yandex_music/rotor/ad_params.py ノーマルファイル
ファイルの表示

@ -0,0 +1,35 @@
from yandex_music import YandexMusicObject
class AdParams(YandexMusicObject):
def __init__(self,
partner_id,
category_id,
page_ref,
target_ref,
other_params,
ad_volume,
genre_id=None,
genre_name=None,
client=None,
**kwargs):
self.partner_id = partner_id
self.category_id = category_id
self.page_ref = page_ref
self.target_ref = target_ref
self.other_params = other_params
self.ad_volume = ad_volume
self.genre_id = genre_id
self.genre_name = genre_name
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(AdParams, cls).de_json(data, client)
return cls(client=client, **data)

27
yandex_music/rotor/dashboard.py ノーマルファイル
ファイルの表示

@ -0,0 +1,27 @@
from yandex_music import YandexMusicObject
class Dashboard(YandexMusicObject):
def __init__(self,
dashboard_id,
stations,
pumpkin,
client=None,
**kwargs):
self.dashboard_id = dashboard_id
self.stations = stations
self.pumpkin = pumpkin
self.client = client
self._id_attrs = (self.dashboard_id, )
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Dashboard, cls).de_json(data, client)
from yandex_music import StationResult
data['stations'] = StationResult.de_list(data.get('stations'), client)
return cls(client=client, **data)

29
yandex_music/rotor/discrete_scale.py ノーマルファイル
ファイルの表示

@ -0,0 +1,29 @@
from yandex_music import YandexMusicObject
class DiscreteScale(YandexMusicObject):
def __init__(self,
type,
name,
min,
max,
client=None,
**kwargs):
self.type = type
self.name = name
self.min = min
self.max = max
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(DiscreteScale, cls).de_json(data, client)
from yandex_music import Value
data['min'] = Value.de_json(data.get('min'), client)
data['max'] = Value.de_json(data.get('max'), client)
return cls(client=client, **data)

26
yandex_music/rotor/enum.py ノーマルファイル
ファイルの表示

@ -0,0 +1,26 @@
from yandex_music import YandexMusicObject
class Enum(YandexMusicObject):
def __init__(self,
type,
name,
possible_values,
client=None,
**kwargs):
self.type = type
self.name = name
self.possible_values = possible_values
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Enum, cls).de_json(data, client)
from yandex_music import Value
data['possible_values'] = Value.de_list(data.get('possible_values'), client)
return cls(client=client, **data)

22
yandex_music/rotor/id.py ノーマルファイル
ファイルの表示

@ -0,0 +1,22 @@
from yandex_music import YandexMusicObject
class Id(YandexMusicObject):
def __init__(self,
type,
tag,
client=None,
**kwargs):
self.type = type
self.tag = tag
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Id, cls).de_json(data, client)
return cls(client=client, **data)

34
yandex_music/rotor/restrictions.py ノーマルファイル
ファイルの表示

@ -0,0 +1,34 @@
from yandex_music import YandexMusicObject
class Restrictions(YandexMusicObject):
def __init__(self,
language,
diversity,
mood=None,
energy=None,
mood_energy=None,
client=None,
**kwargs):
self.language = language
self.diversity = diversity
self.mood = mood
self.energy = energy
self.mood_energy = mood_energy
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Restrictions, cls).de_json(data, client)
from yandex_music import Enum, DiscreteScale
for key, value in data.items():
restriction_type = data[key].get('type')
data[key] = Enum.de_json(data[key], client) if restriction_type == 'enum'\
else DiscreteScale.de_json(data[key], client)
return cls(client=client, **data)

29
yandex_music/rotor/rotor_settings.py ノーマルファイル
ファイルの表示

@ -0,0 +1,29 @@
from yandex_music import YandexMusicObject
class RotorSettings(YandexMusicObject):
def __init__(self,
language,
diversity,
mood=None,
energy=None,
mood_energy=None,
client=None,
**kwargs):
self.language = language
self.diversity = diversity
self.mood = mood
self.energy = energy
self.mood_energy = mood_energy
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(RotorSettings, cls).de_json(data, client)
return cls(client=client, **data)

37
yandex_music/rotor/sequence.py ノーマルファイル
ファイルの表示

@ -0,0 +1,37 @@
from yandex_music import YandexMusicObject
class Sequence(YandexMusicObject):
def __init__(self,
type,
track,
liked,
client=None,
**kwargs):
self.type = type
self.track = track
self.liked = liked
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Sequence, cls).de_json(data, client)
from yandex_music import Track
data['track'] = Track.de_json(data.get('track'), client)
return cls(client=client, **data)
@classmethod
def de_list(cls, data, client):
if not data:
return []
sequences = list()
for sequence in data:
sequences.append(cls.de_json(sequence, client))
return sequences

45
yandex_music/rotor/station.py ノーマルファイル
ファイルの表示

@ -0,0 +1,45 @@
from yandex_music import YandexMusicObject
class Station(YandexMusicObject):
def __init__(self,
id,
name,
icon,
mts_icon,
geocell_icon,
id_for_from,
restrictions,
restrictions2,
parent_id=None,
client=None,
**kwargs):
self.id = id
self.name = name
self.icon = icon
self.mts_icon = mts_icon
self.geocell_icon = geocell_icon
self.id_for_from = id_for_from
self.restrictions = restrictions
self.restrictions2 = restrictions2
self.parent_id = parent_id
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Station, cls).de_json(data, client)
from yandex_music import Id, Icon, Restrictions
data['id'] = Id.de_json(data.get('id'), client)
data['parent_id'] = Id.de_json(data.get('parent_id'), client)
data['icon'] = Icon.de_json(data.get('icon'), client)
data['mts_icon'] = Icon.de_json(data.get('mts_icon'), client)
data['geocell_icon'] = Icon.de_json(data.get('geocell_icon'), client)
data['restrictions'] = Restrictions.de_json(data.get('restrictions'), client)
data['restrictions2'] = Restrictions.de_json(data.get('restrictions2'), client)
return cls(client=client, **data)

46
yandex_music/rotor/station_result.py ノーマルファイル
ファイルの表示

@ -0,0 +1,46 @@
from yandex_music import YandexMusicObject
class StationResult(YandexMusicObject):
def __init__(self,
station,
settings,
settings2,
ad_params,
explanation=None,
prerolls=None,
client=None,
**kwargs):
self.station = station
self.settings = settings
self.settings2 = settings2
self.ad_params = ad_params
self.explanation = explanation
self.prerolls = prerolls
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(StationResult, cls).de_json(data, client)
from yandex_music import Station, RotorSettings, AdParams
data['station'] = Station.de_json(data.get('station'), client)
data['settings'] = RotorSettings.de_json(data.get('settings'), client)
data['settings2'] = RotorSettings.de_json(data.get('settings2'), client)
data['ad_params'] = AdParams.de_json(data.get('ad_params'), client)
return cls(client=client, **data)
@classmethod
def de_list(cls, data, client):
if not data:
return []
station_results = list()
for station_result in data:
station_results.append(cls.de_json(station_result, client))
return station_results

29
yandex_music/rotor/station_tracks_result.py ノーマルファイル
ファイルの表示

@ -0,0 +1,29 @@
from yandex_music import YandexMusicObject
class StationTracksResult(YandexMusicObject):
def __init__(self,
id,
sequence,
batch_id,
pumpkin,
client=None,
**kwargs):
self.id = id
self.sequence = sequence
self.batch_id = batch_id
self.pumpkin = pumpkin
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(StationTracksResult, cls).de_json(data, client)
from yandex_music import Id, Sequence
data['id'] = Id.de_json(data.get('id'), client)
data['sequence'] = Sequence.de_list(data.get('sequence'), client)
return cls(client=client, **data)

34
yandex_music/rotor/value.py ノーマルファイル
ファイルの表示

@ -0,0 +1,34 @@
from yandex_music import YandexMusicObject
class Value(YandexMusicObject):
def __init__(self,
value,
name,
client=None,
**kwargs):
self.value = value
self.name = name
self.client = client
@classmethod
def de_json(cls, data, client):
if not data:
return None
data = super(Value, cls).de_json(data, client)
return cls(client=client, **data)
@classmethod
def de_list(cls, data, client):
if not data:
return []
values = list()
for value in data:
values.append(cls.de_json(value, client))
return values

ファイルの表示

@ -8,7 +8,6 @@ class Account(YandexMusicObject):
now,
uid,
login,
region,
full_name,
second_name,
first_name,
@ -16,7 +15,8 @@ class Account(YandexMusicObject):
birthday,
service_available,
hosted_user,
passport_phones,
region=None,
passport_phones=None,
registered_at=None,
has_info_for_app_metrica=False,
client=None,

ファイルの表示

@ -5,23 +5,29 @@ class Status(YandexMusicObject):
def __init__(self,
account,
permissions,
cache_limit,
subscription,
subeditor,
subeditor_level,
plus,
cache_limit=None,
subeditor=None,
subeditor_level=None,
plus=None,
default_email=None,
skips_per_hour=None,
station_exists=None,
premium_region=None,
client=None,
**kwargs):
self.account = account
self.permissions = permissions
self.cache_limit = cache_limit
self.subscription = subscription
self.cache_limit = cache_limit
self.subeditor = subeditor
self.subeditor_level = subeditor_level
self.plus = plus
self.default_email = default_email
self.skips_per_hour = skips_per_hour
self.station_exists = station_exists
self.premium_region = premium_region
self.client = client
self._id_attrs = (self.account,)

ファイルの表示

@ -3,14 +3,16 @@ from yandex_music import YandexMusicObject
class Subscription(YandexMusicObject):
def __init__(self,
auto_renewable,
can_start_trial,
mcdonalds,
auto_renewable=None,
can_start_trial=None,
mcdonalds=None,
end=None,
client=None,
**kwargs):
self.auto_renewable = auto_renewable
self.can_start_trial = can_start_trial
self.mcdonalds = mcdonalds
self.end = end
self.client = client

ファイルの表示

@ -24,6 +24,7 @@ class Track(YandexMusicObject):
available_as_rbt=None,
content_warning=None,
explicit=None,
preview_duration_ms=None,
client=None,
**kwargs):
self.id = id
@ -37,7 +38,7 @@ class Track(YandexMusicObject):
self.real_id = real_id
self.og_image = og_image
self.type = type
self.cover_uri = cover_uri
self.cover_uri = 'https://' + cover_uri
self.major = major
self.duration_ms = duration_ms
self.storage_dir = storage_dir
@ -48,6 +49,7 @@ class Track(YandexMusicObject):
self.available_as_rbt = available_as_rbt
self.content_warning = content_warning
self.explicit = explicit
self.preview_duration_ms = preview_duration_ms
self.download_info = None
@ -59,8 +61,8 @@ class Track(YandexMusicObject):
return self.download_info
def download_cover(self, filename):
self.client._request.download(self.cover_uri, filename)
def download_cover(self, filename, size='200x200'):
self.client._request.download(self.cover_uri.replace('%%', size), filename)
def download(self, filename, codec='mp3', bitrate_in_kbps=192):
if self.download_info is None: