swingmusic/app/api/playlist.py
geoffrey45 bcc4873766 handle XDG_CONFIG_HOME specification ...
+ fix bug that caused duplicate artist color entries to db
+ check if app is windows (prep for windows build)
+ remove caribou migrations lib
+ rename all api blueprints to "api"
+ unregister child directories when customizing root dirs
+ misc
2023-01-22 23:57:12 +03:00

228 lines
5.8 KiB
Python

"""
All playlist-related routes.
"""
import json
from datetime import datetime
from flask import Blueprint, request
from PIL import UnidentifiedImageError
from app import models, serializer
from app.db.sqlite.playlists import SQLitePlaylistMethods
from app.db.store import Store
from app.lib import playlistlib
from app.utils import create_new_date, remove_duplicates
api = Blueprint("playlist", __name__, url_prefix="/")
PL = SQLitePlaylistMethods
insert_one_playlist = PL.insert_one_playlist
get_playlist_by_name = PL.get_playlist_by_name
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
update_playlist = PL.update_playlist
delete_playlist = PL.delete_playlist
# get_tracks_by_trackhashes = SQLiteTrackMethods.get_tracks_by_trackhashes
@api.route("/playlists", methods=["GET"])
def send_all_playlists():
"""
Gets all the playlists.
"""
playlists = get_all_playlists()
playlists = list(playlists)
playlists.sort(
key=lambda p: datetime.strptime(p.last_updated, "%Y-%m-%d %H:%M:%S"),
reverse=True,
)
return {"data": playlists}
@api.route("/playlist/new", methods=["POST"])
def create_playlist():
"""
Creates a new playlist. Accepts POST method with a JSON body.
"""
data = request.get_json()
if data is None:
return {"error": "Playlist name not provided"}, 400
existing_playlist_count = count_playlist_by_name(data["name"])
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)
if playlist is None:
return {"error": "Playlist could not be created"}, 500
return {"playlist": playlist}, 201
@api.route("/playlist/<playlist_id>/add", methods=["POST"])
def add_track_to_playlist(playlist_id: str):
"""
Takes a playlist ID and a track hash, and adds the track to the playlist
"""
data = request.get_json()
if data is None:
return {"error": "Track hash not provided"}, 400
trackhash = data["track"]
insert_count = tracks_to_playlist(int(playlist_id), [trackhash])
if insert_count == 0:
return {"error": "Track already exists in playlist"}, 409
add_artist_to_playlist(int(playlist_id), trackhash)
PL.update_last_updated(playlist_id)
return {"msg": "Done"}, 200
@api.route("/playlist/<playlistid>")
def get_playlist(playlistid: str):
"""
Gets a playlist by id, and if it exists, it gets all the tracks in the playlist and returns them.
"""
playlist = get_playlist_by_id(int(playlistid))
if playlist is None:
return {"msg": "Playlist not found"}, 404
tracks = Store.get_tracks_by_trackhashes(list(playlist.trackhashes))
tracks = remove_duplicates(tracks)
duration = sum(t.duration for t in tracks)
playlist.last_updated = serializer.date_string_to_time_passed(playlist.last_updated)
playlist.duration = duration
return {"info": playlist, "tracks": tracks}
@api.route("/playlist/<playlistid>/update", methods=["PUT"])
def update_playlist_info(playlistid: str):
if playlistid is None:
return {"error": "Playlist ID not provided"}, 400
db_playlist = get_playlist_by_id(int(playlistid))
if db_playlist is None:
return {"error": "Playlist not found"}, 404
image = None
if "image" in request.files:
image = request.files["image"]
data = request.form
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(),
"trackhashes": json.dumps([]),
}
if image:
try:
playlist["image"] = playlistlib.save_p_image(image, playlistid)
if image.content_type == "image/gif":
playlist["has_gif"] = 1
# reset banner position to center.
playlist["banner_pos"] = 50
PL.update_banner_pos(int(playlistid), 50)
except UnidentifiedImageError:
return {"error": "Failed: Invalid image"}, 400
p_tuple = (*playlist.values(),)
print("banner pos:", playlist["banner_pos"])
update_playlist(int(playlistid), playlist)
playlist = models.Playlist(*p_tuple)
playlist.last_updated = serializer.date_string_to_time_passed(playlist.last_updated)
return {
"data": playlist,
}
# @playlist_bp.route("/playlist/artists", methods=["POST"])
# def get_playlist_artists():
# data = request.get_json()
# pid = data["pid"]
# artists = playlistlib.GetPlaylistArtists(pid)()
# return {"data": artists}
@api.route("/playlist/delete", methods=["POST"])
def remove_playlist():
"""
Deletes a playlist by ID.
"""
message = {"error": "Playlist ID not provided"}
data = request.get_json()
if data is None:
return message, 400
try:
pid = data["pid"]
except KeyError:
return message, 400
delete_playlist(pid)
return {"msg": "Done"}, 200
@api.route("/playlist/<pid>/set-image-pos", methods=["POST"])
def update_image_position(pid: int):
data = request.get_json()
message = {"msg": "No data provided"}
if data is None:
return message, 400
try:
pos = data["pos"]
except KeyError:
return message, 400
PL.update_banner_pos(pid, pos)
return {"msg": "Image position saved"}, 200