Skip to content
This repository was archived by the owner on Jan 22, 2022. It is now read-only.

Support random mixes without creating a radio station #263

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 104 additions & 0 deletions gmusicapi/clients/mobileclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,110 @@ def get_station_tracks(self, station_id, num_tracks=25):

return stations[0].get('tracks', [])

def get_artist_mix_tracks(self, artist_id, num_tracks=25):
"""Returns a list of dictionaries that each represent a track.

:param artist_id: the id of the artist being related to the tracks to retreive
:param num_tracks: the number of tracks to retrieve

See :func:`get_all_songs` for the format of a track dictionary.
"""

seed = {'artistId': artist_id, 'seedType': 3}

res = self._make_call(mobileclient.ListMixTracks, seed,
num_tracks, recently_played=[])

stations = res.get('data', {}).get('stations')
if not stations:
return []

return stations[0].get('tracks', [])

def get_artist_only_mix_tracks(self, artist_id, num_tracks=25):
"""Returns a list of dictionaries that each represent a track.

:param artist_id: the id of the artist to retreive tracks from
:param num_tracks: the number of tracks to retrieve

See :func:`get_all_songs` for the format of a track dictionary.
"""

seed = {'artistId': artist_id, 'seedType': 7}

res = self._make_call(mobileclient.ListMixTracks, seed,
num_tracks, recently_played=[])

stations = res.get('data', {}).get('stations')
if not stations:
return []

return stations[0].get('tracks', [])

def get_album_mix_tracks(self, album_id, num_tracks=25):
"""Returns a list of dictionaries that each represent a track.

:param album_id: the id of the album being related to the tracks to retreive
:param num_tracks: the number of tracks to retrieve

See :func:`get_all_songs` for the format of a track dictionary.
"""

seed = {'albumId': album_id}

res = self._make_call(mobileclient.ListMixTracks, seed,
num_tracks, recently_played=[])

stations = res.get('data', {}).get('stations')
if not stations:
return []

return stations[0].get('tracks', [])

def get_track_mix_tracks(self, track_id, num_tracks=25):
"""Returns a list of dictionaries that each represent a track.

:param track_id: the id of the track being related to the tracks to retreive
:param num_tracks: the number of tracks to retrieve

See :func:`get_all_songs` for the format of a track dictionary.
"""

seed = {}
if track_id[0] == 'T':
seed['trackId'] = track_id
else:
seed['trackLockerId'] = track_id

res = self._make_call(mobileclient.ListMixTracks, seed,
num_tracks, recently_played=[])

stations = res.get('data', {}).get('stations')
if not stations:
return []

return stations[0].get('tracks', [])

def get_genre_mix_tracks(self, genre_id, num_tracks=25):
"""Returns a list of dictionaries that each represent a track.

:param genre_id: the id of the genre to retrieve tracks from
:param num_tracks: the number of tracks to retrieve

See :func:`get_all_songs` for the format of a track dictionary.
"""

seed = {'genreId': genre_id}

res = self._make_call(mobileclient.ListMixTracks, seed,
num_tracks, recently_played=[])

stations = res.get('data', {}).get('stations')
if not stations:
return []

return stations[0].get('tracks', [])

def search_all_access(self, query, max_results=50):
"""Queries the server for All Access songs and albums.

Expand Down
48 changes: 48 additions & 0 deletions gmusicapi/protocol/mobileclient.py
Original file line number Diff line number Diff line change
Expand Up @@ -704,6 +704,54 @@ def filter_response(msg):
return filtered


class ListMixTracks(McCall):
_res_schema = {
'type': 'object',
'additionalProperties': False,
'properties': {
'kind': {'type': 'string'},
'data': {'type': 'object',
'stations': {'type': 'array', 'items': sj_station},
'required': False,
},
},
}

static_headers = {'Content-Type': 'application/json'}
static_params = {'alt': 'json'}
static_method = 'POST'
static_url = sj_url + 'radio/stationfeed'

@staticmethod
def dynamic_data(seed, num_entries, recently_played):
"""
:param seed
:param num_entries: maximum number of tracks to return
:param recently_played: a list of...song ids? never seen an example
"""
#TODO
# clearly, this supports more than one at a time,
# but then that might introduce paging?
# I'll leave it for someone else

return json.dumps({'contentFilter': 1,
'stations': [
{
'numEntries': num_entries,
'seed': seed,
'recentlyPlayed': recently_played
}
]})

@staticmethod
def filter_response(msg):
filtered = copy.deepcopy(msg)
if 'stations' in filtered['data']:
filtered['data']['stations'] = \
["<%s stations>" % len(filtered['data']['stations'])]
return filtered


class BatchMutateStations(McBatchMutateCall):
static_method = 'POST'
static_url = sj_url + 'radio/editstation'
Expand Down