def submit_listen(): """ Submit listens to the server. A user token (found on https://listenbrainz.org/user/import ) must be provided in the Authorization header! For complete details on the format of the JSON to be POSTed to this endpoint, see :ref:`json-doc`. :reqheader Authorization: Token <user token> :statuscode 200: listen(s) accepted. :statuscode 400: invalid JSON sent, see error message for details. :statuscode 401: invalid authorization. See error message for details. :resheader Content-Type: *application/json* """ user = _validate_auth_header() raw_data = request.get_data() try: data = ujson.loads(raw_data.decode("utf-8")) except ValueError as e: log_raise_400("Cannot parse JSON document: %s" % e, raw_data) try: payload = data['payload'] if len(payload) == 0: return "success" if len(raw_data) > len(payload) * MAX_LISTEN_SIZE: log_raise_400( "JSON document is too large. In aggregate, listens may not " "be larger than %d characters." % MAX_LISTEN_SIZE, payload) if data['listen_type'] not in ('playing_now', 'single', 'import'): log_raise_400("JSON document requires a valid listen_type key.", payload) listen_type = _get_listen_type(data['listen_type']) if (listen_type == LISTEN_TYPE_SINGLE or listen_type == LISTEN_TYPE_PLAYING_NOW) and len(payload) > 1: log_raise_400( "JSON document contains more than listen for a single/playing_now. " "It should contain only one.", payload) except KeyError: log_raise_400("Invalid JSON document submitted.", raw_data) # validate listens to make sure json is okay for listen in payload: validate_listen(listen, listen_type) try: insert_payload(payload, user, listen_type=_get_listen_type(data['listen_type'])) except Exception, e: raise InternalServerError("Something went wrong. Please try again.")
def submit_listen(): """ Submit listens to the server. A user token (found on https://listenbrainz.org/user/import ) must be provided in the Authorization header! For complete details on the format of the JSON to be POSTed to this endpoint, see :ref:`json-doc`. :reqheader Authorization: token <user token> :statuscode 200: listen(s) accepted. :statuscode 400: invalid JSON sent, see error message for details. :statuscode 401: invalid authorization. See error message for details. :resheader Content-Type: *application/json* """ user = _validate_auth_header() raw_data = request.get_data() try: data = ujson.loads(raw_data.decode("utf-8")) except ValueError as e: log_raise_400("Cannot parse JSON document: %s" % e, raw_data) try: payload = data['payload'] if len(payload) == 0: return "success" if len(raw_data) > len(payload) * MAX_LISTEN_SIZE: log_raise_400("JSON document is too large. In aggregate, listens may not " "be larger than %d characters." % MAX_LISTEN_SIZE, payload) if data['listen_type'] not in ('playing_now', 'single', 'import'): log_raise_400("JSON document requires a valid listen_type key.", payload) listen_type = data['listen_type'] if (listen_type == LISTEN_TYPE_SINGLE or listen_type == LISTEN_TYPE_PLAYING_NOW) and len(payload) > 1: _log_raise_400("JSON document contains more than listen for a single/playing_now. " "It should contain only one.", payload) except KeyError: log_raise_400("Invalid JSON document submitted.", raw_data) try: insert_payload(payload, user["id"], listen_type=data['listen_type']) except Exception, e: raise InternalServerError("Something went wrong. Please try again.")
def record_listens(request, data): """ Submit the listen in the lastfm format to be inserted in db. Accepts listens for both track.updateNowPlaying and track.scrobble methods. """ output_format = data.get('format', 'xml') try: sk, api_key = data['sk'], data['api_key'] except KeyError: raise InvalidAPIUsage( CompatError.INVALID_PARAMETERS, output_format=output_format) # Invalid parameters session = Session.load(sk, api_key) if not session: if not Token.is_valid_api_key(api_key): raise InvalidAPIUsage( CompatError.INVALID_API_KEY, output_format=output_format) # Invalid API_KEY raise InvalidAPIUsage( CompatError.INVALID_SESSION_KEY, output_format=output_format) # Invalid Session KEY lookup = defaultdict(dict) for key, value in data.items(): if key in ["sk", "token", "api_key", "method", "api_sig"]: continue matches = re.match('(.*)\[(\d+)\]', key) if matches: key = matches.group(1) number = matches.group(2) else: number = 0 lookup[number][key] = value if request.form['method'].lower() == 'track.updatenowplaying': for i, listen in lookup.iteritems(): if 'timestamp' not in listen: listen['timestamp'] = calendar.timegm( datetime.now().utctimetuple()) # Convert to native payload then submit 'em after validation. listen_type, native_payload = _to_native_api(lookup, data['method'], output_format) for listen in native_payload: validate_listen(listen, listen_type) augmented_listens = insert_payload(native_payload, session.user, listen_type=listen_type) # With corrections than the original submitted listen. doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('nowplaying' if listen_type == 'playing_now' else 'scrobbles'): for origL, augL in zip(lookup.values(), augmented_listens): corr = defaultdict(lambda: '0') track = augL['track_metadata']['track_name'] if origL['track'] != augL['track_metadata']['track_name']: corr['track'] = '1' artist = augL['track_metadata']['artist_name'] if origL['artist'] != augL['track_metadata']['artist_name']: corr['artist'] = '1' ts = augL['listened_at'] albumArtist = artist if origL.get('albumArtist', origL['artist']) != artist: corr['albumArtist'] = '1' album = augL['track_metadata'].get('release_name', '') if origL.get('album', '') != album: corr['album'] = '1' with tag('scrobble'): with tag('track', corrected=corr['track']): text(track) with tag('artist', corrected=corr['artist']): text(artist) with tag('album', corrected=corr['album']): text(album) with tag('albumArtist', corrected=corr['albumArtist']): text(albumArtist) with tag('timestamp'): text(ts) with tag('ignoredMessage', code="0"): text('') return format_response( '<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), output_format)
def record_listens(request, data): """ Submit the listen in the lastfm format to be inserted in db. Accepts listens for both track.updateNowPlaying and track.scrobble methods. """ output_format = data.get('format', 'xml') try: sk, api_key = data['sk'], data['api_key'] except KeyError: raise InvalidAPIUsage(6, output_format=output_format) # Invalid parameters session = Session.load(sk, api_key) if not session: if not Token.is_valid_api_key(api_key): raise InvalidAPIUsage(10, output_format=output_format) # Invalid API_KEY raise InvalidAPIUsage(9, output_format=output_format) # Invalid Session KEY lookup = defaultdict(dict) for key, value in data.items(): if key == "sk" or key == "token" or key == "api_key" or key == "method": continue matches = re.match('(.*)\[(\d+)\]', key) if matches: key = matches.group(1) number = matches.group(2) else: number = 0 lookup[number][key] = value if request.form['method'].lower() == 'track.updatenowplaying': for i, listen in lookup.iteritems(): if 'timestamp' not in listen: listen['timestamp'] = calendar.timegm(datetime.now().utctimetuple()) # Convert to native payload then submit 'em. listen_type, native_payload = _to_native_api(lookup, data['method'], output_format) augmented_listens = insert_payload(native_payload, str(session.user.id), listen_type=listen_type) # With corrections than the original submitted listen. doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('nowplaying' if listen_type == 'playing_now' else 'scrobbles'): for origL, augL in zip(lookup.values(), augmented_listens): corr = defaultdict(lambda: '0') track = augL['track_metadata']['track_name'] if origL['track'] != augL['track_metadata']['track_name']: corr['track'] = '1' artist = augL['track_metadata']['artist_name'] if origL['artist'] != augL['track_metadata']['artist_name']: corr['artist'] = '1' ts = augL['listened_at'] albumArtist = artist if origL.get('albumArtist', origL['artist']) != artist: corr['albumArtist'] = '1' # TODO: Add the album part album = "" with tag('scrobble'): with tag('track', corrected=corr['track']): text(track) with tag('artist', corrected=corr['artist']): text(artist) with tag('album', corrected=corr['album']): text(album) with tag('albumArtist', corrected=corr['albumArtist']): text(albumArtist) with tag('timestamp'): text(ts) with tag('ignoredMessage', code="0"): text('') return format_response('<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), output_format)