def dynamic_data(cls, playlist_id):
        """
        :param playlist_id: id to retrieve from, or 'all' to get all playlists.
        """

        # This call has a dynamic response schema based on the request.
        # TODO wow, this is a terrible idea

        if playlist_id == "all":
            cls._res_schema = {"type": "object", "properties": {"playlists": pl_array}, "additionalProperties": False}

            return {"json": json.dumps({})}

        else:
            cls._res_schema = pl_schema
            return {"json": json.dumps({"id": playlist_id})}
    def dynamic_data(playlist_id, song_ids_moving, entry_ids_moving,
                     after_entry_id=None, before_entry_id=None):
        """
        :param playlist_id: id of the playlist getting reordered.
        :param song_ids_moving: a list of consecutive song ids. Matches entry_ids_moving.
        :param entry_ids_moving: a list of consecutive entry ids to move. Matches song_ids_moving.
        :param after_entry_id: the entry id to place these songs after. Default first position.
        :param before_entry_id: the entry id to place these songs before. Default last position.
        """

        # empty string means first/last position
        if after_entry_id is None:
            after_entry_id = ""
        if before_entry_id is None:
            before_entry_id = ""

        return {
            'json': json.dumps(
                {
                    "playlistId": playlist_id,
                    "movedSongIds": song_ids_moving,
                    "movedEntryIds": entry_ids_moving,
                    "afterEntryId": after_entry_id,
                    "beforeEntryId": before_entry_id
                }
            )
        }
    def dynamic_data(cont_token=None):
        """:param cont_token: (optional) token to get the next library chunk."""
        if not cont_token:
            req = {}
        else:
            req = {"continuationToken": cont_token}

        return {'json': json.dumps(req)}
예제 #4
0
 def dynamic_data(sid, plays, playtime):
     #TODO this can support multiple
     return json.dumps({'track_stats': [{
         'id': sid,
         'incremental_plays': plays,
         'last_play_time_millis': str(utils.datetime_to_microseconds(playtime)),
         'type': 2 if sid.startswith('T') else 1,
         'track_events': [],
     }]})
    def dynamic_data(playlist_id, song_ids):
        """
        :param playlist_id: id of the playlist to add to.
        :param song_ids: a list of song ids
        """
        # TODO unsure what type means here. Likely involves uploaded vs store/free.
        song_refs = [{"id": sid, "type": 1} for sid in song_ids]

        return {"json": json.dumps({"playlistId": playlist_id, "songRefs": song_refs})}
 def dynamic_data(playlist_id):
     """
     :param playlist_id: id of the playlist to delete.
     """
     return {
         'json': json.dumps(
             {"id": playlist_id}
         )
     }
 def dynamic_data(playlist_id, new_name):
     """
     :param playlist_id: id of the playlist to rename.
     :param new_title: desired title.
     """
     return {
         'json': json.dumps(
             {"playlistId": playlist_id, "playlistName": new_name}
         )
     }
    def dynamic_data(song_ids, playlist_id="all", entry_ids=None):
        """
        :param song_ids: a list of song ids.
        :param playlist_id: playlist id to delete from, or 'all' for deleting from library.
        :param entry_ids: when deleting from playlists, corresponding list of entry ids.
        """

        if entry_ids is None:
            # this is strange, but apparently correct
            entry_ids = [""] * len(song_ids)

        return {"json": json.dumps({"songIds": song_ids, "entryIds": entry_ids, "listId": playlist_id})}
    def dynamic_data(cls, playlist_id):
        """
        :param playlist_id: id to retrieve from, or 'all' to get all playlists.
        """

        #This call has a dynamic response schema based on the request.

        if playlist_id == 'all':
            cls._res_schema = {
                "type": "object",
                "properties": {
                    "playlists": pl_array,
                },
                "additionalProperties": False
            }

            return {'json': json.dumps({})}

        else:
            cls._res_schema = pl_schema
            return {'json': json.dumps({'id': playlist_id})}
    def 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."""
        #small info goes inline, big things get their own external PUT.
        #still not sure as to thresholds - I've seen big album art go inline.
        inlined = {
            "title": "jumper-uploader-title-42",
            "ClientId": track.client_id,
            "ClientTotalSongCount": "1",  # TODO think this is ie "how many will you upload"
            "CurrentTotalUploadedCount": str(num_already_uploaded),
            "CurrentUploadingTrack": track.title,
            "ServerId": server_id,
            "SyncNow": "true",
            "TrackBitRate": track.original_bit_rate,
            "TrackDoNotRematch": str(do_not_rematch).lower(),
            "UploaderId": uploader_id,
        }

        message = {
            "clientId": "Jumper Uploader",
            "createSessionRequest": {
                "fields": [
                    {
                        "external": {
                            "filename": os.path.basename(filepath),
                            "name": os.path.abspath(filepath),
                            "put": {},
                            #used to use this; don't see it in examples
                            #"size": track.estimated_size,
                        }
                    }
                ]
            },
            "protocolVersion": "0.8"
        }

        #Insert the inline info.
        for key in inlined:
            payload = inlined[key]
            if not isinstance(payload, basestring):
                payload = str(payload)

            message['createSessionRequest']['fields'].append(
                {
                    "inlined": {
                        "content": payload,
                        "name": key
                    }
                }
            )

        return json.dumps(message)
    def dynamic_data(songs, session_id=""):
        """
        :param songs: a list of dicts ``{'id': '...', 'albumArtUrl': '...'}``
        """
        if any([s for s in songs if set(s.keys()) != set(['id', 'albumArtUrl'])]):
            raise ValueError("ChangeSongMetadata only supports the 'id' and 'albumArtUrl' keys."
                             " All other keys must be removed.")

        # jsarray is just wonderful
        jsarray = [[session_id, 1]]
        song_arrays = [[s['id'], None, s['albumArtUrl']] + [None] * 36 + [[]] for s in songs]
        jsarray.append([song_arrays])

        return json.dumps(jsarray)
예제 #12
0
    def dynamic_data(cls, updated_after=None, start_token=None, max_results=None):
        """
        :param updated_after: ignored
        :param start_token: nextPageToken from a previous response
        :param max_results: a positive int; if not provided, server defaults to 1000
        """
        data = {}

        if start_token is not None:
            data['start-token'] = start_token

        if max_results is not None:
            data['max-results'] = str(max_results)

        return json.dumps(data)
예제 #13
0
    def dynamic_data(station_id, num_entries, recently_played):
        """
        :param station_id
        :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, "radioId": station_id, "recentlyPlayed": recently_played}],
            }
        )
예제 #14
0
    def dynamic_data(song_ids, playlist_id='all', entry_ids=None):
        """
        :param song_ids: a list of song ids.
        :param playlist_id: playlist id to delete from, or 'all' for deleting from library.
        :param entry_ids: when deleting from playlists, corresponding list of entry ids.
        """

        if entry_ids is None:
            #this is strange, but apparently correct
            entry_ids = [''] * len(song_ids)

        return {
            'json':
            json.dumps({
                "songIds": song_ids,
                "entryIds": entry_ids,
                "listId": playlist_id
            })
        }
예제 #15
0
    def dynamic_data(sid, plays, playtime):
        # TODO this can support multiple tracks at a time

        play_timestamp = utils.datetime_to_microseconds(playtime)
        event = {
            'context_type': 1,
            'event_timestamp_micros': str(play_timestamp),
            'event_type': 2,
            # This can also send a context_id which is the album/artist id
            # the song was found from.
        }

        return json.dumps({'track_stats': [{
            'id': sid,
            'incremental_plays': plays,
            'last_play_time_millis': str(play_timestamp / 1000),
            'type': 2 if sid.startswith('T') else 1,
            'track_events': [event] * plays,
        }]})
예제 #16
0
    def dynamic_data(station_id, num_entries, recently_played):
        """
        :param station_id
        :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,
                                   'radioId': station_id,
                                   'recentlyPlayed': recently_played
                               }
                           ]})
예제 #17
0
def credentials_from_refresh_token(token):
    # why doesn't Google provide this!?

    cred_json = {
        "_module": "oauth2client.client",
        "token_expiry": "2000-01-01T00:13:37Z",  # to refresh now
        "access_token": "bogus",
        "token_uri": "https://accounts.google.com/o/oauth2/token",
        "invalid": False,
        "token_response": {"access_token": "bogus", "token_type": "Bearer", "expires_in": 3600, "refresh_token": token},
        "client_id": oauth.client_id,
        "id_token": None,
        "client_secret": oauth.client_secret,
        "revoke_uri": "https://accounts.google.com/o/oauth2/revoke",
        "_class": "OAuth2Credentials",
        "refresh_token": token,
        "user_agent": None,
    }

    return OAuth2Credentials.new_from_json(json.dumps(cred_json))
def credentials_from_refresh_token(token):
    # why doesn't Google provide this!?

    cred_json = {"_module": "oauth2client.client",
                 "token_expiry": "2000-01-01T00:13:37Z",  # to refresh now
                 "access_token": 'bogus',
                 "token_uri": "https://accounts.google.com/o/oauth2/token",
                 "invalid": False,
                 "token_response": {
                     "access_token": 'bogus',
                     "token_type": "Bearer",
                     "expires_in": 3600,
                     "refresh_token": token},
                 "client_id": oauth.client_id,
                 "id_token": None,
                 "client_secret": oauth.client_secret,
                 "revoke_uri": "https://accounts.google.com/o/oauth2/revoke",
                 "_class": "OAuth2Credentials",
                 "refresh_token": token,
                 "user_agent": None}

    return OAuth2Credentials.new_from_json(json.dumps(cred_json))
    def dynamic_data(cls,
                     share_token,
                     updated_after=None,
                     start_token=None,
                     max_results=None):
        """
        :param share_token: from a shared playlist
        :param updated_after: ignored
        :param start_token: nextPageToken from a previous response
        :param max_results: a positive int; if not provided, server defaults to 1000
        """
        data = {}

        data['shareToken'] = share_token

        if start_token is not None:
            data['start-token'] = start_token

        if max_results is not None:
            data['max-results'] = str(max_results)

        return json.dumps({'entries': [data]})
 def dynamic_data(songs):
     """
     :param songs: a list of dictionary representations of songs
     """
     return {"json": json.dumps({"entries": songs})}
예제 #21
0
 def dynamic_data(query):
     return {'json': json.dumps({'q': query})}
 def dynamic_data(session_id):
     """
     :param: session_id
     """
     return {'json': json.dumps({'sessionId': session_id})}
 def dynamic_data(device_id, session_id):
     return {"json": json.dumps({"deauth": device_id, "sessionId": session_id})}
 def dynamic_data(name, description, public, session_id=""):
     return json.dumps([[session_id, 1], [public, name, description, []]])
 def dynamic_data(song_ids):
     """
     :param: (list) song_ids
     """
     return {'json': json.dumps({'songIds': song_ids})}
 def dynamic_data(device_id, session_id):
     return {'json': json.dumps({'deauth': device_id, 'sessionId': session_id})}
 def dynamic_data(query):
     return {'json': json.dumps({'q': query})}
 def dynamic_data(session_id):
     """
     :param: session_id
     """
     return {"json": json.dumps({"sessionId": session_id})}
 def dynamic_data(session_id):
     """
     :param: session_id
     """
     return {'json': json.dumps({'sessionId': session_id})}
 def dynamic_data(name, description, public, session_id=""):
     return json.dumps([[session_id, 1], [public, name, description, []]])
예제 #31
0
 def dynamic_data(title):
     """
     :param title: the title of the playlist to create.
     """
     return {'json': json.dumps({"title": title})}
예제 #32
0
    def dynamic_data(mutations):
        """
        :param mutations: list of mutation dictionaries
        """

        return json.dumps({'mutations': mutations})
 def dynamic_data(songs):
     """
     :param songs: a list of dictionary representations of songs
     """
     return {'json': json.dumps({'entries': songs})}
 def dynamic_data(session_id, share_token):
     return json.dumps([
         [session_id, 1],
         [share_token]
     ])
 def dynamic_data(song_ids):
     """
     :param: (list) song_ids
     """
     return {'json': json.dumps({'songIds': song_ids})}
 def dynamic_data(title):
     """
     :param title: the title of the playlist to create.
     """
     return {'json': json.dumps({"title": title})}
 def dynamic_data(song_ids):
     return json.dumps([["", 1], [song_ids]])
 def dynamic_data(song_ids):
     """
     :param: (list) song_ids
     """
     return {"json": json.dumps({"songIds": song_ids})}
 def dynamic_data(playlist_id):
     """
     :param playlist_id: id of the playlist to delete.
     """
     return {'json': json.dumps({"id": playlist_id})}
예제 #40
0
    def dynamic_data(cls):
        tz_offset = calendar.timegm(time.localtime()) - calendar.timegm(time.gmtime())

        return json.dumps({
            'requestSignals': {'timeZoneOffsetSecs': tz_offset}
        })
 def dynamic_data(song_ids):
     return json.dumps([["", 1], [song_ids]])
예제 #42
0
 def dynamic_data(device_id, session_id):
     return {'json': json.dumps({'deauth': device_id, 'sessionId': session_id})}
 def dynamic_data(session_id, share_token):
     return json.dumps([[session_id, 1], [share_token]])
예제 #44
0
 def dynamic_data(songs):
     """
     :param songs: a list of dictionary representations of songs
     """
     return {'json': json.dumps({'entries': songs})}