Protocol Details

The following definitions represent known endpoints relating to Google Music. They are organized by the client that uses them.

The names of these classes are semantic, and may not match their actual endpoint.

Most of the time, endusers will want to use one of the Client Interfaces. However, any of the definitions listed here can be called by using the _make_call member of a Client and providing the parameters needed by dynamic_* functions.

It’s tough to generate the exact schema of every call in a readable fashion, so this information is left out. If you need exact specifications, look at the code - or submit a pull request to generate the docs =)

Android Client

Calls made by the mobile client.

class gmusicapi.protocol.mobileclient.BatchMutatePlaylistEntries
static build_plentry_adds(playlist_id, song_ids)
Parameters:
  • playlist_id
  • song_ids
static build_plentry_deletes(entry_ids)
Parameters:entry_ids
static build_plentry_reorder(plentry, preceding_cid, following_cid)
Parameters:
  • plentry – plentry that is moving
  • preceding_cid – clientid of entry that will be before the moved entry
  • following_cid – “” that will be after the moved entry
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/plentriesbatch'
class gmusicapi.protocol.mobileclient.BatchMutatePlaylists
static build_playlist_adds(pl_descriptions)
Parameters:pl_descriptions – [{‘name’: ‘’, ‘description’: ‘’,’public’: ‘’}]
static build_playlist_deletes(playlist_ids)
Parameters:playlist_ids
static build_playlist_updates(pl_updates)
Parameters:pl_updates – [{‘id’: ‘’, name’: ‘’, ‘description’: ‘’, ‘public’: ‘’}]
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/playlistbatch'
class gmusicapi.protocol.mobileclient.BatchMutatePodcastSeries
static build_podcast_updates(updates)
Parameters:updates{'seriesId': '', 'subscribed': '', 'userPreferences': {'notifyOnNewEpisode': '', 'subscribed': ''}}...
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/podcastseries/batchmutate'
class gmusicapi.protocol.mobileclient.BatchMutateStations
static build_add(name, seed, include_tracks, num_tracks, recent_datetime=None)
Parameters:
  • name – the title
  • seed – a dict {‘itemId’: id, ‘seedType’: int}
  • include_tracks – if True, return num_tracks tracks in the response
  • num_tracks
  • recent_datetime – purpose unknown. defaults to now.
static build_deletes(station_ids)
Parameters:station_ids
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/radio/editstation'
class gmusicapi.protocol.mobileclient.BatchMutateTracks
static build_track_add(store_track_info)
Parameters:store_track_info – sj_track
static build_track_deletes(track_ids)
Parameters:track_ids
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/trackbatch'
class gmusicapi.protocol.mobileclient.Config
static_method = 'GET'
static_url = 'https://mclients.googleapis.com/sj/v2.5/config'
class gmusicapi.protocol.mobileclient.DeauthDevice

Deauthorize a device from devicemanagementinfo.

static dynamic_params(device_id)
static_method = 'DELETE'
static_url = 'https://mclients.googleapis.com/sj/v2.5/devicemanagementinfo'
class gmusicapi.protocol.mobileclient.GetAlbum
static dynamic_params(album_id, tracks)
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/fetchalbum'
class gmusicapi.protocol.mobileclient.GetArtist
static dynamic_params(artist_id, include_albums, num_top_tracks, num_rel_artist)
Parameters:
  • include_albums – bool
  • num_top_tracks – int
  • num_rel_artist – int
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/fetchartist'
class gmusicapi.protocol.mobileclient.GetBrowsePodcastHierarchy
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/podcast/browsehierarchy'
class gmusicapi.protocol.mobileclient.GetDeviceManagementInfo

Get registered device information.

static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/devicemanagementinfo'
class gmusicapi.protocol.mobileclient.GetGenres
static dynamic_params(parent_genre_id)
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/explore/genres'
class gmusicapi.protocol.mobileclient.GetPodcastEpisode
static dynamic_params(podcast_episode_id)
static_headers = {'Content-Type': 'application/json'}
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/podcast/fetchepisode'
class gmusicapi.protocol.mobileclient.GetPodcastEpisodeStreamUrl
static_method = 'GET'
static_url = 'https://mclients.googleapis.com/music/fplay'
class gmusicapi.protocol.mobileclient.GetPodcastSeries
static dynamic_params(podcast_series_id, num_episodes)
static_headers = {'Content-Type': 'application/json'}
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/podcast/fetchseries'
class gmusicapi.protocol.mobileclient.GetStationTrackStreamUrl
static dynamic_headers(item_id, wentry_id, session_token, quality)
classmethod dynamic_params(song_id, wentry_id, session_token, quality)
static parse_response(response)

Parses a requests.Response to data.

static_method = 'GET'
static_url = 'https://mclients.googleapis.com/music/wplay'
class gmusicapi.protocol.mobileclient.GetStoreTrack
static dynamic_params(track_id)
static_headers = {'Content-Type': 'application/json'}
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/fetchtrack'
class gmusicapi.protocol.mobileclient.GetStreamUrl
static_method = 'GET'
static_url = 'https://mclients.googleapis.com/music/mplay'
class gmusicapi.protocol.mobileclient.IncrementPlayCount
static dynamic_data(sid, plays, playtime)
static_headers = {'Content-Type': 'application/json'}
static_method = 'POST'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/trackstats'
class gmusicapi.protocol.mobileclient.ListBrowsePodcastSeries
classmethod dynamic_params(id=None)
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/podcast/browse'
class gmusicapi.protocol.mobileclient.ListListenNowItems
static_method = 'GET'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/listennow/getlistennowitems'
class gmusicapi.protocol.mobileclient.ListListenNowSituations
classmethod dynamic_data()
static_headers = {'Content-Type': 'application/json'}
static_method = 'POST'
static_params = {'alt': 'json'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/listennow/situations'
class gmusicapi.protocol.mobileclient.ListPlaylistEntries
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/plentryfeed'
class gmusicapi.protocol.mobileclient.ListPlaylists
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/playlistfeed'
class gmusicapi.protocol.mobileclient.ListPodcastEpisodes
classmethod dynamic_data(device_id=None, updated_after=None, start_token=None, max_results=None)
Parameters:
  • updated_after – ignored
  • start_token – nextPageToken from a previous response
  • max_results – a positive int; if not provided, server defaults to 1000
static dynamic_headers(device_id, updated_after=None, start_token=None, max_results=None)
classmethod dynamic_params(device_id=None, updated_after=None, start_token=None, max_results=None)
Parameters:updated_after – datetime.datetime; defaults to epoch
static_method = 'GET'
static_url = 'https://mclients.googleapis.com/sj/v2.5/podcastepisode'
class gmusicapi.protocol.mobileclient.ListPodcastSeries
classmethod dynamic_data(device_id=None, updated_after=None, start_token=None, max_results=None)
Parameters:
  • updated_after – ignored
  • start_token – nextPageToken from a previous response
  • max_results – a positive int; if not provided, server defaults to 1000
static dynamic_headers(device_id, updated_after=None, start_token=None, max_results=None)
classmethod dynamic_params(device_id=None, updated_after=None, start_token=None, max_results=None)
Parameters:updated_after – datetime.datetime; defaults to epoch
static_method = 'GET'
static_url = 'https://mclients.googleapis.com/sj/v2.5/podcastseries'
class gmusicapi.protocol.mobileclient.ListPromotedTracks
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/ephemeral/top'
class gmusicapi.protocol.mobileclient.ListSharedPlaylistEntries
classmethod dynamic_data(share_token, updated_after=None, start_token=None, max_results=None)
Parameters:
  • share_token – from a shared playlist
  • updated_after – ignored
  • start_token – nextPageToken from a previous response
  • max_results – a positive int; if not provided, server defaults to 1000
classmethod dynamic_params(share_token, updated_after=None, start_token=None, max_results=None)
Parameters:updated_after – datetime.datetime; defaults to epoch
classmethod parse_response(response)

Parses a requests.Response to data.

static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/plentries/shared'
class gmusicapi.protocol.mobileclient.ListStationTracks
static dynamic_data(station_id, num_entries, recently_played)
Parameters:
  • station_id
  • num_entries – maximum number of tracks to return
  • recently_played – a list of…song ids? never seen an example
static_headers = {'Content-Type': 'application/json'}
static_method = 'POST'
static_params = {'alt': 'json', 'include-tracks': 'true'}
static_url = 'https://mclients.googleapis.com/sj/v2.5/radio/stationfeed'
class gmusicapi.protocol.mobileclient.ListStations
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/radio/station'
class gmusicapi.protocol.mobileclient.ListTracks
static_method = 'POST'
static_url = 'https://mclients.googleapis.com/sj/v2.5/trackfeed'
class gmusicapi.protocol.mobileclient.McBatchMutateCall

Abc for batch mutation calls.

classmethod check_success(response, msg)

Raise CallFailure on problems.

Parameters:
  • response – a requests.Response
  • msg – the result of parse_response on response
static dynamic_data(mutations)
Parameters:mutations – list of mutation dictionaries
static_headers = {'Content-Type': 'application/json'}
static_params = {'alt': 'json'}
class gmusicapi.protocol.mobileclient.McListCall

Abc for calls that list a resource.

classmethod dynamic_data(updated_after=None, start_token=None, max_results=None)
Parameters:
  • updated_after – ignored
  • start_token – nextPageToken from a previous response
  • max_results – a positive int; if not provided, server defaults to 1000
classmethod dynamic_params(updated_after=None, start_token=None, max_results=None)
Parameters:updated_after – datetime.datetime; defaults to epoch
classmethod parse_response(response)

Parses a requests.Response to data.

static_headers = {'Content-Type': 'application/json'}
static_params = {'alt': 'json', 'include-tracks': 'true'}
class gmusicapi.protocol.mobileclient.McStreamCall
static dynamic_headers(item_id, device_id, quality)
classmethod dynamic_params(item_id, device_id, quality)
classmethod get_signature(item_id, salt=None)

Return a (sig, salt) pair for url signing.

static parse_response(response)

Parses a requests.Response to data.

static_allow_redirects = False
class gmusicapi.protocol.mobileclient.Search

Search for All Access tracks.

static dynamic_params(query, max_results)
static_method = 'GET'
static_params = {'ct': '1,2,3,4,5,6,7,8,9', 'ic': True}
static_url = 'https://mclients.googleapis.com/sj/v2.5/query'

Music Manager

Calls made by the Music Manager (related to uploading).

class gmusicapi.protocol.musicmanager.AuthenticateUploader

Sent to auth, reauth, or register our upload client.

classmethod check_success(response, msg)

Raise CallFailure on problems.

Parameters:
  • response – a requests.Response
  • msg – the result of parse_response on response
classmethod dynamic_data(uploader_id, uploader_friendly_name)
Parameters:
  • uploader_id – MM uses host MAC address
  • uploader_friendly_name – MM uses hostname
static_url = 'https://android.clients.google.com/upsj/upauth'
class gmusicapi.protocol.musicmanager.CancelUploadJobs

This call will cancel any outstanding upload jobs (ie from GetJobs). The Music Manager only calls it when the user changes the location of their local collection.

It doesn’t actually return anything useful.

static dynamic_data(uploader_id)
Parameters:uploader_id – id
static_method = 'POST'
static_url = 'https://android.clients.google.com/upsj/deleteuploadrequested'
class gmusicapi.protocol.musicmanager.DownloadTrack

Given a url, retrieve a track. Unlike the Webclient, this requires authentication.

The entire Requests.Response is returned.

static dynamic_url(url)
Parameters:url – result of a call to GetDownloadLink
classmethod parse_response(response)

Parse the cls.res_msg_type proto msg.

static_method = 'GET'
class gmusicapi.protocol.musicmanager.GetClientState
classmethod dynamic_data(uploader_id)
Parameters:uploader_id – MM uses host MAC address
static_url = 'https://android.clients.google.com/upsj/clientstate'

Get a url where a track can be downloaded.

Auth is not needed to retrieve the resulting url.

static dynamic_headers(sid, client_id)
static dynamic_params(sid, client_id)
classmethod parse_response(response)

Parse the cls.res_msg_type proto msg.

static_headers = {}
static_method = 'GET'
static_params = {'version': 2}
static_url = 'https://music.google.com/music/export'
class gmusicapi.protocol.musicmanager.GetUploadJobs
classmethod check_success(response, msg)

Raise CallFailure on problems.

Parameters:
  • response – a requests.Response
  • msg – the result of parse_response on response
classmethod dynamic_data(uploader_id)
Parameters:uploader_id – MM uses host MAC address
static_params = {'version': 1}
static_url = 'https://android.clients.google.com/upsj/getjobs'
class gmusicapi.protocol.musicmanager.GetUploadSession

Called when we want to upload; the server returns the url to use. This is a json call, and doesn’t share much with the other calls.

static dynamic_data(uploader_id, num_already_uploaded, track, filepath, server_id, do_not_rematch=False)

track is a locker_pb2.Track, and the server_id is from a metadata upload.

classmethod parse_response(response)

Parse the cls.res_msg_type proto msg.

static process_session(res)

Return (got_session, error_details). error_details is (should_retry, reason, error_code) or None if got_session.

static_method = 'POST'
static_url = 'https://uploadsj.clients.google.com/uploadsj/scottyagent'
class gmusicapi.protocol.musicmanager.ListTracks

List all tracks. Returns a subset of all available metadata. Can optionally filter for only free/purchased tracks.

classmethod check_success(response, msg)

Raise CallFailure on problems.

Parameters:
  • response – a requests.Response
  • msg – the result of parse_response on response
static dynamic_data(client_id, cont_token=None, export_type=1, updated_min=0)

Works similarly to the webclient method. Chunks are up to 1000 tracks.

Parameters:
  • client_id – an authorized uploader_id
  • cont_token – (optional) token to get the next library chunk.
  • export_type – 1=’ALL’, 2=’PURCHASED_AND_PROMOTIONAL’
  • updated_min – likely a timestamp; never seen an example of this != 0
static dynamic_headers(client_id, *args, **kwargs)
res_msg_type

alias of download_pb2.GetTracksToExportResponse

static_method = 'POST'
static_url = 'https://music.google.com/music/exportids'
class gmusicapi.protocol.musicmanager.ProvideSample

Give the server a scan and match sample. The sample is a 128k mp3 slice of the file, usually 15 seconds long.

static dynamic_data(filepath, server_challenge, track, uploader_id, mock_sample=None)

Raise OSError on transcoding problems, or ValueError for invalid input.

Parameters:mock_sample – if provided, will be sent in place of a proper sample
static_method = 'POST'
static_params = {'version': 1}
static_url = 'https://android.clients.google.com/upsj/sample'
class gmusicapi.protocol.musicmanager.UpdateUploadState

Notify the server that we will be starting/stopping/pausing our upload.

I believe this is used for the webclient ‘currently uploading’ widget, but that might also be the current_uploading information.

static dynamic_data(to_state, uploader_id)

Raise ValueError on problems.

Parameters:to_state – one of ‘start’, ‘paused’, or ‘stopped’
static_method = 'POST'
static_params = {'version': 1}
static_url = 'https://android.clients.google.com/upsj/uploadstate'
class gmusicapi.protocol.musicmanager.UploadFile

Called after getting a session to actually upload a file.

static dynamic_data(session_url, content_type, audio)
static dynamic_headers(session_url, content_type, audio)
static dynamic_url(session_url, content_type, audio)
classmethod parse_response(response)

Parse the cls.res_msg_type proto msg.

static_method = 'PUT'
class gmusicapi.protocol.musicmanager.UploadMetadata
count_fields = {'discnumber': ('disc_number', 'total_disc_count'), 'tracknumber': ('track_number', 'total_track_count')}
classmethod dynamic_data(tracks, uploader_id, do_not_rematch=False)
Parameters:
  • tracks – list of filled locker_pb2.Track
  • uploader_id
  • do_not_rematch – seems to be ignored
field_map = {'albumartist': 'album_artist', 'bpm': 'beats_per_minute'}
classmethod fill_track_info(filepath)

Given the path and contents of a track, return a filled locker_pb2.Track. On problems, raise ValueError.

static get_track_clientid(filepath)
shared_fields = ('album', 'artist', 'composer', 'genre')
static_params = {'version': 1}
static_url = 'https://android.clients.google.com/upsj/metadata'
gmusicapi.protocol.musicmanager.pb(f, *args, **kwargs)

Decorator to serialize a protobuf message.

Web Client

Calls made by the web client.

class gmusicapi.protocol.webclient.AddToPlaylist

Adds songs to a playlist.

static dynamic_data(playlist_id, song_ids)
Parameters:
  • playlist_id – id of the playlist to add to.
  • song_ids – a list of song ids
static_method = 'POST'
static_url = 'https://play.google.com/music/services/addtoplaylist'
class gmusicapi.protocol.webclient.ChangePlaylistOrder

Reorder existing tracks in a playlist.

static dynamic_data(playlist_id, song_ids_moving, entry_ids_moving, after_entry_id=None, before_entry_id=None)
Parameters:
  • playlist_id – id of the playlist getting reordered.
  • song_ids_moving – a list of consecutive song ids. Matches entry_ids_moving.
  • entry_ids_moving – a list of consecutive entry ids to move. Matches song_ids_moving.
  • after_entry_id – the entry id to place these songs after. Default first position.
  • before_entry_id – the entry id to place these songs before. Default last position.
static_method = 'POST'
static_url = 'https://play.google.com/music/services/changeplaylistorder'
class gmusicapi.protocol.webclient.ChangeSongMetadata

Edit the metadata of songs.

static dynamic_data(songs, session_id='')
Parameters:songs – a list of dicts {'id': '...', 'albumArtUrl': '...'}
static_method = 'POST'
static_params = {'format': 'jsarray'}
static_url = 'https://play.google.com/music/services/modifytracks'
class gmusicapi.protocol.webclient.CreatePlaylist

Adds songs to a playlist.

static dynamic_data(name, description, public, session_id='')
static_method = 'POST'
static_params = {'format': 'jsarray'}
static_url = 'https://play.google.com/music/services/createplaylist'
class gmusicapi.protocol.webclient.DeauthDevice

Deauthorize a device from GetSettings.

static dynamic_data(device_id, session_id)
static_method = 'POST'
static_url = 'https://play.google.com/music/services/modifysettings'
class gmusicapi.protocol.webclient.DeletePlaylist

Delete a playlist.

static dynamic_data(playlist_id)
Parameters:playlist_id – id of the playlist to delete.
static_method = 'POST'
static_url = 'https://play.google.com/music/services/deleteplaylist'
class gmusicapi.protocol.webclient.DeleteSongs

Delete a song from the entire library or a single playlist.

static dynamic_data(song_ids, playlist_id='all', entry_ids=None)
Parameters:
  • song_ids – a list of song ids.
  • playlist_id – playlist id to delete from, or ‘all’ for deleting from library.
  • entry_ids – when deleting from playlists, corresponding list of entry ids.
static_method = 'POST'
static_url = 'https://play.google.com/music/services/deletesong'
class gmusicapi.protocol.webclient.GetDownloadInfo

Get download links and counts for songs.

static dynamic_data(song_ids)
Param:(list) song_ids
static_method = 'POST'
static_url = 'https://play.google.com/music/services/multidownload'
class gmusicapi.protocol.webclient.GetSettings

Get data that populates the settings tab: labs and devices.

static dynamic_data(session_id)
Param:session_id
static_method = 'POST'
static_url = 'https://play.google.com/music/services/fetchsettings'
class gmusicapi.protocol.webclient.GetSharedPlaylist

Get the contents and metadata for a shared playlist.

static dynamic_data(session_id, share_token)
classmethod parse_response(response)

Parses a requests.Response to data.

static_method = 'POST'
static_params = {'format': 'jsarray'}
static_url = 'https://play.google.com/music/services/loadsharedplaylist'
class gmusicapi.protocol.webclient.GetStreamUrl

Used to request a streaming link of a track.

static dynamic_params(song_id)
required_auth = AuthTypes(xt=False, sso=True, oauth=False, gpsoauth=False)
static_method = 'GET'
static_url = 'https://play.google.com/music/play'
class gmusicapi.protocol.webclient.Init

Called one time per session, immediately after login.

This performs one-time setup: it gathers the cookies we need (specifically xt), and Google uses it to create the webclient DOM.

Note the use of the HEAD verb. Google uses GET, but we don’t need the large response containing Google’s webui.

classmethod check_success(response, msg)

Raise CallFailure on problems.

Parameters:
  • response – a requests.Response
  • msg – the result of parse_response on response
static parse_response(response)

Parses a requests.Response to data.

required_auth = AuthTypes(xt=False, sso=True, oauth=False, gpsoauth=False)
static_method = 'HEAD'
static_url = 'https://play.google.com/music/listen'
class gmusicapi.protocol.webclient.ReportBadSongMatch

Request to signal the uploader to reupload a matched track.

static dynamic_data(song_ids)
static_method = 'POST'
static_params = {'format': 'jsarray'}
static_url = 'https://play.google.com/music/services/fixsongmatch'
class gmusicapi.protocol.webclient.UploadImage

Upload an image for use as album art.

static dynamic_files(image_filepath)
Parameters:image_filepath – path to an image
static_method = 'POST'
static_params = {'u': 0, 'zx': ''}
static_url = 'https://play.google.com/music/services/imageupload'