rewrite album and artist stores using in-mem hashmap stores

This commit is contained in:
cwilvx
2024-07-15 00:26:56 +03:00
parent 83e105a198
commit 58c90d95b1
11 changed files with 297 additions and 237 deletions
+36 -27
View File
@@ -4,26 +4,24 @@ Contains all the album routes.
import random
from pydantic import Field
from pydantic import BaseModel, Field
from flask_openapi3 import Tag
from flask_openapi3 import APIBlueprint
from app.api.apischemas import AlbumHashSchema, AlbumLimitSchema, ArtistHashSchema
from app.config import UserConfig
from app.db.libdata import ArtistTable
from app.db.libdata import AlbumTable as AlbumDb, TrackTable as TrackDb
from app.db.userdata import SimilarArtistTable
from app.models.album import Album
from app.settings import Defaults
from app.utils import flatten
from app.store.albums import AlbumStore
from app.store.artists import ArtistStore
from app.store.tracks import TrackStore
from app.utils.hashing import create_hash
from app.lib.albumslib import sort_by_track_no
from app.serializers.album import serialize_for_card_many
from app.serializers.track import serialize_tracks
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb
get_albums_by_albumartist = adb.get_albums_by_albumartist
check_is_fav = favdb.check_is_favorite
bp_tag = Tag(name="Album", description="Single album")
@@ -39,12 +37,14 @@ def get_album_tracks_and_info(body: AlbumHashSchema):
Returns album info and tracks for the given albumhash.
"""
albumhash = body.albumhash
album = AlbumDb.get_album_by_albumhash(albumhash)
# album = AlbumDb.get_album_by_albumhash(albumhash)
albumentry = AlbumStore.albummap.get(albumhash)
if album is None:
if albumentry is None:
return {"error": "Album not found"}, 404
tracks = TrackDb.get_tracks_by_albumhash(albumhash)
album = albumentry.album
tracks = TrackStore.get_tracks_by_trackhashes(albumentry.trackhashes)
album.trackcount = len(tracks)
album.duration = sum(t.duration for t in tracks)
album.check_type(
@@ -52,6 +52,7 @@ def get_album_tracks_and_info(body: AlbumHashSchema):
)
track_total = sum({int(t.extra.get("track_total", 1) or 1) for t in tracks})
avg_bitrate = sum(t.bitrate for t in tracks) // (len(tracks) or 1)
return {
"info": album,
@@ -61,7 +62,7 @@ def get_album_tracks_and_info(body: AlbumHashSchema):
# 1. All the tracks have the correct track totals
# 2. Tracks with the same track total are from the same disc
"track_total": track_total,
"avg_bitrate": sum(t.bitrate for t in tracks) // len(tracks),
"avg_bitrate": avg_bitrate,
},
"copyright": tracks[0].copyright,
"tracks": serialize_tracks(tracks, remove_disc=False),
@@ -76,7 +77,7 @@ def get_album_tracks(path: AlbumHashSchema):
Returns all the tracks in the given album, sorted by disc and track number.
NOTE: No album info is returned.
"""
tracks = TrackDb.get_tracks_by_albumhash(path.albumhash)
tracks = AlbumStore.get_album_tracks(path.albumhash)
tracks = sort_by_track_no(tracks)
return serialize_tracks(tracks)
@@ -105,7 +106,11 @@ def get_more_from_artist(body: GetMoreFromArtistsBody):
limit = body.limit
base_title = body.base_title
all_albums = AlbumDb.get_albums_by_artisthashes(albumartists)
all_albums: dict[str, list[Album]] = {}
for artisthash in albumartists:
all_albums[artisthash] = AlbumStore.get_albums_by_artisthash(artisthash)
seen_hashes = set()
for artisthash, albums in all_albums.items():
@@ -128,14 +133,15 @@ def get_more_from_artist(body: GetMoreFromArtistsBody):
return all_albums
class GetAlbumVersionsBody(ArtistHashSchema):
class GetAlbumVersionsBody(BaseModel):
og_album_title: str = Field(
description="The original album title (album.og_title)",
example=Defaults.API_ALBUMNAME,
)
base_title: str = Field(
description="The base title of the album to exclude from the results.",
example=Defaults.API_ALBUMNAME,
albumhash: str = Field(
description="The album hash of the album to exclude from the results.",
example=Defaults.API_ALBUMHASH,
)
@@ -146,18 +152,23 @@ def get_album_versions(body: GetAlbumVersionsBody):
Returns other versions of the given album.
"""
og_album_title = body.og_album_title
base_title = body.base_title
artisthash = body.artisthash
albumhash = body.albumhash
albums = AlbumDb.get_albums_by_base_title(base_title)
album = AlbumStore.albummap.get(albumhash)
if not album:
return []
artisthash = album.album.artisthashes[0]
albums = AlbumStore.get_albums_by_artisthash(artisthash)
basetitle = album.basetitle
albums = [
a
for a in albums
if a.og_title != og_album_title
if a.og_title != album.album.og_title
if a.base_title == basetitle
and artisthash in {a["artisthash"] for a in a.albumartists}
]
print(albums)
return serialize_for_card_many(albums)
@@ -181,10 +192,8 @@ def get_similar_albums(query: GetSimilarAlbumsQuery):
return []
artisthashes = similar_artists.get_artist_hash_set()
artists = ArtistTable.get_artists_by_artisthashes(artisthashes)
albums = AlbumDb.get_albums_by_artisthashes([a.artisthash for a in artists])
albums = flatten(albums.values())
artists = ArtistStore.get_artists_by_hashes(artisthashes)
albums = AlbumStore.get_albums_by_artisthashes([a.artisthash for a in artists])
sample = random.sample(albums, min(len(albums), limit))
return serialize_for_card_many(sample[:limit])
+17 -14
View File
@@ -17,14 +17,16 @@ from app.api.apischemas import (
)
from app.config import UserConfig
from app.db.libdata import ArtistTable
from app.db.libdata import AlbumTable, TrackTable
from app.db.userdata import SimilarArtistTable
from app.serializers.album import serialize_for_card_many
from app.serializers.artist import serialize_for_cards
from app.serializers.track import serialize_tracks
from app.store.albums import AlbumStore
from app.store.artists import ArtistStore
from app.store.tracks import TrackStore
bp_tag = Tag(name="Artist", description="Single artist")
api = APIBlueprint("artist", __name__, url_prefix="/artist", abp_tags=[bp_tag])
@@ -39,13 +41,15 @@ def get_artist(path: ArtistHashSchema, query: TrackLimitSchema):
artisthash = path.artisthash
limit = query.limit
artist = ArtistTable.get_artist_by_hash(artisthash)
if artist is None:
entry = ArtistStore.artistmap.get(artisthash)
if entry is None:
return {"error": "Artist not found"}, 404
tracks = TrackTable.get_tracks_by_artisthash(artisthash)
tracks = TrackStore.get_tracks_by_trackhashes(entry.trackhashes)
tcount = len(tracks)
artist = entry.artist
if artist.albumcount == 0 and tcount < 10:
limit = tcount
@@ -85,19 +89,19 @@ def get_artist_albums(path: ArtistHashSchema, query: GetArtistAlbumsQuery):
limit = query.limit
artist = ArtistTable.get_artist_by_hash(artisthash)
entry = ArtistStore.artistmap.get(artisthash)
if artist is None:
if entry is None:
return {"error": "Artist not found"}, 404
albums = AlbumTable.get_albums_by_artisthash(artisthash)
tracks = TrackTable.get_tracks_by_artisthash(artisthash)
albums = AlbumStore.get_albums_by_hashes(entry.albumhashes)
tracks = TrackStore.get_tracks_by_trackhashes(entry.trackhashes)
missing_albumhashes = {
t.albumhash for t in tracks if t.albumhash not in {a.albumhash for a in albums}
}
albums.extend(AlbumTable.get_albums_by_albumhashes(missing_albumhashes))
albums.extend(AlbumStore.get_albums_by_hashes(missing_albumhashes))
albumdict = {a.albumhash: a for a in albums}
config = UserConfig()
@@ -135,7 +139,7 @@ def get_artist_albums(path: ArtistHashSchema, query: GetArtistAlbumsQuery):
for key, value in res.items():
res[key] = serialize_for_card_many(value[:limit])
res["artistname"] = artist.name
res["artistname"] = entry.artist.name
return res
@@ -146,8 +150,7 @@ def get_all_artist_tracks(path: ArtistHashSchema):
Returns all artists by a given artist.
"""
# tracks = TrackStore.get_tracks_by_artisthash(path.artisthash)
tracks = TrackTable.get_tracks_by_artisthash(path.artisthash)
tracks = ArtistStore.get_artist_tracks(path.artisthash)
return serialize_tracks(tracks)
@@ -162,7 +165,7 @@ def get_similar_artists(path: ArtistHashSchema, query: ArtistLimitSchema):
if result is None:
return []
similar = ArtistTable.get_artists_by_artisthashes(result.get_artist_hash_set())
similar = ArtistStore.get_artists_by_hashes(result.get_artist_hash_set())
if len(similar) > limit:
similar = random.sample(similar, min(limit, len(similar)))