document + rename stuff

This commit is contained in:
cwilvx
2024-07-07 16:07:27 +03:00
parent 32a2684ea2
commit 2ba5d6c1d7
11 changed files with 72 additions and 72 deletions
+1 -1
View File
@@ -56,8 +56,8 @@
then artist B is similar to A with the same weight, unless overwritten.
- Figure out how to update album/artist tables instead of deleting all rows when the app starts
- Move get all filtering and sorting operations to the database since all sort keys are table columns
- Replace the DbManager class with cls.execute()
- Paginate the following endpoints:
1. Folder tracks
2. Playlist tracks
+1 -4
View File
@@ -76,6 +76,7 @@ def create_api():
CORS(app, origins="*", supports_credentials=True)
# RESPONSE COMPRESSION
# Only compress JSON responses
Compress(app)
app.config["COMPRESS_MIMETYPES"] = [
"application/json",
@@ -84,10 +85,6 @@ def create_api():
# JWT
jwt = JWTManager(app)
# @jwt.user_identity_loader
# def user_identity_lookup(user):
# return user
@jwt.user_lookup_loader
def user_lookup_callback(_jwt_header, jwt_data):
identity = jwt_data["sub"]
+20 -12
View File
@@ -9,14 +9,12 @@ from sqlalchemy import (
from sqlalchemy.engine import Engine
from sqlalchemy import event
from sqlalchemy.orm import (
DeclarativeBase,
MappedAsDataclass,
Session
)
from sqlalchemy.orm import DeclarativeBase, MappedAsDataclass, Session
from app.db.engine import DbEngine
# Enable foreign key constraints for SQLite
@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
cursor = dbapi_connection.cursor()
@@ -25,9 +23,12 @@ def set_sqlite_pragma(dbapi_connection, connection_record):
class DbManager:
""" """
def __init__(self, commit: bool = False):
self.commit = commit
self.conn = DbEngine.engine.connect()
with Session(DbEngine.engine) as session:
session.connection
@@ -42,9 +43,15 @@ class DbManager:
class Base(MappedAsDataclass, DeclarativeBase):
"""
Base class for all database models.
It has methods common to all tables. eg. `insert_one`, `insert_many`, `remove_all`, `remove_one`, `all`, `count`.
"""
@classmethod
def execute(cls, stmt: Any, commit: bool = False):
with DbManager(commit=commit) as conn:
with DbEngine.manager(commit=commit) as conn:
return conn.execute(stmt)
@classmethod
@@ -52,8 +59,7 @@ class Base(MappedAsDataclass, DeclarativeBase):
"""
Inserts multiple items into the database.
"""
with DbManager(commit=True) as conn:
return conn.execute(insert(cls).values(items))
return cls.execute(insert(cls).values(items), commit=True)
@classmethod
def insert_one(cls, item: dict[str, Any]):
@@ -64,12 +70,11 @@ class Base(MappedAsDataclass, DeclarativeBase):
@classmethod
def remove_all(cls):
with DbManager(commit=True) as conn:
conn.execute(delete(cls))
return cls.execute(delete(cls), commit=True)
@classmethod
def remove_one(cls, id: int):
cls.execute(delete(cls).where(cls.id == id), commit=True)
return cls.execute(delete(cls).where(cls.id == id), commit=True)
@classmethod
def all(cls):
@@ -80,5 +85,8 @@ class Base(MappedAsDataclass, DeclarativeBase):
return cls.execute(select(func.count()).select_from(cls)).scalar()
def create_all():
def create_all_tables():
"""
Creates all the tables that build on the Base class.
"""
Base().metadata.create_all(DbEngine.engine)
+26 -1
View File
@@ -1,5 +1,30 @@
from contextlib import contextmanager
from sqlalchemy import Engine
class DbEngine:
engine: Engine = None
"""
The database engine instance.
"""
engine: Engine
@classmethod
@contextmanager
def manager(cls, commit: bool):
"""
This context manager manages access to the database.
When the context manager is entered, it returns a connection object that can be used to execute SQL statements.
If the `commit` parameter is set to `True`, the context manager will commit the transaction when it exits.
"""
try:
conn = cls.engine.connect()
yield conn.execution_options(preserve_rowcount=True)
if commit:
conn.commit()
finally:
conn.close()
+4 -1
View File
@@ -23,6 +23,9 @@ from typing import Any, Iterable, Optional
def create_all():
"""
Create all the tables defined in this file.
NOTE: We need this function because the MasterBase does not collect
the tables defined here (as they are grand-children of the MasterBase)
"""
Base.metadata.create_all(DbEngine.engine)
@@ -317,7 +320,7 @@ class AlbumTable(Base):
# NOTE: The artist dict keys need to in the same order they appear in the db for this to work!
select(AlbumTable).where(AlbumTable.artisthashes.contains(artist))
)
albums[artist] = (albums_to_dataclasses(result.fetchall()))
albums[artist] = albums_to_dataclasses(result.fetchall())
return albums
+2 -2
View File
@@ -90,10 +90,10 @@ class SQLiteManager:
if self.test_db_path:
db_path = self.test_db_path
else:
db_path = settings.Db.get_app_db_path()
db_path = settings.DbPaths.get_app_db_path()
if self.userdata_db:
db_path = settings.Db.get_userdata_db_path()
db_path = settings.DbPaths.get_userdata_db_path()
self.conn = sqlite3.connect(
db_path,
+1 -9
View File
@@ -2,17 +2,11 @@
Contains methods relating to albums.
"""
from dataclasses import asdict
from typing import Any
from itertools import groupby
from app.models.track import Track
from app.store.albums import AlbumStore
from app.store.tracks import TrackStore
def remove_duplicate_on_merge_versions(tracks: list[Track]) -> list[Track]:
def remove_duplicate_on_merge_versions(tracks: list[Track]):
"""
Removes duplicate tracks when merging versions of the same album.
"""
@@ -21,8 +15,6 @@ def remove_duplicate_on_merge_versions(tracks: list[Track]) -> list[Track]:
def sort_by_track_no(tracks: list[Track]):
# tracks = [asdict(t) for t in tracks]
for t in tracks:
track = str(t.track).zfill(3)
t._pos = int(f"{t.disc}{track}")
-31
View File
@@ -145,34 +145,3 @@ class CheckArtistImages:
if url is not None:
return DownloadImage(url, name=f"{artist['artisthash']}.webp")
# def fetch_album_bio(title: str, albumartist: str) -> str | None: """ Returns the album bio for a given album. """
# last_fm_url = "http://ws.audioscrobbler.com/2.0/?method=album.getinfo&api_key={}&artist={}&album={
# }&format=json".format( settings.Paths.LAST_FM_API_KEY, albumartist, title )
# try:
# response = requests.get(last_fm_url)
# data = response.json()
# except:
# return None
# try:
# bio = data["album"]["wiki"]["summary"].split('<a href="https://www.last.fm/')[0]
# except KeyError:
# bio = None
# return bio
# class FetchAlbumBio:
# """
# Returns the album bio for a given album.
# """
# def __init__(self, title: str, albumartist: str):
# self.title = title
# self.albumartist = albumartist
# def __call__(self):
# return fetch_album_bio(self.title, self.albumartist)
+1 -1
View File
@@ -141,7 +141,7 @@ SUPPORTED_FILES = tuple(f".{file}" for file in FILES)
# ===== SQLite =====
class Db:
class DbPaths:
APP_DB_NAME = "swing.db"
USER_DATA_DB_NAME = "userdata.db"
+6 -8
View File
@@ -5,14 +5,12 @@ Applies migrations.
from sqlalchemy import create_engine
from app.db.userdata import UserTable
from app.db.sqlite.auth import SQLiteAuthMethods as authdb
from app.migrations import apply_migrations
from app.settings import Db
from app.db import create_all
from app.db.libdata import create_all as create_all_libdata
from app.settings import DbPaths
from app.db.engine import DbEngine
from app.db import create_all_tables
from app.db.libdata import create_all as create_user_tables
def run_migrations():
@@ -27,14 +25,14 @@ def setup_sqlite():
Create Sqlite databases and tables.
"""
DbEngine.engine = create_engine(
f"sqlite+pysqlite:///{Db.get_app_db_path()}",
f"sqlite+pysqlite:///{DbPaths.get_app_db_path()}",
echo=False,
max_overflow=20,
pool_size=10,
)
create_all()
create_all_libdata()
create_all_tables()
create_user_tables()
if not UserTable.get_all():
UserTable.insert_default_user()
+10 -2
View File
@@ -23,7 +23,6 @@ from app.api import create_api
from app.arg_handler import ProcessArgs
from app.lib.tagger import IndexEverything
from app.lib.watchdogg import Watcher as WatchDog
from app.periodic_scan import run_periodic_scans
from app.plugins.register import register_plugins
from app.settings import FLASKVARS, TCOLOR, Info
from app.setup import load_into_mem, run_setup
@@ -32,8 +31,15 @@ from app.utils.filesystem import get_home_res_path
from app.utils.paths import getClientFilesExtensions
from app.utils.threading import background
mimetypes.add_type("text/css", ".css")
# Load mimetypes for the web client's static files
# Loading mimetypes should happen automatically but
# sometimes the mimetypes are not loaded correctly
# eg. when the Registry is messed up on Windows.
# See the following issues:
# https://github.com/swingmx/swingmusic/issues/137
mimetypes.add_type("text/css", ".css")
mimetypes.add_type("text/javascript", ".js")
mimetypes.add_type("text/plain", ".txt")
mimetypes.add_type("text/html", ".html")
@@ -166,6 +172,8 @@ def serve_client_files(path: str):
gzipped_path = path + ".gz"
user_agent = request.headers.get("User-Agent")
# INFO: Safari doesn't support gzip encoding
# See issue: https://github.com/swingmx/swingmusic/issues/155
is_safari = user_agent.find("Safari") >= 0 and user_agent.find("Chrome") < 0
if is_safari: