def get_top_users(current_user_id):
    """Gets the top users by follows of all of Audius"""
    top_users = []
    db = get_db_read_replica()
    with db.scoped_session() as session:
        top_users = (
            session.query(User)
            .select_from(AggregateUser)
            .join(User, User.user_id == AggregateUser.user_id)
            .filter(AggregateUser.track_count > 0, User.is_current)
            .order_by(desc(AggregateUser.follower_count), User.user_id)
        )
        top_users = paginate_query(top_users).all()
        top_users = helpers.query_result_to_list(top_users)
        user_ids = list(map(lambda user: user["user_id"], top_users))
        top_users = populate_user_metadata(
            session, user_ids, top_users, current_user_id
        )
    return top_users

def get_top_users ( current_user_id ) : top_users = [ ] db = get_db_read_replica ( ) with db . scoped_session ( ) as session : top_users = ( session . query ( User ) . select_from ( AggregateUser ) . join ( User , User . user_id == AggregateUser . user_id ) . filter ( AggregateUser . track_count > 0 , User . is_current ) . order_by ( desc ( AggregateUser . follower_count ) , User . user_id ) ) top_users = paginate_query ( top_users ) . all ( ) top_users = helpers . query_result_to_list ( top_users ) user_ids = list ( map ( lambda user : user [ "user_id" ] , top_users ) ) top_users = populate_user_metadata ( session , user_ids , top_users , current_user_id ) return top_users


def get_unpopulated_users(session, user_ids):
    """
    Fetches users by checking the redis cache first then
    going to DB and writes to cache if not present

    Args:
        session: DB session
        user_ids: array A list of user ids

    Returns:
        Array of users
    """
    cached_users_results = get_cached_users(user_ids)
    has_all_users_cached = cached_users_results.count(None) == 0
    if has_all_users_cached:
        return cached_users_results

    cached_users = {}
    for cached_user in cached_users_results:
        if cached_user:
            cached_users[cached_user["user_id"]] = cached_user

    user_ids_to_fetch = filter(lambda user_id: user_id not in cached_users, user_ids)

    users = (
        session.query(User)
        .filter(User.is_current == True, User.wallet != None, User.handle != None)
        .filter(User.user_id.in_(user_ids_to_fetch))
        .all()
    )
    users = helpers.query_result_to_list(users)
    queried_users = {user["user_id"]: user for user in users}

    set_users_in_cache(users)

    users_response = []
    for user_id in user_ids:
        if user_id in cached_users:
            users_response.append(cached_users[user_id])
        elif user_id in queried_users:
            users_response.append(queried_users[user_id])

    return users_response

def get_unpopulated_users ( session , user_ids ) : cached_users_results = get_cached_users ( user_ids ) has_all_users_cached = cached_users_results . count ( None ) == 0 if has_all_users_cached : return cached_users_results cached_users = { } for cached_user in cached_users_results : if cached_user : cached_users [ cached_user [ "user_id" ] ] = cached_user user_ids_to_fetch = filter ( lambda user_id : user_id not in cached_users , user_ids ) users = ( session . query ( User ) . filter ( User . is_current == True , User . wallet != None , User . handle != None ) . filter ( User . user_id . in_ ( user_ids_to_fetch ) ) . all ( ) ) users = helpers . query_result_to_list ( users ) queried_users = { user [ "user_id" ] : user for user in users } set_users_in_cache ( users ) users_response = [ ] for user_id in user_ids : if user_id in cached_users : users_response . append ( cached_users [ user_id ] ) elif user_id in queried_users : users_response . append ( queried_users [ user_id ] ) return users_response


def get_app_names(args):
    """
    Returns a list of app names

    Args:
        args: dict The parsed args from the request
        args.offset: number The offset to start querying from
        args.limit: number The max number of queries to return
        args.start_time: date The start of the query
        args.include_unknown: bool Whether or not to include a line item for unknown

    Returns:
        Array of dictionaries with name, count, and unique_count fields
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        app_names = (
            session.query(
                AppNameMetrics.application_name,
                func.sum(AppNameMetrics.count).label("count"),
                func.count(AppNameMetrics.ip.distinct()),
            )
            .filter(AppNameMetrics.timestamp > args.get("start_time"))
            .group_by(AppNameMetrics.application_name)
            .order_by(desc("count"), asc(AppNameMetrics.application_name))
            .limit(args.get("limit"))
            .offset(args.get("offset"))
            .all()
        )

        names = [
            {"name": app_name[0], "count": app_name[1], "unique_count": app_name[2]}
            for app_name in app_names
        ]

        if args.get("include_unknown", False):
            existing_count = reduce(lambda x, y: x + y["count"], names, 0)
            existing_unique_count = reduce(lambda x, y: x + y["unique_count"], names, 0)
            total_requests = (
                session.query(
                    func.sum(RouteMetrics.count).label("count"),
                    func.count(RouteMetrics.ip.distinct()),
                )
                .filter(RouteMetrics.timestamp > args.get("start_time"))
                .first()
            )
            unknown_count = total_requests[0] - existing_count
            unique_count = total_requests[1] - existing_unique_count
            # Insert unique counts "in order" (desc by count)
            for i, name in enumerate(names[:]):
                if unknown_count > name["count"] or i == len(names):
                    names.insert(
                        i,
                        {
                            "name": "unknown",
                            "count": unknown_count,
                            "unique_count": unique_count,
                        },
                    )
                    break

        return names


def get_remixable_tracks(args):
    """Gets a list of remixable tracks"""
    db = get_db_read_replica()
    limit = args.get("limit", 25)
    current_user_id = args.get("current_user_id", None)

    StemTrack = aliased(Track)

    with db.scoped_session() as session:
        # Subquery to get current tracks that have stems
        remixable_tracks_subquery = (
            session.query(Track)
            .join(Stem, Stem.parent_track_id == Track.track_id)
            .join(StemTrack, Stem.child_track_id == StemTrack.track_id)
            .filter(
                Track.is_current == True,
                Track.is_unlisted == False,
                Track.is_delete == False,
                StemTrack.is_current == True,
                StemTrack.is_unlisted == False,
                StemTrack.is_delete == False,
            )
            .distinct(Track.track_id)
            .subquery()
        )
        track_alias = aliased(Track, remixable_tracks_subquery)

        count_subquery = session.query(
            AggregateTrack.track_id.label("id"),
            (AggregateTrack.repost_count + AggregateTrack.save_count).label("count"),
        ).subquery()

        query = (
            session.query(
                track_alias,
                count_subquery.c["count"],
                decayed_score(count_subquery.c["count"], track_alias.created_at).label(
                    "score"
                ),
            )
            .join(
                count_subquery,
                count_subquery.c["id"] == track_alias.track_id,
            )
            .order_by(desc("score"), desc(track_alias.track_id))
            .limit(limit)
        )

        results = query.all()

        tracks = []
        for result in results:
            track = result[0]
            score = result[-1]
            track = helpers.model_to_dictionary(track)
            track["score"] = score
            tracks.append(track)

        track_ids = list(map(lambda track: track["track_id"], tracks))

        # Get user specific data for tracks
        tracks = populate_track_metadata(session, track_ids, tracks, current_user_id)

        if args.get("with_users", False):
            add_users_to_tracks(session, tracks, current_user_id)
        else:
            # Remove the user from the tracks
            tracks = [
                {key: val for key, val in dict.items() if key != "user"}
                for dict in tracks
            ]

    return tracks


Gets the indexing transaction status : PASSED FAILED or NOT_FOUND given a blocknumber blockhash and transaction first checks whether there is an indexing error in reduis and whether the entry matches the given params otherwise checks the skipped_transactions in the database

def get_transaction_status(blocknumber, blockhash, txhash):
    """Gets the indexing transaction status: 'PASSED', 'FAILED', or 'NOT_FOUND'
    given a blocknumber, blockhash, and transaction
    first checks whether there is an indexing error in reduis
    and whether the entry matches the given params
    otherwise checks the skipped_transactions in the database
    """
    indexing_error = get_indexing_error(REDIS)

    if indexing_error:
        blocknumber_match = (
            "blocknumber" in indexing_error
            and indexing_error["blocknumber"] == blocknumber
        )
        blockhash_match = (
            "blockhash" in indexing_error and indexing_error["blockhash"] == blockhash
        )
        txhash_match = "txhash" in indexing_error and indexing_error["txhash"] == txhash
        if blocknumber_match and blockhash_match and txhash_match:
            return "FAILED"

    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        skipped_transactions_results = (
            session.query(SkippedTransaction)
            .filter(
                SkippedTransaction.blocknumber == blocknumber,
                SkippedTransaction.blockhash == blockhash,
                SkippedTransaction.txhash == txhash,
            )
            .all()
        )
        if len(skipped_transactions_results) > 1:
            raise Exception(
                f"Expected no more than 1 row for skipped indexing transaction with \
                blocknumber={blocknumber}, blockhash={blockhash}, txhash={txhash}"
            )
        if len(skipped_transactions_results) == 1:
            return "FAILED"

        block_transaction_results = (
            session.query(Block)
            .filter(Block.number == blocknumber, Block.blockhash == blockhash)
            .all()
        )
        if len(block_transaction_results) > 1:
            raise Exception(
                f"Expected no more than 1 row for blocknumber={blocknumber}, blockhash={blockhash}"
            )
        if len(block_transaction_results) == 1:
            return "PASSED"

        return "NOT_FOUND"


def search_track_tags(session, args):
    """
    Gets the tracks with a given tag

    Args:
        session: sqlalchemy db session instance
        args: dict of arguments
        args.search_str: string the tag search string
        args.current_user_id: id | null The user id making the query
        args.limit: number the query limit of number of returns tracks
        args.offset: number the query offset for results

    Returns:
        list of tracks sorted by play count
    """

    track_ids = (
        session.query(TagTrackUserMatview.track_id)
        .filter(TagTrackUserMatview.tag == args["search_str"].lower())
        .all()
    )

    # track_ids is list of tuples - simplify to 1-D list
    track_ids = [i[0] for i in track_ids]

    tracks = (
        session.query(Track)
        .filter(
            Track.is_current == True,
            Track.is_delete == False,
            Track.is_unlisted == False,
            Track.stem_of == None,
            Track.track_id.in_(track_ids),
        )
        .all()
    )

    tracks = helpers.query_result_to_list(tracks)
    track_play_counts = get_track_play_counts(session, track_ids)

    tracks = populate_track_metadata(
        session, track_ids, tracks, args["current_user_id"]
    )

    for track in tracks:
        track_id = track["track_id"]
        track[response_name_constants.play_count] = track_play_counts.get(track_id, 0)

    play_count_sorted_tracks = sorted(
        tracks, key=lambda i: i[response_name_constants.play_count], reverse=True
    )

    # Add pagination parameters to track and user results
    play_count_sorted_tracks = play_count_sorted_tracks[
        slice(args["offset"], args["offset"] + args["limit"], 1)
    ]

    return play_count_sorted_tracks


Makes a cache key resembling generated - trending : week : electronic

def make_trending_cache_key(
    time_range, genre, version=DEFAULT_TRENDING_VERSIONS[TrendingType.TRACKS]
):
    """Makes a cache key resembling `generated-trending:week:electronic`"""
    version_name = (
        f":{version.name}"
        if version != DEFAULT_TRENDING_VERSIONS[TrendingType.TRACKS]
        else ""
    )
    return f"generated-trending{version_name}:{time_range}:{(genre.lower() if genre else '')}"


Wraps a call to generate_unpopulated_trending for use in use_redis_cache which expects to be passed a function with no arguments .

def make_generate_unpopulated_trending(session, genre, time_range, strategy):
    """Wraps a call to `generate_unpopulated_trending` for use in `use_redis_cache`, which
    expects to be passed a function with no arguments."""

    def wrapped():
        if strategy.use_mat_view:
            return generate_unpopulated_trending_from_mat_views(
                session, genre, time_range, strategy
            )
        return generate_unpopulated_trending(session, genre, time_range, strategy)

    return wrapped


Gets trending by getting the currently cached tracks and then populating them .

def get_trending_tracks(args: GetTrendingTracksArgs, strategy: BaseTrendingStrategy):
    """Gets trending by getting the currently cached tracks and then populating them."""
    db = get_db_read_replica()
    with db.scoped_session() as session:
        return _get_trending_tracks_with_session(session, args, strategy)

def get_trending_tracks ( args : GetTrendingTracksArgs , strategy : BaseTrendingStrategy ) : db = get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_trending_tracks_with_session ( session , args , strategy )


Get Trending shared between full and regular endpoints .

def get_trending(args, strategy):
    """Get Trending, shared between full and regular endpoints."""
    # construct args
    time = args.get("time") if args.get("time") is not None else "week"
    current_user_id = args.get("user_id")
    args = {
        "time": time,
        "genre": args.get("genre", None),
        "with_users": True,
        "limit": TRENDING_LIMIT,
        "offset": 0,
    }

    # decode and add user_id if necessary
    if current_user_id:
        decoded_id = decode_string_id(current_user_id)
        args["current_user_id"] = decoded_id

    tracks = get_trending_tracks(args, strategy)
    return list(map(extend_track, tracks))

def
get_trending
(
args
,
strategy
)
:
# construct args
time
=
args
.
get
(
"time"
)
if
args
.
get
(
"time"
)
is
not
else
"week"
current_user_id
=
args
.
get
(
"user_id"
)
args
=
{
"time"
:
time
,
"genre"
:
args
.
get
(
"genre"
,
)
,
"with_users"
:
True
,
"limit"
:
TRENDING_LIMIT
,
"offset"
:
0
,
}
# decode and add user_id if necessary
if
current_user_id
:
decoded_id
=
decode_string_id
(
current_user_id
)
args
[
"current_user_id"
]
=
decoded_id
tracks
=
get_trending_tracks
(
args
,
strategy
)
return
list
(
map
(
extend_track
,
tracks
)
)


def get_associated_user_wallet(args: AssociatedUserWalletArgs) -> AssociatedUserWallet:
    """
    Returns a list of associated wallets

    Args:
        args: dict The parsed args from the request
        args.user_id: number The blockchain user id

    Returns:
        Array of strings representing the user's associated wallets
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        user_wallet: List[Tuple[str, str]] = (
            session.query(AssociatedWallet.wallet, AssociatedWallet.chain)
            .filter(AssociatedWallet.is_current == True)
            .filter(AssociatedWallet.is_delete == False)
            .filter(AssociatedWallet.user_id == args.get("user_id"))
            .all()
        )
        eth_wallets: List[str] = []
        sol_wallets: List[str] = []
        for wallet, chain in user_wallet:
            if chain == "eth":
                eth_wallets.append(wallet)
            elif chain == "sol":
                sol_wallets.append(wallet)
        return {"eth": eth_wallets, "sol": sol_wallets}

def get_associated_user_wallet ( args : AssociatedUserWalletArgs ) -> AssociatedUserWallet : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : user_wallet : List [ Tuple [ str , str ] ] = ( session . query ( AssociatedWallet . wallet , AssociatedWallet . chain ) . filter ( AssociatedWallet . is_current == True ) . filter ( AssociatedWallet . is_delete == False ) . filter ( AssociatedWallet . user_id == args . get ( "user_id" ) ) . all ( ) ) eth_wallets : List [ str ] = [ ] sol_wallets : List [ str ] = [ ] for wallet , chain in user_wallet : if chain == "eth" : eth_wallets . append ( wallet ) elif chain == "sol" : sol_wallets . append ( wallet ) return { "eth" : eth_wallets , "sol" : sol_wallets }


Comparison util for ordering user search results .

def compare_users(user1, user2):
    """Comparison util for ordering user search results."""
    # Any verified user is ranked higher
    if user1["is_verified"] and not user2["is_verified"]:
        return -1
    if user2["is_verified"] and not user1["is_verified"]:
        return 1
    return 0


Performs a search query of a given search_type . Handles it s own session . Used concurrently .

def perform_search_query(db, search_type, args):
    """Performs a search query of a given `search_type`. Handles it's own session. Used concurrently."""
    with db.scoped_session() as session:
        search_str = args.get("search_str")
        limit = args.get("limit")
        offset = args.get("offset")
        is_auto_complete = args.get("is_auto_complete")
        current_user_id = args.get("current_user_id")
        only_downloadable = args.get("only_downloadable")

        results = None
        if search_type == "tracks":
            results = track_search_query(
                session,
                search_str,
                limit,
                offset,
                is_auto_complete,
                current_user_id,
                only_downloadable,
            )
        elif search_type == "users":
            results = user_search_query(
                session,
                search_str,
                limit,
                offset,
                is_auto_complete,
                current_user_id,
            )
        elif search_type == "playlists":
            results = playlist_search_query(
                session,
                search_str,
                limit,
                offset,
                False,
                is_auto_complete,
                current_user_id,
            )
        elif search_type == "albums":
            results = playlist_search_query(
                session,
                search_str,
                limit,
                offset,
                True,
                is_auto_complete,
                current_user_id,
            )
        return results

def perform_search_query ( db , search_type , args ) : with db . scoped_session ( ) as session : search_str = args . get ( "search_str" ) limit = args . get ( "limit" ) offset = args . get ( "offset" ) is_auto_complete = args . get ( "is_auto_complete" ) current_user_id = args . get ( "current_user_id" ) only_downloadable = args . get ( "only_downloadable" ) results = None if search_type == "tracks" : results = track_search_query ( session , search_str , limit , offset , is_auto_complete , current_user_id , only_downloadable , ) elif search_type == "users" : results = user_search_query ( session , search_str , limit , offset , is_auto_complete , current_user_id , ) elif search_type == "playlists" : results = playlist_search_query ( session , search_str , limit , offset , False , is_auto_complete , current_user_id , ) elif search_type == "albums" : results = playlist_search_query ( session , search_str , limit , offset , True , is_auto_complete , current_user_id , ) return results


Perform a search . args should contain is_auto_complete query kind current_user_id and only_downloadable

def search(args):
    """Perform a search. `args` should contain `is_auto_complete`,
    `query`, `kind`, `current_user_id`, and `only_downloadable`
    """
    search_str = args.get("query")

    # when creating query table, we substitute this too
    search_str = search_str.replace("&", "and")

    kind = args.get("kind", "all")
    is_auto_complete = args.get("is_auto_complete")
    current_user_id = args.get("current_user_id")
    only_downloadable = args.get("only_downloadable")
    limit = args.get("limit")
    offset = args.get("offset")

    searchKind = SearchKind[kind]

    results = {}

    # Accumulate user_ids for later
    user_ids = set()

    # Create args for perform_search_query
    search_args = {
        "search_str": search_str,
        "limit": limit,
        "offset": offset,
        "is_auto_complete": is_auto_complete,
        "current_user_id": current_user_id,
        "only_downloadable": only_downloadable,
    }

    if search_str:
        db = get_db_read_replica()
        # Concurrency approach:
        # Spin up a ThreadPoolExecutor for each request to perform_search_query
        # to perform the different search types in parallel.
        # After each future resolves, we then add users for each entity in a single
        # db round trip.
        with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
            # Keep a mapping of future -> search_type
            futures_map = {}
            futures = []

            # Helper fn to submit a future and add it to bookkeeping data structures
            def submit_and_add(search_type):
                future = executor.submit(
                    perform_search_query, db, search_type, search_args
                )
                futures.append(future)
                futures_map[future] = search_type

            if searchKind in [SearchKind.all, SearchKind.tracks]:
                submit_and_add("tracks")

            if searchKind in [SearchKind.all, SearchKind.users]:
                submit_and_add("users")
            if searchKind in [SearchKind.all, SearchKind.playlists]:
                submit_and_add("playlists")

            if searchKind in [SearchKind.all, SearchKind.albums]:
                submit_and_add("albums")

            for future in concurrent.futures.as_completed(futures):
                search_result = future.result()
                future_type = futures_map[future]

                # Add to the final results
                # Add to user_ids
                if future_type == "tracks":
                    results["tracks"] = search_result["all"]
                    results["saved_tracks"] = search_result["saved"]
                elif future_type == "users":
                    results["users"] = search_result["all"]
                    results["followed_users"] = search_result["followed"]
                elif future_type == "playlists":
                    results["playlists"] = search_result["all"]
                    results["saved_playlists"] = search_result["saved"]
                elif future_type == "albums":
                    results["albums"] = search_result["all"]
                    results["saved_albums"] = search_result["saved"]
                user_ids.update(get_users_ids(search_result["all"]))

            with db.scoped_session() as session:
                # Add users back
                users = get_users_by_id(session, list(user_ids), current_user_id)

                for (_, result_list) in results.items():
                    for result in result_list:
                        user_id = None
                        if "playlist_owner_id" in result:
                            user_id = result["playlist_owner_id"]
                        elif "owner_id" in result:
                            user_id = result["owner_id"]

                        if user_id is not None:
                            user = users[user_id]
                            result["user"] = user
    return results


Accepts args : { # optionally pass in full playlists to avoid having to fetch playlists : Playlist []

def get_playlist_tracks(session, args):
    """Accepts args:
    {
        # optionally pass in full playlists to avoid having to fetch
        "playlists": Playlist[]

        # not needed if playlists are passed
        "playlist_ids": string[]
        "current_user_id": int
        "populate_tracks": boolean # whether to add users & metadata to tracks
    }

    Returns: {
        playlist_id: Playlist
    }
    """

    try:
        playlists = args.get("playlists")
        if not playlists:
            playlist_ids = args.get("playlist_ids", [])
            playlists = session.query(Playlist).filter(
                Playlist.is_current == True, Playlist.playlist_id.in_(playlist_ids)
            )
            playlists = list(map(helpers.model_to_dictionary, playlists))

        if not playlists:
            return {}

        # track_id -> [playlist_id]
        track_ids_set = set()
        for playlist in playlists:
            playlist_id = playlist["playlist_id"]
            for track_id_dict in playlist["playlist_contents"]["track_ids"]:
                track_id = track_id_dict["track"]
                track_ids_set.add(track_id)

        playlist_tracks = (
            session.query(Track)
            .filter(Track.is_current == True, Track.track_id.in_(list(track_ids_set)))
            .all()
        )

        tracks = helpers.query_result_to_list(playlist_tracks)

        if args.get("populate_tracks"):
            current_user_id = args.get("current_user_id")
            tracks = populate_track_metadata(
                session, list(track_ids_set), tracks, current_user_id
            )

            add_users_to_tracks(session, tracks, current_user_id)

        # { track_id => track }
        track_ids_map = {track["track_id"]: track for track in tracks}

        # { playlist_id => [track]}
        playlists_map = {}
        for playlist in playlists:
            playlist_id = playlist["playlist_id"]
            playlists_map[playlist_id] = []
            for track_id_dict in playlist["playlist_contents"]["track_ids"]:
                track_id = track_id_dict["track"]
                track = track_ids_map[track_id]
                playlists_map[playlist_id].append(track)

        return playlists_map

    except sqlalchemy.orm.exc.NoResultFound:
        return {}

def
get_playlist_tracks
(
session
,
args
)
:
try
:
playlists
=
args
.
get
(
"playlists"
)
if
not
playlists
:
playlist_ids
=
args
.
get
(
"playlist_ids"
,
[
]
)
playlists
=
session
.
query
(
Playlist
)
.
filter
(
Playlist
.
is_current
==
True
,
Playlist
.
playlist_id
.
in_
(
playlist_ids
)
)
playlists
=
list
(
map
(
helpers
.
model_to_dictionary
,
playlists
)
)
if
not
playlists
:
return
{
}
# track_id -> [playlist_id]
track_ids_set
=
set
(
)
for
playlist
in
playlists
:
playlist_id
=
playlist
[
"playlist_id"
]
for
track_id_dict
in
playlist
[
"playlist_contents"
]
[
"track_ids"
]
:
track_id
=
track_id_dict
[
"track"
]
track_ids_set
.
add
(
track_id
)
playlist_tracks
=
(
session
.
query
(
Track
)
.
filter
(
Track
.
is_current
==
True
,
Track
.
track_id
.
in_
(
list
(
track_ids_set
)
)
)
.
all
(
)
)
tracks
=
helpers
.
query_result_to_list
(
playlist_tracks
)
if
args
.
get
(
"populate_tracks"
)
:
current_user_id
=
args
.
get
(
"current_user_id"
)
tracks
=
populate_track_metadata
(
session
,
list
(
track_ids_set
)
,
tracks
,
current_user_id
)
add_users_to_tracks
(
session
,
tracks
,
current_user_id
)
# { track_id => track }
track_ids_map
=
{
track
[
"track_id"
]
:
track
for
track
in
tracks
}
# { playlist_id => [track]}
playlists_map
=
{
}
for
playlist
in
playlists
:
playlist_id
=
playlist
[
"playlist_id"
]
playlists_map
[
playlist_id
]
=
[
]
for
track_id_dict
in
playlist
[
"playlist_contents"
]
[
"track_ids"
]
:
track_id
=
track_id_dict
[
"track"
]
track
=
track_ids_map
[
track_id
]
playlists_map
[
playlist_id
]
.
append
(
track
)
return
playlists_map
except
sqlalchemy
.
orm
.
exc
.
NoResultFound
:
return
{
}


Gets the previous state of tracks in the database given a list of tracks .

def get_prev_track_entries(session, entries):
    """
    Gets the previous state of tracks in the database given a list of tracks.

    Args:
        session: (DB) sqlalchemy scoped db session
        entries: (List<Track>) List of current track entries

    Returns:
        prev_track_entries: (List<Track>) List of previous track entries corresponding to the passed track entries
    """

    if len(entries) == 0:
        return []

    def get_prev_query_pairs(entry):
        return [entry["track_id"], entry["blocknumber"]]

    prev_query_pairs = map(get_prev_query_pairs, entries)

    prev_entries_subquery = (
        session.query(
            Track.track_id, func.max(Track.blocknumber).label("max_blocknumber")
        )
        .filter(
            or_(
                and_(Track.track_id == pair[0], Track.blocknumber < pair[1])
                for pair in prev_query_pairs
            )
        )
        .group_by(Track.track_id)
        .subquery()
    )

    prev_entries_query = session.query(Track).join(
        prev_entries_subquery,
        and_(
            prev_entries_subquery.c.track_id == Track.track_id,
            prev_entries_subquery.c.max_blocknumber == Track.blocknumber,
        ),
    )

    return prev_entries_query.all()

def get_prev_track_entries ( session , entries ) : if len ( entries ) == 0 : return [ ] def get_prev_query_pairs ( entry ) : return [ entry [ "track_id" ] , entry [ "blocknumber" ] ] prev_query_pairs = map ( get_prev_query_pairs , entries ) prev_entries_subquery = ( session . query ( Track . track_id , func . max ( Track . blocknumber ) . label ( "max_blocknumber" ) ) . filter ( or_ ( and_ ( Track . track_id == pair [ 0 ] , Track . blocknumber < pair [ 1 ] ) for pair in prev_query_pairs ) ) . group_by ( Track . track_id ) . subquery ( ) ) prev_entries_query = session . query ( Track ) . join ( prev_entries_subquery , and_ ( prev_entries_subquery . c . track_id == Track . track_id , prev_entries_subquery . c . max_blocknumber == Track . blocknumber , ) , ) return prev_entries_query . all ( )


def get_unpopulated_playlists(session, playlist_ids, filter_deleted=False):
    """
    Fetches playlists by checking the redis cache first then
    going to DB and writes to cache if not present

    Args:
        session: DB session
        playlist_ids: array A list of playlist ids

    Returns:
        Array of playlists
    """
    # Check the cached playlists
    cached_playlists_results = get_cached_playlists(playlist_ids)
    has_all_playlists_cached = cached_playlists_results.count(None) == 0
    if has_all_playlists_cached:
        if filter_deleted:
            return list(
                filter(
                    lambda playlist: not playlist["is_delete"], cached_playlists_results
                )
            )
        return cached_playlists_results

    # Create a dict of cached playlists
    cached_playlists = {}
    for cached_playlist in cached_playlists_results:
        if cached_playlist:
            cached_playlists[cached_playlist["playlist_id"]] = cached_playlist

    playlist_ids_to_fetch = filter(
        lambda playlist_id: playlist_id not in cached_playlists, playlist_ids
    )

    playlists_query = (
        session.query(Playlist)
        .filter(Playlist.is_current == True)
        .filter(Playlist.playlist_id.in_(playlist_ids_to_fetch))
    )
    if filter_deleted:
        playlists_query = playlists_query.filter(Playlist.is_delete == False)

    playlists = playlists_query.all()
    playlists = helpers.query_result_to_list(playlists)
    queried_playlists = {playlist["playlist_id"]: playlist for playlist in playlists}

    # cache playlists for future use
    set_playlists_in_cache(playlists)

    playlists_response = []
    for playlist_id in playlist_ids:
        if playlist_id in cached_playlists:
            if not filter_deleted or not cached_playlists[playlist_id]["is_delete"]:
                playlists_response.append(cached_playlists[playlist_id])
        elif playlist_id in queried_playlists:
            playlists_response.append(queried_playlists[playlist_id])

    return playlists_response

def
get_unpopulated_playlists
(
session
,
playlist_ids
,
filter_deleted
=
False
)
:
# Check the cached playlists
cached_playlists_results
=
get_cached_playlists
(
playlist_ids
)
has_all_playlists_cached
=
cached_playlists_results
.
count
(
)
==
0
if
has_all_playlists_cached
:
if
filter_deleted
:
return
list
(
filter
(
lambda
playlist
:
not
playlist
[
"is_delete"
]
,
cached_playlists_results
)
)
return
cached_playlists_results
# Create a dict of cached playlists
cached_playlists
=
{
}
for
cached_playlist
in
cached_playlists_results
:
if
cached_playlist
:
cached_playlists
[
cached_playlist
[
"playlist_id"
]
]
=
cached_playlist
playlist_ids_to_fetch
=
filter
(
lambda
playlist_id
:
playlist_id
not
in
cached_playlists
,
playlist_ids
)
playlists_query
=
(
session
.
query
(
Playlist
)
.
filter
(
Playlist
.
is_current
==
True
)
.
filter
(
Playlist
.
playlist_id
.
in_
(
playlist_ids_to_fetch
)
)
)
if
filter_deleted
:
playlists_query
=
playlists_query
.
filter
(
Playlist
.
is_delete
==
False
)
playlists
=
playlists_query
.
all
(
)
playlists
=
helpers
.
query_result_to_list
(
playlists
)
queried_playlists
=
{
playlist
[
"playlist_id"
]
:
playlist
for
playlist
in
playlists
}
# cache playlists for future use
set_playlists_in_cache
(
playlists
)
playlists_response
=
[
]
for
playlist_id
in
playlist_ids
:
if
playlist_id
in
cached_playlists
:
if
not
filter_deleted
or
not
cached_playlists
[
playlist_id
]
[
"is_delete"
]
:
playlists_response
.
append
(
cached_playlists
[
playlist_id
]
)
elif
playlist_id
in
queried_playlists
:
playlists_response
.
append
(
queried_playlists
[
playlist_id
]
)
return
playlists_response


def get_remix_track_parents(args):
    """Fetch remix parents for a given track.

    Args:
        args:dict
        args.track_id: track id
        args.limit: limit
        args.offset: offset
        args.with_users: with users
        args.current_user_id: current user ID
    """
    track_id = args.get("track_id")
    current_user_id = args.get("current_user_id")
    limit = args.get("limit")
    offset = args.get("offset")
    db = get_db_read_replica()

    with db.scoped_session() as session:

        def get_unpopulated_remix_parents():
            base_query = (
                session.query(Track)
                .join(
                    Remix,
                    and_(
                        Remix.parent_track_id == Track.track_id,
                        Remix.child_track_id == track_id,
                    ),
                )
                .filter(Track.is_current == True, Track.is_unlisted == False)
                .order_by(desc(Track.created_at), desc(Track.track_id))
            )

            tracks = add_query_pagination(base_query, limit, offset).all()
            tracks = helpers.query_result_to_list(tracks)
            track_ids = list(map(lambda track: track["track_id"], tracks))
            return (tracks, track_ids)

        key = make_cache_key(args)
        (tracks, track_ids) = use_redis_cache(
            key,
            UNPOPULATED_REMIX_PARENTS_CACHE_DURATION_SEC,
            get_unpopulated_remix_parents,
        )

        tracks = populate_track_metadata(session, track_ids, tracks, current_user_id)
        if args.get("with_users", False):
            add_users_to_tracks(session, tracks, current_user_id)

    return tracks


def get_health(args: GetHealthArgs, use_redis_cache: bool = True) -> Tuple[Dict, bool]:
    """
    Gets health status for the service

    Returns a tuple of health results and a boolean indicating an error
    """
    redis = redis_connection.get_redis()
    web3 = web3_provider.get_web3()

    verbose = args.get("verbose")
    enforce_block_diff = args.get("enforce_block_diff")
    qs_healthy_block_diff = cast(Optional[int], args.get("healthy_block_diff"))
    challenge_events_age_max_drift = args.get("challenge_events_age_max_drift")
    plays_count_max_drift = args.get("plays_count_max_drift")

    # If healthy block diff is given in url and positive, override config value
    healthy_block_diff = (
        qs_healthy_block_diff
        if qs_healthy_block_diff is not None and qs_healthy_block_diff >= 0
        else default_healthy_block_diff
    )

    latest_block_num = None
    latest_block_hash = None
    latest_indexed_block_num = None
    latest_indexed_block_hash = None

    if use_redis_cache:
        # get latest blockchain state from redis cache, or fallback to chain if None
        latest_block_num, latest_block_hash = get_latest_chain_block_set_if_nx(
            redis, web3
        )

        # get latest db state from redis cache
        latest_indexed_block_num = redis.get(most_recent_indexed_block_redis_key)
        if latest_indexed_block_num is not None:
            latest_indexed_block_num = int(latest_indexed_block_num)

        latest_indexed_block_hash = redis.get(most_recent_indexed_block_hash_redis_key)
        if latest_indexed_block_hash is not None:
            latest_indexed_block_hash = latest_indexed_block_hash.decode("utf-8")

    # fetch latest blockchain state from web3 if:
    # we explicitly don't want to use redis cache or
    # value from redis cache is None
    if not use_redis_cache or latest_block_num is None or latest_block_hash is None:
        # get latest blockchain state from web3
        latest_block = web3.eth.getBlock("latest", True)
        latest_block_num = latest_block.number
        latest_block_hash = latest_block.hash.hex()

    play_health_info = get_play_health_info(redis, plays_count_max_drift)
    rewards_manager_health_info = get_rewards_manager_health_info(redis)
    user_bank_health_info = get_user_bank_health_info(redis)

    # fetch latest db state if:
    # we explicitly don't want to use redis cache or
    # value from redis cache is None
    if (
        not use_redis_cache
        or latest_indexed_block_num is None
        or latest_indexed_block_hash is None
    ):
        db_block_state = _get_db_block_state()
        latest_indexed_block_num = db_block_state["number"] or 0
        latest_indexed_block_hash = db_block_state["blockhash"]

    trending_tracks_age_sec = get_elapsed_time_redis(
        redis, trending_tracks_last_completion_redis_key
    )
    trending_playlists_age_sec = get_elapsed_time_redis(
        redis, trending_playlists_last_completion_redis_key
    )
    challenge_events_age_sec = get_elapsed_time_redis(
        redis, challenges_last_processed_event_redis_key
    )
    user_balances_age_sec = get_elapsed_time_redis(
        redis, user_balances_refresh_last_completion_redis_key
    )
    num_users_in_lazy_balance_refresh_queue = len(
        redis.smembers(LAZY_REFRESH_REDIS_PREFIX)
    )
    num_users_in_immediate_balance_refresh_queue = len(
        redis.smembers(IMMEDIATE_REFRESH_REDIS_PREFIX)
    )
    last_scanned_block_for_balance_refresh = redis_get_or_restore(
        redis, eth_indexing_last_scanned_block_key
    )
    index_eth_age_sec = get_elapsed_time_redis(
        redis, index_eth_last_completion_redis_key
    )
    last_scanned_block_for_balance_refresh = (
        int(last_scanned_block_for_balance_refresh)
        if last_scanned_block_for_balance_refresh
        else None
    )
    # Get system information monitor values
    sys_info = monitors.get_monitors(
        [
            MONITORS[monitor_names.database_size],
            MONITORS[monitor_names.database_connections],
            MONITORS[monitor_names.total_memory],
            MONITORS[monitor_names.used_memory],
            MONITORS[monitor_names.filesystem_size],
            MONITORS[monitor_names.filesystem_used],
            MONITORS[monitor_names.received_bytes_per_sec],
            MONITORS[monitor_names.transferred_bytes_per_sec],
            MONITORS[monitor_names.redis_total_memory],
        ]
    )

    health_results = {
        "web": {
            "blocknumber": latest_block_num,
            "blockhash": latest_block_hash,
        },
        "db": {
            "number": latest_indexed_block_num,
            "blockhash": latest_indexed_block_hash,
        },
        "git": os.getenv("GIT_SHA"),
        "trending_tracks_age_sec": trending_tracks_age_sec,
        "trending_playlists_age_sec": trending_playlists_age_sec,
        "challenge_last_event_age_sec": challenge_events_age_sec,
        "user_balances_age_sec": user_balances_age_sec,
        "num_users_in_lazy_balance_refresh_queue": num_users_in_lazy_balance_refresh_queue,
        "num_users_in_immediate_balance_refresh_queue": num_users_in_immediate_balance_refresh_queue,
        "last_scanned_block_for_balance_refresh": last_scanned_block_for_balance_refresh,
        "index_eth_age_sec": index_eth_age_sec,
        "number_of_cpus": number_of_cpus,
        **sys_info,
        "plays": play_health_info,
        "rewards_manager": rewards_manager_health_info,
        "user_bank": user_bank_health_info,
        "openresty_public_key": openresty_public_key,
    }

    block_difference = abs(latest_block_num - latest_indexed_block_num)
    health_results["block_difference"] = block_difference
    health_results["maximum_healthy_block_difference"] = default_healthy_block_diff
    health_results.update(disc_prov_version)

    # Check that this node meets the minimum system requirements
    num_cpus: int = cast(int, health_results["number_of_cpus"] or 0)
    total_memory: int = cast(int, health_results["total_memory"] or 0)
    filesystem_size: int = cast(int, health_results["filesystem_size"] or 0)
    if (
        num_cpus < min_number_of_cpus
        or total_memory < min_total_memory
        or filesystem_size < min_filesystem_size
    ):
        health_results["meets_min_requirements"] = False
        # TODO - this will become strictly enforced in upcoming service versions and return with error
    else:
        health_results["meets_min_requirements"] = True

    if verbose:
        # DB connections check
        db_connections_json, db_connections_error = _get_db_conn_state()
        health_results["db_connections"] = db_connections_json
        health_results["country"] = shared_config["serviceLocation"]["serviceCountry"]
        health_results["latitude"] = shared_config["serviceLocation"]["serviceLatitude"]
        health_results["longitude"] = shared_config["serviceLocation"][
            "serviceLongitude"
        ]

        if db_connections_error:
            return health_results, db_connections_error

        query_insights_json, query_insights_error = _get_query_insights()
        health_results["query_insights"] = query_insights_json

        if query_insights_error:
            return health_results, query_insights_error

        table_size_info_json = monitors.get_monitors(
            [
                MONITORS[monitor_names.table_size_info],
            ]
        )

        health_results["tables"] = table_size_info_json

    unhealthy_blocks = bool(
        enforce_block_diff and block_difference > healthy_block_diff
    )
    unhealthy_challenges = bool(
        challenge_events_age_max_drift
        and challenge_events_age_sec
        and challenge_events_age_sec > challenge_events_age_max_drift
    )

    is_unhealthy = (
        unhealthy_blocks or unhealthy_challenges or play_health_info["is_unhealthy"]
    )

    return health_results, is_unhealthy


Retrieves the latest block number and blockhash from redis if the keys exist . Otherwise it sets these values in redis by querying web3 and returns them

def get_latest_chain_block_set_if_nx(redis=None, web3=None):
    """
    Retrieves the latest block number and blockhash from redis if the keys exist.
    Otherwise it sets these values in redis by querying web3 and returns them

    :param redis: redis connection
    :param web3: web3 connection

    :rtype (int, string)
    """

    latest_block_num = None
    latest_block_hash = None

    if redis is None or web3 is None:
        raise Exception("Invalid arguments for get_latest_chain_block_set_if_nx")

    # also check for 'eth' attribute in web3 which means it's initialized and connected to a provider
    if not hasattr(web3, "eth"):
        raise Exception(
            "Invalid web3 argument for get_latest_chain_block_set_if_nx, web3 is not initialized"
        )

    stored_latest_block_num = redis.get(latest_block_redis_key)
    if stored_latest_block_num is not None:
        latest_block_num = int(stored_latest_block_num)

    stored_latest_blockhash = redis.get(latest_block_hash_redis_key)
    if stored_latest_blockhash is not None:
        latest_block_hash = stored_latest_blockhash.decode("utf-8")

    if latest_block_num is None or latest_block_hash is None:
        latest_block = web3.eth.getBlock("latest", True)
        latest_block_num = latest_block.number
        latest_block_hash = latest_block.hash.hex()

        # if we had attempted to use redis cache and the values weren't there, set the values now
        try:
            # ex sets expiration time and nx only sets if key doesn't exist in redis
            redis.set(
                latest_block_redis_key,
                latest_block_num,
                ex=default_indexing_interval_seconds,
                nx=True,
            )
            redis.set(
                latest_block_hash_redis_key,
                latest_block_hash,
                ex=default_indexing_interval_seconds,
                nx=True,
            )
        except Exception as e:
            logger.error(
                f"Could not set values in redis for get_latest_chain_block_set_if_nx: {e}"
            )

    return latest_block_num, latest_block_hash


def get_aggregate_route_metrics_trailing_month():
    """
    Returns trailing count and unique count for all routes in the last trailing 30 days

    Returns:
        { unique_count, total_count }
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_aggregate_route_metrics_trailing_month(session)


Returns trailing count and unique count for all routes in the last month calculated from the RouteMetricsTrailingMonth matview .

def get_monthly_trailing_route_metrics():
    """
    Returns trailing count and unique count for all routes in the last month,
    calculated from the RouteMetricsTrailingMonth matview.

    Returns:
        { count, unique_count }
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        metrics = session.query(RouteMetricsTrailingMonth).all()
        return {"count": metrics[0].count, "unique_count": metrics[0].unique_count}

def get_monthly_trailing_route_metrics ( ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : metrics = session . query ( RouteMetricsTrailingMonth ) . all ( ) return { "count" : metrics [ 0 ] . count , "unique_count" : metrics [ 0 ] . unique_count }


Returns trailing app_name metrics for a given time period .

def get_trailing_app_metrics(args):
    """
    Returns trailing app_name metrics for a given time period.

    Args:
        args: dict The parsed args from the request
        args.limit: number The max number of apps to return
        args.time_range: one of "week", "month", "all_time"
    Returns:
        [{ name: string, count: number }, ...]
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_trailing_app_metrics(session, args)

def get_trailing_app_metrics ( args ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_trailing_app_metrics ( session , args )


def get_alembic_version() -> AlembicVersion:
    """
    Fetches the alembic version at head from the database
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        version = session.execute(
            sqlalchemy.text(
                """
                SELECT * FROM "alembic_version";
                """
            )
        ).first()
        return cast(AlembicVersion, dict(version))


Fetches tracks remix parent owners and if they have saved / reposted the tracks

def get_track_remix_metadata(session, tracks, current_user_id):
    """
    Fetches tracks' remix parent owners and if they have saved/reposted the tracks

    Args:
        session: (DB) The scoped db session for running db queries
        tracks: (List<Track>) The tracks table objects to fetch remix parent user's information for
        current_user_id?: (int) Requesting user's id for adding additional metadata to the fetched users

    Returns:
        remixes: (dict) Mapping of child track ids to parent track ids to parent track user's metadata
        {
            [childTrackId] : {
                [parentTrackId]: {
                    has_remix_author_saved: boolean,
                    has_remix_author_reposted: boolean,
                    user: populated user metadata
                }
            }
        }
    """
    track_ids_with_remix = []
    remix_query = []
    for track in tracks:
        if response_name_constants.remix_of in track:
            track_ids_with_remix.append(track["track_id"])

    if track_ids_with_remix:
        # Fetch the remix parent track's user and if that user has saved/favorited the child track
        remix_query = (
            session.query(
                Track.owner_id.label("track_owner_id"),
                Remix.parent_track_id.label("parent_track_id"),
                Remix.child_track_id.label("child_track_id"),
                Save.is_current.label("has_remix_author_saved"),
                Repost.is_current.label("has_remix_author_reposted"),
                User,
            )
            .join(
                Remix,
                and_(
                    Remix.parent_track_id == Track.track_id,
                    Remix.child_track_id.in_(track_ids_with_remix),
                ),
            )
            .join(User, and_(User.user_id == Track.owner_id, User.is_current == True))
            .outerjoin(
                Save,
                and_(
                    Save.save_item_id == Remix.child_track_id,
                    Save.save_type == SaveType.track,
                    Save.is_current == True,
                    Save.is_delete == False,
                    Save.user_id == Track.owner_id,
                ),
            )
            .outerjoin(
                Repost,
                and_(
                    Repost.repost_item_id == Remix.child_track_id,
                    Repost.user_id == Track.owner_id,
                    Repost.repost_type == RepostType.track,
                    Repost.is_current == True,
                    Repost.is_delete == False,
                ),
            )
            .filter(Track.is_current == True, Track.is_unlisted == False)
            .all()
        )

    remixes = {}
    remix_parent_owners = {}
    populated_users = {}

    # Build a dict of user id -> user model obj of the remixed track's parent owner to dedupe users
    for remix_relationship in remix_query:
        [track_owner_id, _, _, _, _, user] = remix_relationship
        if track_owner_id not in remix_parent_owners:
            remix_parent_owners[track_owner_id] = user

    # populate the user's metadata for the remixed track's parent owner
    # build `populated_users` as a map of userId -> json user
    if remix_parent_owners:
        [remix_parent_owner_ids, remix_parent_owners] = list(
            zip(
                *[
                    [k, remix_parent_owner]
                    for k, remix_parent_owner in remix_parent_owners.items()
                ]
            )
        )
        remix_parent_owners = helpers.query_result_to_list(list(remix_parent_owners))
        populated_remix_parent_users = populate_user_metadata(
            session, list(remix_parent_owner_ids), remix_parent_owners, current_user_id
        )
        for user in populated_remix_parent_users:
            populated_users[user["user_id"]] = user

    # Build a dict of child track id => parent track id => { user, has_remix_author_saved, has_remix_author_reposted }
    for remix_relationship in remix_query:
        [
            track_owner_id,
            parent_track_id,
            child_track_id,
            has_remix_author_saved,
            has_remix_author_reposted,
            _,
        ] = remix_relationship
        if child_track_id not in remixes:
            remixes[child_track_id] = {
                parent_track_id: {
                    response_name_constants.has_remix_author_saved: bool(
                        has_remix_author_saved
                    ),
                    response_name_constants.has_remix_author_reposted: bool(
                        has_remix_author_reposted
                    ),
                    "user": populated_users[track_owner_id],
                }
            }
        else:
            remixes[child_track_id][parent_track_id] = {
                response_name_constants.has_remix_author_saved: bool(
                    has_remix_author_saved
                ),
                response_name_constants.has_remix_author_reposted: bool(
                    has_remix_author_reposted
                ),
                "user": populated_users[track_owner_id],
            }

    return remixes


Gets the total karma for provided ids ( track or playlist )

def get_karma(
    session: Session,
    ids: Tuple[int],
    strategy: TrendingVersion,
    time: str = None,
    is_playlist: bool = False,
    xf: bool = False,
):
    """Gets the total karma for provided ids (track or playlist)"""

    repost_type = RepostType.playlist if is_playlist else RepostType.track
    save_type = SaveType.playlist if is_playlist else SaveType.track

    reposters = session.query(
        Repost.user_id.label("user_id"), Repost.repost_item_id.label("item_id")
    ).filter(
        Repost.repost_item_id.in_(ids),
        Repost.is_delete == False,
        Repost.is_current == True,
        Repost.repost_type == repost_type,
    )

    savers = session.query(
        Save.user_id.label("user_id"), Save.save_item_id.label("item_id")
    ).filter(
        Save.save_item_id.in_(ids),
        Save.is_current == True,
        Save.is_delete == False,
        Save.save_type == save_type,
    )
    if time is not None:
        interval = f"NOW() - interval '1 {time}'"
        savers = savers.filter(Save.created_at >= text(interval))
        reposters = reposters.filter(Repost.created_at >= text(interval))

    saves_and_reposts = reposters.union_all(savers).subquery()
    if xf:
        saves_and_reposts = (
            session.query(
                saves_and_reposts.c.user_id.label("user_id"),
                saves_and_reposts.c.item_id.label("item_id"),
            )
            .select_from(saves_and_reposts)
            .join(User, saves_and_reposts.c.user_id == User.user_id)
        )
        saves_and_reposts = saves_and_reposts.filter(
            or_(User.cover_photo != None, User.cover_photo_sizes != None),
            or_(User.profile_picture != None, User.profile_picture_sizes != None),
            User.bio != None,
        )
        saves_and_reposts = saves_and_reposts.subquery()

    query = (
        session.query(
            saves_and_reposts.c.item_id,
            cast(func.sum(AggregateUser.follower_count), Integer),
        )
        .select_from(saves_and_reposts)
        .join(AggregateUser, saves_and_reposts.c.user_id == AggregateUser.user_id)
        .group_by(saves_and_reposts.c.item_id)
    )

    return query.all()

def
get_karma
(
session
:
Session
,
ids
:
Tuple
[
int
]
,
strategy
:
TrendingVersion
,
time
:
str
=
,
is_playlist
:
bool
=
False
,
xf
:
bool
=
False
,
)
:
repost_type
=
RepostType
.
playlist
if
is_playlist
else
RepostType
.
track
save_type
=
SaveType
.
playlist
if
is_playlist
else
SaveType
.
track
reposters
=
session
.
query
(
Repost
.
user_id
.
label
(
"user_id"
)
,
Repost
.
repost_item_id
.
label
(
"item_id"
)
)
.
filter
(
Repost
.
repost_item_id
.
in_
(
ids
)
,
Repost
.
is_delete
==
False
,
Repost
.
is_current
==
True
,
Repost
.
repost_type
==
repost_type
,
)
savers
=
session
.
query
(
Save
.
user_id
.
label
(
"user_id"
)
,
Save
.
save_item_id
.
label
(
"item_id"
)
)
.
filter
(
Save
.
save_item_id
.
in_
(
ids
)
,
Save
.
is_current
==
True
,
Save
.
is_delete
==
False
,
Save
.
save_type
==
save_type
,
)
if
time
is
not
:
interval
=
f"NOW() - interval '1 {time}'"
savers
=
savers
.
filter
(
Save
.
created_at
>=
text
(
interval
)
)
reposters
=
reposters
.
filter
(
Repost
.
created_at
>=
text
(
interval
)
)
saves_and_reposts
=
reposters
.
union_all
(
savers
)
.
subquery
(
)
if
xf
:
saves_and_reposts
=
(
session
.
query
(
saves_and_reposts
.
c
.
user_id
.
label
(
"user_id"
)
,
saves_and_reposts
.
c
.
item_id
.
label
(
"item_id"
)
,
)
.
select_from
(
saves_and_reposts
)
.
join
(
User
,
saves_and_reposts
.
c
.
user_id
==
User
.
user_id
)
)
saves_and_reposts
=
saves_and_reposts
.
filter
(
or_
(
User
.
cover_photo
!=
,
User
.
cover_photo_sizes
!=
)
,
or_
(
User
.
profile_picture
!=
,
User
.
profile_picture_sizes
!=
)
,
User
.
bio
!=
,
)
saves_and_reposts
=
saves_and_reposts
.
subquery
(
)
query
=
(
session
.
query
(
saves_and_reposts
.
c
.
item_id
,
cast
(
func
.
sum
(
AggregateUser
.
follower_count
)
,
Integer
)
,
)
.
select_from
(
saves_and_reposts
)
.
join
(
AggregateUser
,
saves_and_reposts
.
c
.
user_id
==
AggregateUser
.
user_id
)
.
group_by
(
saves_and_reposts
.
c
.
item_id
)
)
return
query
.
all
(
)


Gets the track play counts for the given track_ids Args : db : sqlalchemy db session instance track_ids : list of track ids

def get_track_play_counts(db, track_ids):
    """Gets the track play counts for the given track_ids
    Args:
        db: sqlalchemy db session instance
        track_ids: list of track ids

    Returns:
        dict of track id keys to track play count values
    """

    track_listen_counts = {}

    if not track_ids:
        return track_listen_counts

    track_plays = (
        db.query(AggregatePlays)
        .filter(AggregatePlays.play_item_id.in_(track_ids))
        .all()
    )

    for track_play in track_plays:
        track_listen_counts[track_play.play_item_id] = track_play.count

    for track_id in track_ids:
        if track_id not in track_listen_counts:
            track_listen_counts[track_id] = 0

    return track_listen_counts

def get_track_play_counts ( db , track_ids ) : track_listen_counts = { } if not track_ids : return track_listen_counts track_plays = ( db . query ( AggregatePlays ) . filter ( AggregatePlays . play_item_id . in_ ( track_ids ) ) . all ( ) ) for track_play in track_plays : track_listen_counts [ track_play . play_item_id ] = track_play . count for track_id in track_ids : if track_id not in track_listen_counts : track_listen_counts [ track_id ] = 0 return track_listen_counts


Gets the sum of all aggregate plays Args : db : sqlalchemy db session instance

def get_sum_aggregate_plays(db):
    """Gets the sum of all aggregate plays
    Args:
        db: sqlalchemy db session instance

    Returns:
        int of total play count
    """

    plays = db.query(func.sum(AggregatePlays.count)).scalar()

    return int(plays)

def get_sum_aggregate_plays ( db ) : plays = db . query ( func . sum ( AggregatePlays . count ) ) . scalar ( ) return int ( plays )


Creates a subquery for type that represents a combined save + repost count .

def create_save_repost_count_subquery(session, type):
    """
    Creates a subquery for `type` that represents a combined save + repost count.

    For example, to get the tracks with the largest combined save and repost count, use:
        subquery = create_save_repost_count_subquery(session, 'track')
        session
            .query(tracks)
            .join(subquery, tracks.track_id = subquery.c.id)
            .order_by(desc(subquery.c.count))

    Args:
        session: SQLAlchemy session.
        type: (string) The type of save/repost (album, playlist, track)

    Returns: A subquery with two fields `id` and `count`.
    """
    # Get reposts by item id
    reposts_count_subquery = (
        session.query(
            Repost.repost_item_id,
        )
        .filter(
            Repost.is_current == True,
            Repost.is_delete == False,
            Repost.repost_type == type,
        )
        .subquery()
    )

    # Query saves joined against reposts grouped by id and calculate
    # a combined count for each
    subquery = (
        session.query(
            Save.save_item_id.label("id"),
            (
                func.count(Save.save_item_id)
                + func.count(reposts_count_subquery.c.repost_item_id)
            ).label("count"),
        )
        # Join against reposts filtering to matching ids.
        # Inner-join drops no-match ids.
        .join(
            reposts_count_subquery,
            Save.save_item_id == reposts_count_subquery.c.repost_item_id,
        )
        .filter(
            Save.is_current == True, Save.is_delete == False, Save.save_type == type
        )
        .group_by(Save.save_item_id)
        .subquery()
    )
    return subquery


Creates a subquery for type that represents the save count .

def create_save_count_subquery(session, type):
    """
    Creates a subquery for `type` that represents the save count.

    For example, to get the tracks with the largest save count:
        subquery = create_save_count_subquery(session, 'track')
        session
            .query(tracks)
            .join(subquery, tracks.track_id = subquery.c.id)
            .order_by(desc(subquery.c.save_count))

    Args:
        session: SQLAlchemy session.
        type: (string) The type of save/repost (album, playlist, track)

    Returns: A subquery with two fields `id` and `save_count`.
    """
    subquery = (
        session.query(
            Save.save_item_id.label("id"),
            func.count(Save.save_item_id).label(response_name_constants.save_count),
        )
        .filter(
            Save.is_current == True, Save.is_delete == False, Save.save_type == type
        )
        .group_by(Save.save_item_id)
        .subquery()
    )
    return subquery

def create_save_count_subquery ( session , type ) : subquery = ( session . query ( Save . save_item_id . label ( "id" ) , func . count ( Save . save_item_id ) . label ( response_name_constants . save_count ) , ) . filter ( Save . is_current == True , Save . is_delete == False , Save . save_type == type ) . group_by ( Save . save_item_id ) . subquery ( ) ) return subquery


Creates a subquery for type that represents the repost count .

def create_repost_count_subquery(session, type):
    """
    Creates a subquery for `type` that represents the repost count.

    For example, to get the tracks with the largest repost count:
        subquery = create_repost_count_subquery(session, 'track')
        session
            .query(tracks)
            .join(subquery, tracks.track_id = subquery.c.id)
            .order_by(desc(subquery.c.repost_count))

    Args:
        session: SQLAlchemy session.
        type: (string) The type of save/repost (album, playlist, track)

    Returns: A subquery with two fields `id` and `repost_count`.
    """
    subquery = (
        session.query(
            Repost.repost_item_id.label("id"),
            func.count(Repost.repost_item_id).label(
                response_name_constants.repost_count
            ),
        )
        .filter(
            Repost.is_current == True,
            Repost.is_delete == False,
            Repost.repost_type == type,
        )
        .group_by(Repost.repost_item_id)
        .subquery()
    )
    return subquery

def create_repost_count_subquery ( session , type ) : subquery = ( session . query ( Repost . repost_item_id . label ( "id" ) , func . count ( Repost . repost_item_id ) . label ( response_name_constants . repost_count ) , ) . filter ( Repost . is_current == True , Repost . is_delete == False , Repost . repost_type == type , ) . group_by ( Repost . repost_item_id ) . subquery ( ) ) return subquery


Creates a subquery that returns playlists created by users that current_user_id follows .

def create_followee_playlists_subquery(session, current_user_id):
    """
    Creates a subquery that returns playlists created by users that
    `current_user_id` follows.

    Args:
        session: SQLAlchemy session.
        current_user_id: The current user id to query against
    """
    # Get active followees
    followee_user_ids_subquery = (
        session.query(Follow.followee_user_id)
        .filter(
            Follow.follower_user_id == current_user_id,
            Follow.is_current == True,
            Follow.is_delete == False,
        )
        .subquery()
    )
    followee_playlists_subquery = (
        session.query(Playlist)
        .select_from(Playlist)
        .join(
            followee_user_ids_subquery,
            Playlist.playlist_owner_id == followee_user_ids_subquery.c.followee_user_id,
        )
        .subquery()
    )
    return followee_playlists_subquery

def
create_followee_playlists_subquery
(
session
,
current_user_id
)
:
# Get active followees
followee_user_ids_subquery
=
(
session
.
query
(
Follow
.
followee_user_id
)
.
filter
(
Follow
.
follower_user_id
==
current_user_id
,
Follow
.
is_current
==
True
,
Follow
.
is_delete
==
False
,
)
.
subquery
(
)
)
followee_playlists_subquery
=
(
session
.
query
(
Playlist
)
.
select_from
(
Playlist
)
.
join
(
followee_user_ids_subquery
,
Playlist
.
playlist_owner_id
==
followee_user_ids_subquery
.
c
.
followee_user_id
,
)
.
subquery
(
)
)
return
followee_playlists_subquery


Gets the number of seconds ago timestamp was from now as a SqlAlchemy expression .

def seconds_ago(timestamp):
    """Gets the number of seconds ago `timestamp` was from now as a SqlAlchemy expression."""
    return func.extract("epoch", (func.now() - timestamp))

def seconds_ago ( timestamp ) : return func . extract ( "epoch" , ( func . now ( ) - timestamp ) )


Creates a decaying ( over time ) version of the provided score . The returned value is score * a multiplier determined by peak and nominal_timestamp .

def decayed_score(score, created_at, peak=1000, nominal_timestamp=60 * 24 * 60 * 60):
    """
    Creates a decaying (over time) version of the provided `score`. The returned
    value is score * a multiplier determined by `peak` and `nominal_timestamp`.

    Args:
        score: (number) The base score to modify
        created_at: (timestamp) The timestamp the score is attributed to
        peak?: (number) The peak multipler possible

    Returns:
        A SQLAlchemy expression representing decayed score (score * multipler)
        where multipler is represented by:
        peak ^ 1 - min(time_ago / nominal_timestamp, 1)
    """
    decay_exponent = 1 - func.least(
        seconds_ago(created_at) / nominal_timestamp, 1
    )  # goes from 1 -> 0
    decay_value = func.pow(peak, decay_exponent) / peak  # decay slope value
    return score * decay_value

def
decayed_score
(
score
,
created_at
,
peak
=
1000
,
nominal_timestamp
=
60
*
24
*
60
*
60
)
:
decay_exponent
=
1
func
.
least
(
seconds_ago
(
created_at
)
/
nominal_timestamp
,
1
)
# goes from 1 -> 0
decay_value
=
func
.
pow
(
peak
,
decay_exponent
)
/
peak
# decay slope value
return
score
*
decay_value


Takes a session that is querying for playlists and filters the playlists to only those with the dominant mood provided . Dominant mood means that * most * of its tracks are of the specified mood .

def filter_to_playlist_mood(session, mood, query, correlation):
    """
    Takes a session that is querying for playlists and filters the playlists
    to only those with the dominant mood provided.
    Dominant mood means that *most* of its tracks are of the specified mood.

    This method takes a query inserts a filter clause on it and returns the same query.
    We filter down those playlists to dominant mood by running an "exists" clause
    on a dominant mood subquery.

    Args:
        session: SQLALchemy session.
        mood: (string) The mood to query against.
        query: The base query to filter on
        correlation: An optional correlation / subquery to correlate against.

    Returns: A modified version of `query` with an extra filter clause.
    """
    if not mood:
        return query

    tracks_subquery = session.query(
        func.jsonb_array_elements(correlation.c.playlist_contents["track_ids"])
        .op("->>")("track")
        .cast(Integer)
    )

    if correlation is not None:
        # If this query runs against a nested subquery, it might need to
        # be manually correlated to that subquery so it doesn't pull in all
        # playlists here.
        tracks_subquery = tracks_subquery.correlate(correlation)

    # Query for the most common mood in a playlist
    dominant_mood_subquery = (
        session.query(
            Track.mood.label("mood"),
            func.max(Track.track_id).label("latest"),
            func.count(Track.mood).label("cnt"),
        )
        .filter(
            Track.is_current == True,
            Track.is_delete == False,
            Track.track_id.in_(tracks_subquery),
        )
        .group_by(Track.mood)
        .order_by(desc("cnt"), desc("latest"))
        .limit(1)
        .subquery()
    )

    # Match the provided mood against the dominant mood for playlists
    mood_exists_query = session.query(dominant_mood_subquery.c.mood).filter(
        func.lower(dominant_mood_subquery.c.mood) == func.lower(mood)
    )

    # Filter playlist query to those that have the most common mood checking that
    # there `exists` such a playlist with the dominant mood
    return query.filter(mood_exists_query.exists())


Fetches the owners for the tracks and adds them to the track dict under the key user

def add_users_to_tracks(session, tracks, current_user_id=None):
    """
    Fetches the owners for the tracks and adds them to the track dict under the key 'user'

    Args:
        session: (DB) sqlalchemy scoped db session
        tracks: (Array<track dict>) Array of tracks dict

    Side Effects:
        Modifies the track dictionaries to add a nested owner user

    Returns: None
    """
    user_ids = get_users_ids(tracks)
    users = []
    if tracks and len(tracks) > 0 and tracks[0].get("user"):
        users = list(map(lambda t: t["user"][0], tracks))
    else:
        # This shouldn't happen - all tracks should come preloaded with their owners per the relationship
        users = get_unpopulated_users(session, user_ids)
        logger.warning("add_users_to_tracks() called but tracks have no users")
    set_users_in_cache(users)
    # bundle peripheral info into user results
    populated_users = populate_user_metadata(session, user_ids, users, current_user_id)
    user_map = {}
    for user in populated_users:
        user_map[user["user_id"]] = user

    for track in tracks:
        user = user_map[track["owner_id"]]
        if user:
            track["user"] = user


def get_plays_metrics(args: GetPlayMetricsArgs):
    """
    Returns metrics for play counts

    Args:
        args: GetPlayMetrics the parsed args from the request

    Returns:
        Array of dictionaries with the play counts and timestamp
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_plays_metrics(session, args)

def get_plays_metrics ( args : GetPlayMetricsArgs ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_plays_metrics ( session , args )


Gets data about playlists to be scored . Returns : Array< { playlist_id : number created_at : string owner_id : string windowed_save_count : number save_count : number repost_count : number windowed_repost_count : number listens : number ( always 1 ) } >

def get_scorable_playlist_data(session, time_range, strategy):
    """Gets data about playlists to be scored. Returns:
    Array<{
        "playlist_id": number
        "created_at": string
        "owner_id": string
        "windowed_save_count": number
        "save_count": number
        "repost_count: number,
        "windowed_repost_count: number
        "listens": number (always 1)
    }>
    """
    score_params = strategy.get_score_params()
    zq = score_params["zq"]
    xf = score_params["xf"]
    pt = score_params["pt"]
    mt = score_params["mt"]

    delta = time_delta_map.get(time_range) or time_delta_map.get("week")

    # Get all playlists saved within time range (windowed_save_count):
    # Queries by Playlists Joined with Saves,
    # where a given playlist was saved at least once in the past `time_delta`.
    # Limits to `TRENDING_LIMIT` and sorts by saves for later scoring.
    playlists = (
        session.query(
            Save.save_item_id,
            Playlist.created_at,
            Playlist.playlist_owner_id,
            func.count(Save.save_item_id),
        )
        .join(Playlist, Playlist.playlist_id == Save.save_item_id)
        .join(AggregateUser, AggregateUser.user_id == Playlist.playlist_owner_id)
        .filter(
            Save.is_current == True,
            Save.is_delete == False,
            Save.save_type == SaveType.playlist,  # Albums are filtered out
            Save.created_at > datetime.now() - delta,
            Playlist.is_current == True,
            Playlist.is_delete == False,
            Playlist.is_private == False,
            jsonb_array_length(Playlist.playlist_contents["track_ids"]) >= mt,
            AggregateUser.following_count < zq,
        )
        .group_by(Save.save_item_id, Playlist.created_at, Playlist.playlist_owner_id)
        .order_by(desc(func.count(Save.save_item_id)))
        .limit(TRENDING_LIMIT)
    ).all()

    # Build up a map of playlist data
    # playlist_id -> data
    # Some fields initialized at zero
    playlist_map = {
        record[0]: {
            response_name_constants.playlist_id: record[0],
            response_name_constants.created_at: record[1].isoformat(timespec="seconds"),
            response_name_constants.owner_id: record[2],
            response_name_constants.windowed_save_count: record[3],
            response_name_constants.save_count: 0,
            response_name_constants.repost_count: 0,
            response_name_constants.windowed_repost_count: 0,
            response_name_constants.owner_follower_count: 0,
            "karma": 1,
            "listens": 1,
        }
        for record in playlists
    }

    playlist_ids = [record[0] for record in playlists]
    # map owner_id -> [playlist_id], accounting for multiple playlists with the same ID
    # used in follows
    playlist_owner_id_map = {}
    for (playlist_id, _, owner_id, _) in playlists:
        if owner_id not in playlist_owner_id_map:
            playlist_owner_id_map[owner_id] = [playlist_id]
        else:
            playlist_owner_id_map[owner_id].append(playlist_id)

    # Add repost counts
    repost_counts = get_repost_counts(
        session, False, False, playlist_ids, [RepostType.playlist]
    )
    for (playlist_id, repost_count) in repost_counts:
        playlist_map[playlist_id][response_name_constants.repost_count] = repost_count

    # Add windowed repost counts
    repost_counts_for_time = get_repost_counts(
        session, False, False, playlist_ids, [RepostType.playlist], None, time_range
    )
    for (playlist_id, repost_count) in repost_counts_for_time:
        playlist_map[playlist_id][
            response_name_constants.windowed_repost_count
        ] = repost_count

    # Add save counts
    save_counts = get_save_counts(
        session, False, False, playlist_ids, [SaveType.playlist]
    )
    for (playlist_id, save_count) in save_counts:
        playlist_map[playlist_id][response_name_constants.save_count] = save_count

    # Add follower counts
    follower_counts = (
        session.query(Follow.followee_user_id, func.count(Follow.followee_user_id))
        .filter(
            Follow.is_current == True,
            Follow.is_delete == False,
            Follow.followee_user_id.in_(list(playlist_owner_id_map.keys())),
        )
        .group_by(Follow.followee_user_id)
        .all()
    )
    for (followee_user_id, follower_count) in follower_counts:
        if follower_count >= pt:
            owned_playlist_ids = playlist_owner_id_map[followee_user_id]
            for playlist_id in owned_playlist_ids:
                playlist_map[playlist_id][
                    response_name_constants.owner_follower_count
                ] = follower_count

    # Add karma
    karma_scores = get_karma(session, tuple(playlist_ids), strategy, None, True, xf)
    for (playlist_id, karma) in karma_scores:
        playlist_map[playlist_id]["karma"] = karma

    return playlist_map.values()


Gets scorable data scores and sorts then returns full unpopulated playlists . Returns a function because this is used in a Redis cache hook

def make_get_unpopulated_playlists(session, time_range, strategy):
    """Gets scorable data, scores and sorts, then returns full unpopulated playlists.
    Returns a function, because this is used in a Redis cache hook"""

    def wrapped():
        playlist_scoring_data = get_scorable_playlist_data(
            session, time_range, strategy
        )

        # score the playlists
        scored_playlists = [
            strategy.get_track_score(time_range, playlist)
            for playlist in playlist_scoring_data
        ]
        sorted_playlists = sorted(
            scored_playlists, key=lambda k: k["score"], reverse=True
        )

        # Get the unpopulated playlist metadata
        playlist_ids = [playlist["playlist_id"] for playlist in sorted_playlists]
        playlists = get_unpopulated_playlists(session, playlist_ids)

        playlist_tracks_map = get_playlist_tracks(session, {"playlists": playlists})

        for playlist in playlists:
            playlist["tracks"] = playlist_tracks_map.get(playlist["playlist_id"], [])

        return (playlists, playlist_ids)

    return wrapped

def
make_get_unpopulated_playlists
(
session
,
time_range
,
strategy
)
:
def
wrapped
(
)
:
playlist_scoring_data
=
get_scorable_playlist_data
(
session
,
time_range
,
strategy
)
# score the playlists
scored_playlists
=
[
strategy
.
get_track_score
(
time_range
,
playlist
)
for
playlist
in
playlist_scoring_data
]
sorted_playlists
=
sorted
(
scored_playlists
,
key
=
lambda
k
:
k
[
"score"
]
,
reverse
=
True
)
# Get the unpopulated playlist metadata
playlist_ids
=
[
playlist
[
"playlist_id"
]
for
playlist
in
sorted_playlists
]
playlists
=
get_unpopulated_playlists
(
session
,
playlist_ids
)
playlist_tracks_map
=
get_playlist_tracks
(
session
,
{
"playlists"
:
playlists
}
)
for
playlist
in
playlists
:
playlist
[
"tracks"
]
=
playlist_tracks_map
.
get
(
playlist
[
"playlist_id"
]
,
[
]
)
return
(
playlists
,
playlist_ids
)
return
wrapped


Returns Trending Playlists . Checks Redis cache for unpopulated playlists .

def _get_trending_playlists_with_session(
    session: Session, args: GetTrendingPlaylistsArgs, strategy, use_request_context=True
):
    """Returns Trending Playlists. Checks Redis cache for unpopulated playlists."""
    current_user_id = args.get("current_user_id", None)
    with_tracks = args.get("with_tracks", False)
    time = args.get("time")
    limit, offset = args.get("limit"), args.get("offset")
    key = make_trending_cache_key(time, strategy.version)

    # Get unpopulated playlists,
    # cached if it exists.
    (playlists, playlist_ids) = use_redis_cache(
        key, None, make_get_unpopulated_playlists(session, time, strategy)
    )

    # Apply limit + offset early to reduce the amount of
    # population work we have to do
    if limit is not None and offset is not None:
        playlists = playlists[offset : limit + offset]
        playlist_ids = playlist_ids[offset : limit + offset]

    # Populate playlist metadata
    playlists = populate_playlist_metadata(
        session,
        playlist_ids,
        playlists,
        [RepostType.playlist, RepostType.album],
        [SaveType.playlist, SaveType.album],
        current_user_id,
    )

    for playlist in playlists:
        playlist["track_count"] = len(playlist["tracks"])
        playlist["tracks"] = playlist["tracks"][:PLAYLIST_TRACKS_LIMIT]
        # Trim track_ids, which ultimately become added_timestamps
        # and need to match the tracks.
        trimmed_track_ids = {track["track_id"] for track in playlist["tracks"]}
        playlist_track_ids = playlist["playlist_contents"]["track_ids"]
        playlist_track_ids = list(
            filter(
                lambda track_id: track_id["track"]
                in trimmed_track_ids,  # pylint: disable=W0640
                playlist_track_ids,
            )
        )
        playlist["playlist_contents"]["track_ids"] = playlist_track_ids

    playlists_map = {playlist["playlist_id"]: playlist for playlist in playlists}

    if with_tracks:
        # populate track metadata
        tracks = []
        for playlist in playlists:
            playlist_tracks = playlist["tracks"]
            tracks.extend(playlist_tracks)
        track_ids = [track["track_id"] for track in tracks]
        populated_tracks = populate_track_metadata(
            session, track_ids, tracks, current_user_id
        )

        # Add users if necessary
        add_users_to_tracks(session, populated_tracks, current_user_id)

        # Re-associate tracks with playlists
        # track_id -> populated_track
        populated_track_map = {track["track_id"]: track for track in populated_tracks}
        for playlist in playlists_map.values():
            for i in range(len(playlist["tracks"])):
                track_id = playlist["tracks"][i]["track_id"]
                populated = populated_track_map[track_id]
                playlist["tracks"][i] = populated
            playlist["tracks"] = list(map(extend_track, playlist["tracks"]))

    # re-sort playlists to original order, because populate_playlist_metadata
    # unsorts.
    sorted_playlists = [playlists_map[playlist_id] for playlist_id in playlist_ids]

    # Add users to playlists
    user_id_list = get_users_ids(sorted_playlists)
    users = get_users_by_id(session, user_id_list, current_user_id, use_request_context)
    for playlist in sorted_playlists:
        user = users[playlist["playlist_owner_id"]]
        if user:
            playlist["user"] = user

    # Extend the playlists
    playlists = list(map(extend_playlist, playlists))
    return sorted_playlists


def get_trending_playlists(args: GetTrendingPlaylistsArgs, strategy):
    """Returns Trending Playlists. Checks Redis cache for unpopulated playlists."""
    db = get_db_read_replica()
    with db.scoped_session() as session:
        return _get_trending_playlists_with_session(session, args, strategy)

def get_trending_playlists ( args : GetTrendingPlaylistsArgs , strategy ) : db = get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_trending_playlists_with_session ( session , args , strategy )


def get_genre_metrics(args):
    """
    Returns metrics for track genres over the provided bucket

    Args:
        args: dict The parsed args from the request
        args.offset: number The offset to start querying from
        args.limit: number The max number of queries to return
        args.start_time: date The start of the query

    Returns:
        Array of dictionaries with the play counts and timestamp
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_genre_metrics(session, args)

def get_genre_metrics ( args ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_genre_metrics ( session , args )


def get_top_user_track_tags(args):
    """
    Gets the most used tags for tracks owned by the query user

    Args:
        args: dict The parsed args from the request
        args.limit: number optional The max number of tags to return
        args.user_id: number The user id used to query for tracks

    Returns:
        Array of strings ordered by most used tag in track
    """
    db = get_db_read_replica()
    with db.scoped_session() as session:
        return _get_top_user_track_tags(session, args)

def get_top_user_track_tags ( args ) : db = get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_top_user_track_tags ( session , args )


def get_historical_app_metrics():
    """
    Returns daily metrics for the last thirty days and all time monthly metrics

    Returns:
        {
            daily: {
                2021/01/15: {app1: ..., app2: ...}
                ...
            },
            monthly: {
                2021/01/01: {app1: ..., app2: ...}
                ...
            }
        }
    """

    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_historical_app_metrics(session)

def get_historical_app_metrics ( ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_historical_app_metrics ( session )


gets historical app metrics monthly and daily request counts .

def _get_historical_app_metrics(session, min_count=100):
    """
    gets historical app metrics monthly and daily request counts.

    Args:
        session: Database session
        min_count: Minimum count an app must have in order to be returned
    """
    today = date.today()
    thirty_days_ago = today - timedelta(days=30)
    first_day_of_month = today.replace(day=1)

    daily_query = (
        session.query(
            AggregateDailyAppNameMetrics.timestamp,
            AggregateDailyAppNameMetrics.application_name,
            AggregateDailyAppNameMetrics.count,
        )
        .filter(min_count <= AggregateDailyAppNameMetrics.count)
        .filter(thirty_days_ago <= AggregateDailyAppNameMetrics.timestamp)
        .filter(AggregateDailyAppNameMetrics.timestamp < today)
        .all()
    )
    daily_metrics = {}
    for attribute in daily_query:
        day = str(attribute[0])
        if day not in daily_metrics:
            daily_metrics[day] = {attribute[1]: attribute[2]}
        else:
            daily_metrics[day][attribute[1]] = attribute[2]

    monthly_query = (
        session.query(
            AggregateMonthlyAppNameMetrics.timestamp,
            AggregateMonthlyAppNameMetrics.application_name,
            AggregateMonthlyAppNameMetrics.count,
        )
        .filter(min_count <= AggregateMonthlyAppNameMetrics.count)
        .filter(AggregateMonthlyAppNameMetrics.timestamp < first_day_of_month)
        .all()
    )
    monthly_metrics = {}
    for attribute in monthly_query:
        month = str(attribute[0])
        if month not in monthly_metrics:
            monthly_metrics[month] = {attribute[1]: attribute[2]}
        else:
            monthly_metrics[month][attribute[1]] = attribute[2]

    return {"daily": daily_metrics, "monthly": monthly_metrics}

def _get_historical_app_metrics ( session , min_count = 100 ) : today = date . today ( ) thirty_days_ago = today - timedelta ( days = 30 ) first_day_of_month = today . replace ( day = 1 ) daily_query = ( session . query ( AggregateDailyAppNameMetrics . timestamp , AggregateDailyAppNameMetrics . application_name , AggregateDailyAppNameMetrics . count , ) . filter ( min_count <= AggregateDailyAppNameMetrics . count ) . filter ( thirty_days_ago <= AggregateDailyAppNameMetrics . timestamp ) . filter ( AggregateDailyAppNameMetrics . timestamp < today ) . all ( ) ) daily_metrics = { } for attribute in daily_query : day = str ( attribute [ 0 ] ) if day not in daily_metrics : daily_metrics [ day ] = { attribute [ 1 ] : attribute [ 2 ] } else : daily_metrics [ day ] [ attribute [ 1 ] ] = attribute [ 2 ] monthly_query = ( session . query ( AggregateMonthlyAppNameMetrics . timestamp , AggregateMonthlyAppNameMetrics . application_name , AggregateMonthlyAppNameMetrics . count , ) . filter ( min_count <= AggregateMonthlyAppNameMetrics . count ) . filter ( AggregateMonthlyAppNameMetrics . timestamp < first_day_of_month ) . all ( ) ) monthly_metrics = { } for attribute in monthly_query : month = str ( attribute [ 0 ] ) if month not in monthly_metrics : monthly_metrics [ month ] = { attribute [ 1 ] : attribute [ 2 ] } else : monthly_metrics [ month ] [ attribute [ 1 ] ] = attribute [ 2 ] return { "daily" : daily_metrics , "monthly" : monthly_metrics }


def get_aggregate_app_metrics(time_range, limit):
    """
    Returns app name metrics for a given time range

    Args:
        time_range: one of "week", "month", "all_time"
        limit: number The max number of apps to return
    Returns:
        [{ name: string, count: number }, ...]
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_aggregate_app_metrics(session, time_range, limit)

def get_aggregate_app_metrics ( time_range , limit ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_aggregate_app_metrics ( session , time_range , limit )


def get_app_name_metrics(app_name, args):
    """
    Returns the usage metrics for a specified app_name

    Args:
        app_name: string The name of the app to query for metrics
        args: dict The parsed args from the request
        args.start_time: date The date to start the query from
        args.limit: number The max number of metrics to return
        args.bucket_size: string A date_trunc operation to aggregate timestamps by

    Returns:
        Array of dictionaries with the timestamp, count, and unique_count
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_app_name_metrics(session, app_name, args)

def get_app_name_metrics ( app_name , args ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_app_name_metrics ( session , app_name , args )


def get_historical_route_metrics():
    """
    Returns daily metrics for the last thirty days and all time monthly metrics

    Returns:
        {
            daily: {
                2021/01/15: {unique_count: ..., total_count: ...}
                ...
            },
            monthly: {
                2021/01/01: {unique_count: ..., total_count: ...}
                ...
            }
        }
    """

    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_historical_route_metrics(session)

def get_historical_route_metrics ( ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_historical_route_metrics ( session )


def get_aggregate_route_metrics(time_range, bucket_size):
    """
    Returns a list of timestamp with unique count and total count for all routes
    based on given time range and grouped by bucket size

    Returns:
        [{ timestamp, unique_count, total_count }]
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_aggregate_route_metrics(session, time_range, bucket_size)

def get_aggregate_route_metrics ( time_range , bucket_size ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_aggregate_route_metrics ( session , time_range , bucket_size )


def get_route_metrics(args):
    """
    Returns the usage metrics for routes

    Args:
        args: dict The parsed args from the request
        args.path: string The route path of the query
        args.start_time: date The start of the query
        args.query_string: optional string The query string to filter on
        args.limit: number The max number of responses to return
        args.bucket_size: string  date_trunc operation to aggregate timestamps by

    Returns:
        Array of dictionaries with the route, timestamp, count, and unique_count
    """
    db = db_session.get_db_read_replica()
    with db.scoped_session() as session:
        return _get_route_metrics(session, args)

def get_route_metrics ( args ) : db = db_session . get_db_read_replica ( ) with db . scoped_session ( ) as session : return _get_route_metrics ( session , args )


def to_dict(multi_dict):
    """Converts a multi dict into a dict where only list entries are not flat"""
    return {
        k: v if len(v) > 1 else v[0]
        for (k, v) in multi_dict.to_dict(flat=False).items()
    }

def to_dict ( multi_dict ) : return { k : v if len ( v ) > 1 else v [ 0 ] for ( k , v ) in multi_dict . to_dict ( flat = False ) . items ( ) }


def parse_bool_param(field):
    """Converts a url param to a boolean value"""
    return field.lower() == "true" if field else False

def parse_bool_param ( field ) : return field . lower ( ) == "true" if field else False


def parse_id_array_param(list):
    """Converts a list of strings ids to int"""
    return [int(y) for y in list]

def parse_id_array_param ( list ) : return [ int ( y ) for y in list ]


An endpoint to retrieve the top of a certain demographic of playlists or albums . This endpoint is useful in generating views like : - Top playlists - Top Albums - Top playlists of a certain mood - Top playlists of a certain mood from people you follow

def get_top_playlists_route(type):
    """
    An endpoint to retrieve the "top" of a certain demographic of playlists or albums.
    This endpoint is useful in generating views like:
        - Top playlists
        - Top Albums
        - Top playlists of a certain mood
        - Top playlists of a certain mood from people you follow

    Args:
        type: (string) The `type` (same as repost/save type) to query from.
        limit?: (number) default=16, max=100
        mood?: (string) default=None
        filter?: (string) Optional filter to include (supports 'followees') default=None
    """
    args = to_dict(request.args)
    if "limit" in request.args:
        args["limit"] = min(request.args.get("limit", type=int), 100)
    else:
        args["limit"] = 16

    if "mood" in request.args:
        args["mood"] = request.args.get("mood")
    else:
        args["mood"] = None
    if "with_users" in request.args:
        args["with_users"] = parse_bool_param(request.args.get("with_users"))
    try:
        playlists = get_top_playlists(type, args)
        return api_helpers.success_response(playlists)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)

def get_top_playlists_route ( type ) : args = to_dict ( request . args ) if "limit" in request . args : args [ "limit" ] = min ( request . args . get ( "limit" , type = int ) , 100 ) else : args [ "limit" ] = 16 if "mood" in request . args : args [ "mood" ] = request . args . get ( "mood" ) else : args [ "mood" ] = None if "with_users" in request . args : args [ "with_users" ] = parse_bool_param ( request . args . get ( "with_users" ) ) try : playlists = get_top_playlists ( type , args ) return api_helpers . success_response ( playlists ) except exceptions . ArgumentError as e : return api_helpers . error_response ( str ( e ) , 400 )


Gets a windowed ( over a certain timerange ) view into the top of a certain type amongst followees . Requires an account . This endpoint is useful in generating views like : - New releases

def get_top_followee_windowed_route(type, window):
    """
    Gets a windowed (over a certain timerange) view into the "top" of a certain type
    amongst followees. Requires an account.
    This endpoint is useful in generating views like:
        - New releases

    Args:
        type: (string) The `type` (same as repost/save type) to query from. Currently only
            track is supported.
        window: (string) The window from now() to look back over. Supports all standard
            SqlAlchemy interval notation (week, month, year, etc.).
        limit?: (number) default=25, max=100
    """
    args = to_dict(request.args)
    if "limit" in request.args:
        args["limit"] = min(request.args.get("limit", type=int), 100)
    else:
        args["limit"] = 25
    if "with_users" in request.args:
        args["with_users"] = parse_bool_param(request.args.get("with_users"))

    try:
        tracks = get_top_followee_windowed(type, window, args)
        return api_helpers.success_response(tracks)
    except exceptions.ArgumentError as e:
        return api_helpers.error_response(str(e), 400)

def get_top_followee_windowed_route ( type , window ) : args = to_dict ( request . args ) if "limit" in request . args : args [ "limit" ] = min ( request . args . get ( "limit" , type = int ) , 100 ) else : args [ "limit" ] = 25 if "with_users" in request . args : args [ "with_users" ] = parse_bool_param ( request . args . get ( "with_users" ) ) try : tracks = get_top_followee_windowed ( type , window , args ) return api_helpers . success_response ( tracks ) except exceptions . ArgumentError as e : return api_helpers . error_response ( str ( e ) , 400 )