# Mobileclient Interface

class `gmusicapi.clients.``Mobileclient`(debug_logging=True, validate=True, verify_ssl=True)

  Allows library management and streaming by posing as the googleapis.com mobile clients.

  Uploading is not supported by this client (use the `Musicmanager` to upload).

## Setup and login

`Mobileclient.``__init__`(debug_logging=True, validate=True, verify_ssl=True)

  Parameters:

  - debug_logging –

    each Client has a `logger` member. The logger is named `gmusicapi.<client class><client number>` and will propogate to the `gmusicapi` root logger.

    If this param is `True`, handlers will be configured to send this client’s debug log output to disk, with warnings and above printed to stderr. Appdirs `user_log_dir` is used by default. Users can run:

        from gmusicapi.utils import utils
        print utils.log_filepath

    to see the exact location on their system.

    If `False`, no handlers will be configured; users must create their own handlers.

    Completely ignoring logging is dangerous and not recommended. The Google Music protocol can change at any time; if something were to go wrong, the logs would be necessary for recovery.

  - validate –

    if False, do not validate server responses against known schemas. This helps to catch protocol changes, but requires significant cpu work.

    This arg is stored as `self.validate` and can be safely modified at runtime.

  - verify_ssl – if False, exceptions will not be raised if there are problems verifying SSL certificates. Be wary of using this option; it’s almost always better to fix the machine’s SSL configuration than to ignore errors.

classmethod `Mobileclient.``perform_oauth`(storage_filepath=<object object>, open_browser=False)

  Provides a series of prompts for a user to follow to authenticate. Returns `oauth2client.client.OAuth2Credentials` when successful.

  In most cases, this should only be run once per machine to store credentials to disk, then never be needed again.

  If the user refuses to give access, `oauth2client.client.FlowExchangeError` is raised.

  Parameters:

  - storage_filepath –

    a filepath to write the credentials to, or `None` to not write the credentials to disk (which is not recommended).

    Appdirs `user_data_dir` is used by default. Check the OAUTH_FILEPATH field on this class to see the exact location that will be used.

  - open_browser – if True, attempt to open the auth url in the system default web browser. The url will be printed regardless of this param’s setting.

  This flow is intentionally very simple. For complete control over the OAuth flow, pass an `oauth2client.client.OAuth2Credentials` to `login()` instead.

`Mobileclient.``oauth_login`(device_id, oauth_credentials=None, locale='en_US')

  Authenticates the mobileclient with pre-existing OAuth credentials. Returns `True` on success, `False` on failure.

  Parameters:

  - oauth_credentials –

    `oauth2client.client.OAuth2Credentials` or the path to a `oauth2client.file.Storage` file. By default, the same default path used by `perform_oauth()` is used.

    Endusers will likely call `perform_oauth()` once to write credentials to disk and then ignore this parameter.

    This param is mostly intended to allow flexibility for developers of a 3rd party service who intend to perform their own OAuth flow (eg on their website).

  - device_id –

    A string of 16 hex digits for Android or “ios:<uuid>” for iOS.

    Alternatively, pass `Mobileclient.FROM_MAC_ADDRESS` to attempt to use this machine’s MAC address as an id. If a valid MAC address cannot be determined on this machine (which is often the case when running on a VPS), raise OSError.

    This will likely be deprecated, since Google now rejects ids of this form.

  - locale – ICU locale used to localize certain responses. This must be a locale supported by Android. Defaults to `'en_US'`.

`Mobileclient.``login`(email, password, android_id, locale='en_US')

  Authenticates the Mobileclient using full account credentials. Returns `True` on success, `False` on failure.

  Behind the scenes, this performs a Google-specific Android login flow with the provided credentials, then trades those for a Google Music auth token. It is deprecated in favor of the more robust `oauth_login()`, which performs a normal OAuth flow instead of taking account credentials.

  Parameters:

  - email – eg `'test@gmail.com'` or just `'test'`.
  - password – password or app-specific password for 2-factor users. This is not stored locally, and is sent securely over SSL.
  - android_id –

    16 hex digits, eg `'1234567890abcdef'`.

    Pass Mobileclient.FROM_MAC_ADDRESS instead to attempt to use this machine’s MAC address as an android id. Use this at your own risk: the id will be a non-standard 12 characters, but appears to work fine in testing. If a valid MAC address cannot be determined on this machine (which is often the case when running on a VPS), raise OSError.

  - locale – ICU locale used to localize certain responses. This must be a locale supported by Android. Defaults to `'en_US'`.

`Mobileclient.``logout`()

  Forgets local authentication and cached properties in this Api instance. Returns `True` on success.

`Mobileclient.``is_authenticated`()

  Returns `True` if the Api can make an authenticated request.

`Mobileclient.``locale`

  The locale of the Mobileclient session used to localize some responses.

  Should be an ICU locale supported by Android.

  Set during login but can be changed at any time.

## Account Management

`Mobileclient.``is_subscribed`

  Returns the subscription status of the Google Music account.

  Result is cached with a TTL of 10 minutes. To get live status before the TTL is up, delete the `is_subscribed` property of the Mobileclient instance.

      >>> mc = Mobileclient()
      >>> mc.is_subscribed  # Live status.
      >>> mc.is_subscribed  # Cached status.
      >>> del mc.is_subscribed  # Delete is_subscribed property.
      >>> mc.is_subscribed  # Live status.

`Mobileclient.``get_registered_devices`()

  Returns a list of dictionaries representing devices associated with the account.

  Performing the `Musicmanager` OAuth flow will register a device of type `'DESKTOP_APP'`.

  Installing the Android or iOS Google Music app and logging into it will register a device of type `'ANDROID'` or `'IOS'` respectively, which is required for streaming with the `Mobileclient`.

  Here is an example response:

      [
        {
          u'kind':               u'sj#devicemanagementinfo',
          u'friendlyName':       u'my-hostname',
          u'id':                 u'AA:BB:CC:11:22:33',
          u'lastAccessedTimeMs': u'1394138679694',
          u'type':               u'DESKTOP_APP'
        },
        {
          u"kind":               u"sj#devicemanagementinfo",
          u'friendlyName':       u'Nexus 7',
          u'id':                 u'0x00112233aabbccdd',  # remove 0x when streaming
          u'lastAccessedTimeMs': u'1344808742774',
          u'type':               u'ANDROID'
          u'smartPhone':         True
        },
        {
          u"kind":               u"sj#devicemanagementinfo",
          u'friendlyName':       u'iPhone 6',
          u'id':                 u'ios:01234567-0123-0123-0123-0123456789AB',
          u'lastAccessedTimeMs': 1394138679694,
          u'type':               u'IOS'
          u'smartPhone':         True
        }
        {
          u'kind':               u'sj#devicemanagementinfo',
          u'friendlyName':       u'Google Play Music for Chrome on Windows',
          u'id':                 u'rt2qfkh0qjhos4bxrgc0oae...',  # 64 characters, alphanumeric
          u'lastAccessedTimeMs': u'1425602805052',
          u'type':               u'DESKTOP_APP'
        },
      ]

`Mobileclient.``deauthorize_device`(device_id)

  Deauthorize a registered device.

  Returns `True` on success, `False` on failure.

  Parameters: | device_id – A mobile device id as a string. Android ids are 16 characters with ‘0x’ prepended, iOS ids are uuids with ‘ios:’ prepended, while desktop ids are in the form of a MAC address. Providing an invalid or unregistered device id will result in a 400 HTTP error.

  Google limits the number of device deauthorizations to 4 per year. Attempts to deauthorize a device when that limit is reached results in a 403 HTTP error with: `X-Rejected-Reason: TOO_MANY_DEAUTHORIZATIONS`.

## Songs

Songs are uniquely referred to within a library with a track id in uuid format.

Store tracks also have track ids, but they are in a different format than library track ids. `song_id.startswith('T')` is always `True` for store track ids and `False` for library track ids.

Adding a store track to a library will yield a normal song id.

Store track ids can be used in most places that normal song ids can (e.g. playlist addition or streaming). Note that sometimes they are stored under the `'nid'` key, not the `'id'` key.

`Mobileclient.``get_all_songs`(incremental=False, include_deleted=None, updated_after=None)

  Returns a list of dictionaries that each represent a song.

  Parameters:

  - incremental – if True, return a generator that yields lists of at most 1000 tracks as they are retrieved from the server. This can be useful for presenting a loading bar to a user.
  - include_deleted – ignored. Will be removed in a future release.
  - updated_after – a datetime.datetime; defaults to unix epoch. If provided, deleted songs may be returned.

  Here is an example song dictionary:

      {
         'comment':'',
         'rating':'0',
         'albumArtRef':[
           {
             'url': 'http://lh6.ggpht.com/...'
           }
         ],
         'artistId':[
           'Aod62yyj3u3xsjtooghh2glwsdi'
         ],
         'composer':'',
         'year':2011,
         'creationTimestamp':'1330879409467830',
         'id':'5924d75a-931c-30ed-8790-f7fce8943c85',
         'album':'Heritage ',
         'totalDiscCount':0,
         'title':'Haxprocess',
         'recentTimestamp':'1372040508935000',
         'albumArtist':'',
         'trackNumber':6,
         'discNumber':0,
         'deleted':False,
         'storeId':'Txsffypukmmeg3iwl3w5a5s3vzy',
         'nid':'Txsffypukmmeg3iwl3w5a5s3vzy',
         'totalTrackCount':10,
         'estimatedSize':'17229205',
         'albumId':'Bdkf6ywxmrhflvtasnayxlkgpcm',
         'beatsPerMinute':0,
         'genre':'Progressive Metal',
         'playCount':7,
         'artistArtRef':[
           {
             'url': 'http://lh3.ggpht.com/...'
           }
         ],
         'kind':'sj#track',
         'artist':'Opeth',
         'lastModifiedTimestamp':'1330881158830924',
         'clientId':'+eGFGTbiyMktbPuvB5MfsA',
         'durationMillis':'418000'
       }

`Mobileclient.``get_stream_url`(song_id, device_id=None, quality='hi')

  Returns a url that will point to an mp3 file.

  Parameters:

  - song_id – A single song id. This can be `'storeId'` from a store song, `'id'` from an uploaded song, or `'trackId'` from a playlist entry.
  - device_id –

    (optional) defaults to `android_id` from login.

    Otherwise, provide a mobile device id as a string. Android device ids are 16 characters, while iOS ids are uuids with ‘ios:’ prepended.

    If you have already used Google Music on a mobile device, `Mobileclient.get_registered_devices` will provide at least one working id. Omit `'0x'` from the start of the string if present.

    Registered computer ids (a MAC address) will not be accepted and will 403.

    Providing an unregistered mobile device id will register it to your account, subject to Google’s device limits. Registering a device id that you do not own is likely a violation of the TOS.

  - quality – (optional) stream bits per second quality One of three possible values, hi: 320kbps, med: 160kbps, low: 128kbps. The default is hi

  When handling the resulting url, keep in mind that:
    - you will likely need to handle redirects
    - the url expires after a minute
    - only one IP can be streaming music at once. This can result in an http 403 with `X-Rejected-Reason: ANOTHER_STREAM_BEING_PLAYED`.

  The file will not contain metadata. Use `Webclient.get_song_download_info` or `Musicmanager.download_song` to download files with metadata.

`Mobileclient.``rate_songs`(songs, rating)

  Rate library or store songs.

  Returns rated song ids.

  Parameters:

  - songs – a list of song dictionaries or a single song dictionary. required keys: ‘id’ for library songs or ‘nid’ and ‘trackType’ for store songs.
  - rating – set to `'0'` (no thumb), `'1'` (down thumb), or `'5'` (up thumb).

`Mobileclient.``change_song_metadata`(songs)

  Changes the metadata of tracks. Returns a list of the song ids changed.

  Parameters: | songs – a list of song dictionaries or a single song dictionary.

  Currently, only the `rating` key can be changed. Set it to `'0'` (no thumb), `'1'` (down thumb), or `'5'` (up thumb).

  You can also use this to rate store tracks that aren’t in your library, eg:

      song = mc.get_track_info('<some store track id>')
      song['rating'] = '5'
      mc.change_song_metadata(song)

`Mobileclient.``delete_songs`(library_song_ids)

  Deletes songs from the library. Returns a list of deleted song ids.

  Parameters: | song_ids – a list of song ids, or a single song id.

`Mobileclient.``get_top_songs`()

  Returns a list of dictionaries that each represent a track.

  Only store tracks will be returned.

  Tops songs seem to be an auto-generated playlist of positively-rated songs (Thumbs up).

  See `get_track_info()` for the format of a track dictionary.

`Mobileclient.``increment_song_playcount`(song_id, plays=1, playtime=None)

  Increments a song’s playcount and returns its song id.

  Params song_id: | a song id. Providing the id of a store track that has been added to the library will not increment the corresponding library song’s playcount. To do this, use the ‘id’ field (which looks like a uuid and doesn’t begin with ‘T’), not the ‘nid’ field.
  Params plays: | (optional) positive number of plays to increment by. The default is 1.
  Params playtime:
  | (optional) a datetime.datetime of the time the song was played. It will default to the time of the call.

`Mobileclient.``add_store_track`(store_song_id)

  Adds a store track to the library

  Returns the library track id of added store track.

  Parameters: | store_song_id – store song id

`Mobileclient.``add_store_tracks`(store_song_ids)

  Add store tracks to the library

  Returns a list of the library track ids of added store tracks.

  Parameters: | store_song_ids – a list of store song ids or a single store song id

`Mobileclient.``get_station_track_stream_url`(song_id, wentry_id, session_token, quality='hi')

  Returns a url that will point to an mp3 file.

  This is only for use by free accounts, and requires a call to `get_station_info()` first to provide wentry_id and session_token. Subscribers should instead use `get_stream_url()`.

  Parameters:

  - song_id – a single song id
  - wentry_id – a free radio station track entry id (wentryid from `get_station_info()`)
  - session_token – a free radio station session token (sessionToken from `get_station_info()`)
  - quality – (optional) stream bits per second quality One of three possible values, hi: 320kbps, med: 160kbps, low: 128kbps. The default is hi

## Playlists

Like songs, playlists have unique ids within a library. However, their names do not need to be unique.

The tracks making up a playlist are referred to as ‘playlist entries’, and have unique entry ids within the entire library (not just their containing playlist).

`Mobileclient.``get_all_playlists`(incremental=False, include_deleted=None, updated_after=None)

  Returns a list of dictionaries that each represent a playlist.

  Parameters:

  - incremental – if True, return a generator that yields lists of at most 1000 playlists as they are retrieved from the server. This can be useful for presenting a loading bar to a user.
  - include_deleted – ignored. Will be removed in a future release.
  - updated_after – a datetime.datetime; defaults to unix epoch If provided, deleted playlists may be returned.

  Here is an example playlist dictionary:

      {
           # can also be SHARED (public/subscribed to), MAGIC or omitted
          'type': 'USER_GENERATED',

          'kind': 'sj#playlist',
          'name': 'Something Mix',
          'deleted': False,
          'lastModifiedTimestamp': '1325458766483033',
          'recentTimestamp': '1325458766479000',
          'shareToken': '<long string>',
          'ownerProfilePhotoUrl': 'http://lh3.googleusercontent.com/...',
          'ownerName': 'Simon Weber',
          'accessControlled': False,  # has to do with shared playlists
          'creationTimestamp': '1325285553626172',
          'id': '3d72c9b5-baad-4ff7-815d-cdef717e5d61'
      }

`Mobileclient.``get_all_user_playlist_contents`()

  Retrieves the contents of all user-created playlists – the Mobileclient does not support retrieving only the contents of one playlist.

  This will not return results for public playlists that the user is subscribed to; use `get_shared_playlist_contents()` instead.

  The same structure as `get_all_playlists()` will be returned, but with the addition of a `'tracks'` key in each dict set to a list of properly-ordered playlist entry dicts.

  Here is an example playlist entry for an individual track:

      {
          'kind': 'sj#playlistEntry',
          'deleted': False,
          'trackId': '2bb0ab1c-ce1a-3c0f-9217-a06da207b7a7',
          'lastModifiedTimestamp': '1325285553655027',
          'playlistId': '3d72c9b5-baad-4ff7-815d-cdef717e5d61',
          'absolutePosition': '01729382256910287871',  # denotes playlist ordering
          'source': '1',  # '2' if hosted on Google Music, '1' otherwise (see below)
          'creationTimestamp': '1325285553655027',
          'id': 'c9f1aff5-f93d-4b98-b13a-429cc7972fea' ## see below
      }

  If a user uploads local music to Google Music using the Music Manager, Google will attempt to match each uploaded track to a track already hosted on its servers. If a match is found for a track, the playlist entry key `'source'` has the value `'2'`, and the entry will have a key `'track'` with a value that is a dict of track metadata (title, artist, etc).

  If a track is not hosted on Google Music, then the playlist entry key `'source'` has the value `'1'`, and may not have a `'track'` key (e.g., for an MP3 without ID3 tags). In this case, the key `'trackId'` corresponds to the column `ServerId` in the table `XFILES` in Music Manager’s local SQLite database (stored, e.g., at ~/Library/ApplicationSupport/Google/MusicManager/ServerDatabase.db on OS X). Among other things, the SQLite database exposes the track’s local file path, and Music Manager’s imputed metadata.

  (Note that the above behavior is documented for the Music Manager set to sync from local Folders, and may differ if it instead syncs from iTunes.)

`Mobileclient.``get_shared_playlist_contents`(share_token)

  Retrieves the contents of a public playlist.

  Parameters: | share_token – from `playlist['shareToken']`, or a playlist share url (`https://play.google.com/music/playlist/<token>`). Note that tokens from urls will need to be url-decoded, eg `AM...%3D%3D` becomes `AM...==`.

  For example, to retrieve the contents of a playlist that the user is subscribed to:

      subscribed_to = [p for p in mc.get_all_playlists() if p.get('type') == 'SHARED']
      share_tok = subscribed_to[0]['shareToken']
      tracks = mc.get_shared_playlist_contents(share_tok)

  The user need not be subscribed to a playlist to list its tracks.

  Returns a list of playlist entries with structure the same as those returned by `get_all_user_playlist_contents()`, but without the `'clientId'` or `'playlistId'` keys.

`Mobileclient.``create_playlist`(name, description=None, public=False)

  Creates a new empty playlist and returns its id.

  Parameters:

  - name – the desired title. Creating multiple playlists with the same name is allowed.
  - description – (optional) the desired description
  - public – (optional) if True and the user has a subscription, share playlist.

`Mobileclient.``delete_playlist`(playlist_id)

  Deletes a playlist and returns its id.

  Parameters: | playlist_id – the id to delete.

`Mobileclient.``edit_playlist`(playlist_id, new_name=None, new_description=None, public=None)

  Changes the name of a playlist and returns its id.

  Parameters:

  - playlist_id – the id of the playlist
  - new_name – (optional) desired title
  - new_description – (optional) desired description
  - public – (optional) if True and the user has a subscription, share playlist.

`Mobileclient.``add_songs_to_playlist`(playlist_id, song_ids)

  Appends songs to the end of a playlist. Returns a list of playlist entry ids that were added.

  Parameters:

  - playlist_id – the id of the playlist to add to.
  - song_ids – a list of song ids, or a single song id. These can be `'storeId'` from a store song, `'id'` from an uploaded song, or `'trackId'` from a playlist entry.

  Playlists have a maximum size of 1000 songs. Calls may fail before that point (presumably) due to an error on Google’s end (see #239).

`Mobileclient.``remove_entries_from_playlist`(entry_ids)

  Removes specific entries from a playlist. Returns a list of entry ids that were removed.

  Parameters: | entry_ids – a list of entry ids, or a single entry id.

`Mobileclient.``reorder_playlist_entry`(entry, to_follow_entry=None, to_precede_entry=None)

  Reorders a single entry in a playlist and returns its id.

  Read `reorder_playlist_entry(foo, bar, gaz)` as “reorder playlist entry foo to follow entry bar and precede entry gaz.”

  Parameters:

  - entry – the playlist entry to move.
  - to_follow_entry – the playlist entry that will come before entry in the resulting playlist, or None if entry is to be the first entry in the playlist.
  - to_precede_entry – the playlist entry that will come after entry in the resulting playlist or None if entry is to be the last entry in the playlist.

  `reorder_playlist_entry(foo)` is invalid and will raise ValueError; provide at least one of to_follow_entry or to_precede_entry.

  Leaving to_follow_entry or to_precede_entry as None when entry is not to be the first or last entry in the playlist is undefined.

  All params are dicts returned by `get_all_user_playlist_contents()` or `get_shared_playlist_contents()`.

## Radio Stations

Radio Stations are available for free in the US only. A subscription is required in other countries.

`Mobileclient.``get_all_stations`(incremental=False, include_deleted=None, updated_after=None)

  Retrieve all library stations.

  Returns a list of dictionaries that each represent a radio station.

  This includes any stations listened to recently, which might not be in the library.

  Parameters:

  - incremental – if True, return a generator that yields lists of at most 1000 stations as they are retrieved from the server. This can be useful for presenting a loading bar to a user.
  - include_deleted – ignored. Will be removed in a future release.
  - updated_after – a datetime.datetime; defaults to unix epoch

  Here is an example station dictionary:

      {
          'imageUrl': 'http://lh6.ggpht.com/...',
          'kind': 'sj#radioStation',
          'name': 'station',
          'deleted': False,
          'lastModifiedTimestamp': '1370796487455005',
          'recentTimestamp': '1370796487454000',
          'clientId': 'c2639bf4-af24-4e4f-ab37-855fc89d15a1',
          'seed':
          {
              'kind': 'sj#radioSeed',
              'trackLockerId': '7df3aadd-9a18-3dc1-b92e-a7cf7619da7e'
              # possible keys:
              #  albumId, artistId, genreId, trackId, trackLockerId
          },
          'id': '69f1bfce-308a-313e-9ed2-e50abe33a25d',
          'inLibrary': True
      },

`Mobileclient.``create_station`(name, track_id=None, artist_id=None, album_id=None, genre_id=None, playlist_token=None, curated_station_id=None)

  Creates a radio station and returns its id.

  Parameters:

  - name – the name of the station to create
  - *_id – the id of an item to seed the station from.
  - playlist_token – The shareToken of a playlist to seed the station from.

  Exactly one of the id/token params must be provided, or ValueError will be raised.

`Mobileclient.``delete_stations`(station_ids)

  Deletes radio stations and returns their ids.

  Parameters: | station_ids – a single id, or a list of ids to delete

`Mobileclient.``get_station_tracks`(station_id, num_tracks=25, recently_played_ids=None)

  Returns a list of dictionaries that each represent a track.

  Each call performs a separate sampling (with replacement?) from all possible tracks for the station.

  Nonexistent stations will return an empty list.

  Parameters:

  - station_id – the id of a radio station to retrieve tracks from. Use the special id `'IFL'` for the “I’m Feeling Lucky” station.
  - num_tracks – the number of tracks to retrieve
  - recently_played_ids – a list of recently played track ids retrieved from this station. This avoids playing duplicates.

  See `get_all_songs()` for the format of a track dictionary.

## Podcasts

`Mobileclient.``get_all_podcast_series`(device_id=None, incremental=False, include_deleted=None, updated_after=None)

  Retrieve list of user-subscribed podcast series.

  Parameters:

  - device_id –

    (optional) defaults to `android_id` from login.

    Otherwise, provide a mobile device id as a string. Android device ids are 16 characters, while iOS ids are uuids with ‘ios:’ prepended.

    If you have already used Google Music on a mobile device, `Mobileclient.get_registered_devices` will provide at least one working id. Omit `'0x'` from the start of the string if present.

    Registered computer ids (a MAC address) will not be accepted and will 403.

    Providing an unregistered mobile device id will register it to your account, subject to Google’s device limits. Registering a device id that you do not own is likely a violation of the TOS.

  - incremental – if True, return a generator that yields lists of at most 1000 podcast series as they are retrieved from the server. This can be useful for presenting a loading bar to a user.
  - include_deleted – ignored. Will be removed in a future release.
  - updated_after – a datetime.datetime; defaults to unix epoch

  Returns a list of podcast series dicts.

  Here is an example podcast series dict:

      {
          'art': [
              {
                  'aspectRatio': '1',
                  'autogen': False,
                  'kind': 'sj#imageRef',
                  'url': 'http://lh3.googleusercontent.com/bNoyxoGTwCGkUscMjHsvKe5W80uMOfq...'
              }
          ],
          'author': 'Chris Hardwick',
          'continuationToken': '',
          'description': 'I am Chris Hardwick. I am on TV a lot and have a blog at '
                         'nerdist.com. This podcast is basically just me talking about '
                         'stuff and things with my two nerdy friends Jonah Ray and Matt '
                         'Mira, and usually someone more famous than all of us. '
                         'Occasionally we swear because that is fun. I hope you like '
                         "it, but if you don't I'm sure you will not hesitate to unfurl "
                         "your rage in the 'reviews' section because that's how the "
                         'Internet works.',
          'explicitType': '1',
          'link': 'http://nerdist.com/',
          'seriesId': 'Iliyrhelw74vdqrro77kq2vrdhy',
          'title': 'The Nerdist',
          'totalNumEpisodes': 829,
          'userPreferences': {
              'autoDownload': False,
              'notifyOnNewEpisode': False,
              'subscribed': True
          }
      }

`Mobileclient.``get_all_podcast_episodes`(device_id=None, incremental=False, include_deleted=None, updated_after=None)

  Retrieve list of episodes from user-subscribed podcast series.

  Parameters:

  - device_id –

    (optional) defaults to `android_id` from login.

    Otherwise, provide a mobile device id as a string. Android device ids are 16 characters, while iOS ids are uuids with ‘ios:’ prepended.

    If you have already used Google Music on a mobile device, `Mobileclient.get_registered_devices` will provide at least one working id. Omit `'0x'` from the start of the string if present.

    Registered computer ids (a MAC address) will not be accepted and will 403.

    Providing an unregistered mobile device id will register it to your account, subject to Google’s device limits. Registering a device id that you do not own is likely a violation of the TOS.

  - incremental – if True, return a generator that yields lists of at most 1000 podcast episodes as they are retrieved from the server. This can be useful for presenting a loading bar to a user.
  - include_deleted – ignored. Will be removed in a future release.
  - updated_after – a datetime.datetime; defaults to unix epoch

  Returns a list of podcast episode dicts.

  Here is an example podcast episode dict:

      {
          'art': [
              {
                  'aspectRatio': '1',
                  'autogen': False,
                  'kind': 'sj#imageRef',
                  'url': 'http://lh3.googleusercontent.com/bNoyxoGTwCGkUscMjHsvKe5W80uMOfq...'
              }
          ],
          'deleted': False,
          'description': 'Comedian Bill Burr yelled at Philadelphia, Chris vaguely '
                         'understands hockey, Jonah understands it even less, and Matt '
                         'is weirdly not tired of the running "Matt loves the Dave '
                         'Matthews Band" joke, though I'm sure all of you are.',
          'durationMillis': '4310000',
          'episodeId': 'D6i26frpxu53t2ws3lpbjtpovum',
          'explicitType': '2',
          'fileSize': '69064793',
          'publicationTimestampMillis': '1277791500000',
          'seriesId': 'Iliyrhelw74vdqrro77kq2vrdhy',
          'seriesTitle': 'The Nerdist',
          'title': 'Bill Burr'
      }

`Mobileclient.``add_podcast_series`(podcast_id, notify_on_new_episode=False)

  Subscribe to a podcast series.

  Parameters:

  - podcast_id – A podcast series id (hint: they always start with ‘I’).
  - notify_on_new_episode – Get device notifications on new episodes.

  Returns podcast series id of added podcast series

`Mobileclient.``delete_podcast_series`(podcast_id)

  Unsubscribe to a podcast series.

  Parameters: | podcast_id – A podcast series id (hint: they always start with ‘I’).

  Returns podcast series id of removed podcast series

`Mobileclient.``edit_podcast_series`(podcast_id, subscribe=True, notify_on_new_episode=False)

  Edit a podcast series subscription.

  Parameters:

  - podcast_id – A podcast series id (hint: they always start with ‘I’).
  - subscribe – Subscribe to podcast.
  - notify_on_new_episode – Get device notifications on new episodes.

  Returns podcast series id of edited podcast series

`Mobileclient.``get_podcast_episode_stream_url`(podcast_episode_id, device_id=None, quality='hi')

  Returns a url that will point to an mp3 file.

  Parameters:

  - podcast_episde_id – a single podcast episode id (hint: they always start with ‘D’).
  - device_id –

    (optional) defaults to `android_id` from login.

    Otherwise, provide a mobile device id as a string. Android device ids are 16 characters, while iOS ids are uuids with ‘ios:’ prepended.

    If you have already used Google Music on a mobile device, `Mobileclient.get_registered_devices` will provide at least one working id. Omit `'0x'` from the start of the string if present.

    Registered computer ids (a MAC address) will not be accepted and will 403.

    Providing an unregistered mobile device id will register it to your account, subject to Google’s device limits. Registering a device id that you do not own is likely a violation of the TOS.

  - quality – (optional) stream bits per second quality One of three possible values, hi: 320kbps, med: 160kbps, low: 128kbps. The default is hi

  When handling the resulting url, keep in mind that:
    - you will likely need to handle redirects
    - the url expires after a minute
    - only one IP can be streaming music at once. This can result in an http 403 with `X-Rejected-Reason: ANOTHER_STREAM_BEING_PLAYED`.

  The file will not contain metadata.

## Search

Search Google Play for information about artists, albums, tracks, and more.

`Mobileclient.``search`(query, max_results=100)

  Queries Google Music for content.

  Most result types will be empty unless using a subscription account.

  Parameters:

  - query – a string keyword to search with. Capitalization and punctuation are ignored.
  - max_results – Maximum number of items to be retrieved. The maximum accepted value is 100. If set higher, results are limited to 10. A value of `None` allows up to 1000 results per type but won’t return playlist nor situation results. Default is `100`.

  The results are returned as a dictionary of lists mapped by result type: * album_hits * artist_hits * genre_hits * playlist_hits * podcast_hits * situation_hits * song_hits * station_hits * video_hits

  Here is a sample of results for a search of `'workout'` on a subscription account:

      {
          'album_hits': [{
              'album': {
                  'albumArtRef': 'http://lh5.ggpht.com/DVIg4GiD6msHfgPs_Vu_2eRxCyAoz0fF...',
                  'albumArtist': 'J.Cole',
                  'albumId': 'Bfp2tuhynyqppnp6zennhmf6w3y',
                  'artist': 'J.Cole',
                  'artistId': ['Ajgnxme45wcqqv44vykrleifpji'],
                  'description_attribution': {
                      'kind': 'sj#attribution',
                      'license_title': 'Creative Commons Attribution CC-BY',
                      'license_url': 'http://creativecommons.org/licenses/by/4.0/legalcode',
                      'source_title': 'Freebase',
                      'source_url': ''
                  },
                  'explicitType': '1',
                  'kind': 'sj#album',
                  'name': 'Work Out',
                  'year': 2011
              },
              'type': '3'
          }],
          'artist_hits': [{
              'artist': {
                  'artistArtRef': 'http://lh3.googleusercontent.com/MJe-cDw9uQ-pUagoLlm...',
                  'artistArtRefs': [{
                      'aspectRatio': '2',
                      'autogen': False,
                      'kind': 'sj#imageRef',
                      'url': 'http://lh3.googleusercontent.com/MJe-cDw9uQ-pUagoLlmKX3x_K...'
                  }],
                  'artistId': 'Ajgnxme45wcqqv44vykrleifpji',
                  'artist_bio_attribution': {
                      'kind': 'sj#attribution',
                      'source_title': 'David Jeffries, Rovi'
                  },
                  'kind': 'sj#artist',
                  'name': 'J. Cole'
              },
              'type': '2'
          }],
          'playlist_hits': [{
              'playlist': {
                  'albumArtRef': [
                      {'url': 'http://lh3.googleusercontent.com/KJsAhrg8Jk_5A4xYLA68LFC...'}
                  ],
                  'description': 'Workout Plan ',
                  'kind': 'sj#playlist',
                  'name': 'Workout',
                  'ownerName': 'Ida Sarver',
                  'shareToken': 'AMaBXyktyF6Yy_G-8wQy8Rru0tkueIbIFblt2h0BpkvTzHDz-fFj6P...',
                  'type': 'SHARED'
              },
              'type': '4'
          }],
          'podcast_hits': [{
              'series': {
                  'art': [
                      {
                          'aspectRatio': '1',
                          'autogen': False,
                          'kind': 'sj#imageRef',
                          'url': 'https://lh3.googleusercontent.com/je4lsaiQCdfcOWoYm3Z_mC...'
                      }
                  ],
                  'author': 'Steve Boyett',
                  'continuationToken': '',
                  'copyright': 'Music copyright c the respective artists. All other '
                               'material c2006, 2016 by Podrunner, LLC. All rights '
                               'reserved. For personal use only. Unauthorized '
                               'reproduction, sale, rental, exchange, public '
                               'performance, or broadcast of this audio is '
                               'prohibited.',
                  'description': 'Nonstop, one-hour, high-energy workout music mixes '
                                 "to help you groove while you move. Podrunner's "
                                 'fixed-tempo and interval exercise mixes are '
                                 'perfect for power walking, jogging, running, '
                                 'spinning, elliptical, aerobics, and many other '
                                 'tempo-based forms of exercise. An iTunes '
                                 'award-winner six years in a row!',
                  'explicitType': '2',
                  'link': 'http://www.podrunner.com/',
                  'seriesId': 'Ilx4ufdua5rdvzplnojtloulo3a',
                  'title': 'PODRUNNER: Workout Music',
                  'totalNumEpisodes': 0
              },
              'type': '9'
          }],
          'situation_hits': [{
              'situation': {
                  'description':
                      'Level up and enter beast mode with some loud, aggressive music.',
                  'id': 'Nrklpcyfewwrmodvtds5qlfp5ve',
                  'imageUrl': 'http://lh3.googleusercontent.com/Cd8WRMaG_pDwjTC_dSPIIuf...',
                  'title': 'Entering Beast Mode',
                  'wideImageUrl': 'http://lh3.googleusercontent.com/8A9S-nTb5pfJLcpS8P...'},
              'type': '7'
          }],
          'song_hits': [{
              'track': {
                  'album': 'Work Out',
                  'albumArtRef': [{
                      'aspectRatio': '1',
                      'autogen': False,
                      'kind': 'sj#imageRef',
                      'url': 'http://lh5.ggpht.com/DVIg4GiD6msHfgPs_Vu_2eRxCyAoz0fFdxj5w...'
                  }],
                  'albumArtist': 'J.Cole',
                  'albumAvailableForPurchase': True,
                  'albumId': 'Bfp2tuhynyqppnp6zennhmf6w3y',
                  'artist': 'J Cole',
                  'artistId': ['Ajgnxme45wcqqv44vykrleifpji', 'Ampniqsqcwxk7btbgh5ycujij5i'],
                  'composer': '',
                  'discNumber': 1,
                  'durationMillis': '234000',
                  'estimatedSize': '9368582',
                  'explicitType': '1',
                  'genre': 'Pop',
                  'kind': 'sj#track',
                  'nid': 'Tq3nsmzeumhilpegkimjcnbr6aq',
                  'primaryVideo': {
                      'id': '6PN78PS_QsM',
                      'kind': 'sj#video',
                      'thumbnails': [{
                          'height': 180,
                          'url': 'https://i.ytimg.com/vi/6PN78PS_QsM/mqdefault.jpg',
                          'width': 320
                      }]
                  },
                  'storeId': 'Tq3nsmzeumhilpegkimjcnbr6aq',
                  'title': 'Work Out',
                  'trackAvailableForPurchase': True,
                  'trackAvailableForSubscription': True,
                  'trackNumber': 1,
                  'trackType': '7',
                  'year': 2011
              },
              'type': '1'
          }],
          'station_hits': [{
              'station': {
                  'compositeArtRefs': [{
                          'aspectRatio': '1',
                          'kind': 'sj#imageRef',
                          'url': 'http://lh3.googleusercontent.com/3aD9mFppy6PwjADnjwv_w...'
                  }],
                  'contentTypes': ['1'],
                  'description':
                      'These riff-tastic metal tracks are perfect '
                      'for getting the blood pumping.',
                  'imageUrls': [{
                      'aspectRatio': '1',
                      'autogen': False,
                      'kind': 'sj#imageRef',
                      'url': 'http://lh5.ggpht.com/YNGkFdrtk43e8H941fuAHjflrNZ1CJUeqdoys...'
                  }],
                  'kind': 'sj#radioStation',
                  'name': 'Heavy Metal Workout',
                  'seed': {
                      'curatedStationId': 'Lcwg73w3bd64hsrgarnorif52r',
                      'kind': 'sj#radioSeed',
                      'seedType': '9'
                  },
                  'skipEventHistory': [],
                  'stationSeeds': [{
                      'curatedStationId': 'Lcwg73w3bd64hsrgarnorif52r',
                      'kind': 'sj#radioSeed',
                      'seedType': '9'}
                  ]},
              'type': '6'
          }],
          'video_hits': [{
              'score': 629.6226806640625,
              'type': '8',
              'youtube_video': {
                  'id': '6PN78PS_QsM',
                  'kind': 'sj#video',
                  'thumbnails': [{
                      'height': 180,
                      'url': 'https://i.ytimg.com/vi/6PN78PS_QsM/mqdefault.jpg',
                      'width': 320
                  }],
                  'title': 'J. Cole - Work Out'
              }
          }]
      }

`Mobileclient.``get_genres`(parent_genre_id=None)

  Retrieves information on Google Music genres.

  Parameters: | parent_genre_id – (optional) If provided, only child genres will be returned. By default, all root genres are returned. If this id is invalid, an empty list will be returned.

  Returns a list of dicts of the form, eg:

      {
          'name': 'Alternative/Indie',
          'id': 'ALTERNATIVE_INDIE'
          'kind': 'sj#musicGenre',
          'children': [             # this key may not be present
              'ALTERNATIVE_80S',    # these are ids
              'ALT_COUNTRY',
              # ...
              ],
          'images': [
              {
                  # these are album covers representative of the genre
                  'url': 'http://lh6.ggpht.com/...'
              },
              # ...
          ],
      }

  Note that the id can be used with `create_station()` to seed a radio station.

`Mobileclient.``get_album_info`(album_id, include_tracks=True)

  Retrieves details on an album.

  Parameters:

  - album_id – an album id (hint: they always start with ‘B’)
  - include_tracks – when True, create the `'tracks'` substructure

  Returns a dict, eg:

      {
          'kind': 'sj#album',
          'name': 'Circle',
          'artist': 'Amorphis',
          'albumArtRef': 'http://lh6.ggpht.com/...',
          'tracks': [  # if `include_tracks` is True
          {
              'album': 'Circle',
              'kind': 'sj#track',
              'storeId': 'T5zb7luo2vkroozmj57g2nljdsy',  # can be used as a song id
              'artist': 'Amorphis',
              'albumArtRef': [
              {
                  'url': 'http://lh6.ggpht.com/...'
              }],
              'title': 'Shades of Grey',
              'nid': 'T5zb7luo2vkroozmj57g2nljdsy',
              'estimatedSize': '13115591',
              'albumId': 'Bfr2onjv7g7tm4rzosewnnwxxyy',
              'artistId': ['Apoecs6off3y6k4h5nvqqos4b5e'],
              'albumArtist': 'Amorphis',
              'durationMillis': '327000',
              'composer': '',
              'genre': 'Metal',
              'trackNumber': 1,
              'discNumber': 1,
              'trackAvailableForPurchase': True,
              'trackType': '7',
              'albumAvailableForPurchase': True
          }, # ...
          ],
          'albumId': 'Bfr2onjv7g7tm4rzosewnnwxxyy',
          'artistId': ['Apoecs6off3y6k4h5nvqqos4b5e'],
          'albumArtist': 'Amorphis',
          'year': 2013
      }

`Mobileclient.``get_artist_info`(artist_id, include_albums=True, max_top_tracks=5, max_rel_artist=5)

  Retrieves details on an artist.

  Parameters:

  - artist_id – an artist id (hint: they always start with ‘A’)
  - include_albums – when True, create the `'albums'` substructure
  - max_top_tracks – maximum number of top tracks to retrieve
  - max_rel_artist – maximum number of related artists to retrieve

  Returns a dict, eg:

      {
        'albums':[  # only if include_albums is True
          {
            'albumArtRef':'http://lh6.ggpht.com/...',
            'albumArtist':'Amorphis',
            'albumId':'Bfr2onjv7g7tm4rzosewnnwxxyy',
            'artist':'Amorphis',
            'artistId':[
              'Apoecs6off3y6k4h5nvqqos4b5e'
            ],
            'kind':'sj#album',
            'name':'Circle',
            'year':2013
          },
        ],
        'artistArtRef':  'http://lh6.ggpht.com/...',
        'artistId':'Apoecs6off3y6k4h5nvqqos4b5e',
        'kind':'sj#artist',
        'name':'Amorphis',
        'related_artists':[  # only if max_rel_artists > 0
          {
            'artistArtRef':      'http://lh5.ggpht.com/...',
            'artistId':'Aheqc7kveljtq7rptd7cy5gvk2q',
            'kind':'sj#artist',
            'name':'Dark Tranquillity'
          }
        ],
        'topTracks':[  # only if max_top_tracks > 0
          {
            'album':'Skyforger',
            'albumArtRef':[
              {
                'url':          'http://lh4.ggpht.com/...'
              }
            ],
            'albumArtist':'Amorphis',
            'albumAvailableForPurchase':True,
            'albumId':'B5nc22xlcmdwi3zn5htkohstg44',
            'artist':'Amorphis',
            'artistId':[
              'Apoecs6off3y6k4h5nvqqos4b5e'
            ],
            'discNumber':1,
            'durationMillis':'253000',
            'estimatedSize':'10137633',
            'kind':'sj#track',
            'nid':'Tn2ugrgkeinrrb2a4ji7khungoy',
            'playCount':1,
            'storeId':'Tn2ugrgkeinrrb2a4ji7khungoy',
            'title':'Silver Bride',
            'trackAvailableForPurchase':True,
            'trackNumber':2,
            'trackType':'7'
          }
        ],
        'total_albums':21
      }

`Mobileclient.``get_podcast_episode_info`(podcast_episode_id)

  Retrieves information about a podcast episode.

  Parameters: | podcast_episode_id – A podcast episode id (hint: they always start with ‘D’).

  Returns a dict, eg:

      {
          'art': [
              {
                  'aspectRatio': '1',
                  'autogen': False,
                  'kind': 'sj#imageRef',
                  'url': 'http://lh3.googleusercontent.com/bNoyxoGTwCGkUscMjHsvKe5...'
              }
          ],
          'description': 'Sarah Jessica Parker (Sex and the City) '
                         'chats with Chris about growing up without '
                         'television, her time on Square Pegs and '
                         'her character in L.A. Story. Sarah Jessica '
                         'then talks about how she felt when she first '
                         'got the part of Carrie on Sex and the '
                         'City, how she dealt with her sudden '
                         'celebrity of being Carrie Bradshaw and they '
                         'come up with a crazy theory about the show! '
                         'They also talk about Sarah Jessica’s new '
                         'show Divorce on HBO!',
          'durationMillis': '5101000',
          'episodeId': 'Dcz67vtkhrerzh4hptfqpadt5vm',
          'explicitType': '1',
          'fileSize': '40995252',
          'publicationTimestampMillis': '1475640000000',
          'seriesId': 'Iliyrhelw74vdqrro77kq2vrdhy',
          'seriesTitle': 'The Nerdist',
          'title': 'Sarah Jessica Parker'
      }

`Mobileclient.``get_podcast_series_info`(podcast_series_id, max_episodes=50)

  Retrieves information about a podcast series.

  Parameters:

  - podcast_series_id – A podcast series id (hint: they always start with ‘I’).
  - max_episodes – Maximum number of episodes to retrieve

  Returns a dict, eg:

      {
          'art': [
              {
                  'aspectRatio': '1',
                  'autogen': False,
                  'kind': 'sj#imageRef',
                  'url': 'http://lh3.googleusercontent.com/bNoyxoGTwCGkUscMjHsvKe5W80uMOfq...'
              }
          ],
          'author': 'Chris Hardwick',
          'continuationToken': '',
          'description': 'I am Chris Hardwick. I am on TV a lot and have a blog at '
                         'nerdist.com. This podcast is basically just me talking about '
                         'stuff and things with my two nerdy friends Jonah Ray and Matt '
                         'Mira, and usually someone more famous than all of us. '
                         'Occasionally we swear because that is fun. I hope you like '
                         "it, but if you don't I'm sure you will not hesitate to unfurl "
                         "your rage in the 'reviews' section because that's how the "
                         'Internet works.',
          'episodes': [
              {
                  'art': [
                      {
                          'aspectRatio': '1',
                          'autogen': False,
                          'kind': 'sj#imageRef',
                          'url': 'http://lh3.googleusercontent.com/bNoyxoGTwCGkUscMjHsvKe5...'
                      }
                  ],
                  'description': 'Sarah Jessica Parker (Sex and the City) '
                                 'chats with Chris about growing up without '
                                 'television, her time on Square Pegs and '
                                 'her character in L.A. Story. Sarah Jessica '
                                 'then talks about how she felt when she first '
                                 'got the part of Carrie on Sex and the '
                                 'City, how she dealt with her sudden '
                                 'celebrity of being Carrie Bradshaw and they '
                                 'come up with a crazy theory about the show! '
                                 'They also talk about Sarah Jessica’s new '
                                 'show Divorce on HBO!',
                  'durationMillis': '5101000',
                  'episodeId': 'Dcz67vtkhrerzh4hptfqpadt5vm',
                  'explicitType': '1',
                  'fileSize': '40995252',
                  'publicationTimestampMillis': '1475640000000',
                  'seriesId': 'Iliyrhelw74vdqrro77kq2vrdhy',
                  'seriesTitle': 'The Nerdist',
                  'title': 'Sarah Jessica Parker'
              },
          ]
          'explicitType': '1',
          'link': 'http://nerdist.com/',
          'seriesId': 'Iliyrhelw74vdqrro77kq2vrdhy',
          'title': 'The Nerdist',
          'totalNumEpisodes': 829,
          'userPreferences': {
              'autoDownload': False,
              'notifyOnNewEpisode': False,
              'subscribed': True
          }
      }

`Mobileclient.``get_track_info`(store_track_id)

  Retrieves information about a store track.

  Parameters: | store_track_id – a store track id (hint: they always start with ‘T’)

  Returns a dict, eg:

      {
          'album': 'Best Of',
          'kind': 'sj#track',
          'storeId': 'Te2qokfjmhqxw4bnkswbfphzs4m',
          'artist': 'Amorphis',
          'albumArtRef': [
          {
              'url': 'http://lh5.ggpht.com/...'
          }],
          'title': 'Hopeless Days',
          'nid': 'Te2qokfjmhqxw4bnkswbfphzs4m',
          'estimatedSize': '12325643',
          'albumId': 'Bsbjjc24a5xutbutvbvg3h4y2k4',
          'artistId': ['Apoecs6off3y6k4h5nvqqos4b5e'],
          'albumArtist': 'Amorphis',
          'durationMillis': '308000',
          'composer': '',
          'genre': 'Metal',
          'trackNumber': 2,
          'discNumber': 1,
          'trackAvailableForPurchase': True,
          'trackType': '7',
          'albumAvailableForPurchase': True
      }

`Mobileclient.``get_station_info`(station_id, num_tracks=25)

  Retrieves information about a station.

  Parameters:

  - station_id – a station id
  - include_tracks – when True, create the `'tracks'` substructure
  - num_tracks – maximum number of tracks to return

  Returns a dict, eg:

      {
          'kind':'sj#radioStation',
          'byline':'By Google Play Music',
          'name':'Neo Soul',
          'compositeArtRefs':[
              {
                  'url':'http://lh3.googleusercontent.com/Aa-WBVTbKegp6McwqeHlj6KX5EYHKOBag74uwNl4xIHSv1g7Mi-NkMzwig',
                  'kind':'sj#imageRef',
                  'aspectRatio':'2'
              }                ],
          'deleted':False,
          'enforcementResult':{
              'sessionInvalidated':False
          },
          'lastModifiedTimestamp':'1497410517701000',
          'recentTimestamp':'1497410516945000',
          'clientId':'9e66e89e-50b0-11e7-aaa3-bc5ff4545c4b',
          'sessionToken':'AFTSR9PtB_PbyqZ3jsnl-PFma4upK1MEtlhVnIlxRNynGalctoJF4TpgzaxymOnk0Gv5DQG7gb_W3eLamPU_Mg1cWylhrowQi1EFMBKWHeDDYWzpU1cEOF-D3c_gnwsBRHIuOetph2veY2Fd-dKVzjOkN6mtidE-XPR2VnpR9PG83wRLVRtJq5593-Vvbu6wjCHD9f23ohxg-ki0tyD3fjFW1463zy63YzN5Aa2SpbvOskEWhwhS3u9ASgEoX08lePE-ZZAq1XtmVvLa8DnDMVb7i95Qhp0dM2it1uruKHH85u7tMYnttbAW4022d0rqrp3ULDKOYMvIIouXH44-bkbKLuVIADiqeNavwTVzcoJxWo4mMKjCaxM=',
          'tracks':[
              {
                  'albumArtRef':[
                      {
                          'url':'http://lh5.ggpht.com/vWRj9DkKZ7cFj-qXoGoBGsv7ngUWdtGNl1SSOdzj2efDwdAs3F0kJ3Xq6zLxKjgv1v3ive5S',
                          'kind':'sj#imageRef',
                          'aspectRatio':'1',
                          'autogen':False
                      }
                  ],
                  'artistId':[
                      'Atmjrctnubes5zhftrey2xjkzl'
                  ],
                  'composer':'',
                  'year':1996,
                  'trackAvailableForSubscription':True,
                  'trackType':'7',
                  'album':u"Maxwell's Urban Hang Suite",
                  'title':u"Ascension (Don't Ever Wonder)",
                  'albumArtist':'Maxwell',
                  'trackNumber':4,
                  'discNumber':1,
                  'albumAvailableForPurchase':False,
                  'explicitType':'2',
                  'trackAvailableForPurchase':True,
                  'storeId':'T6utayayrlyfmpovgj4ulacpat',
                  'nid':'T6utayayrlyfmpovgj4ulacpat',
                  'estimatedSize':'13848059',
                  'albumId':'Bpwzztxynfjwtnrtgiugem3b56e',
                  'genre':'Neo-Soul',
                  'kind':'sj#track',
                  'primaryVideo':{
                      'kind':'sj#video',
                      'id':'D7rm9t5S4uE',
                      'thumbnails':[
                          {
                              'url':'https://i.ytimg.com/vi/D7rm9t5S4uE/mqdefault.jpg',
                              'width':320,
                              'height':180
                          }
                      ]
                  },
                  'artist':'Maxwell',
                  'wentryid':'ec9428eb-2676-4e92-901d-2de9a72fe581',
                  'durationMillis':'346000'
              }
          ],
          'seed':{
              'kind':'sj#radioSeed',
              'curatedStationId':'L3lu7bpcqtd3e7pa7w37rf7gdu',
              'seedType':'9'
          },
          'skipEventHistory':[
          ],
          'inLibrary':False,
          'imageUrls':[
              {
                  'url':'http://lh3.googleusercontent.com/iceDDsQjQ683AD4w21WWlekg115Ixy_kMTivkFJTjo3w7vuW4-SSs3F3KQOaR8qoI-QYVuOQoA',
                  'kind':'sj#imageRef',
                  'aspectRatio':'1',
                  'autogen':False
              }
          ],
          'id':'1a9ec96c-6c98-3c43-b123-9e2743203f5d'
      }

## Misc

`Mobileclient.``get_browse_podcast_hierarchy`()

  Retrieve the hierarchy of podcast browse genres.

  Returns a list of podcast genres and subgenres:

      {
          "groups": [
              {
                  "id": "JZCpodcasttopchart",
                  "displayName": "Top Charts",
                  "subgroups": [
                      {
                       "id": "JZCpodcasttopchartall",
                       "displayName": "All categories"
                      },
                      {
                       "id": "JZCpodcasttopchartarts",
                       "displayName": "Arts"
                      },
                      {
                       "id": "JZCpodcasttopchartbusiness",
                       "displayName": "Business"
                      },
                      {
                       "id": "JZCpodcasttopchartcomedy",
                       "displayName": "Comedy"
                      },
                      {
                       "id": "JZCpodcasttopcharteducation",
                       "displayName": "Education"
                      },
                      {
                       "id": "JZCpodcasttopchartgames",
                       "displayName": "Games & hobbies"
                      },
                      {
                       "id": "JZCpodcasttopchartgovernment",
                       "displayName": "Government & organizations"
                      },
                      {
                       "id": "JZCpodcasttopcharthealth",
                       "displayName": "Health"
                      },
                      {
                       "id": "JZCpodcasttopchartkids",
                       "displayName": "Kids & families"
                      },
                      {
                       "id": "JZCpodcasttopchartmusic",
                       "displayName": "Music"
                      },
                      {
                       "id": "JZCpodcasttopchartnews",
                       "displayName": "News & politics"
                      },
                      {
                       "id": "JZCpodcasttopchartreligion",
                       "displayName": "Religion & spirituality"
                      },
                      {
                       "id": "JZCpodcasttopchartscience",
                       "displayName": "Science & medicine"
                      },
                      {
                       "id": "JZCpodcasttopchartsociety",
                       "displayName": "Society & culture"
                      },
                      {
                       "id": "JZCpodcasttopchartsports",
                       "displayName": "Sports & recreation"
                      },
                      {
                       "id": "JZCpodcasttopcharttechnology",
                       "displayName": "Technology"
                      },
                      {
                       "id": "JZCpodcasttopcharttv",
                       "displayName": "TV & film"
                      }
                  ]
              }
          ]
      }

`Mobileclient.``get_browse_podcast_series`(genre_id='JZCpodcasttopchartall')

  Retrieve podcast series from browse podcasts by genre.

  Parameters: | genre_id – A podcast genre id as returned by `get_podcast_browse_hierarchy()`. Defaults to Top Chart ‘All categories’.

  Returns a list of podcast series dicts.

  Here is an example podcast series dict:

      {
          'art': [
              {
                  'aspectRatio': '1',
                  'autogen': False,
                  'kind': 'sj#imageRef',
                  'url': 'http://lh3.googleusercontent.com/liR-Pm7EhB58wrAa4uo9Y33LcJJ8keU...'
              }
          ],
          'author': 'NBC Sports Radio',
          'continuationToken': '',
          'description': 'Mike Florio talks about the biggest NFL topics with the '
                        'people who are most passionate about the game: League execs, '
                        'players, coaches and the journalists who cover pro football.',
          'explicitType': '2',
          'link': 'https://audioboom.com/channel/pro-football-talk-live-with-mike-florio',
          'seriesId': 'I3iad5heqorm3nck6yp7giruc5i',
          'title': 'Pro Football Talk Live with Mike Florio',
          'totalNumEpisodes': 0
      }

`Mobileclient.``get_listen_now_items`()

  Returns a list of dictionaries of Listen Now albums and stations.

  See `get_listen_now_situations()` for Listen Now situations.

  Here is an example Listen Now album:

      {
        'album': {
          'artist_metajam_id': 'A2mfgoustq7iqjdbvlenw7pnap4',
          'artist_name': 'Justin Bieber',
          'artist_profile_image': {
            'url': 'http://lh3.googleusercontent.com/XgktDR74DWE9xD...'',
          },
          'description': 'Purpose is the fourth studio album by Canadian...',
          'description_attribution': {
            'kind': 'sj#attribution',
            'license_title': 'Creative Commons Attribution CC-BY-SA 4.0',
            'license_url': 'http://creativecommons.org/licenses/by-sa/4.0/legalcode',
            'source_title': 'Wikipedia',
            'source_url': 'http://en.wikipedia.org/wiki/Purpose_(Justin_Bieber_album)',
          },
          'id': {
            'artist': 'Justin Bieber',
            'metajamCompactKey': 'Bqpez5cimsze2fh6w7j2rcf55xa',
            'title': 'Purpose (Deluxe)',
          },
          'title': 'Purpose (Deluxe)'
          'images': [
            {
              'kind': 'sj#imageRef',
              'url': 'http://lh3.googleusercontent.com/m66cbl4Jl3VNz...',
            },
          ],
        }
        'kind': 'sj#listennowitem',
        'suggestion_reason': '9',
        'suggestion_text': 'Popular album on Google Play Music',
        'type': '1'
      }

  Here is an example Listen Now station:

      {
        'radio_station': {
          'id': {
            'seeds': [
              {
                'artistId': 'Ax6ociylvowozcz2iepfqsar54i',
                'kind': 'sj#radioSeed',
                'metadataSeed': {
                  'artist': {
                    'artistArtRef': 'http://lh3.googleusercontent.com/x9qukAx...',
                    'artistArtRefs': [
                      {
                        'aspectRatio': '2',
                        'autogen': False,
                        'kind': 'sj#imageRef',
                        'url': 'http://lh3.googleusercontent.com/x9qukAx...',
                      },
                    ],
                    'artistId': 'Ax6ociylvowozcz2iepfqsar54i',
                    'artist_bio_attribution': {
                    'kind': 'sj#attribution',
                    'source_title': 'artist representative',
                    },
                    'kind': 'sj#artist',
                    'name': 'Drake',
                  },
                  'kind': 'sj#radioSeedMetadata',
                },
               'seedType': '3',
              },
            ]
          },
          'title': 'Drake',
        },
        'compositeArtRefs': [
          {
            'aspectRatio': '2',
            'kind': 'sj#imageRef',
            'url': 'http://lh3.googleusercontent.com/rE39ky1yZN...',
          },
          {
            'aspectRatio': '1',
            'kind': 'sj#imageRef',
            'url': 'http://lh3.googleusercontent.com/Pcwg_HngBr...',
          },
        ],
        'images': [
          {
            'aspectRatio': '2',
            'autogen': False,
            'kind': 'sj#imageRef',
            'url': 'http://lh3.googleusercontent.com/x9qukAx_TMam...',
          },
        ],
        'suggestion_reason': '9',
        'suggestion_text': 'Popular artist on Google Play Music',
        'type': '3'
      }

`Mobileclient.``get_listen_now_situations`()

  Returns a list of dictionaries that each represent a Listen Now situation.

  See `get_listen_now_items()` for Listen Now albums and stations.

  A situation contains a list of related stations or other situations.

  Here is an example situation:

      {
          'description': 'Select a station of today's most popular songs.',
          'id': 'Ntiiwllegkw73p27o236mfsj674',
          'imageUrl': 'http://lh3.googleusercontent.com/egm4NgIK-Cmh84GjVgH...',
          'stations': [
              {
                  'compositeArtRefs': [
                      {
                          'aspectRatio': '2',
                          'kind': 'sj#imageRef',
                          'url': 'http://lh3.googleusercontent.com/ffDI377y...',
                      },
                  ],
                  'contentTypes': ['1'],
                  'description': "This playlist features today's biggest pop songs...",
                  'imageUrls': [
                      {
                          'aspectRatio': '1',
                          'autogen': False,
                          'kind': 'sj#imageRef',
                          'url': 'http://lh3.googleusercontent.com/B4iKX23Z...',
                      },
                  ],
                  'kind': 'sj#radioStation',
                  'name': "Today's Pop Hits",
                  'seed': {
                      'curatedStationId': 'Lgen6kdn43tz5b3edimqd5e4ckq',
                      'kind': 'sj#radioSeed',
                      'seedType': '9',
                  },
                  'skipEventHistory': [],
                  'stationSeeds': [
                      {
                          'curatedStationId': 'Lgen6kdn43tz5b3edimqd5e4ckq',
                          'kind': 'sj#radioSeed',
                          'seedType': '9',
                      },
                  ],
              }
          ],
          'title': "Today's Biggest Hits",
          'wideImageUrl': 'http://lh3.googleusercontent.com/13W-bm3sNmSfOjUkEqY...'
      }