Files
swingmusic-extended/app/api/album.py
T
cwilvx 4a9f804e70 combine userdata and swing db into one
+ port populate to new db interface
+ add genrehashes and hash info to tracks
+ properly structure new db table files
+ move helpers to dedicated utils file
+ move settings from db to config file
+ move artists, albums, auth and favorites endpoint to new db interface
+ use folder store to index filepaths
+ paginate favorite pages
+ 56 moretiny changes 😅
2024-06-30 15:06:33 +03:00

189 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.libdata import ArtistTable
from app.db.libdata import AlbumTable as AlbumDb, TrackTable as TrackDb
from app.db.userdata import SimilarArtistTable
from app.settings import Defaults
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, 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")
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
)
track_total = sum({int(t.extra.get("track_total", 1) or 1) for t in tracks})
return {
"info": album,
"extra": {
# INFO: track_total is the sum of a set of track_total values from each track
# ASSUMPTIONS
# 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),
},
"copyright": tracks[0].copyright,
"tracks": serialize_tracks(tracks, remove_disc=False),
}
@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 serialize_tracks(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)
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)
return serialize_for_card_many(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 = SimilarArtistTable.get_by_hash(artisthash)
if similar_artists is None:
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])
sample = random.sample(albums, min(len(albums), limit))
return serialize_for_card_many(sample[:limit])