def get_recording_pin_events(users_for_events: List[dict], min_ts: int, max_ts: int, count: int) -> List[APITimelineEvent]: """ Gets all recording pin events in the feed.""" id_username_map = { user['id']: user['musicbrainz_id'] for user in users_for_events } recording_pin_events_db = get_pins_for_feed( user_ids=(user['id'] for user in users_for_events), min_ts=min_ts, max_ts=max_ts, count=count, ) recording_pin_events_db = fetch_track_metadata_for_pins( recording_pin_events_db) events = [] for pin in recording_pin_events_db: try: pinEvent = APIPinEvent( user_name=id_username_map[pin.user_id], blurb_content=pin.blurb_content, track_metadata=TrackMetadata( artist_name=pin.track_metadata["artist_name"], track_name=pin.track_metadata["track_name"], release_name=None, additional_info=AdditionalInfo( recording_msid=pin.recording_msid, recording_mbid=pin.recording_mbid, artist_msid=pin.track_metadata["artist_msid"], ))) events.append( APITimelineEvent( event_type=UserTimelineEventType.RECORDING_PIN, user_name=pinEvent.user_name, created=pin.created.timestamp(), metadata=pinEvent, )) except pydantic.ValidationError as e: current_app.logger.error('Validation error: ' + str(e), exc_info=True) continue return events
def pins(user_name: str): """ Show user pin history """ user = _get_user(user_name) user_data = { "name": user.musicbrainz_id, "id": user.id, } pins = get_pin_history_for_user(user_id=user.id, count=25, offset=0) pins = [dict(pin) for pin in fetch_track_metadata_for_pins(pins)] total_count = get_pin_count_for_user(user_id=user.id) props = { "user": user_data, "pins": pins, "profile_url": url_for('user.profile', user_name=user_name), "total_count": total_count } return render_template("user/pins.html", active_section="pins", props=ujson.dumps(props), user=user)
def get_pins_for_user_following(user_name): """ Get a list containing the active pinned recordings for all users in a user's ``user_name`` following list. The returned pinned recordings are sorted in descending order of the time they were pinned. The JSON returned by the API will look like the following: .. code-block:: json { "count": 1, "offset": 0, "pinned_recordings": [ { "blurb_content": "Spectacular recording!", "created": 1624000841, "row_id": 1, "pinned_until": 1624605641, "recording_mbid": null, "recording_msid": "40ef0ae1-5626-43eb-838f-1b34187519bf", "track_metadata": { "artist_msid": "8c7b4641-e363-4598-ae70-7709840fb934", "artist_name": "Rick Astley", "track_name": "Never Gonna Give You Up" }, "user_name": "-- the MusicBrainz ID of the user who pinned this recording --" }, "-- more pinned recordings from different users here ---" ], "user_name": "-- the MusicBrainz ID of the original user --" } :param user_name: the MusicBrainz ID of the user whose followed user's pinned recordings are being requested. :type user_name: ``str`` :param count: Optional, number of pinned recording items to return, Default: :data:`~webserver.views.api.DEFAULT_ITEMS_PER_GET` Max: :data:`~webserver.views.api.MAX_ITEMS_PER_GET` :type count: ``int`` :param offset: Optional, number of pinned recording items to skip from the beginning, for pagination. Ex. An offset of 5 means the most recent pinned recordings from the first 5 users will be skipped, defaults to 0 :type offset: ``int`` :statuscode 200: Yay, you have data! :statuscode 400: Invalid query parameters. See error message for details. :statuscode 404: The requested user was not found. :resheader Content-Type: *application/json* """ count = get_non_negative_param("count", default=DEFAULT_ITEMS_PER_GET) offset = get_non_negative_param("offset", default=0) count = min(count, MAX_ITEMS_PER_GET) user = db_user.get_by_mb_id(user_name) if user is None: raise APINotFound("Cannot find user: %s" % user_name) pinned_recordings = db_pinned_rec.get_pins_for_user_following( user_id=user["id"], count=count, offset=offset) pinned_recordings = fetch_track_metadata_for_pins(pinned_recordings) pinned_recordings = [ _pinned_recording_to_api(pin) for pin in pinned_recordings ] return jsonify({ "pinned_recordings": pinned_recordings, "count": len(pinned_recordings), "offset": offset, "user_name": user_name, })
def get_pins_for_user(user_name): """ Get a list of all recordings ever pinned by a user with given ``user_name`` in descending order of the time they were originally pinned. The JSON returned by the API will look like the following: .. code-block:: json { "count": 10, "offset": 0, "pinned_recordings": [ { "blurb_content": "Awesome recording!", "created": 1623997168, "row_id": 10, "pinned_until": 1623997485, "recording_mbid": null, "recording_msid": "fd7d9162-a284-4a10-906c-faae4f1e166b" "track_metadata": { "artist_msid": "8c7b4641-e363-4598-ae70-7709840fb934", "artist_name": "Rick Astley", "track_name": "Never Gonna Give You Up" } }, "-- more pinned recording items here ---" ], "total_count": 10, "user_name": "-- the MusicBrainz ID of the user --" } :param user_name: the MusicBrainz ID of the user whose pin track history requested. :type user_name: ``str`` :param count: Optional, number of pinned recording items to return, Default: :data:`~webserver.views.api.DEFAULT_ITEMS_PER_GET` Max: :data:`~webserver.views.api.MAX_ITEMS_PER_GET` :type count: ``int`` :param offset: Optional, number of pinned recording items to skip from the beginning, for pagination. Ex. An offset of 5 means the most recent 5 pinned recordings from the user will be skipped, defaults to 0 :type offset: ``int`` :statuscode 200: Yay, you have data! :statuscode 400: Invalid query parameters. See error message for details. :statuscode 404: The requested user was not found. :resheader Content-Type: *application/json* """ offset = get_non_negative_param("offset", default=0) count = get_non_negative_param("count", default=DEFAULT_ITEMS_PER_GET) count = min(count, MAX_ITEMS_PER_GET) user = db_user.get_by_mb_id(user_name) if user is None: raise APINotFound("Cannot find user: %s" % user_name) try: pinned_recordings = db_pinned_rec.get_pin_history_for_user( user_id=user["id"], count=count, offset=offset) except Exception as e: current_app.logger.error( "Error while retrieving pins for user: {}".format(e)) raise APIInternalServerError("Something went wrong. Please try again.") pinned_recordings = fetch_track_metadata_for_pins(pinned_recordings) pinned_recordings = [ _pinned_recording_to_api(pin) for pin in pinned_recordings ] total_count = db_pinned_rec.get_pin_count_for_user(user_id=user["id"]) return jsonify({ "pinned_recordings": pinned_recordings, "total_count": total_count, "count": len(pinned_recordings), "offset": offset, "user_name": user_name, })
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")) args = {} if max_ts: args['to_ts'] = max_ts else: args['from_ts'] = min_ts data, min_ts_per_user, max_ts_per_user = db_conn.fetch_listens( user_name, limit=LISTENS_PER_PAGE, **args) listens = [] for listen in data: listens.append(listen.to_api()) # 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_stats(user.id, 'all_time', 'artists') logged_in_user_follows_user = None already_reported_user = False if current_user.is_authenticated: logged_in_user_follows_user = db_user_relationship.is_following_user( current_user.id, user.id) already_reported_user = db_user.is_user_reported( current_user.id, user.id) pin = get_current_pin_for_user(user_id=user.id) if pin: pin = dict(fetch_track_metadata_for_pins([pin])[0]) props = { "user": { "id": user.id, "name": user.musicbrainz_id, }, "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(user_stats.count, ",d") if user_stats else None, "profile_url": url_for('user.profile', user_name=user_name), "mode": "listens", "userPinnedRecording": pin, "web_sockets_server_url": current_app.config['WEBSOCKETS_SERVER_URL'], "logged_in_user_follows_user": logged_in_user_follows_user, "already_reported_user": already_reported_user, } return render_template("user/profile.html", props=ujson.dumps(props), mode='listens', user=user, active_section='listens')