add serializer functions for track and album objects

This commit is contained in:
mungai-njoroge 2023-06-24 16:47:54 +03:00
parent 88be80b25d
commit dbfa395207
7 changed files with 169 additions and 43 deletions

View File

@ -6,14 +6,16 @@ from dataclasses import asdict
from flask import Blueprint, request from flask import Blueprint, request
from app.models import FavType, Track
from app.serializers.track import track_serializer
from app.store.albums import AlbumStore
from app.store.tracks import TrackStore
from app.db.sqlite.albums import SQLiteAlbumMethods as adb from app.db.sqlite.albums import SQLiteAlbumMethods as adb
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.models import FavType, Track
from app.utils.hashing import create_hash
from app.utils.remove_duplicates import remove_duplicates
from app.store.tracks import TrackStore from app.utils.hashing import create_hash
from app.store.albums import AlbumStore from app.serializers.album import serialize_for_card
from app.utils.remove_duplicates import remove_duplicates
get_albums_by_albumartist = adb.get_albums_by_albumartist get_albums_by_albumartist = adb.get_albums_by_albumartist
check_is_fav = favdb.check_is_favorite check_is_fav = favdb.check_is_favorite
@ -79,7 +81,10 @@ def get_album_tracks_and_info():
album.is_favorite = check_is_fav(albumhash, FavType.album) album.is_favorite = check_is_fav(albumhash, FavType.album)
return {"tracks": tracks, "info": album} return {
"tracks": [track_serializer(t, retain_disc=True) for t in tracks],
"info": album,
}
@api.route("/album/<albumhash>/tracks", methods=["GET"]) @api.route("/album/<albumhash>/tracks", methods=["GET"])
@ -92,9 +97,10 @@ def get_album_tracks(albumhash: str):
for t in tracks: for t in tracks:
track = str(t["track"]).zfill(3) track = str(t["track"]).zfill(3)
t["pos"] = int(f"{t['disc']}{track}") t["_pos"] = int(f"{t['disc']}{track}")
tracks = sorted(tracks, key=lambda t: t["pos"]) tracks = sorted(tracks, key=lambda t: t["_pos"])
tracks = [track_serializer(t, _remove={"_pos"}) for t in tracks]
return {"tracks": tracks} return {"tracks": tracks}
@ -122,7 +128,14 @@ def get_artist_albums():
for a in albumartists for a in albumartists
] ]
albums = [a for a in albums if len(a["albums"]) > 0] albums = [
{
"artisthash": a["artisthash"],
"albums": [serialize_for_card(a_) for a_ in (a["albums"])],
}
for a in albums
if len(a["albums"]) > 0
]
return {"data": albums} return {"data": albums}

View File

@ -7,6 +7,8 @@ from flask import Blueprint, request
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.models import Album, FavType, Track from app.models import Album, FavType, Track
from app.serializers.album import serialize_for_card_many
from app.serializers.track import serialize_tracks
from app.utils.remove_duplicates import remove_duplicates from app.utils.remove_duplicates import remove_duplicates
from app.store.albums import AlbumStore from app.store.albums import AlbumStore
@ -22,7 +24,7 @@ class CacheEntry:
""" """
def __init__( def __init__(
self, artisthash: str, albumhashes: set[str], tracks: list[Track] self, artisthash: str, albumhashes: set[str], tracks: list[Track]
) -> None: ) -> None:
self.albums: list[Album] = [] self.albums: list[Album] = []
self.tracks: list[Track] = [] self.tracks: list[Track] = []
@ -208,7 +210,7 @@ def get_artist(artisthash: str):
artist.is_favorite = favdb.check_is_favorite(artisthash, FavType.artist) artist.is_favorite = favdb.check_is_favorite(artisthash, FavType.artist)
return {"artist": artist, "tracks": tracks[:limit]} return {"artist": artist, "tracks": serialize_tracks(tracks[:limit])}
@api.route("/artist/<artisthash>/albums", methods=["GET"]) @api.route("/artist/<artisthash>/albums", methods=["GET"])
@ -265,11 +267,11 @@ def get_artist_albums(artisthash: str):
return { return {
"artistname": artist.name, "artistname": artist.name,
"albums": albums[:limit], "albums": serialize_for_card_many(albums[:limit]),
"singles": singles[:limit], "singles": serialize_for_card_many(singles[:limit]),
"eps": eps[:limit], "eps": serialize_for_card_many(eps[:limit]),
"appearances": appearances[:limit], "appearances": serialize_for_card_many(appearances[:limit]),
"compilations": compilations[:limit] "compilations": serialize_for_card_many(compilations[:limit]),
} }
@ -280,7 +282,8 @@ def get_all_artist_tracks(artisthash: str):
""" """
tracks = TrackStore.get_tracks_by_artist(artisthash) tracks = TrackStore.get_tracks_by_artist(artisthash)
return {"tracks": tracks} return {"tracks": serialize_tracks(tracks)}
# #
# @api.route("/artist/<artisthash>/similar", methods=["GET"]) # @api.route("/artist/<artisthash>/similar", methods=["GET"])

View File

@ -2,13 +2,17 @@ from flask import Blueprint, request
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
from app.models import FavType from app.models import FavType
from app.serializers.album import serialize_for_card_many
from app.serializers.track import serialize_tracks
from app.utils.bisection import UseBisection from app.utils.bisection import UseBisection
from app.store.artists import ArtistStore from app.store.artists import ArtistStore
from app.store.albums import AlbumStore from app.store.albums import AlbumStore
from app.store.tracks import TrackStore from app.store.tracks import TrackStore
from app.serializers.favorites_serializer import recent_fav_track_serializer, recent_fav_album_serializer, \ from app.serializers.favorites_serializer import (
recent_fav_artist_serializer recent_fav_album_serializer,
recent_fav_artist_serializer,
)
api = Blueprint("favorite", __name__, url_prefix="/") api = Blueprint("favorite", __name__, url_prefix="/")
@ -80,7 +84,7 @@ def get_favorite_albums():
if limit == 0: if limit == 0:
limit = len(albums) limit = len(albums)
return {"albums": fav_albums[:limit]} return {"albums": serialize_for_card_many(fav_albums[:limit])}
@api.route("/tracks/favorite") @api.route("/tracks/favorite")
@ -103,7 +107,7 @@ def get_favorite_tracks():
if limit == 0: if limit == 0:
limit = len(tracks) limit = len(tracks)
return {"tracks": tracks[:limit]} return {"tracks": serialize_tracks(tracks[:limit])}
@api.route("/artists/favorite") @api.route("/artists/favorite")
@ -194,20 +198,18 @@ def get_all_favorites():
if fav[2] == FavType.album: if fav[2] == FavType.album:
try: try:
album = [a for a in albums if a.albumhash == fav[1]][0] album = [a for a in albums if a.albumhash == fav[1]][0]
recents.append({ recents.append(
"type": "album", {"type": "album", "item": recent_fav_album_serializer(album)}
"item": recent_fav_album_serializer(album) )
})
except IndexError: except IndexError:
continue continue
if fav[2] == FavType.artist: if fav[2] == FavType.artist:
try: try:
artist = [a for a in artists if a.artisthash == fav[1]][0] artist = [a for a in artists if a.artisthash == fav[1]][0]
recents.append({ recents.append(
"type": "artist", {"type": "artist", "item": recent_fav_artist_serializer(artist)}
"item": recent_fav_artist_serializer(artist) )
})
except IndexError: except IndexError:
continue continue

View File

@ -1,5 +1,6 @@
import dataclasses import dataclasses
from dataclasses import dataclass from dataclasses import dataclass
import datetime
from .track import Track from .track import Track
from .artist import Artist from .artist import Artist
@ -47,21 +48,28 @@ class Album:
if len(featured) > 0: if len(featured) > 0:
original_lower = "-".join([a.name.lower() for a in self.albumartists]) original_lower = "-".join([a.name.lower() for a in self.albumartists])
self.albumartists.extend([Artist(a) for a in featured if a.lower() not in original_lower]) self.albumartists.extend(
[Artist(a) for a in featured if a.lower() not in original_lower]
)
from ..store.tracks import TrackStore from ..store.tracks import TrackStore
TrackStore.append_track_artists(self.albumhash, featured, self.title) TrackStore.append_track_artists(self.albumhash, featured, self.title)
if get_flag(ParserFlags.CLEAN_ALBUM_TITLE): if get_flag(ParserFlags.CLEAN_ALBUM_TITLE):
get_versions = not get_flag(ParserFlags.MERGE_ALBUM_VERSIONS) get_versions = not get_flag(ParserFlags.MERGE_ALBUM_VERSIONS)
self.title, self.versions = get_base_title_and_versions(self.title, get_versions=get_versions) self.title, self.versions = get_base_title_and_versions(
self.title, get_versions=get_versions
)
self.base_title = self.title self.base_title = self.title
if "super_deluxe" in self.versions: if "super_deluxe" in self.versions:
self.versions.remove("deluxe") self.versions.remove("deluxe")
else: else:
self.base_title = get_base_title_and_versions(self.title, get_versions=False)[0] self.base_title = get_base_title_and_versions(
self.title, get_versions=False
)[0]
self.albumartists_hashes = "-".join(a.artisthash for a in self.albumartists) self.albumartists_hashes = "-".join(a.artisthash for a in self.albumartists)
@ -108,8 +116,17 @@ class Album:
return True return True
substrings = [ substrings = [
"the essential", "best of", "greatest hits", "#1 hits", "number ones", "super hits", "the essential",
"ultimate collection", "anthology", "great hits", "biggest hits", "the hits" "best of",
"greatest hits",
"#1 hits",
"number ones",
"super hits",
"ultimate collection",
"anthology",
"great hits",
"biggest hits",
"the hits",
] ]
for substring in substrings: for substring in substrings:
@ -147,16 +164,26 @@ class Album:
return return
if ( if (
len(tracks) == 1 len(tracks) == 1
and create_hash(tracks[0].title) == create_hash(self.title) # if they have the same title and create_hash(tracks[0].title)
# and tracks[0].track == 1 == create_hash(self.title) # if they have the same title
# and tracks[0].disc == 1 # and tracks[0].track == 1
# TODO: Review -> Are the above commented checks necessary? # and tracks[0].disc == 1
# TODO: Review -> Are the above commented checks necessary?
): ):
self.is_single = True self.is_single = True
def get_date_from_tracks(self, tracks: list[Track]): def get_date_from_tracks(self, tracks: list[Track]):
for track in tracks: """
if track.date != "Unknown": Gets the date of the album its tracks.
self.date = track.date
break Args:
tracks (list[Track]): The tracks of the album.
"""
dates = {t.date for t in tracks if t.date}
if len(dates) == 0:
self.date = 0
return
self.date = datetime.datetime.fromtimestamp(min(dates)).year

28
app/serializers/album.py Normal file
View File

@ -0,0 +1,28 @@
from dataclasses import asdict
from app.models.album import Album
def album_serializer(album: Album, to_remove: set[str]) -> dict:
album_dict = asdict(album)
to_remove.update(key for key in album_dict.keys() if key.startswith("is_"))
for key in to_remove:
album_dict.pop(key, None)
return album_dict
def serialize_for_card(album: Album):
props_to_remove = {
"duration",
"count",
"albumartist_hashes",
"og_title",
"base_title",
}
return album_serializer(album, props_to_remove)
def serialize_for_card_many(albums: list[Album]):
return [serialize_for_card(a) for a in albums]

25
app/serializers/artist.py Normal file
View File

@ -0,0 +1,25 @@
# from dataclasses import asdict
# def album_serializer(album: Artist, to_remove: set[str]) -> ArtistMinimal:
# album_dict = asdict(album)
# to_remove.update(key for key in album_dict.keys() if key.startswith("is_"))
# for key in to_remove:
# album_dict.pop(key, None)
# return album_dict
# Traceback (most recent call last):
# File "/usr/lib/python3.10/threading.py", line 1016, in _bootstrap_inner
# self.run()
# File "/usr/lib/python3.10/threading.py", line 953, in run
# self._target(*self._args, **self._kwargs)
# File "/usr/lib/python3.10/multiprocessing/pool.py", line 579, in _handle_results
# task = get()
# File "/usr/lib/python3.10/multiprocessing/connection.py", line 251, in recv
# return _ForkingPickler.loads(buf.getbuffer())
# File "/home/cwilvx/.cache/pypoetry/virtualenvs/swing_music_player-xIXBgWdk-py3.10/lib/python3.10/site-packages/requests/exceptions.py", line 41, in __init__
# CompatJSONDecodeError.__init__(self, *args)
# TypeError: JSONDecodeError.__init__() missing 2 required positional arguments: 'doc' and 'pos'

28
app/serializers/track.py Normal file
View File

@ -0,0 +1,28 @@
from dataclasses import asdict
from app.models.track import Track
def track_serializer(track: Track, _remove: set = {}, retain_disc=False) -> dict:
album_dict = asdict(track)
to_remove = {
"date",
"genre",
"last_mod",
"og_title",
"og_album",
}.union(_remove)
if not retain_disc:
to_remove.union("disc", "track")
to_remove.update(key for key in album_dict.keys() if key.startswith("is_"))
for key in to_remove:
album_dict.pop(key, None)
return album_dict
def serialize_tracks(
tracks: list[Track], _remove: set = {}, retain_disc=False
) -> list[dict]:
return [track_serializer(t, _remove, retain_disc) for t in tracks]