Beispiel #1
0
def recent_listens():

    recent = []
    for listen in _redis.get_recent_listens(NUMBER_OF_RECENT_LISTENS):
        recent.append({
                "track_metadata": listen.data,
                "user_name" : listen.user_name,
                "listened_at": listen.ts_since_epoch,
                "listened_at_iso": listen.timestamp.isoformat() + "Z",
            })

    spotify_user = {}
    if current_user.is_authenticated:
        spotify_user = spotify.get_user_dict(current_user.id)

    props = {
        "listens": recent,
        "mode": "recent",
        "spotify": spotify_user,
        "api_url": current_app.config["API_URL"],
    }

    return render_template("index/recent.html",
        props=ujson.dumps(props),
        mode='recent',
        active_section='listens')
def load_playlist(playlist_mbid: str):
    """Load a single playlist by id
    """
    if not is_valid_uuid(playlist_mbid):
        raise BadRequest("Provided playlist ID is invalid: %s" % playlist_mbid)

    playlist = db_playlist.get_by_mbid(playlist_mbid, True)
    # TODO: Allow playlist collaborators to access private playlist
    if playlist is None or not playlist.public and (not current_user.is_authenticated or playlist.creator_id != current_user.id):
        raise NotFound("Cannot find playlist: %s" % playlist_mbid)

    fetch_playlist_recording_metadata(playlist)

    spotify_data = {}
    current_user_data = {}
    if current_user.is_authenticated:
        spotify_data = spotify.get_user_dict(current_user.id)

        current_user_data = {
                "id": current_user.id,
                "name": current_user.musicbrainz_id,
                "auth_token": current_user.auth_token,
        }
    props = {
        "current_user": current_user_data,
        "spotify": spotify_data,
        "api_url": current_app.config["API_URL"],
        "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'],
        "playlist": serialize_jspf(playlist)
    }

    return render_template(
        "playlists/playlist.html",
        props=ujson.dumps(props)
    )
Beispiel #3
0
def recommendation_playlists(user_name: str):
    """ Show playlists created for user """
    
    if not current_app.config.get("FEATURE_PLAYLIST", False):
        raise NotFound()
    
    offset = request.args.get('offset', 0)
    try:
        offset = int(offset)
    except ValueError:
        raise BadRequest("Incorrect int argument offset: %s" % request.args.get("offset"))
    
    count = request.args.get("count", DEFAULT_NUMBER_OF_PLAYLISTS_PER_CALL)
    try:
        count = int(count)
    except ValueError:
        raise BadRequest("Incorrect int argument count: %s" % request.args.get("count"))
    
    
    user = _get_user(user_name)
    user_data = {
        "name": user.musicbrainz_id,
        "id": user.id,
    }
    
    spotify_data = {}
    current_user_data = {}
    if current_user.is_authenticated:
        spotify_data = spotify.get_user_dict(current_user.id)
        current_user_data = {
            "id": current_user.id,
            "name": current_user.musicbrainz_id,
            "auth_token": current_user.auth_token,
        }
    
    playlists = []
    user_playlists, playlist_count = get_playlists_created_for_user(user.id, False, count, offset)
    for playlist in user_playlists:
        playlists.append(serialize_jspf(playlist))


    props = {
        "current_user": current_user_data,
        "api_url": current_app.config["API_URL"],
        "playlists": playlists,
        "user": user_data,
        "active_section": "recommendations",
        "playlist_count": playlist_count,
    }

    return render_template(
        "playlists/playlists.html",
        active_section="recommendations",
        props=ujson.dumps(props),
        user=user
    )
def load():
    """This is the start of the BrainzPlayer concept where anyone (logged into LB) can post a playlist
        composed of an array of listens-formatted items and get returned a playable playlist page.
    """

    try:
        raw_listens = request.form['listens']
    except KeyError:
        return render_template(
            "index/player.html",
            error_msg="Missing form data key 'listens'"
        )

    try:
        listens = ujson.loads(raw_listens)
    except ValueError as e:
        return render_template(
            "index/player.html",
            error_msg="Could not parse JSON array. Error: %s" % e
        )

    if not isinstance(listens, list):
        return render_template(
            "index/player.html",
            error_msg="'listens' should be a stringified JSON array."
        )

    if len(listens) <= 0:
        return render_template(
            "index/player.html",
            error_msg="'Listens' array must have one or more items."
        )

    user_data = {
        "id": current_user.id,
        "name": current_user.musicbrainz_id,
        "auth_token": current_user.auth_token,
    }
    spotify_data = spotify.get_user_dict(current_user.id)
    props = {
        "user": user_data,
        "spotify": spotify_data,
        "api_url": current_app.config["API_URL"],
        "listens": listens
    }

    return render_template(
        "index/player.html",
        props=ujson.dumps(props),
        user=current_user
    )
def feed():

    spotify_user = {}
    if current_user.is_authenticated:
        spotify_user = spotify.get_user_dict(current_user.id)

    current_user_data = {
        "id": current_user.id,
        "name": current_user.musicbrainz_id,
        "auth_token": current_user.auth_token,
    }

    props = {
        "current_user": current_user_data,
        "spotify": spotify_user,
        "api_url": current_app.config["API_URL"],
    }
    return render_template('index/feed.html', props=ujson.dumps(props))
def follow(user_list):
    """ Allow an LB user to follow the stream of one or more other LB users.
    """

    if user_list:
        default_list = {'name': ''}
        follow_list_members = parse_param_list(user_list)
    else:
        default_list = db_follow_list.get_latest(creator=current_user.id)
        if not default_list:
            default_list = {'name': '', 'members': []}
        follow_list_members = [
            member['musicbrainz_id'] for member in default_list['members']
        ]

    user_data = {
        "id": current_user.id,
        "name": current_user.musicbrainz_id,
        "auth_token": current_user.auth_token,
    }
    spotify_data = spotify.get_user_dict(current_user.id)
    props = {
        "user": user_data,
        "mode": "follow",
        "follow_list": follow_list_members,
        "spotify": spotify_data,
        "web_sockets_server_url": current_app.config["WEBSOCKETS_SERVER_URL"],
        "api_url": current_app.config["API_URL"],
        "save_url": "{}/1/follow/save".format(current_app.config["API_URL"]),
        "follow_list_name": default_list["name"],
        "follow_list_id": default_list["id"] if "id" in default_list else None,
    }

    return render_template(
        "index/follow.html",
        props=ujson.dumps(props),
        mode='follow',
        user=current_user,
        follow_list=follow_list_members,
        active_section='listens',
    )
Beispiel #7
0
def load_playlist(playlist_mbid: str):
    """Load a single playlist by id
    """
    if not is_valid_uuid(playlist_mbid):
        raise BadRequest("Provided playlist ID is invalid: %s" % playlist_mbid)

    current_user_id = None
    if current_user.is_authenticated:
        current_user_id = current_user.id

    playlist = db_playlist.get_by_mbid(playlist_mbid, True)
    if playlist is None or not playlist.is_visible_by(current_user_id):
        raise NotFound("Cannot find playlist: %s" % playlist_mbid)

    fetch_playlist_recording_metadata(playlist)

    spotify_data = {}
    current_user_data = {}
    if current_user.is_authenticated:
        spotify_data = spotify.get_user_dict(current_user.id)

        current_user_data = {
                "id": current_user.id,
                "name": current_user.musicbrainz_id,
                "auth_token": current_user.auth_token,
        }
    props = {
        "current_user": current_user_data,
        "spotify": spotify_data,
        "api_url": current_app.config["API_URL"],
        "labs_api_url": current_app.config["LISTENBRAINZ_LABS_API_URL"],
        "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'],
        "playlist": serialize_jspf(playlist),
        "sentry_dsn": current_app.config.get("LOG_SENTRY", {}).get("dsn")
    }

    return render_template(
        "playlists/playlist.html",
        props=ujson.dumps(props)
    )
Beispiel #8
0
def profile(user_name):
    # Which database to use to showing user listens.
    db_conn = webserver.timescale_connection._ts
    # Which database to use to show playing_now stream.
    playing_now_conn = webserver.redis_connection._redis

    user = _get_user(user_name)
    # User name used to get user may not have the same case as original user name.
    user_name = user.musicbrainz_id

    # Getting data for current page
    max_ts = request.args.get("max_ts")
    if max_ts is not None:
        try:
            max_ts = int(max_ts)
        except ValueError:
            raise BadRequest("Incorrect timestamp argument max_ts: %s" % request.args.get("max_ts"))

    min_ts = request.args.get("min_ts")
    if min_ts is not None:
        try:
            min_ts = int(min_ts)
        except ValueError:
            raise BadRequest("Incorrect timestamp argument min_ts: %s" % request.args.get("min_ts"))

    # Send min and max listen times to allow React component to hide prev/next buttons accordingly
    (min_ts_per_user, max_ts_per_user) = db_conn.get_timestamps_for_user(user_name)

    if max_ts is None and min_ts is None:
        if max_ts_per_user:
            max_ts = max_ts_per_user + 1
        else:
            max_ts = int(time.time())

    listens = []
    if min_ts_per_user != max_ts_per_user:
        args = {}
        if max_ts:
            args['to_ts'] = max_ts
        else:
            args['from_ts'] = min_ts
        for listen in db_conn.fetch_listens(user_name, limit=LISTENS_PER_PAGE, **args):
            listens.append({
                "track_metadata": listen.data,
                "listened_at": listen.ts_since_epoch,
                "listened_at_iso": listen.timestamp.isoformat() + "Z",
            })

    # If there are no previous listens then display now_playing
    if not listens or listens[0]['listened_at'] >= max_ts_per_user:
        playing_now = playing_now_conn.get_playing_now(user.id)
        if playing_now:
            listen = {
                "track_metadata": playing_now.data,
                "playing_now": "true",
            }
            listens.insert(0, listen)

    user_stats = db_stats.get_user_artists(user.id, 'all_time')
    try:
        artist_count = user_stats.all_time.count
    except (AttributeError, ValidationError):
        artist_count = None

    spotify_data = {}
    current_user_data = {}
    logged_in_user_follows_user = None
    if current_user.is_authenticated:
        spotify_data = spotify.get_user_dict(current_user.id)
        current_user_data = {
            "id": current_user.id,
            "name": current_user.musicbrainz_id,
            "auth_token": current_user.auth_token,
        }
        logged_in_user_follows_user = db_user_relationship.is_following_user(current_user.id, user.id)

    props = {
        "user": {
            "id": user.id,
            "name": user.musicbrainz_id,
        },
        "current_user": current_user_data,
        "listens": listens,
        "latest_listen_ts": max_ts_per_user,
        "oldest_listen_ts": min_ts_per_user,
        "latest_spotify_uri": _get_spotify_uri_for_listens(listens),
        "artist_count": format(artist_count, ",d") if artist_count else None,
        "profile_url": url_for('user.profile', user_name=user_name),
        "mode": "listens",
        "spotify": spotify_data,
        "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'],
        "api_url": current_app.config['API_URL'],
        "logged_in_user_follows_user": logged_in_user_follows_user,
    }

    return render_template("user/profile.html",
                           props=ujson.dumps(props),
                           mode='listens',
                           user=user,
                           active_section='listens')
def _get_template(active_section, user):
    """ Get template to render based on active section.

        Args:
            active_section (str): Type of recommendation playlist to render i.e top_artist, similar_artist
            user: Database user object.

        Returns:
            Template to render.
    """

    data = db_recommendations_cf_recording.get_user_recommendation(user.id)

    if data is None:
        current_app.logger.error('Inactive user: "******"'.format(user.musicbrainz_id))
        return render_template(
            "recommendations_cf_recording/{}.html".format(active_section),
            active_section=active_section,
            user=user,
            error_msg="Looks like the user wasn't active in the last week. Submit your listens and check back after a week!"
        )

    result = getattr(data, 'recording_mbid').dict()[active_section]

    if not result:
        current_app.logger.error('Top/Similar artists not found in Mapping/artist relation for "{}"'.format(user.musicbrainz_id))
        return render_template(
            "recommendations_cf_recording/{}.html".format(active_section),
            active_section=active_section,
            user=user,
            error_msg="Looks like the recommendations weren't generated because of anomalies in our data." \
                      "We are working on it. Check back later."
        )

    listens = _get_listens_from_recording_mbid(result)
    if not listens:
        current_app.logger.error('The API returned an empty response for {} recommendations.\nData: {}'
                                 .format(active_section, result))
        return render_template(
            "recommendations_cf_recording/{}.html".format(active_section),
            active_section=active_section,
            user=user,
            error_msg="An error occurred while processing your request. Check back later!"
        )

    spotify_data = {}
    current_user_data = {}

    if current_user.is_authenticated:
        spotify_data = spotify.get_user_dict(current_user.id)

        current_user_data = {
                "id": current_user.id,
                "name": current_user.musicbrainz_id,
                "auth_token": current_user.auth_token,
        }

    props = {
        "user": {
            "id": user.id,
            "name": user.musicbrainz_id,
        },
        "current_user": current_user_data,
        "spotify": spotify_data,
        "api_url": current_app.config["API_URL"],
        "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'],
        "listens": listens,
        "mode": "cf_recs"
    }

    return render_template(
        "recommendations_cf_recording/{}.html".format(active_section),
        active_section=active_section,
        props=ujson.dumps(props),
        user=user,
        last_updated=getattr(data, 'created').strftime('%d %b %Y')
    )
Beispiel #10
0
def profile(user_name):
    # Which database to use to showing user listens.
    db_conn = webserver.influx_connection._influx
    # Which database to use to show playing_now stream.
    playing_now_conn = webserver.redis_connection._redis

    user = _get_user(user_name)
    # User name used to get user may not have the same case as original user name.
    user_name = user.musicbrainz_id

    try:
        have_listen_count = True
        listen_count = db_conn.get_listen_count_for_user(user_name)
    except (InfluxDBServerError, InfluxDBClientError):
        have_listen_count = False
        listen_count = 0

    # Getting data for current page
    max_ts = request.args.get("max_ts")
    if max_ts is not None:
        try:
            max_ts = int(max_ts)
        except ValueError:
            raise BadRequest("Incorrect timestamp argument max_ts: %s" %
                             request.args.get("max_ts"))

    min_ts = request.args.get("min_ts")
    if min_ts is not None:
        try:
            min_ts = int(min_ts)
        except ValueError:
            raise BadRequest("Incorrect timestamp argument min_ts: %s" %
                             request.args.get("min_ts"))

    if max_ts is None and min_ts is None:
        max_ts = int(time.time())

    args = {}
    if max_ts:
        args['to_ts'] = max_ts
    else:
        args['from_ts'] = min_ts

    listens = []
    for listen in db_conn.fetch_listens(user_name,
                                        limit=LISTENS_PER_PAGE,
                                        **args):
        # Let's fetch one more listen, so we know to show a next page link or not
        listens.append({
            "track_metadata": listen.data,
            "listened_at": listen.ts_since_epoch,
            "listened_at_iso": listen.timestamp.isoformat() + "Z",
        })

    latest_listen = db_conn.fetch_listens(user_name=user_name,
                                          limit=1,
                                          to_ts=int(time.time()))
    latest_listen_ts = latest_listen[0].ts_since_epoch if len(
        latest_listen) > 0 else 0

    # Calculate if we need to show next/prev buttons
    previous_listen_ts = None
    next_listen_ts = None
    if listens:
        (min_ts_per_user,
         max_ts_per_user) = db_conn.get_timestamps_for_user(user_name)
        if min_ts_per_user >= 0:
            if listens[-1]['listened_at'] > min_ts_per_user:
                next_listen_ts = listens[-1]['listened_at']
            else:
                next_listen_ts = None

            if listens[0]['listened_at'] < max_ts_per_user:
                previous_listen_ts = listens[0]['listened_at']
            else:
                previous_listen_ts = None

    # If there are no previous listens then display now_playing
    if not previous_listen_ts:
        playing_now = playing_now_conn.get_playing_now(user.id)
        if playing_now:
            listen = {
                "track_metadata": playing_now.data,
                "playing_now": "true",
            }
            listens.insert(0, listen)

    user_stats = db_stats.get_user_artists(user.id)
    try:
        artist_count = int(user_stats['artist']['count'])
    except (KeyError, TypeError):
        artist_count = None

    spotify_data = {}
    if current_user.is_authenticated:
        spotify_data = spotify.get_user_dict(current_user.id)

    props = {
        "user": {
            "id": user.id,
            "name": user.musicbrainz_id,
        },
        "listens": listens,
        "previous_listen_ts": previous_listen_ts,
        "next_listen_ts": next_listen_ts,
        "latest_listen_ts": latest_listen_ts,
        "latest_spotify_uri": _get_spotify_uri_for_listens(listens),
        "have_listen_count": have_listen_count,
        "listen_count": format(int(listen_count), ",d"),
        "artist_count": format(artist_count, ",d") if artist_count else None,
        "profile_url": url_for('user.profile', user_name=user_name),
        "mode": "listens",
        "spotify": spotify_data,
        "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'],
        "api_url": current_app.config['API_URL'],
    }

    return render_template("user/profile.html",
                           props=ujson.dumps(props),
                           mode='listens',
                           user=user,
                           active_section='listens')