From dbfa3952078eaf4ae8e8baa139cf33d18e9488b0 Mon Sep 17 00:00:00 2001 From: mungai-njoroge Date: Sat, 24 Jun 2023 16:47:54 +0300 Subject: [PATCH] add serializer functions for track and album objects --- app/api/album.py | 31 +++++++++++++++------- app/api/artist.py | 19 ++++++++------ app/api/favorites.py | 26 +++++++++--------- app/models/album.py | 55 +++++++++++++++++++++++++++++---------- app/serializers/album.py | 28 ++++++++++++++++++++ app/serializers/artist.py | 25 ++++++++++++++++++ app/serializers/track.py | 28 ++++++++++++++++++++ 7 files changed, 169 insertions(+), 43 deletions(-) create mode 100644 app/serializers/album.py create mode 100644 app/serializers/artist.py create mode 100644 app/serializers/track.py diff --git a/app/api/album.py b/app/api/album.py index a530cb8..e4e5110 100644 --- a/app/api/album.py +++ b/app/api/album.py @@ -6,14 +6,16 @@ from dataclasses import asdict 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.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.store.albums import AlbumStore +from app.utils.hashing import create_hash +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 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) - return {"tracks": tracks, "info": album} + return { + "tracks": [track_serializer(t, retain_disc=True) for t in tracks], + "info": album, + } @api.route("/album//tracks", methods=["GET"]) @@ -92,9 +97,10 @@ def get_album_tracks(albumhash: str): for t in tracks: 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} @@ -122,7 +128,14 @@ def get_artist_albums(): 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} diff --git a/app/api/artist.py b/app/api/artist.py index 511a35c..6cc1580 100644 --- a/app/api/artist.py +++ b/app/api/artist.py @@ -7,6 +7,8 @@ from flask import Blueprint, request from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb 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.store.albums import AlbumStore @@ -22,7 +24,7 @@ class CacheEntry: """ def __init__( - self, artisthash: str, albumhashes: set[str], tracks: list[Track] + self, artisthash: str, albumhashes: set[str], tracks: list[Track] ) -> None: self.albums: list[Album] = [] self.tracks: list[Track] = [] @@ -208,7 +210,7 @@ def get_artist(artisthash: str): 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//albums", methods=["GET"]) @@ -265,11 +267,11 @@ def get_artist_albums(artisthash: str): return { "artistname": artist.name, - "albums": albums[:limit], - "singles": singles[:limit], - "eps": eps[:limit], - "appearances": appearances[:limit], - "compilations": compilations[:limit] + "albums": serialize_for_card_many(albums[:limit]), + "singles": serialize_for_card_many(singles[:limit]), + "eps": serialize_for_card_many(eps[:limit]), + "appearances": serialize_for_card_many(appearances[: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) - return {"tracks": tracks} + return {"tracks": serialize_tracks(tracks)} + # # @api.route("/artist//similar", methods=["GET"]) diff --git a/app/api/favorites.py b/app/api/favorites.py index 39aa96f..01f2a4d 100644 --- a/app/api/favorites.py +++ b/app/api/favorites.py @@ -2,13 +2,17 @@ from flask import Blueprint, request from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb 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.store.artists import ArtistStore from app.store.albums import AlbumStore from app.store.tracks import TrackStore -from app.serializers.favorites_serializer import recent_fav_track_serializer, recent_fav_album_serializer, \ - recent_fav_artist_serializer +from app.serializers.favorites_serializer import ( + recent_fav_album_serializer, + recent_fav_artist_serializer, +) api = Blueprint("favorite", __name__, url_prefix="/") @@ -80,7 +84,7 @@ def get_favorite_albums(): if limit == 0: limit = len(albums) - return {"albums": fav_albums[:limit]} + return {"albums": serialize_for_card_many(fav_albums[:limit])} @api.route("/tracks/favorite") @@ -103,7 +107,7 @@ def get_favorite_tracks(): if limit == 0: limit = len(tracks) - return {"tracks": tracks[:limit]} + return {"tracks": serialize_tracks(tracks[:limit])} @api.route("/artists/favorite") @@ -194,20 +198,18 @@ def get_all_favorites(): if fav[2] == FavType.album: try: album = [a for a in albums if a.albumhash == fav[1]][0] - recents.append({ - "type": "album", - "item": recent_fav_album_serializer(album) - }) + recents.append( + {"type": "album", "item": recent_fav_album_serializer(album)} + ) except IndexError: continue if fav[2] == FavType.artist: try: artist = [a for a in artists if a.artisthash == fav[1]][0] - recents.append({ - "type": "artist", - "item": recent_fav_artist_serializer(artist) - }) + recents.append( + {"type": "artist", "item": recent_fav_artist_serializer(artist)} + ) except IndexError: continue diff --git a/app/models/album.py b/app/models/album.py index 39ba188..14c54d0 100644 --- a/app/models/album.py +++ b/app/models/album.py @@ -1,5 +1,6 @@ import dataclasses from dataclasses import dataclass +import datetime from .track import Track from .artist import Artist @@ -47,21 +48,28 @@ class Album: if len(featured) > 0: 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 + TrackStore.append_track_artists(self.albumhash, featured, self.title) if get_flag(ParserFlags.CLEAN_ALBUM_TITLE): 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 if "super_deluxe" in self.versions: self.versions.remove("deluxe") 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) @@ -108,8 +116,17 @@ class Album: return True substrings = [ - "the essential", "best of", "greatest hits", "#1 hits", "number ones", "super hits", - "ultimate collection", "anthology", "great hits", "biggest hits", "the hits" + "the essential", + "best of", + "greatest hits", + "#1 hits", + "number ones", + "super hits", + "ultimate collection", + "anthology", + "great hits", + "biggest hits", + "the hits", ] for substring in substrings: @@ -147,16 +164,26 @@ class Album: return if ( - len(tracks) == 1 - and create_hash(tracks[0].title) == create_hash(self.title) # if they have the same title - # and tracks[0].track == 1 - # and tracks[0].disc == 1 - # TODO: Review -> Are the above commented checks necessary? + len(tracks) == 1 + and create_hash(tracks[0].title) + == create_hash(self.title) # if they have the same title + # and tracks[0].track == 1 + # and tracks[0].disc == 1 + # TODO: Review -> Are the above commented checks necessary? ): self.is_single = True def get_date_from_tracks(self, tracks: list[Track]): - for track in tracks: - if track.date != "Unknown": - self.date = track.date - break + """ + Gets the date of the album its tracks. + + 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 diff --git a/app/serializers/album.py b/app/serializers/album.py new file mode 100644 index 0000000..f59dcde --- /dev/null +++ b/app/serializers/album.py @@ -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] diff --git a/app/serializers/artist.py b/app/serializers/artist.py new file mode 100644 index 0000000..4c531be --- /dev/null +++ b/app/serializers/artist.py @@ -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' diff --git a/app/serializers/track.py b/app/serializers/track.py new file mode 100644 index 0000000..d9b5d25 --- /dev/null +++ b/app/serializers/track.py @@ -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]