move imgserver to app/api folder

+ add sqlite methods to configure custom root directories
+ add sqlite.settings module
+ remove date and app name from logger messages
+ add api route to browse directories
This commit is contained in:
geoffrey45 2023-01-21 18:07:20 +03:00
parent 3dc9bc1f15
commit 4e6e1f03dc
9 changed files with 179 additions and 31 deletions

View File

@ -5,8 +5,17 @@ This module combines all API blueprints into a single Flask app instance.
from flask import Flask from flask import Flask
from flask_cors import CORS from flask_cors import CORS
from app.api import album, artist, favorites, folder, playlist, search, track from app.api import (
from app.imgserver import imgbp as imgserver album,
artist,
favorites,
folder,
playlist,
search,
track,
settings,
imgserver,
)
def create_api(): def create_api():
@ -25,6 +34,7 @@ def create_api():
app.register_blueprint(folder.folderbp) app.register_blueprint(folder.folderbp)
app.register_blueprint(playlist.playlistbp) app.register_blueprint(playlist.playlistbp)
app.register_blueprint(favorites.favbp) app.register_blueprint(favorites.favbp)
app.register_blueprint(imgserver) app.register_blueprint(imgserver.imgbp)
app.register_blueprint(settings.settingsbp)
return app return app

View File

@ -1,11 +1,13 @@
""" """
Contains all the folder routes. Contains all the folder routes.
""" """
import os
from flask import Blueprint, request from flask import Blueprint, request
from app import settings from app import settings
from app.lib.folderslib import GetFilesAndDirs from app.lib.folderslib import GetFilesAndDirs
folderbp = Blueprint("folder", __name__, url_prefix="/") folderbp = Blueprint("folder", __name__, url_prefix="/")
@ -30,3 +32,28 @@ def get_folder_tree():
"tracks": tracks, "tracks": tracks,
"folders": sorted(folders, key=lambda i: i.name), "folders": sorted(folders, key=lambda i: i.name),
} }
@folderbp.route("/folder/dir-browser", methods=["POST"])
def list_folders():
"""
Returns a list of all the folders in the given folder.
"""
data = request.get_json()
try:
req_dir: str = data["folder"]
except KeyError:
req_dir = settings.HOME_DIR
if req_dir == "$home":
req_dir = settings.HOME_DIR
entries = os.scandir(req_dir)
dirs = [e.name for e in entries if e.is_dir() and not e.name.startswith(".")]
dirs = [{"name": d, "path": os.path.join(req_dir, d)} for d in dirs]
return {
"folders": sorted(dirs, key=lambda i: i["name"]),
}

View File

@ -1,7 +1,7 @@
import os import os
from pathlib import Path from pathlib import Path
from flask import Blueprint, request, send_from_directory from flask import Blueprint, send_from_directory
imgbp = Blueprint("imgserver", __name__, url_prefix="/img") imgbp = Blueprint("imgserver", __name__, url_prefix="/img")
SUPPORTED_IMAGES = (".jpg", ".png", ".webp", ".jpeg") SUPPORTED_IMAGES = (".jpg", ".png", ".webp", ".jpeg")

61
app/api/settings.py Normal file
View File

@ -0,0 +1,61 @@
from flask import Blueprint, request
from app.db.sqlite.settings import SettingsSQLMethods as sdb
settingsbp = Blueprint("settings", __name__, url_prefix="/")
@settingsbp.route("/settings/add-root-dirs", methods=["POST"])
def add_root_dirs():
"""
Add custom root directories to the database.
"""
msg = {"msg": "Failed! No directories were given."}
data = request.get_json()
if data is None:
return msg, 400
try:
new_dirs = data["new_dirs"]
removed_dirs = data["removed"]
except KeyError:
return msg, 400
sdb.add_root_dirs(new_dirs)
sdb.remove_root_dirs(removed_dirs)
return {"msg": "Added root directories to the database."}
@settingsbp.route("/settings/get-root-dirs", methods=["GET"])
def get_root_dirs():
"""
Get custom root directories from the database.
"""
dirs = sdb.get_root_dirs()
return {"dirs": dirs}
# CURRENTLY UNUSED ROUTE 👇
@settingsbp.route("/settings/remove-root-dirs", methods=["POST"])
def remove_root_dirs():
"""
Remove custom root directories from the database.
"""
msg = {"msg": "Failed! No directories were given."}
data = request.get_json()
if data is None:
return msg, 400
try:
dirs = data["dirs"]
except KeyError:
return msg, 400
sdb.remove_root_dirs(dirs)
return {"msg": "Removed root directories from the database."}

View File

@ -7,44 +7,81 @@ class SettingsSQLMethods:
Methods for interacting with the settings table. Methods for interacting with the settings table.
""" """
@staticmethod
def update_root_dirs(dirs: list[str]):
"""
Updates custom root directories in the database.
"""
sql = "UPDATE settings SET root_dirs = ?"
dirs_str = json.dumps(dirs)
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (dirs_str,))
@staticmethod @staticmethod
def get_root_dirs() -> list[str]: def get_root_dirs() -> list[str]:
""" """
Gets custom root directories from the database. Gets custom root directories from the database.
""" """
sql = "SELECT value FROM settings" sql = "SELECT root_dirs FROM settings"
with SQLiteManager(userdata_db=True) as cur: with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql) cur.execute(sql)
dirs = cur.fetchall()
data = cur.fetchone() return [dir[0] for dir in dirs]
if data is not None:
return json.loads(data[0])
return []
@staticmethod @staticmethod
def update_exclude_dirs(dirs: list[str]): def add_root_dirs(dirs: list[str]):
""" """
Updates excluded directories in the database. Add custom root directories to the database.
""" """
sql = "UPDATE settings SET exclude_dirs = ?" sql = "INSERT INTO settings (root_dirs) VALUES (?)"
dirs_str = json.dumps(dirs) existing_dirs = SettingsSQLMethods.get_root_dirs()
dirs = [dir for dir in dirs if dir not in existing_dirs]
if len(dirs) == 0:
return
with SQLiteManager(userdata_db=True) as cur: with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (dirs_str,)) for _dir in dirs:
cur.execute(sql, (_dir,))
@staticmethod
def remove_root_dirs(dirs: list[str]):
"""
Remove custom root directories from the database.
"""
sql = "DELETE FROM settings WHERE root_dirs = ?"
with SQLiteManager(userdata_db=True) as cur:
for _dir in dirs:
cur.execute(sql, (_dir,))
@staticmethod
def add_excluded_dirs(dirs: list[str]):
"""
Add custom exclude directories to the database.
"""
sql = "INSERT INTO settings (exclude_dirs) VALUES (?)"
with SQLiteManager(userdata_db=True) as cur:
cur.executemany(sql, dirs)
@staticmethod
def remove_excluded_dirs(dirs: list[str]):
"""
Remove custom exclude directories from the database.
"""
sql = "DELETE FROM settings WHERE exclude_dirs = ?"
with SQLiteManager(userdata_db=True) as cur:
cur.executemany(sql, dirs)
@staticmethod
def get_excluded_dirs() -> list[str]:
"""
Gets custom exclude directories from the database.
"""
sql = "SELECT exclude_dirs FROM settings"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql)
dirs = cur.fetchall()
return [dir[0] for dir in dirs]

View File

@ -61,6 +61,8 @@ class SQLiteTrackMethods:
), ),
) )
# TODO: rewrite the above code using an ordered dict and destructuring
@classmethod @classmethod
def insert_many_tracks(cls, tracks: list[dict]): def insert_many_tracks(cls, tracks: list[dict]):
""" """

View File

@ -3,6 +3,7 @@ from tqdm import tqdm
from app import settings from app import settings
from app.db.sqlite.tracks import SQLiteTrackMethods from app.db.sqlite.tracks import SQLiteTrackMethods
from app.db.sqlite.settings import SettingsSQLMethods as sdb
from app.db.store import Store from app.db.store import Store
from app.lib.taglib import extract_thumb, get_tags from app.lib.taglib import extract_thumb, get_tags
@ -27,7 +28,18 @@ class Populate:
tracks = get_all_tracks() tracks = get_all_tracks()
tracks = list(tracks) tracks = list(tracks)
files = run_fast_scandir(settings.HOME_DIR, full=True)[1] dirs_to_scan = sdb.get_root_dirs()
if len(dirs_to_scan) == 0:
log.error(
"The root directory is not set. No folders will be scanned for music files. Open the app in your web browser to configure."
)
return
files = []
for _dir in dirs_to_scan:
files.extend(run_fast_scandir(_dir, full=True)[1])
untagged = self.filter_untagged(tracks, files) untagged = self.filter_untagged(tracks, files)

View File

@ -18,7 +18,7 @@ class CustomFormatter(logging.Formatter):
# format = ( # format = (
# "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)" # "%(asctime)s - %(name)s - %(levelname)s - %(message)s (%(filename)s:%(lineno)d)"
# ) # )
format_ = "[%(asctime)s]@%(name)s%(message)s" format_ = "%(message)s"
FORMATS = { FORMATS = {
logging.DEBUG: grey + format_ + reset, logging.DEBUG: grey + format_ + reset,

View File

@ -186,6 +186,5 @@ if __name__ == "__main__":
use_reloader=False, use_reloader=False,
) )
# TODO: Find out how to print in color: red for errors, etc.
# TODO: Find a way to verify the host string # TODO: Find a way to verify the host string
# TODO: Organize code in this file: move args to new file, etc. # TODO: Organize code in this file: move args to new file, etc.