def test_load(self): token = Token.generate(self.user.api_key) self.assertIsInstance(token, Token) self.assertIsNone(token.user) """ Before approving """ # Load with token token1 = Token.load(token.token) self.assertIsNone(token1.user) self.assertDictEqual(token1.__dict__, token.__dict__) # Load with token & api_key token2 = Token.load(token.token, token.api_key) self.assertIsNone(token2.user) self.assertDictEqual(token2.__dict__, token.__dict__) token.approve(self.user.name) """ After approving the token """ # Load with token token1 = Token.load(token.token) self.assertIsInstance(token1.user, User) self.assertDictEqual(token1.user.__dict__, token.user.__dict__) token_user = token.user token.user, token1.user = None, None self.assertDictEqual(token1.__dict__, token.__dict__) token.user = token_user # Load with token & api_key token2 = Token.load(token.token, token.api_key) self.assertIsInstance(token2.user, User) self.assertDictEqual(token2.user.__dict__, token.user.__dict__) token.user, token1.user = None, None self.assertDictEqual(token1.__dict__, token.__dict__)
def get_session(request, data): """ Create new session after validating the API_key and token. """ output_format = data.get('format', 'xml') try: api_key = data['api_key'] token = Token.load(data['token'], api_key) except KeyError: raise InvalidAPIUsage(CompatError.INVALID_PARAMETERS, output_format=output_format) # Missing Required Params if not token: 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_TOKEN, output_format=output_format) # Invalid token if token.has_expired(): raise InvalidAPIUsage(CompatError.TOKEN_EXPIRED, output_format=output_format) # Token expired if not token.user: raise InvalidAPIUsage(CompatError.UNAUTHORIZED_TOKEN, output_format=output_format) # Unauthorized token session = Session.create(token) doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('session'): with tag('name'): text(session.user.name) with tag('key'): text(session.sid) with tag('subscriber'): text('0') return format_response('<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), data.get('format', "xml"))
def test_record_listen(self): """ Tests if listen is recorded correctly if valid information is provided. """ token = Token.generate(self.lfm_user.api_key) token.approve(self.lfm_user.name) session = Session.create(token) timestamp = int(time.time()) data = { 'method': 'track.scrobble', 'api_key': self.lfm_user.api_key, 'sk': session.sid, 'artist[0]': 'Kishore Kumar', 'track[0]': 'Saamne Ye Kaun Aya', 'album[0]': 'Jawani Diwani', 'duration[0]': 300, 'timestamp[0]': timestamp, } r = self.client.post(url_for('api_compat.api_methods'), data=data) self.assert200(r) response = xmltodict.parse(r.data) self.assertEqual(response['lfm']['@status'], 'ok') self.assertEqual(response['lfm']['scrobbles']['@accepted'], '1') # Check if listen reached the influx listenstore time.sleep(1) listens = self.ls.fetch_listens(self.lb_user['musicbrainz_id'], from_ts=timestamp-1) self.assertEqual(len(listens), 1)
def test_record_listen_now_playing(self): """ Tests if listen of type 'nowplaying' is recorded correctly if valid information is provided. """ token = Token.generate(self.lfm_user.api_key) token.approve(self.lfm_user.name) session = Session.create(token) data = { 'method': 'track.updateNowPlaying', 'api_key': self.lfm_user.api_key, 'sk': session.sid, 'artist[0]': 'Kishore Kumar', 'track[0]': 'Saamne Ye Kaun Aya', 'album[0]': 'Jawani Diwani', 'duration[0]': 300, 'timestamp[0]': int(time.time()), } r = self.client.post(url_for('api_compat.api_methods'), data=data) self.assert200(r) response = xmltodict.parse(r.data) self.assertEqual(response['lfm']['@status'], 'ok') self.assertIsNotNone(response['lfm']['nowplaying'])
def test_record_listen(self): """ Tests if listen is recorded correctly if valid information is provided. """ token = Token.generate(self.lfm_user.api_key) token.approve(self.lfm_user.name) session = Session.create(token) timestamp = int(time.time()) data = { 'method': 'track.scrobble', 'api_key': self.lfm_user.api_key, 'sk': session.sid, 'artist[0]': 'Kishore Kumar', 'track[0]': 'Saamne Ye Kaun Aya', 'album[0]': 'Jawani Diwani', 'duration[0]': 300, 'timestamp[0]': timestamp, } r = self.client.post(url_for('api_compat.api_methods'), data=data) self.assert200(r) response = xmltodict.parse(r.data) self.assertEqual(response['lfm']['@status'], 'ok') self.assertEqual(response['lfm']['scrobbles']['@accepted'], '1') # Check if listen reached the timescale listenstore time.sleep(2) listens, _, _ = self.ls.fetch_listens(self.lb_user['musicbrainz_id'], from_ts=timestamp - 1) self.assertEqual(len(listens), 1)
def api_auth_approve(): """ Authenticate the user token provided. """ user = User.load_by_name(current_user.musicbrainz_id) if "token" not in request.form: return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg="Missing required parameters. Please provide correct parameters and try again." ) token = Token.load(request.form['token']) if not token: return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg="Either this token is already used or invalid. Please try again." ) if token.user: return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg="This token is already approved. Please check the token and try again." ) if token.has_expired(): return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg="This token has expired. Please create a new token and try again." ) token.approve(user.name) return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg="Token %s approved for user %s, press continue in client." % (token.token, current_user.musicbrainz_id) )
def test_session_create(self): user = User.load_by_id(db_user.create(1, "test")) token = Token.generate(user.api_key) token.approve(user.name) session = Session.create(token) self.assertIsInstance(session, Session) self.assertDictEqual(user.__dict__, session.user.__dict__)
def test_session_create(self): user = User.load_by_id(db_user.create("test")) token = Token.generate(user.api_key) token.approve(user.name) session = Session.create(token) self.assertIsInstance(session, Session) self.assertDictEqual(user.__dict__, session.user.__dict__)
def test_user_getinfo_no_listenstore(self): """If this listenstore is unavailable, performing a query that gets user information (touches the listenstore for user count) should return an error message in the requested format""" timescale_connection._ts = None token = Token.generate(self.lfm_user.api_key) token.approve(self.lfm_user.name) session = Session.create(token) data = { 'method': 'user.getInfo', 'api_key': self.lfm_user.api_key, 'sk': session.sid } r = self.client.post(url_for('api_compat.api_methods'), data=data) self.assert200(r) self.assertEqual(r.headers["Content-type"], "application/xml; charset=utf-8") expected_message = b"""<?xml version="1.0" encoding="utf-8"?> <lfm status="failed"> <error code="16">The service is temporarily unavailable, please try again.</error> </lfm>""" assert r.data == expected_message
def test_has_expired(self): token = Token.generate(str(uuid.uuid4())) self.assertFalse(token.has_expired()) token.timestamp = token.timestamp - timedelta(minutes=TOKEN_EXPIRATION_TIME - 1) # This is asssertFalse because in the next 1 minute the next statement will get executed self.assertFalse(token.has_expired()) token.timestamp = token.timestamp - timedelta(minutes=1) self.assertTrue(token.has_expired())
def test_has_expired(self): token = Token.generate(str(uuid.uuid4())) self.assertFalse(token.has_expired()) token.timestamp = token.timestamp - timedelta( minutes=TOKEN_EXPIRATION_TIME - 1) # This is asssertFalse because in the next 1 minute the next statement will get executed self.assertFalse(token.has_expired()) token.timestamp = token.timestamp - timedelta(minutes=1) self.assertTrue(token.has_expired())
def get_token(request, data): """ Issue a token to user after verying his API_KEY """ output_format = data.get('format', 'xml') api_key = data.get('api_key') if not api_key: raise InvalidAPIUsage(CompatError.INVALID_PARAMETERS, output_format=output_format) # Missing required params if not Token.is_valid_api_key(api_key): raise InvalidAPIUsage(CompatError.INVALID_API_KEY, output_format=output_format) # Invalid API_KEY token = Token.generate(api_key) doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('token'): text(token.token) 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(CompatError.INVALID_PARAMETERS, output_format=output_format) # Invalid parameters session = Session.load(sk) 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.items(): 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) user = db_user.get(session.user_id) augmented_listens = insert_payload(native_payload, user, listen_type=listen_type) # With corrections than the original submitted listen. doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): if listen_type == 'playing_now': doc.asis(create_response_for_single_listen(list(lookup.values())[0], augmented_listens[0], listen_type)) else: accepted_listens = len(lookup.values()) # Currently LB accepts all the listens and ignores none with tag('scrobbles', accepted=accepted_listens, ignored='0'): for original_listen, augmented_listen in zip(list(lookup.values()), augmented_listens): doc.asis(create_response_for_single_listen(original_listen, augmented_listen, listen_type)) return format_response('<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), output_format)
def get_session(request, data): """ Create new session after validating the API_key and token. """ output_format = data.get('format', 'xml') try: api_key = data['api_key'] token = Token.load(data['token'], api_key) except KeyError: raise InvalidAPIUsage( CompatError.INVALID_PARAMETERS, output_format=output_format) # Missing Required Params if not token: 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_TOKEN, output_format=output_format) # Invalid token if token.has_expired(): raise InvalidAPIUsage(CompatError.TOKEN_EXPIRED, output_format=output_format) # Token expired if not token.user: raise InvalidAPIUsage( CompatError.UNAUTHORIZED_TOKEN, output_format=output_format) # Unauthorized token session = Session.create(token) doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('session'): with tag('name'): text(session.user.name) with tag('key'): text(session.sid) with tag('subscriber'): text('0') return format_response( '<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), data.get('format', "xml"))
def user_info(request, data): """ Gives information about the user specified in the parameters. """ try: output_format = data.get('format', 'xml') api_key = data['api_key'] sk = data.get('sk') username = data.get('user') if not (sk or username): raise KeyError if not Token.is_valid_api_key(api_key): raise InvalidAPIUsage( CompatError.INVALID_API_KEY, output_format=output_format) # Invalid API key user = User.load_by_sessionkey(sk, api_key) if not user: raise InvalidAPIUsage( CompatError.INVALID_SESSION_KEY, output_format=output_format) # Invalid Session key query_user = User.load_by_name(username) if ( username and username != user.name) else user if not query_user: raise InvalidAPIUsage( CompatError.INVALID_RESOURCE, output_format=output_format) # Invalid resource specified except KeyError: raise InvalidAPIUsage( CompatError.INVALID_PARAMETERS, output_format=output_format) # Missing required params doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('user'): with tag('name'): text(query_user.name) with tag('realname'): text(query_user.name) with tag('url'): text('http://listenbrainz.org/user/' + query_user.name) with tag('playcount'): text( User.get_play_count(query_user.id, timescale_connection._ts)) with tag('registered', unixtime=str(query_user.created.strftime("%s"))): text(str(query_user.created)) return format_response( '<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), data.get('format', "xml"))
def test_session_load(self): user = User.load_by_id(db_user.create(1, "test")) token = Token.generate(user.api_key) token.approve(user.name) session = Session.create(token) self.assertIsInstance(session, Session) self.assertDictEqual(user.__dict__, session.user.__dict__) session.user = None # Load with session_key + api_key session2 = Session.load(session.sid) self.assertDictEqual(user.__dict__, session2.__dict__['user'].__dict__) session2.user = None self.assertDictEqual(session.__dict__, session2.__dict__)
def get_token(request, data): """ Issue a token to user after verying his API_KEY """ output_format = data.get('format', 'xml') api_key = data.get('api_key') if not api_key: raise InvalidAPIUsage( CompatError.INVALID_PARAMETERS, output_format=output_format) # Missing required params if not Token.is_valid_api_key(api_key): raise InvalidAPIUsage(CompatError.INVALID_API_KEY, output_format=output_format) # Invalid API_KEY token = Token.generate(api_key) doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('token'): text(token.token) return format_response( '<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), output_format)
def test_session_load(self): user = User.load_by_id(db_user.create("test")) token = Token.generate(user.api_key) token.approve(user.name) session = Session.create(token) self.assertIsInstance(session, Session) self.assertDictEqual(user.__dict__, session.user.__dict__) session.user = None # Load with session_key + api_key session2 = Session.load(session.sid, session.api_key) self.assertDictEqual(user.__dict__, session2.__dict__['user'].__dict__) session2.user = None self.assertDictEqual(session.__dict__, session2.__dict__)
def test_approve(self): token = Token.generate(str(uuid.uuid4())) self.assertIsInstance(token, Token) self.assertIsNone(token.user) before_token = token.__dict__ before_token.pop('user') token.approve(self.user.name) after_token = token.__dict__ self.assertIsInstance(token.user, User) self.assertDictEqual(token.user.__dict__, self.user.__dict__) after_token.pop('user') self.assertDictEqual(after_token, before_token)
def test_get_token(self): """ Tests if the token generated by get_token method is valid. """ data = { 'method': 'auth.gettoken', 'api_key': self.lfm_user.api_key, } r = self.client.post(url_for('api_compat.api_methods'), data=data) self.assert200(r) response = xmltodict.parse(r.data) self.assertEqual(response['lfm']['@status'], 'ok') token = Token.load(response['lfm']['token'], api_key=self.lfm_user.api_key) self.assertIsNotNone(token)
def test_get_session(self): """ Tests if the session key is valid and session is established correctly. """ token = Token.generate(self.lfm_user.api_key) token.approve(self.lfm_user.name) data = { 'method': 'auth.getsession', 'api_key': self.lfm_user.api_key, 'token': token.token, } r = self.client.post(url_for('api_compat.api_methods'), data=data) self.assert200(r) response = xmltodict.parse(r.data) self.assertEqual(response['lfm']['@status'], 'ok') self.assertEqual(response['lfm']['session']['name'], self.lfm_user.name) session_key = Session.load(response['lfm']['session']['key']) self.assertIsNotNone(session_key)
def user_info(request, data): """ Gives information about the user specified in the parameters. """ try: api_key = data['api_key'] output_format = data.get('format', 'xml') sk = data.get('sk') username = data.get('user') if not (sk or username): raise KeyError if not Token.is_valid_api_key(api_key): raise InvalidAPIUsage(CompatError.INVALID_API_KEY, output_format=output_format) # Invalid API key user = User.load_by_sessionkey(sk, api_key) if not user: raise InvalidAPIUsage(CompatError.INVALID_SESSION_KEY, output_format=output_format) # Invalid Session key query_user = User.load_by_name(username) if (username and username != user.name) else user if not query_user: raise InvalidAPIUsage(CompatError.INVALID_RESOURCE, output_format=output_format) # Invalid resource specified except KeyError: raise InvalidAPIUsage(CompatError.INVALID_PARAMETERS, output_format=output_format) # Missing required params doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): with tag('user'): with tag('name'): text(query_user.name) with tag('realname'): text(query_user.name) with tag('url'): text('http://listenbrainz.org/user/' + query_user.name) with tag('playcount'): text(User.get_play_count(query_user.id, _influx)) with tag('registered', unixtime=str(query_user.created.strftime("%s"))): text(str(query_user.created)) return format_response('<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), data.get('format', "xml"))
def test_record_invalid_listen(self): """ Tests that error is raised if submited data contains unicode null """ token = Token.generate(self.lfm_user.api_key) token.approve(self.lfm_user.name) session = Session.create(token) timestamp = int(time.time()) data = { 'method': 'track.scrobble', 'api_key': self.lfm_user.api_key, 'sk': session.sid, 'artist[0]': '\u0000Kishore Kumar', 'track[0]': 'Saamne Ye Kaun Aya', 'album[0]': 'Jawani Diwani', 'duration[0]': 300, 'timestamp[0]': timestamp, } r = self.client.post(url_for('api_compat.api_methods'), data=data) self.assert400(r) self.assertEqual(r.json["error"], "\u0000Kishore Kumar contains a unicode null")
def api_auth_approve(): """ Authenticate the user token provided. """ user = User.load_by_name(current_user.musicbrainz_id) if "token" not in request.form: return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg= "Missing required parameters. Please provide correct parameters and try again." ) token = Token.load(request.form['token']) if not token: return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg= "Either this token is already used or invalid. Please try again.") if token.user: return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg= "This token is already approved. Please check the token and try again." ) if token.has_expired(): return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg= "This token has expired. Please create a new token and try again.") token.approve(user.name) return render_template( "user/auth.html", user_id=current_user.musicbrainz_id, msg="Token %s approved for user %s, press continue in client." % (token.token, current_user.musicbrainz_id))
def record_listens(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) 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 user = db_user.get(session.user_id, fetch_email=True) if mb_engine and current_app.config[ "REJECT_LISTENS_WITHOUT_USER_EMAIL"] and user["email"] is None: raise InvalidAPIUsage( CompatError.NO_EMAIL, output_format=output_format) # No email available for user in LB lookup = defaultdict(dict) for key, value in data.items(): if key in ["sk", "token", "api_key", "method", "api_sig", "format"]: continue matches = re.match('(.*)\[(\d+)\]', key) if matches: key = matches.group(1) number = matches.group(2) else: number = 0 lookup[number][key] = value if data['method'].lower() == 'track.updatenowplaying': for i, listen in lookup.items(): 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) try: validated_payload = [ validate_listen(listen, listen_type) for listen in native_payload ] except ListenValidationError as err: # Unsure about which LastFMError code to use but 5 or 6 probably make the most sense. # see listenbrainz.webserver.errors.py for a detailed list of all available codes raise InvalidAPIUsage(LastFMError(code=6, message=err.message), 400, output_format) user_metadata = SubmitListenUserMetadata( user_id=user['id'], musicbrainz_id=user['musicbrainz_id']) augmented_listens = insert_payload(validated_payload, user_metadata, listen_type=listen_type) # With corrections than the original submitted listen. doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): if listen_type == 'playing_now': doc.asis( create_response_for_single_listen( list(lookup.values())[0], augmented_listens[0], listen_type)) else: accepted_listens = len(lookup.values()) # Currently LB accepts all the listens and ignores none with tag('scrobbles', accepted=accepted_listens, ignored='0'): for original_listen, augmented_listen in zip( list(lookup.values()), augmented_listens): doc.asis( create_response_for_single_listen( original_listen, augmented_listen, listen_type)) return format_response( '<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), output_format)
def test_generate(self): token = Token.generate(str(uuid.uuid4())) self.assertIsInstance(token, Token)
def test_is_valid_api_key(self): self.assertTrue(Token.is_valid_api_key(self.user.api_key)) self.assertTrue(Token.is_valid_api_key(str(uuid.uuid4())))
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.items(): 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(list(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( CompatError.INVALID_PARAMETERS, output_format=output_format) # Invalid parameters session = Session.load(sk) 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.items(): 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) user = db_user.get(session.user_id) augmented_listens = insert_payload(native_payload, user, listen_type=listen_type) # With corrections than the original submitted listen. doc, tag, text = Doc().tagtext() with tag('lfm', status='ok'): if listen_type == 'playing_now': doc.asis( create_response_for_single_listen( list(lookup.values())[0], augmented_listens[0], listen_type)) else: accepted_listens = len(lookup.values()) # Currently LB accepts all the listens and ignores none with tag('scrobbles', accepted=accepted_listens, ignored='0'): for original_listen, augmented_listen in zip( list(lookup.values()), augmented_listens): doc.asis( create_response_for_single_listen( original_listen, augmented_listen, listen_type)) return format_response( '<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()), output_format)