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 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_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 influx listenstore
        time.sleep(1)
        listens = self.ls.fetch_listens(self.lb_user['musicbrainz_id'], from_ts=timestamp-1)
        self.assertEqual(len(listens), 1)
Пример #5
0
    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
Пример #6
0
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"))
Пример #7
0
    def test_get_session(self):
        """ Tests _get_session method in api_compat_deprecated """

        s = Session.create_by_user_id(self.user['id'])

        session = _get_session(s.sid)
        self.assertEqual(s.sid, session.sid)
Пример #8
0
def session_info(request, data):
    try:
        sk = data['sk']
        api_key = data['api_key']
        output_format = data.get('format', 'xml')
        username = data['username']
    except KeyError:
        raise InvalidAPIUsage(CompatError.INVALID_PARAMETERS, output_format=output_format)        # Missing Required Params

    session = Session.load(sk)
    if (not session) or User.load_by_name(username).id != session.user.id:
        raise InvalidAPIUsage(CompatError.INVALID_SESSION_KEY, output_format=output_format)       # Invalid Session KEY

    print("SESSION INFO for session %s, user %s" % (session.id, session.user.name))

    doc, tag, text = Doc().tagtext()
    with tag('lfm', status='ok'):
        with tag('application'):
            with tag('session'):
                with tag('name'):
                    text(session.user.name)
                with tag('key'):
                    text(session.id)
                with tag('subscriber'):
                    text('0')
                with tag('country'):
                    text('US')

    return format_response('<?xml version="1.0" encoding="utf-8"?>\n' + yattag.indent(doc.getvalue()),
                           output_format)
Пример #9
0
    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_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_get_session(self):
        """ Tests _get_session method in api_compat_deprecated """

        s = Session.create_by_user_id(self.user['id'])

        session = _get_session(s.sid)
        self.assertEqual(s.sid, session.sid)
 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__)
Пример #13
0
    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 handshake():
    """ View to handshake with the client.

        Creates a new session stored in api_compat.session and then later uses it
        to submit listens. We do auth assuming the LB auth_tokens to be
        passwords, so this should work when users enter their LB auth tokens as passwords
        in clients.
    """

    if request.args.get('hs', '') != 'true':
        return redirect('https://listenbrainz.org/lastfm-proxy')

    user = db_user.get_by_mb_id(request.args.get('u'))
    if user is None:
        return 'BADAUTH\n', 401

    auth_token = request.args.get('a', '')
    timestamp = request.args.get('t', 0)

    correct = _get_audioscrobbler_auth_token(user['auth_token'], timestamp)

    if auth_token != _get_audioscrobbler_auth_token(user['auth_token'], timestamp):
        return 'BADAUTH\n', 401

    session = Session.create_by_user_id(user['id'])
    current_app.logger.info('New session created with id: {}'.format(session.sid))

    return '\n'.join([
        'OK',
        session.sid,
        '{}/np_1.2'.format(current_app.config['LASTFM_PROXY_URL']),
        '{}/protocol_1.2\n'.format(current_app.config['LASTFM_PROXY_URL'])
    ])
Пример #15
0
def handshake():
    """ View to handshake with the client.

        Creates a new session stored in api_compat.session and then later uses it
        to submit listens. We do auth assuming the LB auth_tokens to be
        passwords, so this should work when users enter their LB auth tokens as passwords
        in clients.
    """

    if request.args.get('hs', '') != 'true':
        return redirect('https://listenbrainz.org/lastfm-proxy')

    user = db_user.get_by_mb_id(request.args.get('u'))
    if user is None:
        return 'BADAUTH\n', 401

    auth_token = request.args.get('a', '')
    timestamp = request.args.get('t', 0)

    correct = _get_audioscrobbler_auth_token(user['auth_token'], timestamp)

    if auth_token != _get_audioscrobbler_auth_token(user['auth_token'],
                                                    timestamp):
        return 'BADAUTH\n', 401

    session = Session.create_by_user_id(user['id'])
    current_app.logger.info('New session created with id: {}'.format(
        session.sid))

    return '\n'.join([
        'OK', session.sid,
        '{}/np_1.2'.format(current_app.config['LASTFM_PROXY_URL']),
        '{}/protocol_1.2\n'.format(current_app.config['LASTFM_PROXY_URL'])
    ])
Пример #16
0
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)
Пример #17
0
def _get_session(session_id):
    """ Get the session with the passed session id.

        Returns: Session object with given session id
                 If session is not present in db, raises BadRequest
    """

    session = Session.load(session_id)
    if session is None:
        raise BadRequest("Session not found")
    return session
def _get_session(session_id):
    """ Get the session with the passed session id.

        Returns: Session object with given session id
                 If session is not present in db, raises BadRequest
    """

    session = Session.load(session_id)
    if session is None:
        raise BadRequest
    return session
Пример #19
0
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_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)
Пример #21
0
    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)
Пример #22
0
    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")
Пример #23
0
def session_info(request, data):
    try:
        sk = data['sk']
        api_key = data['api_key']
        output_format = data.get('format', 'xml')
        username = data['username']
    except KeyError:
        raise InvalidAPIUsage(
            CompatError.INVALID_PARAMETERS,
            output_format=output_format)  # Missing Required Params

    session = Session.load(sk, api_key)
    if (not session) or User.load_by_name(username).id != session.user.id:
        raise InvalidAPIUsage(
            CompatError.INVALID_SESSION_KEY,
            output_format=output_format)  # Invalid Session KEY

    print("SESSION INFO for session %s, user %s" %
          (session.id, session.user.name))

    doc, tag, text = Doc().tagtext()
    with tag('lfm', status='ok'):
        with tag('application'):
            with tag('session'):
                with tag('name'):
                    text(session.user.name)
                with tag('key'):
                    text(session.id)
                with tag('subscriber'):
                    text('0')
                with tag('country'):
                    text('US')

    return format_response(
        '<?xml version="1.0" encoding="utf-8"?>\n' +
        yattag.indent(doc.getvalue()), output_format)
Пример #24
0
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 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)
Пример #26
0
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)