mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-03 20:13:02 +00:00
add route to save folder as playlist
+ modify playlist table sql
This commit is contained in:
+73
-23
@@ -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
@@ -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,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
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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))
|
||||||
|
|||||||
Reference in New Issue
Block a user