add route to save folder as playlist

+ modify playlist table sql
This commit is contained in:
mungai-njoroge
2023-07-27 13:37:07 +03:00
parent d4a1a6ee1a
commit a0c51d5f82
6 changed files with 124 additions and 44 deletions
+73 -23
View File
@@ -11,11 +11,10 @@ from app import models
from app.db.sqlite.playlists import SQLitePlaylistMethods from app.db.sqlite.playlists import SQLitePlaylistMethods
from app.lib import playlistlib from app.lib import playlistlib
from app.models.track import Track 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.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="/") 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_all_playlists = PL.get_all_playlists
get_playlist_by_id = PL.get_playlist_by_id get_playlist_by_id = PL.get_playlist_by_id
tracks_to_playlist = PL.add_tracks_to_playlist 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 update_playlist = PL.update_playlist
delete_playlist = PL.delete_playlist delete_playlist = PL.delete_playlist
remove_image = PL.remove_banner remove_image = PL.remove_banner
@@ -100,6 +99,21 @@ def send_all_playlists():
return {"data": 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"]) @api.route("/playlist/new", methods=["POST"])
def create_playlist(): def create_playlist():
""" """
@@ -115,17 +129,7 @@ def create_playlist():
if existing_playlist_count > 0: if existing_playlist_count > 0:
return {"error": "Playlist already exists"}, 409 return {"error": "Playlist already exists"}, 409
playlist = { playlist = insert_playlist(data["name"])
"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)
if playlist is None: if playlist is None:
return {"error": "Playlist could not be created"}, 500 return {"error": "Playlist could not be created"}, 500
@@ -150,7 +154,7 @@ def add_track_to_playlist(playlist_id: str):
if insert_count == 0: if insert_count == 0:
return {"error": "Track already exists in playlist"}, 409 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)) PL.update_last_updated(int(playlist_id))
return {"msg": "Done"}, 200 return {"msg": "Done"}, 200
@@ -209,14 +213,16 @@ def update_playlist_info(playlistid: str):
data = request.form data = request.form
settings = json.loads(data.get("settings"))
settings["has_gif"] = False
playlist = { playlist = {
"id": int(playlistid), "id": int(playlistid),
"artisthashes": json.dumps([]), "artisthashes": json.dumps([]),
"banner_pos": db_playlist.banner_pos,
"has_gif": 0,
"image": db_playlist.image, "image": db_playlist.image,
"last_updated": create_new_date(), "last_updated": create_new_date(),
"name": str(data.get("name")).strip(), "name": str(data.get("name")).strip(),
"settings": settings,
"trackhashes": json.dumps([]), "trackhashes": json.dumps([]),
} }
@@ -225,11 +231,11 @@ def update_playlist_info(playlistid: str):
playlist["image"] = playlistlib.save_p_image(image, playlistid) playlist["image"] = playlistlib.save_p_image(image, playlistid)
if image.content_type == "image/gif": if image.content_type == "image/gif":
playlist["has_gif"] = 1 playlist["settings"]["has_gif"] = True
# reset banner position to center. # reset banner position to center.
playlist["banner_pos"] = 50 playlist["settings"]["banner_pos"] = 50
PL.update_banner_pos(int(playlistid), 50) # PL.update_banner_pos(int(playlistid), 50)
except UnidentifiedImageError: except UnidentifiedImageError:
return {"error": "Failed: Invalid image"}, 400 return {"error": "Failed: Invalid image"}, 400
@@ -260,7 +266,8 @@ def remove_playlist_image(playlistid: str):
remove_image(pid) remove_image(pid)
playlist.image = None playlist.image = None
playlist.has_gif = False playlist.thumb = None
playlist.settings["has_gif"] = False
playlist.has_image = False playlist.has_image = False
playlist.images = get_first_4_images(trackhashes=playlist.trackhashes) 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) PL.update_last_updated(pid)
return {"msg": "Done"}, 200 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
+34 -16
View File
@@ -15,15 +15,16 @@ class SQLitePlaylistMethods:
@staticmethod @staticmethod
def insert_one_playlist(playlist: dict): def insert_one_playlist(playlist: dict):
# banner_pos,
# has_gif,
sql = """INSERT INTO playlists( sql = """INSERT INTO playlists(
artisthashes, artisthashes,
banner_pos,
has_gif,
image, image,
last_updated, last_updated,
name, name,
settings,
trackhashes 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())) 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. # FIXME: Extract the "add_track_to_playlist" method to use it for both the artisthash and trackhash lists.
@staticmethod @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. Adds a string item to a json dumped list using a playlist id and field name.
Takes the playlist ID, a field name, Takes the playlist ID, a field name,
@@ -108,6 +109,7 @@ class SQLitePlaylistMethods:
if data is not None: if data is not None:
db_items: list[str] = json.loads(data[0]) db_items: list[str] = json.loads(data[0])
# Remove duplicates, without changing the order.
for item in items: for item in items:
if item in db_items: if item in db_items:
items.remove(item) items.remove(item)
@@ -124,30 +126,39 @@ class SQLitePlaylistMethods:
@classmethod @classmethod
@background @background
def add_artist_to_playlist(cls, playlist_id: int, trackhash: str): def add_artists_to_playlist(
track = SQLiteTrackMethods.get_track_by_trackhash(trackhash) cls,
if track is None: playlist_id: int,
return 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: set[str] = set() # type: ignore
artisthashes = [a.artisthash for a in artists]
for track in tracks:
for a in track.artist:
artisthashes.add(a.artisthash)
cls.add_item_to_json_list(playlist_id, "artisthashes", artisthashes) cls.add_item_to_json_list(playlist_id, "artisthashes", artisthashes)
@staticmethod @staticmethod
def update_playlist(playlist_id: int, playlist: dict): def update_playlist(playlist_id: int, playlist: dict):
sql = """UPDATE playlists SET sql = """UPDATE playlists SET
has_gif = ?,
image = ?, image = ?,
last_updated = ?, last_updated = ?,
name = ? name = ?,
settings = ?
WHERE id = ? WHERE id = ?
""" """
del playlist["id"] del playlist["id"]
del playlist["trackhashes"] del playlist["trackhashes"]
del playlist["artisthashes"] del playlist["artisthashes"]
del playlist["banner_pos"] playlist["settings"] = json.dumps(playlist["settings"])
playlist = OrderedDict(sorted(playlist.items())) playlist = OrderedDict(sorted(playlist.items()))
params = (*playlist.values(), playlist_id) params = (*playlist.values(), playlist_id)
@@ -172,10 +183,18 @@ class SQLitePlaylistMethods:
@staticmethod @staticmethod
def update_banner_pos(playlistid: int, pos: int): 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: with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (pos, playlistid)) cur.execute(sql, (settings_str, playlistid))
@staticmethod @staticmethod
def remove_banner(playlistid: int): def remove_banner(playlistid: int):
@@ -200,7 +219,6 @@ class SQLitePlaylistMethods:
return return
trackhashes: list[str] = json.loads(data[0]) trackhashes: list[str] = json.loads(data[0])
print(tracks)
for track in tracks: for track in tracks:
# { # {
+3 -2
View File
@@ -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_USERDATA_TABLES = """
CREATE TABLE IF NOT EXISTS playlists ( CREATE TABLE IF NOT EXISTS playlists (
id integer PRIMARY KEY, id integer PRIMARY KEY,
artisthashes text, artisthashes text,
banner_pos integer NOT NULL,
has_gif integer,
image text, image text,
last_updated text not null, last_updated text not null,
name text not null, name text not null,
settings text,
trackhashes text trackhashes text
); );
+1
View File
@@ -55,6 +55,7 @@ def save_p_image(file, pid: str):
Saves a playlist banner image and returns the filepath. Saves a playlist banner image and returns the filepath.
""" """
img = Image.open(file) img = Image.open(file)
random_str = "".join(random.choices(string.ascii_letters + string.digits, k=5)) random_str = "".join(random.choices(string.ascii_letters + string.digits, k=5))
+6 -3
View File
@@ -12,11 +12,10 @@ class Playlist:
id: int id: int
artisthashes: str | list[str] artisthashes: str | list[str]
banner_pos: int
has_gif: str | bool
image: str image: str
last_updated: str last_updated: str
name: str name: str
settings: str | dict
trackhashes: str | list[str] trackhashes: str | list[str]
thumb: str = "" thumb: str = ""
@@ -29,10 +28,14 @@ class Playlist:
self.trackhashes = json.loads(str(self.trackhashes)) self.trackhashes = json.loads(str(self.trackhashes))
# self.artisthashes = json.loads(str(self.artisthashes)) # self.artisthashes = json.loads(str(self.artisthashes))
# commentted until we need it 👆 # commentted until we need it 👆
self.artisthashes = [] self.artisthashes = []
self.count = len(self.trackhashes) 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 = ( self.has_image = (
Path(settings.Paths.get_playlist_img_path()) / str(self.image) Path(settings.Paths.get_playlist_img_path()) / str(self.image)
).exists() ).exists()
+7
View File
@@ -166,3 +166,10 @@ class TrackStore:
""" """
tracks = [t for t in cls.tracks if artisthash in t.artist_hashes] tracks = [t for t in cls.tracks if artisthash in t.artist_hashes]
return remove_duplicates(tracks) 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))