mirror of
https://github.com/tcsenpai/swingmusic.git
synced 2025-06-06 19:25:34 +00:00
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
This commit is contained in:
parent
4e6e1f03dc
commit
bcc4873766
@ -5,17 +5,8 @@ This module combines all API blueprints into a single Flask app instance.
|
||||
from flask import Flask
|
||||
from flask_cors import CORS
|
||||
|
||||
from app.api import (
|
||||
album,
|
||||
artist,
|
||||
favorites,
|
||||
folder,
|
||||
playlist,
|
||||
search,
|
||||
track,
|
||||
settings,
|
||||
imgserver,
|
||||
)
|
||||
from app.api import (album, artist, favorites, folder, imgserver, playlist,
|
||||
search, settings, track)
|
||||
|
||||
|
||||
def create_api():
|
||||
@ -27,14 +18,14 @@ def create_api():
|
||||
|
||||
with app.app_context():
|
||||
|
||||
app.register_blueprint(album.albumbp)
|
||||
app.register_blueprint(artist.artistbp)
|
||||
app.register_blueprint(track.trackbp)
|
||||
app.register_blueprint(search.searchbp)
|
||||
app.register_blueprint(folder.folderbp)
|
||||
app.register_blueprint(playlist.playlistbp)
|
||||
app.register_blueprint(favorites.favbp)
|
||||
app.register_blueprint(imgserver.imgbp)
|
||||
app.register_blueprint(settings.settingsbp)
|
||||
app.register_blueprint(album.api)
|
||||
app.register_blueprint(artist.api)
|
||||
app.register_blueprint(track.api)
|
||||
app.register_blueprint(search.api)
|
||||
app.register_blueprint(folder.api)
|
||||
app.register_blueprint(playlist.api)
|
||||
app.register_blueprint(favorites.api)
|
||||
app.register_blueprint(imgserver.api)
|
||||
app.register_blueprint(settings.api)
|
||||
|
||||
return app
|
||||
|
@ -12,15 +12,14 @@ from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.store import Store
|
||||
from app.models import FavType, Track
|
||||
|
||||
|
||||
get_album_by_id = adb.get_album_by_id
|
||||
get_albums_by_albumartist = adb.get_albums_by_albumartist
|
||||
check_is_fav = favdb.check_is_favorite
|
||||
|
||||
albumbp = Blueprint("album", __name__, url_prefix="")
|
||||
api = Blueprint("album", __name__, url_prefix="")
|
||||
|
||||
|
||||
@albumbp.route("/album", methods=["POST"])
|
||||
@api.route("/album", methods=["POST"])
|
||||
def get_album():
|
||||
"""Returns all the tracks in the given album."""
|
||||
|
||||
@ -88,7 +87,7 @@ def get_album():
|
||||
return {"tracks": tracks, "info": album}
|
||||
|
||||
|
||||
@albumbp.route("/album/<albumhash>/tracks", methods=["GET"])
|
||||
@api.route("/album/<albumhash>/tracks", methods=["GET"])
|
||||
def get_album_tracks(albumhash: str):
|
||||
"""
|
||||
Returns all the tracks in the given album.
|
||||
@ -105,7 +104,7 @@ def get_album_tracks(albumhash: str):
|
||||
return {"tracks": tracks}
|
||||
|
||||
|
||||
@albumbp.route("/album/from-artist", methods=["POST"])
|
||||
@api.route("/album/from-artist", methods=["POST"])
|
||||
def get_artist_albums():
|
||||
data = request.get_json()
|
||||
|
||||
|
@ -5,12 +5,12 @@ from collections import deque
|
||||
|
||||
from flask import Blueprint, request
|
||||
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.store import Store
|
||||
from app.models import Album, FavType, Track
|
||||
from app.utils import remove_duplicates
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
|
||||
artistbp = Blueprint("artist", __name__, url_prefix="/")
|
||||
api = Blueprint("artist", __name__, url_prefix="/")
|
||||
|
||||
|
||||
class CacheEntry:
|
||||
@ -156,7 +156,7 @@ def add_albums_to_cache(artisthash: str):
|
||||
# =======================================================
|
||||
|
||||
|
||||
@artistbp.route("/artist/<artisthash>", methods=["GET"])
|
||||
@api.route("/artist/<artisthash>", methods=["GET"])
|
||||
def get_artist(artisthash: str):
|
||||
"""
|
||||
Get artist data.
|
||||
@ -203,7 +203,7 @@ def get_artist(artisthash: str):
|
||||
return {"artist": artist, "tracks": tracks[:limit]}
|
||||
|
||||
|
||||
@artistbp.route("/artist/<artisthash>/albums", methods=["GET"])
|
||||
@api.route("/artist/<artisthash>/albums", methods=["GET"])
|
||||
def get_artist_albums(artisthash: str):
|
||||
limit = request.args.get("limit")
|
||||
|
||||
@ -261,7 +261,7 @@ def get_artist_albums(artisthash: str):
|
||||
}
|
||||
|
||||
|
||||
@artistbp.route("/artist/<artisthash>/tracks", methods=["GET"])
|
||||
@api.route("/artist/<artisthash>/tracks", methods=["GET"])
|
||||
def get_artist_tracks(artisthash: str):
|
||||
"""
|
||||
Returns all artists by a given artist.
|
||||
|
@ -1,17 +1,18 @@
|
||||
from flask import Blueprint, request
|
||||
|
||||
from app.db.sqlite.favorite import SQLiteFavoriteMethods as favdb
|
||||
from app.db.store import Store
|
||||
from app.models import FavType
|
||||
from app.utils import UseBisection
|
||||
|
||||
favbp = Blueprint("favorite", __name__, url_prefix="/")
|
||||
api = Blueprint("favorite", __name__, url_prefix="/")
|
||||
|
||||
|
||||
def remove_none(items: list):
|
||||
return [i for i in items if i is not None]
|
||||
|
||||
|
||||
@favbp.route("/favorite/add", methods=["POST"])
|
||||
@api.route("/favorite/add", methods=["POST"])
|
||||
def add_favorite():
|
||||
"""
|
||||
Adds a favorite to the database.
|
||||
@ -32,7 +33,7 @@ def add_favorite():
|
||||
return {"msg": "Added to favorites"}
|
||||
|
||||
|
||||
@favbp.route("/favorite/remove", methods=["POST"])
|
||||
@api.route("/favorite/remove", methods=["POST"])
|
||||
def remove_favorite():
|
||||
"""
|
||||
Removes a favorite from the database.
|
||||
@ -53,7 +54,7 @@ def remove_favorite():
|
||||
return {"msg": "Removed from favorites"}
|
||||
|
||||
|
||||
@favbp.route("/albums/favorite")
|
||||
@api.route("/albums/favorite")
|
||||
def get_favorite_albums():
|
||||
limit = request.args.get("limit")
|
||||
|
||||
@ -77,7 +78,7 @@ def get_favorite_albums():
|
||||
return {"albums": fav_albums[:limit]}
|
||||
|
||||
|
||||
@favbp.route("/tracks/favorite")
|
||||
@api.route("/tracks/favorite")
|
||||
def get_favorite_tracks():
|
||||
limit = request.args.get("limit")
|
||||
|
||||
@ -100,7 +101,7 @@ def get_favorite_tracks():
|
||||
return {"tracks": tracks[:limit]}
|
||||
|
||||
|
||||
@favbp.route("/artists/favorite")
|
||||
@api.route("/artists/favorite")
|
||||
def get_favorite_artists():
|
||||
limit = request.args.get("limit")
|
||||
|
||||
@ -124,7 +125,7 @@ def get_favorite_artists():
|
||||
return {"artists": artists[:limit]}
|
||||
|
||||
|
||||
@favbp.route("/favorites")
|
||||
@api.route("/favorites")
|
||||
def get_all_favorites():
|
||||
"""
|
||||
Returns all the favorites in the database.
|
||||
@ -191,7 +192,7 @@ def get_all_favorites():
|
||||
}
|
||||
|
||||
|
||||
@favbp.route("/favorites/check")
|
||||
@api.route("/favorites/check")
|
||||
def check_favorite():
|
||||
"""
|
||||
Checks if a favorite exists in the database.
|
||||
|
@ -2,16 +2,16 @@
|
||||
Contains all the folder routes.
|
||||
"""
|
||||
import os
|
||||
|
||||
from flask import Blueprint, request
|
||||
|
||||
from app import settings
|
||||
from app.lib.folderslib import GetFilesAndDirs
|
||||
|
||||
|
||||
folderbp = Blueprint("folder", __name__, url_prefix="/")
|
||||
api = Blueprint("folder", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@folderbp.route("/folder", methods=["POST"])
|
||||
@api.route("/folder", methods=["POST"])
|
||||
def get_folder_tree():
|
||||
"""
|
||||
Returns a list of all the folders and tracks in the given folder.
|
||||
@ -21,10 +21,10 @@ def get_folder_tree():
|
||||
if data is not None:
|
||||
req_dir: str = data["folder"]
|
||||
else:
|
||||
req_dir = settings.HOME_DIR
|
||||
req_dir = settings.USER_HOME_DIR
|
||||
|
||||
if req_dir == "$home":
|
||||
req_dir = settings.HOME_DIR
|
||||
req_dir = settings.USER_HOME_DIR
|
||||
|
||||
tracks, folders = GetFilesAndDirs(req_dir)()
|
||||
|
||||
@ -34,7 +34,7 @@ def get_folder_tree():
|
||||
}
|
||||
|
||||
|
||||
@folderbp.route("/folder/dir-browser", methods=["POST"])
|
||||
@api.route("/folder/dir-browser", methods=["POST"])
|
||||
def list_folders():
|
||||
"""
|
||||
Returns a list of all the folders in the given folder.
|
||||
@ -44,10 +44,10 @@ def list_folders():
|
||||
try:
|
||||
req_dir: str = data["folder"]
|
||||
except KeyError:
|
||||
req_dir = settings.HOME_DIR
|
||||
req_dir = settings.USER_HOME_DIR
|
||||
|
||||
if req_dir == "$home":
|
||||
req_dir = settings.HOME_DIR
|
||||
req_dir = settings.USER_HOME_DIR
|
||||
|
||||
entries = os.scandir(req_dir)
|
||||
|
||||
|
@ -1,14 +1,13 @@
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from flask import Blueprint, send_from_directory
|
||||
|
||||
imgbp = Blueprint("imgserver", __name__, url_prefix="/img")
|
||||
from app.settings import APP_DIR
|
||||
|
||||
api = Blueprint("imgserver", __name__, url_prefix="/img")
|
||||
SUPPORTED_IMAGES = (".jpg", ".png", ".webp", ".jpeg")
|
||||
|
||||
HOME = os.path.expanduser("~")
|
||||
|
||||
APP_DIR = Path(HOME) / ".swing"
|
||||
APP_DIR = Path(APP_DIR)
|
||||
IMG_PATH = APP_DIR / "images"
|
||||
ASSETS_PATH = APP_DIR / "assets"
|
||||
|
||||
@ -23,7 +22,7 @@ ARTIST_SM_PATH = ARTIST_PATH / "small"
|
||||
PLAYLIST_PATH = IMG_PATH / "playlists"
|
||||
|
||||
|
||||
@imgbp.route("/")
|
||||
@api.route("/")
|
||||
def hello():
|
||||
return "<h1>Image Server</h1>"
|
||||
|
||||
@ -37,7 +36,7 @@ def send_fallback_img(filename: str = "default.webp"):
|
||||
return send_from_directory(ASSETS_PATH, filename)
|
||||
|
||||
|
||||
@imgbp.route("/t/<imgpath>")
|
||||
@api.route("/t/<imgpath>")
|
||||
def send_lg_thumbnail(imgpath: str):
|
||||
fpath = LG_THUMB_PATH / imgpath
|
||||
|
||||
@ -47,7 +46,7 @@ def send_lg_thumbnail(imgpath: str):
|
||||
return send_fallback_img()
|
||||
|
||||
|
||||
@imgbp.route("/t/s/<imgpath>")
|
||||
@api.route("/t/s/<imgpath>")
|
||||
def send_sm_thumbnail(imgpath: str):
|
||||
fpath = SM_THUMB_PATH / imgpath
|
||||
|
||||
@ -57,7 +56,7 @@ def send_sm_thumbnail(imgpath: str):
|
||||
return send_fallback_img()
|
||||
|
||||
|
||||
@imgbp.route("/a/<imgpath>")
|
||||
@api.route("/a/<imgpath>")
|
||||
def send_lg_artist_image(imgpath: str):
|
||||
fpath = ARTIST_LG_PATH / imgpath
|
||||
|
||||
@ -67,7 +66,7 @@ def send_lg_artist_image(imgpath: str):
|
||||
return send_fallback_img("artist.webp")
|
||||
|
||||
|
||||
@imgbp.route("/a/s/<imgpath>")
|
||||
@api.route("/a/s/<imgpath>")
|
||||
def send_sm_artist_image(imgpath: str):
|
||||
fpath = ARTIST_SM_PATH / imgpath
|
||||
|
||||
@ -77,7 +76,7 @@ def send_sm_artist_image(imgpath: str):
|
||||
return send_fallback_img("artist.webp")
|
||||
|
||||
|
||||
@imgbp.route("/p/<imgpath>")
|
||||
@api.route("/p/<imgpath>")
|
||||
def send_playlist_image(imgpath: str):
|
||||
fpath = PLAYLIST_PATH / imgpath
|
||||
|
||||
|
@ -13,7 +13,7 @@ from app.db.store import Store
|
||||
from app.lib import playlistlib
|
||||
from app.utils import create_new_date, remove_duplicates
|
||||
|
||||
playlistbp = Blueprint("playlist", __name__, url_prefix="/")
|
||||
api = Blueprint("playlist", __name__, url_prefix="/")
|
||||
|
||||
PL = SQLitePlaylistMethods
|
||||
|
||||
@ -30,7 +30,7 @@ delete_playlist = PL.delete_playlist
|
||||
# get_tracks_by_trackhashes = SQLiteTrackMethods.get_tracks_by_trackhashes
|
||||
|
||||
|
||||
@playlistbp.route("/playlists", methods=["GET"])
|
||||
@api.route("/playlists", methods=["GET"])
|
||||
def send_all_playlists():
|
||||
"""
|
||||
Gets all the playlists.
|
||||
@ -46,7 +46,7 @@ def send_all_playlists():
|
||||
return {"data": playlists}
|
||||
|
||||
|
||||
@playlistbp.route("/playlist/new", methods=["POST"])
|
||||
@api.route("/playlist/new", methods=["POST"])
|
||||
def create_playlist():
|
||||
"""
|
||||
Creates a new playlist. Accepts POST method with a JSON body.
|
||||
@ -79,7 +79,7 @@ def create_playlist():
|
||||
return {"playlist": playlist}, 201
|
||||
|
||||
|
||||
@playlistbp.route("/playlist/<playlist_id>/add", methods=["POST"])
|
||||
@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
|
||||
@ -102,7 +102,7 @@ def add_track_to_playlist(playlist_id: str):
|
||||
return {"msg": "Done"}, 200
|
||||
|
||||
|
||||
@playlistbp.route("/playlist/<playlistid>")
|
||||
@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.
|
||||
@ -123,7 +123,7 @@ def get_playlist(playlistid: str):
|
||||
return {"info": playlist, "tracks": tracks}
|
||||
|
||||
|
||||
@playlistbp.route("/playlist/<playlistid>/update", methods=["PUT"])
|
||||
@api.route("/playlist/<playlistid>/update", methods=["PUT"])
|
||||
def update_playlist_info(playlistid: str):
|
||||
if playlistid is None:
|
||||
return {"error": "Playlist ID not provided"}, 400
|
||||
@ -188,7 +188,7 @@ def update_playlist_info(playlistid: str):
|
||||
# return {"data": artists}
|
||||
|
||||
|
||||
@playlistbp.route("/playlist/delete", methods=["POST"])
|
||||
@api.route("/playlist/delete", methods=["POST"])
|
||||
def remove_playlist():
|
||||
"""
|
||||
Deletes a playlist by ID.
|
||||
@ -209,7 +209,7 @@ def remove_playlist():
|
||||
return {"msg": "Done"}, 200
|
||||
|
||||
|
||||
@playlistbp.route("/playlist/<pid>/set-image-pos", methods=["POST"])
|
||||
@api.route("/playlist/<pid>/set-image-pos", methods=["POST"])
|
||||
def update_image_position(pid: int):
|
||||
data = request.get_json()
|
||||
message = {"msg": "No data provided"}
|
||||
|
@ -8,7 +8,7 @@ from app import models, utils
|
||||
from app.db.store import Store
|
||||
from app.lib import searchlib
|
||||
|
||||
searchbp = Blueprint("search", __name__, url_prefix="/")
|
||||
api = Blueprint("search", __name__, url_prefix="/")
|
||||
|
||||
|
||||
SEARCH_COUNT = 12
|
||||
@ -95,7 +95,7 @@ class DoSearch:
|
||||
# self.search_playlists()
|
||||
|
||||
|
||||
@searchbp.route("/search/tracks", methods=["GET"])
|
||||
@api.route("/search/tracks", methods=["GET"])
|
||||
def search_tracks():
|
||||
"""
|
||||
Searches for tracks that match the search query.
|
||||
@ -113,7 +113,7 @@ def search_tracks():
|
||||
}
|
||||
|
||||
|
||||
@searchbp.route("/search/albums", methods=["GET"])
|
||||
@api.route("/search/albums", methods=["GET"])
|
||||
def search_albums():
|
||||
"""
|
||||
Searches for albums.
|
||||
@ -131,7 +131,7 @@ def search_albums():
|
||||
}
|
||||
|
||||
|
||||
@searchbp.route("/search/artists", methods=["GET"])
|
||||
@api.route("/search/artists", methods=["GET"])
|
||||
def search_artists():
|
||||
"""
|
||||
Searches for artists.
|
||||
@ -167,7 +167,7 @@ def search_artists():
|
||||
# }
|
||||
|
||||
|
||||
@searchbp.route("/search/top", methods=["GET"])
|
||||
@api.route("/search/top", methods=["GET"])
|
||||
def get_top_results():
|
||||
"""
|
||||
Returns the top results for the search query.
|
||||
@ -188,7 +188,7 @@ def get_top_results():
|
||||
}
|
||||
|
||||
|
||||
@searchbp.route("/search/loadmore")
|
||||
@api.route("/search/loadmore")
|
||||
def search_load_more():
|
||||
"""
|
||||
Returns more songs, albums or artists from a search query.
|
||||
|
@ -1,10 +1,17 @@
|
||||
from flask import Blueprint, request
|
||||
|
||||
from app.db.sqlite.settings import SettingsSQLMethods as sdb
|
||||
|
||||
settingsbp = Blueprint("settings", __name__, url_prefix="/")
|
||||
api = Blueprint("settings", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@settingsbp.route("/settings/add-root-dirs", methods=["POST"])
|
||||
def get_child_dirs(parent: str, children: list[str]):
|
||||
"""Returns child directories in a list, given a parent directory"""
|
||||
|
||||
return [dir for dir in children if dir.startswith(parent)]
|
||||
|
||||
|
||||
@api.route("/settings/add-root-dirs", methods=["POST"])
|
||||
def add_root_dirs():
|
||||
"""
|
||||
Add custom root directories to the database.
|
||||
@ -17,18 +24,26 @@ def add_root_dirs():
|
||||
return msg, 400
|
||||
|
||||
try:
|
||||
new_dirs = data["new_dirs"]
|
||||
removed_dirs = data["removed"]
|
||||
new_dirs: list[str] = data["new_dirs"]
|
||||
removed_dirs: list[str] = data["removed"]
|
||||
except KeyError:
|
||||
return msg, 400
|
||||
|
||||
# --- Unregister child directories ---
|
||||
db_dirs = sdb.get_root_dirs()
|
||||
|
||||
for _dir in new_dirs:
|
||||
children = get_child_dirs(_dir, db_dirs)
|
||||
removed_dirs.extend(children)
|
||||
# ------------------------------------
|
||||
|
||||
sdb.add_root_dirs(new_dirs)
|
||||
sdb.remove_root_dirs(removed_dirs)
|
||||
|
||||
return {"msg": "Added root directories to the database."}
|
||||
return {"msg": "Updated!"}
|
||||
|
||||
|
||||
@settingsbp.route("/settings/get-root-dirs", methods=["GET"])
|
||||
@api.route("/settings/get-root-dirs", methods=["GET"])
|
||||
def get_root_dirs():
|
||||
"""
|
||||
Get custom root directories from the database.
|
||||
@ -39,7 +54,7 @@ def get_root_dirs():
|
||||
|
||||
|
||||
# CURRENTLY UNUSED ROUTE 👇
|
||||
@settingsbp.route("/settings/remove-root-dirs", methods=["POST"])
|
||||
@api.route("/settings/remove-root-dirs", methods=["POST"])
|
||||
def remove_root_dirs():
|
||||
"""
|
||||
Remove custom root directories from the database.
|
||||
|
@ -2,12 +2,13 @@
|
||||
Contains all the track routes.
|
||||
"""
|
||||
from flask import Blueprint, send_file
|
||||
|
||||
from app.db.store import Store
|
||||
|
||||
trackbp = Blueprint("track", __name__, url_prefix="/")
|
||||
api = Blueprint("track", __name__, url_prefix="/")
|
||||
|
||||
|
||||
@trackbp.route("/file/<trackhash>")
|
||||
@api.route("/file/<trackhash>")
|
||||
def send_track_file(trackhash: str):
|
||||
"""
|
||||
Returns an audio file that matches the passed id to the client.
|
||||
|
@ -69,13 +69,12 @@ class ProcessArtistColors:
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
db_colors: list[tuple] = list(adb.get_all_artists())
|
||||
db_artisthashes = "-".join([artist[1] for artist in db_colors])
|
||||
all_artists = Store.artists
|
||||
|
||||
if all_artists is None:
|
||||
return
|
||||
|
||||
for artist in tqdm(all_artists, desc="Processing artist colors"):
|
||||
if len(artist.colors) == 0:
|
||||
if artist.artisthash not in db_artisthashes:
|
||||
self.process_color(artist)
|
||||
|
||||
@staticmethod
|
||||
@ -90,5 +89,3 @@ class ProcessArtistColors:
|
||||
if len(colors) > 0:
|
||||
adb.insert_one_artist(artisthash=artist.artisthash, colors=colors)
|
||||
Store.map_artist_color((0, artist.artisthash, json.dumps(colors)))
|
||||
|
||||
# TODO: Load album and artist colors into the store.
|
||||
|
3
app/migrations/__init__.py
Normal file
3
app/migrations/__init__.py
Normal file
@ -0,0 +1,3 @@
|
||||
"""
|
||||
Migrations module
|
||||
"""
|
@ -1,16 +1,42 @@
|
||||
"""
|
||||
Contains default configs
|
||||
"""
|
||||
import multiprocessing
|
||||
import os
|
||||
|
||||
|
||||
# ------- HELPER METHODS --------
|
||||
def get_xdg_config_dir():
|
||||
"""
|
||||
Returns the XDG_CONFIG_HOME environment variable if it exists, otherwise
|
||||
returns the default config directory. If none of those exist, returns the
|
||||
user's home directory.
|
||||
"""
|
||||
xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
|
||||
|
||||
if xdg_config_home:
|
||||
return xdg_config_home
|
||||
|
||||
try:
|
||||
alt_dir = os.path.join(os.environ.get("HOME"), ".config")
|
||||
|
||||
if os.path.exists(alt_dir):
|
||||
return alt_dir
|
||||
except TypeError:
|
||||
return os.path.expanduser("~")
|
||||
|
||||
|
||||
# ------- HELPER METHODS --------
|
||||
|
||||
|
||||
APP_VERSION = "Swing v.1.0.0.beta.1"
|
||||
|
||||
# paths
|
||||
CONFIG_FOLDER = ".swing"
|
||||
HOME_DIR = os.path.expanduser("~")
|
||||
XDG_CONFIG_DIR = get_xdg_config_dir()
|
||||
USER_HOME_DIR = os.path.expanduser("~")
|
||||
|
||||
APP_DIR = os.path.join(HOME_DIR, CONFIG_FOLDER)
|
||||
CONFIG_FOLDER = "swing" if XDG_CONFIG_DIR != USER_HOME_DIR else ".swing"
|
||||
|
||||
APP_DIR = os.path.join(XDG_CONFIG_DIR, CONFIG_FOLDER)
|
||||
IMG_PATH = os.path.join(APP_DIR, "images")
|
||||
|
||||
ARTIST_IMG_PATH = os.path.join(IMG_PATH, "artists")
|
||||
@ -37,8 +63,6 @@ DEFAULT_ARTIST_IMG = IMG_ARTIST_URI + "0.webp"
|
||||
|
||||
LAST_FM_API_KEY = "762db7a44a9e6fb5585661f5f2bdf23a"
|
||||
|
||||
CPU_COUNT = multiprocessing.cpu_count()
|
||||
|
||||
THUMB_SIZE = 400
|
||||
SM_THUMB_SIZE = 64
|
||||
SM_ARTIST_IMG_SIZE = 64
|
||||
@ -46,24 +70,9 @@ SM_ARTIST_IMG_SIZE = 64
|
||||
The size of extracted images in pixels
|
||||
"""
|
||||
|
||||
LOGGER_ENABLE: bool = True
|
||||
|
||||
FILES = ["flac", "mp3", "wav", "m4a"]
|
||||
SUPPORTED_FILES = tuple(f".{file}" for file in FILES)
|
||||
|
||||
SUPPORTED_IMAGES = (".jpg", ".png", ".webp", ".jpeg")
|
||||
|
||||
SUPPORTED_DIR_IMAGES = [
|
||||
"folder",
|
||||
"cover",
|
||||
"album",
|
||||
"front",
|
||||
]
|
||||
|
||||
# ===== DB =========
|
||||
USE_MONGO = False
|
||||
|
||||
|
||||
# ===== SQLite =====
|
||||
APP_DB_NAME = "swing.db"
|
||||
USER_DATA_DB_NAME = "userdata.db"
|
||||
|
@ -4,7 +4,6 @@ Contains the functions to prepare the server for use.
|
||||
import os
|
||||
import shutil
|
||||
from configparser import ConfigParser
|
||||
import caribou # pylint: disable=import-error
|
||||
|
||||
from app import settings
|
||||
from app.db.sqlite import create_connection, create_tables, queries
|
||||
@ -64,10 +63,6 @@ def create_config_dir() -> None:
|
||||
"""
|
||||
Creates the config directory if it doesn't exist.
|
||||
"""
|
||||
|
||||
home_dir = os.path.expanduser("~")
|
||||
config_folder = os.path.join(home_dir, settings.CONFIG_FOLDER)
|
||||
|
||||
thumb_path = os.path.join("images", "thumbnails")
|
||||
small_thumb_path = os.path.join(thumb_path, "small")
|
||||
large_thumb_path = os.path.join(thumb_path, "large")
|
||||
@ -91,7 +86,7 @@ def create_config_dir() -> None:
|
||||
]
|
||||
|
||||
for _dir in dirs:
|
||||
path = os.path.join(config_folder, _dir)
|
||||
path = os.path.join(settings.APP_DIR, _dir)
|
||||
exists = os.path.exists(path)
|
||||
|
||||
if not exists:
|
||||
@ -114,19 +109,6 @@ def setup_sqlite():
|
||||
create_tables(app_db_conn, queries.CREATE_APPDB_TABLES)
|
||||
create_tables(playlist_db_conn, queries.CREATE_USERDATA_TABLES)
|
||||
|
||||
userdb_migrations = get_home_res_path("app") / "migrations" / "userdata"
|
||||
maindb_migrations = get_home_res_path("app") / "migrations" / "main"
|
||||
|
||||
caribou.upgrade(
|
||||
APP_DB_PATH,
|
||||
maindb_migrations,
|
||||
)
|
||||
|
||||
caribou.upgrade(
|
||||
str(USERDATA_DB_PATH),
|
||||
str(userdb_migrations),
|
||||
)
|
||||
|
||||
app_db_conn.close()
|
||||
playlist_db_conn.close()
|
||||
|
||||
|
29
app/utils.py
29
app/utils.py
@ -5,6 +5,7 @@ from pathlib import Path
|
||||
from datetime import datetime
|
||||
|
||||
import os
|
||||
import platform
|
||||
import socket as Socket
|
||||
import hashlib
|
||||
import threading
|
||||
@ -38,19 +39,22 @@ def run_fast_scandir(__dir: str, full=False) -> tuple[list[str], list[str]]:
|
||||
subfolders = []
|
||||
files = []
|
||||
|
||||
for f in os.scandir(__dir):
|
||||
if f.is_dir() and not f.name.startswith("."):
|
||||
subfolders.append(f.path)
|
||||
if f.is_file():
|
||||
ext = os.path.splitext(f.name)[1].lower()
|
||||
try:
|
||||
for _files in os.scandir(__dir):
|
||||
if _files.is_dir() and not _files.name.startswith("."):
|
||||
subfolders.append(_files.path)
|
||||
if _files.is_file():
|
||||
ext = os.path.splitext(_files.name)[1].lower()
|
||||
if ext in SUPPORTED_FILES:
|
||||
files.append(f.path)
|
||||
files.append(_files.path)
|
||||
|
||||
if full or len(files) == 0:
|
||||
for _dir in list(subfolders):
|
||||
sf, f = run_fast_scandir(_dir, full=True)
|
||||
subfolders.extend(sf)
|
||||
files.extend(f)
|
||||
sub_dirs, _files = run_fast_scandir(_dir, full=True)
|
||||
subfolders.extend(sub_dirs)
|
||||
files.extend(_files)
|
||||
except PermissionError:
|
||||
return [], []
|
||||
|
||||
return subfolders, files
|
||||
|
||||
@ -239,3 +243,10 @@ def get_ip():
|
||||
soc.close()
|
||||
|
||||
return ip_address
|
||||
|
||||
|
||||
def is_windows():
|
||||
"""
|
||||
Returns True if the OS is Windows.
|
||||
"""
|
||||
return platform.system() == "Windows"
|
||||
|
11
manage.py
11
manage.py
@ -13,7 +13,7 @@ from app.functions import run_periodic_checks
|
||||
from app.lib.watchdogg import Watcher as WatchDog
|
||||
from app.settings import APP_VERSION, HELP_MESSAGE, TCOLOR
|
||||
from app.setup import run_setup
|
||||
from app.utils import background, get_home_res_path, get_ip
|
||||
from app.utils import background, get_home_res_path, get_ip, is_windows
|
||||
|
||||
werkzeug = logging.getLogger("werkzeug")
|
||||
werkzeug.setLevel(logging.ERROR)
|
||||
@ -80,6 +80,8 @@ class HandleArgs:
|
||||
config["DEFAULT"]["BUILD"] = "True"
|
||||
config.write(file)
|
||||
|
||||
_s = ";" if is_windows() else ":"
|
||||
|
||||
bundler.run(
|
||||
[
|
||||
"manage.py",
|
||||
@ -87,9 +89,10 @@ class HandleArgs:
|
||||
"--name",
|
||||
"swingmusic",
|
||||
"--clean",
|
||||
"--add-data=assets:assets",
|
||||
"--add-data=client:client",
|
||||
"--add-data=pyinstaller.config.ini:.",
|
||||
f"--add-data=assets{_s}assets",
|
||||
f"--add-data=client{_s}client",
|
||||
f"--add-data=app/migrations{_s}app/migrations",
|
||||
f"--add-data=pyinstaller.config.ini{_s}.",
|
||||
"-y",
|
||||
]
|
||||
)
|
||||
|
46
poetry.lock
generated
46
poetry.lock
generated
@ -12,23 +12,11 @@ files = [
|
||||
{file = "altgraph-0.17.3.tar.gz", hash = "sha256:ad33358114df7c9416cdb8fa1eaa5852166c505118717021c6a8c7c7abbd03dd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argparse"
|
||||
version = "1.4.0"
|
||||
description = "Python command-line parsing library"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "argparse-1.4.0-py2.py3-none-any.whl", hash = "sha256:c31647edb69fd3d465a847ea3157d37bed1f95f19760b11a47aa91c04b666314"},
|
||||
{file = "argparse-1.4.0.tar.gz", hash = "sha256:62b089a55be1d8949cd2bc7e0df0bddb9e028faefc8c32038cc84862aefdd6e4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "astroid"
|
||||
version = "2.12.12"
|
||||
description = "An abstract syntax tree for Python with inference support."
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
@ -107,20 +95,6 @@ d = ["aiohttp (>=3.7.4)"]
|
||||
jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
|
||||
uvloop = ["uvloop (>=0.15.2)"]
|
||||
|
||||
[[package]]
|
||||
name = "caribou"
|
||||
version = "0.3"
|
||||
description = "python migrations for sqlite databases"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "caribou-0.3.0.tar.gz", hash = "sha256:5ca6e6e6ad7d3175137c68d809e203fbd931f79163a5613808a789449fef7863"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
argparse = ">=1.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2022.5.18.1"
|
||||
@ -194,7 +168,7 @@ pillow = ">=3.3.1"
|
||||
name = "dill"
|
||||
version = "0.3.6"
|
||||
description = "serialize all of python"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -351,7 +325,7 @@ files = [
|
||||
name = "isort"
|
||||
version = "5.10.1"
|
||||
description = "A Python utility / library to sort Python imports."
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6.1,<4.0"
|
||||
files = [
|
||||
@ -399,7 +373,7 @@ i18n = ["Babel (>=2.7)"]
|
||||
name = "lazy-object-proxy"
|
||||
version = "1.8.0"
|
||||
description = "A fast and thorough lazy object proxy."
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -493,7 +467,7 @@ files = [
|
||||
name = "mccabe"
|
||||
version = "0.7.0"
|
||||
description = "McCabe checker, plugin for flake8"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -630,7 +604,7 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa
|
||||
name = "platformdirs"
|
||||
version = "2.5.2"
|
||||
description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7"
|
||||
files = [
|
||||
@ -720,7 +694,7 @@ files = [
|
||||
name = "pylint"
|
||||
version = "2.15.5"
|
||||
description = "python code static checker"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.7.2"
|
||||
files = [
|
||||
@ -988,7 +962,7 @@ files = [
|
||||
name = "tomlkit"
|
||||
version = "0.11.6"
|
||||
description = "Style preserving TOML library"
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = ">=3.6"
|
||||
files = [
|
||||
@ -1106,7 +1080,7 @@ watchdog = ["watchdog"]
|
||||
name = "wrapt"
|
||||
version = "1.14.1"
|
||||
description = "Module for decorators, wrappers and monkey patching."
|
||||
category = "main"
|
||||
category = "dev"
|
||||
optional = false
|
||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7"
|
||||
files = [
|
||||
@ -1179,4 +1153,4 @@ files = [
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = ">=3.10,<3.12"
|
||||
content-hash = "83ce6d95a8e6bdefff93a3badca9e7b7b53174eaea85f908e9cea9a37afaec7c"
|
||||
content-hash = "6f6126fbaa8f114c90cef637e0bc996d63d3dc93f6ed2e90e36ef696cdd0cfc5"
|
||||
|
@ -20,7 +20,6 @@ hypothesis = "^6.56.3"
|
||||
pytest = "^7.1.3"
|
||||
Unidecode = "^1.3.6"
|
||||
pyinstaller = "^5.7.0"
|
||||
caribou = "^0.3.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
pylint = "^2.15.5"
|
||||
|
Loading…
x
Reference in New Issue
Block a user