From a0c51d5f82b1e2ccbc82e849c6a061951dc318fa Mon Sep 17 00:00:00 2001 From: mungai-njoroge Date: Thu, 27 Jul 2023 13:37:07 +0300 Subject: [PATCH] add route to save folder as playlist + modify playlist table sql --- app/api/playlist.py | 96 +++++++++++++++++++++++++++++--------- app/db/sqlite/playlists.py | 50 +++++++++++++------- app/db/sqlite/queries.py | 5 +- app/lib/playlistlib.py | 1 + app/models/playlist.py | 9 ++-- app/store/tracks.py | 7 +++ 6 files changed, 124 insertions(+), 44 deletions(-) diff --git a/app/api/playlist.py b/app/api/playlist.py index b1d1ff35..a7e32ce7 100644 --- a/app/api/playlist.py +++ b/app/api/playlist.py @@ -11,11 +11,10 @@ from app import models from app.db.sqlite.playlists import SQLitePlaylistMethods from app.lib import playlistlib from app.models.track import Track -from app.utils.dates import date_string_to_time_passed, create_new_date -from app.utils.remove_duplicates import remove_duplicates - -from app.store.tracks import TrackStore from app.store.albums import AlbumStore +from app.store.tracks import TrackStore +from app.utils.dates import create_new_date, date_string_to_time_passed +from app.utils.remove_duplicates import remove_duplicates api = Blueprint("playlist", __name__, url_prefix="/") @@ -27,7 +26,7 @@ count_playlist_by_name = PL.count_playlist_by_name get_all_playlists = PL.get_all_playlists get_playlist_by_id = PL.get_playlist_by_id tracks_to_playlist = PL.add_tracks_to_playlist -add_artist_to_playlist = PL.add_artist_to_playlist +add_artist_to_playlist = PL.add_artists_to_playlist update_playlist = PL.update_playlist delete_playlist = PL.delete_playlist remove_image = PL.remove_banner @@ -100,6 +99,21 @@ def send_all_playlists(): return {"data": playlists} +def insert_playlist(name: str): + playlist = { + "artisthashes": json.dumps([]), + "image": None, + "last_updated": create_new_date(), + "name": name, + "trackhashes": json.dumps([]), + "settings": json.dumps( + {"has_gif": False, "banner_pos": 50, "square_img": False} + ), + } + + return insert_one_playlist(playlist) + + @api.route("/playlist/new", methods=["POST"]) def create_playlist(): """ @@ -115,17 +129,7 @@ def create_playlist(): if existing_playlist_count > 0: return {"error": "Playlist already exists"}, 409 - playlist = { - "artisthashes": json.dumps([]), - "banner_pos": 50, - "has_gif": 0, - "image": None, - "last_updated": create_new_date(), - "name": data["name"], - "trackhashes": json.dumps([]), - } - - playlist = insert_one_playlist(playlist) + playlist = insert_playlist(data["name"]) if playlist is None: return {"error": "Playlist could not be created"}, 500 @@ -150,7 +154,7 @@ def add_track_to_playlist(playlist_id: str): if insert_count == 0: return {"error": "Track already exists in playlist"}, 409 - add_artist_to_playlist(int(playlist_id), trackhash) + add_artist_to_playlist(int(playlist_id), [trackhash]) PL.update_last_updated(int(playlist_id)) return {"msg": "Done"}, 200 @@ -209,14 +213,16 @@ def update_playlist_info(playlistid: str): data = request.form + settings = json.loads(data.get("settings")) + settings["has_gif"] = False + playlist = { "id": int(playlistid), "artisthashes": json.dumps([]), - "banner_pos": db_playlist.banner_pos, - "has_gif": 0, "image": db_playlist.image, "last_updated": create_new_date(), "name": str(data.get("name")).strip(), + "settings": settings, "trackhashes": json.dumps([]), } @@ -225,11 +231,11 @@ def update_playlist_info(playlistid: str): playlist["image"] = playlistlib.save_p_image(image, playlistid) if image.content_type == "image/gif": - playlist["has_gif"] = 1 + playlist["settings"]["has_gif"] = True # reset banner position to center. - playlist["banner_pos"] = 50 - PL.update_banner_pos(int(playlistid), 50) + playlist["settings"]["banner_pos"] = 50 + # PL.update_banner_pos(int(playlistid), 50) except UnidentifiedImageError: return {"error": "Failed: Invalid image"}, 400 @@ -260,7 +266,8 @@ def remove_playlist_image(playlistid: str): remove_image(pid) playlist.image = None - playlist.has_gif = False + playlist.thumb = None + playlist.settings["has_gif"] = False playlist.has_image = False playlist.images = get_first_4_images(trackhashes=playlist.trackhashes) @@ -326,3 +333,46 @@ def remove_tracks_from_playlist(pid: int): PL.update_last_updated(pid) return {"msg": "Done"}, 200 + + +@api.route("/playlist/save-folder", methods=["POST"]) +def save_folder_as_folder(): + data = request.get_json() + msg = {"error": "'path' and 'playlist_name' not provided"}, 400 + + if data is None: + return msg + + name = data.get("playlist_name") + path = data.get("path") + + if path is None or name is None: + return msg + + p_count = count_playlist_by_name(name) + + if p_count > 0: + return {"error": "Playlist already exists"}, 409 + + tracks = TrackStore.get_tracks_in_path(path) + trackhashes = [t.trackhash for t in tracks] + + if len(trackhashes) == 0: + return {"error": "No tracks found in folder"}, 404 + + artisthashes = set() + + for t in tracks: + for a in t.artist: + artisthashes.add(a.artisthash) + + playlist = insert_playlist(name) + + if playlist is None: + return {"error": "Playlist could not be created"}, 500 + + tracks_to_playlist(playlist.id, trackhashes) + PL.add_artists_to_playlist(playlist.id, artisthashes=artisthashes) + PL.update_last_updated(playlist.id) + + return {"playlist_id": playlist.id}, 201 diff --git a/app/db/sqlite/playlists.py b/app/db/sqlite/playlists.py index c94d788e..f1ff9eca 100644 --- a/app/db/sqlite/playlists.py +++ b/app/db/sqlite/playlists.py @@ -15,15 +15,16 @@ class SQLitePlaylistMethods: @staticmethod def insert_one_playlist(playlist: dict): + # banner_pos, + # has_gif, sql = """INSERT INTO playlists( artisthashes, - banner_pos, - has_gif, image, last_updated, name, + settings, trackhashes - ) VALUES(:artisthashes, :banner_pos, :has_gif, :image, :last_updated, :name, :trackhashes) + ) VALUES(:artisthashes, :image, :last_updated, :name, :settings, :trackhashes) """ playlist = OrderedDict(sorted(playlist.items())) @@ -93,7 +94,7 @@ class SQLitePlaylistMethods: # FIXME: Extract the "add_track_to_playlist" method to use it for both the artisthash and trackhash lists. @staticmethod - def add_item_to_json_list(playlist_id: int, field: str, items: list[str]): + def add_item_to_json_list(playlist_id: int, field: str, items: set[str]): """ Adds a string item to a json dumped list using a playlist id and field name. Takes the playlist ID, a field name, @@ -108,6 +109,7 @@ class SQLitePlaylistMethods: if data is not None: db_items: list[str] = json.loads(data[0]) + # Remove duplicates, without changing the order. for item in items: if item in db_items: items.remove(item) @@ -124,30 +126,39 @@ class SQLitePlaylistMethods: @classmethod @background - def add_artist_to_playlist(cls, playlist_id: int, trackhash: str): - track = SQLiteTrackMethods.get_track_by_trackhash(trackhash) - if track is None: - return + def add_artists_to_playlist( + cls, + playlist_id: int, + trackhashes: list[str] = [], + artisthashes: set[str] = None, + ): + if not artisthashes: + track = [SQLiteTrackMethods.get_track_by_trackhash(t) for t in trackhashes] + tracks = [t for t in track if t is not None] - artists: list[Artist] = track.artist # type: ignore - artisthashes = [a.artisthash for a in artists] + artisthashes: set[str] = set() # type: ignore + + for track in tracks: + for a in track.artist: + artisthashes.add(a.artisthash) cls.add_item_to_json_list(playlist_id, "artisthashes", artisthashes) @staticmethod def update_playlist(playlist_id: int, playlist: dict): sql = """UPDATE playlists SET - has_gif = ?, image = ?, last_updated = ?, - name = ? + name = ?, + settings = ? WHERE id = ? """ del playlist["id"] del playlist["trackhashes"] del playlist["artisthashes"] - del playlist["banner_pos"] + playlist["settings"] = json.dumps(playlist["settings"]) + playlist = OrderedDict(sorted(playlist.items())) params = (*playlist.values(), playlist_id) @@ -172,10 +183,18 @@ class SQLitePlaylistMethods: @staticmethod def update_banner_pos(playlistid: int, pos: int): - sql = """UPDATE playlists SET banner_pos = ? WHERE id = ?""" + playlist = SQLitePlaylistMethods.get_playlist_by_id(playlistid) + + if playlist is None: + return + + playlist.settings["banner_pos"] = pos + settings_str = json.dumps(playlist.settings) + + sql = """UPDATE playlists SET settings = ? WHERE id = ?""" with SQLiteManager(userdata_db=True) as cur: - cur.execute(sql, (pos, playlistid)) + cur.execute(sql, (settings_str, playlistid)) @staticmethod def remove_banner(playlistid: int): @@ -200,7 +219,6 @@ class SQLitePlaylistMethods: return trackhashes: list[str] = json.loads(data[0]) - print(tracks) for track in tracks: # { diff --git a/app/db/sqlite/queries.py b/app/db/sqlite/queries.py index 9616c7f4..77bd13d9 100644 --- a/app/db/sqlite/queries.py +++ b/app/db/sqlite/queries.py @@ -3,15 +3,16 @@ This file contains the SQL queries to create the database tables. """ +# banner_pos integer NOT NULL, +# has_gif integer, CREATE_USERDATA_TABLES = """ CREATE TABLE IF NOT EXISTS playlists ( id integer PRIMARY KEY, artisthashes text, - banner_pos integer NOT NULL, - has_gif integer, image text, last_updated text not null, name text not null, + settings text, trackhashes text ); diff --git a/app/lib/playlistlib.py b/app/lib/playlistlib.py index dfceb0da..2db80405 100644 --- a/app/lib/playlistlib.py +++ b/app/lib/playlistlib.py @@ -55,6 +55,7 @@ def save_p_image(file, pid: str): Saves a playlist banner image and returns the filepath. """ img = Image.open(file) + random_str = "".join(random.choices(string.ascii_letters + string.digits, k=5)) diff --git a/app/models/playlist.py b/app/models/playlist.py index 88cd6fcb..2ef60e68 100644 --- a/app/models/playlist.py +++ b/app/models/playlist.py @@ -12,11 +12,10 @@ class Playlist: id: int artisthashes: str | list[str] - banner_pos: int - has_gif: str | bool image: str last_updated: str name: str + settings: str | dict trackhashes: str | list[str] thumb: str = "" @@ -29,10 +28,14 @@ class Playlist: self.trackhashes = json.loads(str(self.trackhashes)) # self.artisthashes = json.loads(str(self.artisthashes)) # commentted until we need it 👆 + self.artisthashes = [] self.count = len(self.trackhashes) - self.has_gif = bool(int(self.has_gif)) + + if isinstance(self.settings, str): + self.settings = json.loads(self.settings) + self.has_image = ( Path(settings.Paths.get_playlist_img_path()) / str(self.image) ).exists() diff --git a/app/store/tracks.py b/app/store/tracks.py index f49c3ea3..9b1918a6 100644 --- a/app/store/tracks.py +++ b/app/store/tracks.py @@ -166,3 +166,10 @@ class TrackStore: """ tracks = [t for t in cls.tracks if artisthash in t.artist_hashes] return remove_duplicates(tracks) + + @classmethod + def get_tracks_in_path(cls, path: str): + """ + Returns all tracks in the given path. + """ + return (t for t in cls.tracks if t.folder.startswith(path))