fix: duplication of artist albums on album/from-artist

+ remove more fields from artist, album and artist models on serializers
This commit is contained in:
cwilvx
2024-07-05 04:43:39 +03:00
parent 678eed3ab6
commit a76e91cf5a
6 changed files with 53 additions and 27 deletions
+22 -20
View File
@@ -2,10 +2,8 @@
Contains all the album routes. Contains all the album routes.
""" """
from itertools import groupby
import random import random
from flask_jwt_extended import current_user
from pydantic import Field from pydantic import Field
from flask_openapi3 import Tag from flask_openapi3 import Tag
from flask_openapi3 import APIBlueprint from flask_openapi3 import APIBlueprint
@@ -16,10 +14,11 @@ from app.db.libdata import ArtistTable
from app.db.libdata import AlbumTable as AlbumDb, TrackTable as TrackDb from app.db.libdata import AlbumTable as AlbumDb, TrackTable as TrackDb
from app.db.userdata import SimilarArtistTable from app.db.userdata import SimilarArtistTable
from app.settings import Defaults from app.settings import Defaults
from app.utils import flatten
from app.utils.hashing import create_hash from app.utils.hashing import create_hash
from app.lib.albumslib import sort_by_track_no from app.lib.albumslib import sort_by_track_no
from app.serializers.album import serialize_for_card, serialize_for_card_many from app.serializers.album import serialize_for_card_many
from app.serializers.track import serialize_track, serialize_tracks from app.serializers.track import serialize_tracks
from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb from app.db.sqlite.albumcolors import SQLiteAlbumMethods as adb
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb from app.db.sqlite.lastfm.similar_artists import SQLiteLastFMSimilarArtists as lastfmdb
@@ -86,7 +85,6 @@ def get_album_tracks(path: AlbumHashSchema):
class GetMoreFromArtistsBody(AlbumLimitSchema): class GetMoreFromArtistsBody(AlbumLimitSchema):
albumartists: list = Field( albumartists: list = Field(
description="The artist hashes to get more albums from", description="The artist hashes to get more albums from",
example='[{"name": "Khalid", "artisthash": "94ca2dba1c"}]',
) )
base_title: str = Field( base_title: str = Field(
@@ -108,23 +106,26 @@ def get_more_from_artist(body: GetMoreFromArtistsBody):
base_title = body.base_title base_title = body.base_title
all_albums = AlbumDb.get_albums_by_artisthashes(albumartists) all_albums = AlbumDb.get_albums_by_artisthashes(albumartists)
seen_hashes = set()
# filter out albums with the same base title for artisthash, albums in all_albums.items():
all_albums = filter( albums = [
lambda a: create_hash(a.base_title) != create_hash(base_title), all_albums a
) for a in albums
all_albums = list(all_albums) # INFO: filter out albums added to other artists
if a.albumhash not in seen_hashes
# INFO: filter out albums with the same base title
and create_hash(a.base_title) != create_hash(base_title)
]
all_albums[artisthash] = serialize_for_card_many(
[a for a in albums if create_hash(a.base_title) != create_hash(base_title)][
:limit
]
)
# INFO: record albums added to other artists
seen_hashes.update([a.albumhash for a in albums][:limit])
if not len(all_albums): return 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): class GetAlbumVersionsBody(ArtistHashSchema):
@@ -183,6 +184,7 @@ def get_similar_albums(query: GetSimilarAlbumsQuery):
artists = ArtistTable.get_artists_by_artisthashes(artisthashes) artists = ArtistTable.get_artists_by_artisthashes(artisthashes)
albums = AlbumDb.get_albums_by_artisthashes([a.artisthash for a in artists]) albums = AlbumDb.get_albums_by_artisthashes([a.artisthash for a in artists])
albums = flatten(albums.values())
sample = random.sample(albums, min(len(albums), limit)) sample = random.sample(albums, min(len(albums), limit))
return serialize_for_card_many(sample[:limit]) return serialize_for_card_many(sample[:limit])
+2 -1
View File
@@ -22,6 +22,7 @@ from app.db.libdata import AlbumTable, TrackTable
from app.db.userdata import SimilarArtistTable from app.db.userdata import SimilarArtistTable
from app.serializers.album import serialize_for_card_many 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.serializers.track import serialize_tracks
bp_tag = Tag(name="Artist", description="Single artist") bp_tag = Tag(name="Artist", description="Single artist")
@@ -166,4 +167,4 @@ def get_similar_artists(path: ArtistHashSchema, query: ArtistLimitSchema):
if len(similar) > limit: if len(similar) > limit:
similar = random.sample(similar, min(limit, len(similar))) similar = random.sample(similar, min(limit, len(similar)))
return similar[:limit] return serialize_for_cards(similar[:limit])
+3 -3
View File
@@ -311,14 +311,14 @@ class AlbumTable(Base):
@classmethod @classmethod
def get_albums_by_artisthashes(cls, artisthashes: list[str]): def get_albums_by_artisthashes(cls, artisthashes: list[str]):
with DbManager() as conn: with DbManager() as conn:
albums: list[AlbumModel] = [] albums: dict[str, list[AlbumModel]] = {}
for artist in artisthashes: for artist in artisthashes:
result = conn.execute( result = conn.execute(
# NOTE: The artist dict keys need to in the same order they appear in the db for this to work! # NOTE: The artist dict keys need to in the same order they appear in the db for this to work!
select(AlbumTable).where(AlbumTable.albumartists.contains(artist)) select(AlbumTable).where(AlbumTable.artisthashes.contains(artist))
) )
albums.extend(albums_to_dataclasses(result.fetchall())) albums[artist] = (albums_to_dataclasses(result.fetchall()))
return albums return albums
+10 -1
View File
@@ -23,11 +23,20 @@ def serialize_for_card(album: Album):
props_to_remove = { props_to_remove = {
"duration", "duration",
"count", "count",
"artisthashes",
"albumartists_hashes", "albumartists_hashes",
"created_date",
"og_title", "og_title",
"base_title", "base_title",
"genres", "genres",
"playcount" "playcount",
"trackcount",
"type",
"playduration",
"genrehashes",
"extra",
"id",
"lastplayed",
} }
return album_serializer(album, props_to_remove) return album_serializer(album, props_to_remove)
+9
View File
@@ -15,6 +15,15 @@ def serialize_for_card(artist: Artist):
"duration", "duration",
"albumcount", "albumcount",
"playcount", "playcount",
"playduration",
"playcount",
"lastplayed",
"id",
"genres",
"genrehashes",
"extra",
"created_date",
"date",
} }
for key in props_to_remove: for key in props_to_remove:
+7 -2
View File
@@ -3,7 +3,7 @@ from dataclasses import asdict
from app.models.track import Track from app.models.track import Track
def serialize_track(track: Track, to_remove: set = {}, remove_disc=True) -> dict: def serialize_track(track: Track, to_remove: set = set(), remove_disc=True) -> dict:
album_dict = asdict(track) album_dict = asdict(track)
# is_favorite @property is not included in asdict # is_favorite @property is not included in asdict
album_dict["is_favorite"] = track.is_favorite album_dict["is_favorite"] = track.is_favorite
@@ -21,6 +21,11 @@ def serialize_track(track: Track, to_remove: set = {}, remove_disc=True) -> dict
"created_date", "created_date",
"fav_userids", "fav_userids",
"playcount", "playcount",
"genrehashes",
"id",
"lastplayed",
"playduration",
"genres",
}.union(to_remove) }.union(to_remove)
if not remove_disc: if not remove_disc:
@@ -42,6 +47,6 @@ def serialize_track(track: Track, to_remove: set = {}, remove_disc=True) -> dict
def serialize_tracks( def serialize_tracks(
tracks: list[Track], _remove: set = {}, remove_disc=True tracks: list[Track], _remove: set = set(), remove_disc=True
) -> list[dict]: ) -> list[dict]:
return [serialize_track(t, _remove, remove_disc) for t in tracks] return [serialize_track(t, _remove, remove_disc) for t in tracks]