Files
swingmusic-extended/app/api/album.py
T
cwilvx c42ec4dcde start: rewrite the database layer using a freaking ORM
+ start ditching in-mem stores
+ move main db table to a new name
+ experiments!
2024-06-24 00:26:47 +03:00

202 lines
5.6 KiB
Python

"""
Contains all the album routes.
"""
from itertools import groupby
import random
from flask_jwt_extended import current_user
from pydantic import 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 import AlbumTable as AlbumDb, TrackTable as TrackDb
from app.settings import Defaults
from app.models import FavType, Track
from app.store.albums import AlbumStore
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, serialize_for_card_many
from app.serializers.track import serialize_track
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")
api = APIBlueprint("album", __name__, url_prefix="/album", abp_tags=[bp_tag])
# NOTE: Don't use "/" as it will cause redirects (failure)
@api.post("")
def get_album_tracks_and_info(body: AlbumHashSchema):
"""
Get album and tracks
Returns album info and tracks for the given albumhash.
"""
albumhash = body.albumhash
album = AlbumDb.get_album_by_albumhash(albumhash)
if album is None:
return {"error": "Album not found"}, 404
tracks = TrackDb.get_tracks_by_albumhash(albumhash)
album.trackcount = len(tracks)
album.duration = sum(t.duration for t in tracks)
album.type = album.check_type(
tracks=tracks, singleTrackAsSingle=UserConfig().showAlbumsAsSingles
)
album.populate_versions()
return {"info": album, "tracks": tracks}
@api.get("/<albumhash>/tracks")
def get_album_tracks(path: AlbumHashSchema):
"""
Get album tracks
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 = sort_by_track_no(tracks)
return tracks
class GetMoreFromArtistsBody(AlbumLimitSchema):
albumartists: list = Field(
description="The artist hashes to get more albums from",
example='[{"name": "Khalid", "artisthash": "94ca2dba1c"}]',
)
base_title: str = Field(
description="The base title of the album to exclude from the results.",
example=Defaults.API_ALBUMNAME,
default=None,
)
@api.post("/from-artist")
def get_more_from_artist(body: GetMoreFromArtistsBody):
"""
Get more from artist
Returns more albums from the given artist hashes.
"""
albumartists = body.albumartists
limit = body.limit
base_title = body.base_title
all_albums = AlbumDb.get_albums_by_artisthashes(albumartists)
# filter out albums with the same base title
all_albums = filter(
lambda a: create_hash(a.base_title) != create_hash(base_title), all_albums
)
all_albums = list(all_albums)
if not len(all_albums):
return []
# group by first albumartist's artisthash
groups = groupby(all_albums, lambda a: a.albumartists[0]["artisthash"])
return [
{"artisthash": g[0], "albums": serialize_for_card_many(list(g[1])[:limit])}
for g in groups
]
class GetAlbumVersionsBody(ArtistHashSchema):
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,
)
@api.post("/other-versions")
def get_album_versions(body: GetAlbumVersionsBody):
"""
Get other versions
Returns other versions of the given album.
"""
og_album_title = body.og_album_title
base_title = body.base_title
artisthash = body.artisthash
albums = AlbumDb.get_albums_by_base_title(base_title)
print(albums)
albums = [
a
for a in albums
if a.og_title != og_album_title
and artisthash in {a["artisthash"] for a in a.albumartists}
]
print(albums)
# albums = AlbumStore.get_albums_by_artisthash(artisthash)
# albums = [
# a
# for a in albums
# if create_hash(a.base_title) == create_hash(base_title)
# and create_hash(og_album_title) != create_hash(a.og_title)
# ]
# for a in albums:
# tracks = TrackStore.get_tracks_by_albumhash(a.albumhash)
# a.get_date_from_tracks(tracks)
return albums
class GetSimilarAlbumsQuery(ArtistHashSchema, AlbumLimitSchema):
pass
@api.get("/similar")
def get_similar_albums(query: GetSimilarAlbumsQuery):
"""
Get similar albums
Returns similar albums to the given album.
"""
artisthash = query.artisthash
limit = query.limit
similar_artists = lastfmdb.get_similar_artists_for(artisthash)
if similar_artists is None:
return {"albums": []}
artisthashes = similar_artists.get_artist_hash_set()
if len(artisthashes) == 0:
return {"albums": []}
albums = [AlbumStore.get_albums_by_artisthash(a) for a in artisthashes]
albums = [a for sublist in albums for a in sublist]
albums = list({a.albumhash: a for a in albums}.values())
try:
albums = random.sample(albums, min(len(albums), limit))
except ValueError:
pass
return [serialize_for_card(a) for a in albums[:limit]]