remove deprecated db mappings

+ fix: cli password reset
+ delete old migrations
This commit is contained in:
cwilvx
2024-08-04 10:19:11 +03:00
parent 04946831ce
commit c77d0927c7
31 changed files with 40 additions and 2111 deletions
-18
View File
@@ -1,21 +1,3 @@
"""
This module contains the functions to interact with the SQLite database.
"""
import sqlite3
from sqlite3 import Connection as SqlConn
def create_connection(db_file: str) -> SqlConn:
"""
Creates a connection to the specified database.
"""
conn = sqlite3.connect(db_file)
return conn
def create_tables(conn: SqlConn, sql_query: str):
"""
Executes the specifiend SQL file to create database tables.
"""
conn.executescript(sql_query)
-66
View File
@@ -1,66 +0,0 @@
from sqlite3 import Cursor
from .utils import SQLiteManager, tuples_to_albums
class SQLiteAlbumMethods:
@classmethod
def insert_one_album(cls, cur: Cursor, albumhash: str, colors: str):
"""
Inserts one album into the database
"""
sql = """INSERT OR REPLACE INTO albums(
albumhash,
colors
) VALUES(?,?)
"""
cur.execute(sql, (albumhash, colors))
lastrowid = cur.lastrowid
return lastrowid
@classmethod
def get_all_albums(cls):
with SQLiteManager() as cur:
cur.execute("SELECT * FROM albums")
albums = cur.fetchall()
cur.close()
if albums is not None:
return albums
return []
@staticmethod
def get_albums_by_albumartist(albumartist: str):
with SQLiteManager() as cur:
cur.execute("SELECT * FROM albums WHERE albumartist=?", (albumartist,))
albums = cur.fetchall()
cur.close()
if albums is not None:
return tuples_to_albums(albums)
return []
@staticmethod
def exists(albumhash: str, cur: Cursor = None):
"""
Checks if an album exists in the database.
"""
sql = "SELECT COUNT(1) FROM albums WHERE albumhash = ?"
def _exists(cur: Cursor):
cur.execute(sql, (albumhash,))
count = cur.fetchone()[0]
return count != 0
if cur:
return _exists(cur)
with SQLiteManager() as cur:
return _exists(cur)
-64
View File
@@ -1,64 +0,0 @@
"""
Contains methods for reading and writing to the sqlite artists database.
"""
import json
from sqlite3 import Cursor
from .utils import SQLiteManager
class SQLiteArtistMethods:
@staticmethod
def insert_one_artist(cur: Cursor, artisthash: str, colors: list[str]):
"""
Inserts a single artist into the database.
"""
sql = """INSERT OR REPLACE INTO artists(
artisthash,
colors
) VALUES(?,?)
"""
colors = json.dumps(colors)
cur.execute(sql, (artisthash, colors))
@staticmethod
def get_all_artists(cur_: Cursor = None):
"""
Get all artists from the database and return a generator of Artist objects
"""
sql = """SELECT * FROM artists"""
if not cur_:
with SQLiteManager() as cur:
cur.execute(sql)
for artist in cur.fetchall():
yield artist
cur.close()
else:
cur_.execute(sql)
for artist in cur_.fetchall():
yield artist
@staticmethod
def exists(artisthash: str, cur: Cursor = None):
"""
Checks if an artist exists in the database.
"""
sql = "SELECT COUNT(1) FROM artists WHERE artisthash = ?"
def _exists(cur: Cursor):
cur.execute(sql, (artisthash,))
count = cur.fetchone()[0]
return count != 0
if cur:
return _exists(cur)
with SQLiteManager() as cur:
return _exists(cur)
-144
View File
@@ -1,144 +0,0 @@
import json
from app.models.user import User
from app.utils.auth import hash_password
from app.db.sqlite.utils import SQLiteManager
class SQLiteAuthMethods:
"""
Methods for authenticating users.
"""
@staticmethod
def insert_user(user: dict[str, str]):
"""
Insert a user into the database.
:param user: A dict with the username, password and roles.
"""
sql = """INSERT INTO users(
username,
password,
roles
) VALUES(:username, :password, :roles)
"""
user_tuple = tuple(user.values())
with SQLiteManager(userdata_db=True) as cur:
cur = cur.execute(sql, user_tuple)
userid = cur.lastrowid
return userid
# if userid:
# # sleep
# user = SQLiteAuthMethods.get_user_by_id(userid).todict_simplified()
# cur.close()
# return user
raise Exception(f"Failed to insert user: {user}")
@staticmethod
def insert_default_user():
"""
Inserts the default admin user.
"""
user = {
"username": "admin",
"password": hash_password("admin"),
"roles": json.dumps(["admin"]),
}
return SQLiteAuthMethods.insert_user(user)
@staticmethod
def insert_guest_user():
"""
Inserts the default guest user.
"""
user = {
"username": "guest",
"password": hash_password("guest"),
"roles": json.dumps(["guest"]),
}
return SQLiteAuthMethods.insert_user(user)
@staticmethod
def update_user(user: dict[str, str]):
"""
Update a user in the database.
:param user: A dict with the user id and the fields to update. Ommited fields will not be updated.
"""
# get all user dict keys
keys = list(user.keys())
sql = f"""UPDATE users SET
{', '.join([f"{key} = :{key}" for key in keys if key != 'id'])}
WHERE id = :id
"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, user)
cur.close()
return SQLiteAuthMethods.get_user_by_id(user["id"]).todict()
@staticmethod
def get_all_users():
"""
Check if there are any users in the database.
"""
sql = "SELECT * FROM users"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql)
data = cur.fetchall()
cur.close()
return [User(*user) for user in data]
@staticmethod
def get_user_by_username(username: str):
"""
Get a user by username.
"""
sql = "SELECT * FROM users WHERE username = ?"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (username,))
data = cur.fetchone()
cur.close()
if data is not None:
return User(*data)
return None
@staticmethod
def get_user_by_id(userid: int):
"""
Get a user by id.
"""
sql = "SELECT * FROM users WHERE id = ?"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (userid,))
data = cur.fetchone()
cur.close()
if data is not None:
return User(*data)
return None
@staticmethod
def delete_user_by_username(username: str):
"""
Delete a user by username.
"""
sql = "DELETE FROM users WHERE id = ?"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (3,))
cur.close()
-121
View File
@@ -1,121 +0,0 @@
from datetime import datetime
from flask_jwt_extended import current_user
from app.models import FavType
from .utils import SQLiteManager
class SQLiteFavoriteMethods:
"""THis class contains methods for interacting with the favorites table."""
@classmethod
def check_is_favorite(cls, itemhash: str, fav_type: str):
"""
Checks if an item is favorited.
"""
userid = current_user["id"]
sql = """SELECT * FROM favorites WHERE hash = ? AND type = ? AND userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (itemhash, fav_type, userid))
item = cur.fetchone()
cur.close()
return item is not None
@classmethod
def insert_one_favorite(cls, fav_type: str, fav_hash: str):
"""
Inserts a single favorite into the database.
"""
# try to find the favorite in the database, if it exists, don't insert it
if cls.check_is_favorite(fav_hash, fav_type):
return
sql = """INSERT INTO favorites(type, hash, timestamp, userid) VALUES(?,?,?,?)"""
current_timestamp = int(datetime.now().timestamp())
with SQLiteManager(userdata_db=True) as cur:
userid = current_user["id"]
cur.execute(sql, (fav_type, fav_hash, current_timestamp, userid))
cur.close()
@classmethod
def get_all(cls) -> list[tuple]:
"""
Returns a list of all favorites.
"""
sql = """SELECT * FROM favorites WHERE userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
userid = current_user["id"]
cur.execute(sql, (userid,))
favs = cur.fetchall()
cur.close()
return [fav for fav in favs if fav[1] != ""]
@classmethod
def get_favorites(cls, fav_type: str, userid: int = None) -> list[tuple]:
"""
Returns a list of favorite tracks.
If userid is None, all favorites are returned.
"""
sql = """SELECT * FROM favorites WHERE type = ?"""
params = (fav_type,)
if not userid:
sql += " AND userid = ?"
params = (fav_type, userid)
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, params)
all_favs = cur.fetchall()
cur.close()
return all_favs
@classmethod
def get_fav_tracks(cls, userid: int = None) -> list[tuple]:
"""
Returns a list of favorite tracks.
"""
return cls.get_favorites(FavType.track, userid)
@classmethod
def get_fav_albums(cls) -> list[tuple]:
"""
Returns a list of favorite albums.
"""
userid = current_user["id"]
return cls.get_favorites(FavType.album, userid)
@classmethod
def get_fav_artists(cls) -> list[tuple]:
"""
Returns a list of favorite artists.
"""
userid = current_user["id"]
return cls.get_favorites(FavType.artist, userid)
@classmethod
def delete_favorite(cls, fav_type: str, fav_hash: str):
"""
Deletes a favorite from the database.
"""
sql = """DELETE FROM favorites WHERE hash = ? AND type = ? AND userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
userid = current_user["id"]
cur.execute(sql, (fav_hash, fav_type, userid))
cur.close()
@classmethod
def get_track_count(cls) -> int:
"""
Returns the number of favorite tracks.
"""
sql = """SELECT COUNT(*) FROM favorites WHERE type = ? AND userid = ?"""
with SQLiteManager(userdata_db=True) as cur:
userid = current_user["id"]
cur.execute(sql, (FavType.track, userid))
count = cur.fetchone()[0]
cur.close()
return count
View File
-62
View File
@@ -1,62 +0,0 @@
from app.models.lastfm import SimilarArtist
from ..utils import SQLiteManager
class SQLiteLastFMSimilarArtists:
"""
This class contains methods for interacting with the lastfm_similar_artists table.
"""
@classmethod
def insert_one(cls, artist: SimilarArtist):
"""
Inserts a single artist into the database.
"""
sql = """INSERT OR REPLACE INTO lastfm_similar_artists(artisthash, similar_artists) VALUES(?,?)"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (artist.artisthash, artist.similar_artists))
cur.close()
@classmethod
def get_similar_artists_for(cls, artisthash: str):
"""
Returns a list of similar artists.
"""
sql = """SELECT * FROM lastfm_similar_artists WHERE artisthash = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (artisthash,))
similar_artists = cur.fetchone()
cur.close()
if similar_artists is None:
return None
return SimilarArtist(artisthash, similar_artists[2])
@classmethod
def get_all(cls):
"""
Returns a list of all similar artists.
"""
sql = """SELECT * FROM lastfm_similar_artists"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql)
similar_artists = cur.fetchall()
cur.close()
for a in similar_artists:
yield SimilarArtist(a[1], a[2])
@classmethod
def exists(cls, artisthash: str):
"""
Checks if an artist exists in the database by counting the number of rows
"""
sql = """SELECT COUNT(*) FROM lastfm_similar_artists WHERE artisthash = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (artisthash,))
count = cur.fetchone()[0]
cur.close()
return count > 0
-59
View File
@@ -1,59 +0,0 @@
from flask_jwt_extended import current_user
from app.db.sqlite.utils import SQLiteManager
from app.models.logger import TrackLog as TrackLog
from app.utils.auth import get_current_userid
class SQLiteTrackLogger:
@classmethod
def insert_track(cls, trackhash: str, duration: int, source: str, timestamp: int):
"""
Inserts a track play record into the database
"""
userid = get_current_userid()
with SQLiteManager(userdata_db=True) as cur:
sql = """INSERT OR REPLACE INTO track_logger(
trackhash,
duration,
timestamp,
source,
userid
) VALUES(?,?,?,?,?)
"""
cur.execute(
sql, (trackhash, duration, timestamp, source, userid)
)
lastrowid = cur.lastrowid
return lastrowid
@classmethod
def get_all(cls):
"""
Returns all track play records from the database
"""
with SQLiteManager(userdata_db=True) as cur:
userid = get_current_userid()
sql = f"""SELECT * FROM track_logger WHERE userid = {userid} ORDER BY timestamp DESC"""
cur.execute(sql)
rows = cur.fetchall()
return rows
@classmethod
def get_recently_played(cls, start: int = 0, limit: int = 100):
"""
Returns a list of recently played tracks
"""
with SQLiteManager(userdata_db=True) as cur:
sql = f"""SELECT * FROM track_logger WHERE userid = {current_user['id']} ORDER BY timestamp DESC LIMIT ?,?"""
cur.execute(sql, (start, limit))
rows = cur.fetchall()
return [TrackLog(*row) for row in rows]
-228
View File
@@ -1,228 +0,0 @@
import json
from collections import OrderedDict
from flask_jwt_extended import current_user
from app.db.sqlite.utils import SQLiteManager, tuple_to_playlist, tuples_to_playlists
from app.utils.dates import create_new_date
class SQLitePlaylistMethods:
"""
This class contains methods for interacting with the playlists table.
"""
@staticmethod
def update_last_updated(playlist_id: int):
"""Updates the last updated date of a playlist."""
sql = """UPDATE playlists SET last_updated = ? WHERE id = ?"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (create_new_date(), playlist_id))
@staticmethod
def insert_one_playlist(playlist: dict):
# banner_pos,
# has_gif,
sql = """INSERT INTO playlists(
image,
last_updated,
name,
settings,
trackhashes,
userid
) VALUES(:image, :last_updated, :name, :settings, :trackhashes, :userid)
"""
playlist["userid"] = current_user["id"]
playlist = OrderedDict(sorted(playlist.items()))
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, playlist)
pid = cur.lastrowid
cur.close()
p_tuple = (pid, *playlist.values())
return tuple_to_playlist(p_tuple)
@staticmethod
def count_playlist_by_name(name: str):
sql = f"SELECT COUNT(*) FROM playlists WHERE name = ? and userid = {current_user['id']}"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (name,))
data = cur.fetchone()
cur.close()
return int(data[0])
@staticmethod
def get_all_playlists():
with SQLiteManager(userdata_db=True) as cur:
userid = 1
try:
userid = current_user["id"]
except RuntimeError:
# Catch this error raised during migration execution
pass
cur.execute(f"SELECT * FROM playlists WHERE userid = {userid}")
playlists = cur.fetchall()
cur.close()
if playlists is not None:
return tuples_to_playlists(playlists)
return []
@staticmethod
def get_playlist_by_id(playlist_id: int):
sql = f"SELECT * FROM playlists WHERE id = ? and userid = {current_user['id']}"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (playlist_id,))
data = cur.fetchone()
cur.close()
if data is not None:
return tuple_to_playlist(data)
return None
# FIXME: Extract the "add_track_to_playlist" method to use it for both the artisthash and trackhash lists.
@classmethod
def add_item_to_json_list(cls, playlist_id: int, field: str, items: set[str]):
"""
Adds a string item to a json dumped list using a playlist id and field name.
Takes the playlist ID, a field name, an item to add to the field.
"""
userid = 1
try:
userid = current_user["id"]
except RuntimeError:
# Catch this error raised during migration execution
pass
sql = f"SELECT {field} FROM playlists WHERE id = ? and userid = {userid}"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (playlist_id,))
data = cur.fetchone()
if data is not None:
db_items: list[str] = json.loads(data[0])
# Remove duplicates, without changing the order.
for item in items:
if item in db_items:
items.remove(item)
db_items.extend(items)
sql = f"UPDATE playlists SET {field} = ? WHERE id = ?"
cur.execute(sql, (json.dumps(db_items), playlist_id))
return len(items)
cls.update_last_updated(playlist_id)
@classmethod
def add_tracks_to_playlist(cls, playlist_id: int, trackhashes: list[str]):
"""
Adds trackhashes to a playlist
"""
return cls.add_item_to_json_list(playlist_id, "trackhashes", trackhashes)
@classmethod
def update_playlist(cls, playlist_id: int, playlist: dict):
sql = f"""UPDATE playlists SET
image = ?,
last_updated = ?,
name = ?,
settings = ?
WHERE id = ? and userid = {current_user['id']}
"""
del playlist["id"]
del playlist["trackhashes"]
playlist["settings"] = json.dumps(playlist["settings"])
playlist = OrderedDict(sorted(playlist.items()))
params = (*playlist.values(), playlist_id)
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, params)
cls.update_last_updated(playlist_id)
@classmethod
def update_settings(cls, playlist_id: int, settings: dict):
sql = f"""UPDATE playlists SET settings = ? WHERE id = ? and userid = {current_user['id']}"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (json.dumps(settings), playlist_id))
cls.update_last_updated(playlist_id)
@staticmethod
def delete_playlist(pid: str):
sql = f"DELETE FROM playlists WHERE id = ? and userid = {current_user['id']}"
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (pid,))
@staticmethod
def remove_banner(playlistid: int):
sql = f"""UPDATE playlists SET image = NULL WHERE id = ? and userid = {current_user['id']}"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(sql, (playlistid,))
@classmethod
def remove_tracks_from_playlist(cls, playlistid: int, tracks: list[dict[str, int]]):
"""
Removes tracks from a playlist by trackhash and position.
"""
sql = """UPDATE playlists SET trackhashes = ? WHERE id = ?"""
userid = 1
try:
userid = current_user["id"]
except RuntimeError:
# Catch this error raised during migration execution
pass
with SQLiteManager(userdata_db=True) as cur:
cur.execute(
f"SELECT trackhashes FROM playlists WHERE id = ? and userid = {userid}",
(playlistid,),
)
data = cur.fetchone()
if data is None:
return
trackhashes: list[str] = json.loads(data[0])
to_remove = []
for track in tracks:
# {
# trackhash: str;
# index: int;
# }
index = trackhashes.index(track["trackhash"])
if index == track["index"]:
to_remove.append(track["trackhash"])
for trackhash in to_remove:
trackhashes.remove(trackhash)
cur.execute(sql, (json.dumps(trackhashes), playlistid))
cls.update_last_updated(playlistid)
-83
View File
@@ -1,83 +0,0 @@
import json
from app.models.plugins import Plugin
from ..utils import SQLiteManager
def plugin_tuple_to_obj(plugin_tuple: tuple) -> Plugin:
return Plugin(
name=plugin_tuple[1],
active=bool(plugin_tuple[3]),
settings=json.loads(plugin_tuple[4]),
)
class PluginsMethods:
@classmethod
def insert_plugin(cls, plugin: Plugin):
"""
Inserts one plugin into the database
"""
sql = """INSERT OR IGNORE INTO plugins(
name,
description,
active,
settings
) VALUES(?,?,?,?)
"""
with SQLiteManager(userdata_db=True) as cur:
cur.execute(
sql,
(
plugin.name,
plugin.description,
int(plugin.active),
json.dumps(plugin.settings),
),
)
lastrowid = cur.lastrowid
return lastrowid
@classmethod
def get_all_plugins(cls):
with SQLiteManager(userdata_db=True) as cur:
cur.execute("SELECT * FROM plugins")
plugins = cur.fetchall()
cur.close()
if plugins is not None:
return [plugin_tuple_to_obj(plugin) for plugin in plugins]
return []
@classmethod
def plugin_set_active(cls, name: str, active: int):
with SQLiteManager(userdata_db=True) as cur:
cur.execute("UPDATE plugins SET active=? WHERE name=?", (active, name))
cur.close()
@classmethod
def update_plugin_settings(cls, plugin_name: str, settings: dict):
with SQLiteManager(userdata_db=True) as cur:
cur.execute(
"UPDATE plugins SET settings=? WHERE name=?",
(json.dumps(settings), plugin_name),
)
cur.close()
@classmethod
def get_plugin_by_name(cls, name: str):
with SQLiteManager(userdata_db=True) as cur:
cur.execute("SELECT * FROM plugins WHERE name=?", (name,))
plugin = cur.fetchone()
cur.close()
if plugin is not None:
return plugin_tuple_to_obj(plugin)
return None
-123
View File
@@ -1,123 +0,0 @@
"""
This file contains the SQL queries to create the database tables.
"""
CREATE_USERDATA_TABLES = """
CREATE TABLE IF NOT EXISTS playlists (
id integer PRIMARY KEY,
image text,
last_updated text not null,
name text not null,
settings text,
trackhashes text,
userid integer not null,
constraint fk_users foreign key (userid) references users(id) on delete cascade
);
CREATE TABLE IF NOT EXISTS settings (
id integer PRIMARY KEY,
root_dirs text NOT NULL,
exclude_dirs text,
artist_separators text NOT NULL default '/,;',
extract_feat integer NOT NULL DEFAULT 1,
remove_prod integer NOT NULL DEFAULT 1,
clean_album_title integer NOT NULL DEFAULT 1,
remove_remaster integer NOT NULL DEFAULT 1,
merge_albums integer NOT NULL DEFAULT 0,
show_albums_as_singles integer NOT NULL DEFAULT 0
);
CREATE TABLE IF NOT EXISTS lastfm_similar_artists (
id integer PRIMARY KEY,
artisthash text NOT NULL,
similar_artists text NOT NULL,
UNIQUE (artisthash)
);
CREATE TABLE IF NOT EXISTS plugins (
id integer PRIMARY KEY,
name text NOT NULL UNIQUE,
description text NOT NULL,
active integer NOT NULL DEFAULT 0,
settings text
);
CREATE TABLE IF NOT EXISTS track_logger (
id integer PRIMARY KEY,
trackhash text NOT NULL,
duration integer NOT NULL,
timestamp integer NOT NULL,
source text,
userid integer NOT NULL DEFAULT 1,
constraint fk_users foreign key (userid) references users(id) on delete cascade
);
CREATE TABLE IF NOT EXISTS users (
id integer PRIMARY KEY,
username text NOT NULL UNIQUE,
firstname text,
lastname text,
password text NOT NULL,
email text,
image text,
roles text NOT NULL DEFAULT '["user"]'
)
"""
CREATE_APPDB_TABLES = """
CREATE TABLE IF NOT EXISTS tracks (
id integer PRIMARY KEY,
album text NOT NULL,
albumartist text NOT NULL,
albumhash text NOT NULL,
artist text NOT NULL,
bitrate integer NOT NULL,
copyright text,
date integer NOT NULL,
disc integer NOT NULL,
duration integer NOT NULL,
filepath text NOT NULL,
folder text NOT NULL,
genre text,
title text NOT NULL,
track integer NOT NULL,
trackhash text NOT NULL,
last_mod float NOT NULL,
UNIQUE (filepath)
);
CREATE TABLE IF NOT EXISTS albums (
id integer PRIMARY KEY,
albumhash text NOT NULL,
colors text NOT NULL,
UNIQUE (albumhash)
);
CREATE TABLE IF NOT EXISTS artists (
id integer PRIMARY KEY,
artisthash text NOT NULL,
colors text,
bio text,
UNIQUE (artisthash)
);
CREATE TABLE IF NOT EXISTS folders (
id integer PRIMARY KEY,
path text NOT NULL,
trackcount integer NOT NULL
);
"""
# changed from migrations to dbmigrations in v1.3.0
# to avoid conflicts with the previous migrations.
CREATE_MIGRATIONS_TABLE = """
CREATE TABLE IF NOT EXISTS dbmigrations (
id integer PRIMARY KEY,
version integer NOT NULL DEFAULT 0
);
INSERT INTO dbmigrations (version)
SELECT -1
WHERE NOT EXISTS (SELECT 1 FROM dbmigrations);
"""
-151
View File
@@ -1,151 +0,0 @@
from pprint import pprint
from typing import Any
from app.config import UserConfig
from app.db.sqlite.utils import SQLiteManager
from app.utils.wintools import win_replace_slash
# class SettingsSQLMethods:
# """
# Methods for interacting with the settings table.
# """
# @staticmethod
# def get_all_settings():
# """
# Gets all settings from the database.
# """
# sql = "SELECT * FROM settings WHERE id = 1"
# with SQLiteManager(userdata_db=True) as cur:
# cur.execute(sql)
# settings = cur.fetchone()
# cur.close()
# # if root_dirs not set
# if settings is None:
# return []
# # omit id, root_dirs, and exclude_dirs
# return settings[3:]
# @staticmethod
# def get_root_dirs() -> list[str]:
# """
# Gets custom root directories from the database.
# """
# sql = "SELECT root_dirs FROM settings"
# with SQLiteManager(userdata_db=True) as cur:
# cur.execute(sql)
# dirs = cur.fetchall()
# cur.close()
# dirs = [_dir[0] for _dir in dirs]
# return [win_replace_slash(d) for d in dirs]
# @staticmethod
# def add_root_dirs(dirs: list[str]):
# """
# Add custom root directories to the database.
# """
# sql = "INSERT INTO settings (root_dirs) VALUES (?)"
# 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:
# 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,))
# # Not currently used anywhere, to be used later
# @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]
# @staticmethod
# def get_settings() -> dict[str, Any]:
# pass
# @staticmethod
# def set_setting(key: str, value: Any):
# sql = f"UPDATE settings SET {key} = :value WHERE id = 1"
# if type(value) == bool:
# value = str(int(value))
# with SQLiteManager(userdata_db=True) as cur:
# cur.execute(sql, {"value": value})
# def load_settings():
# # s = SettingsSQLMethods.get_all_settings()
# config = UserConfig()
# try:
# db_separators: str = s[0]
# db_separators = db_separators.replace(" ", "")
# separators = db_separators.split(",")
# separators = set(separators)
# except IndexError:
# separators = {";", "/"}
# SessionVars.ARTIST_SEPARATORS = config.artistSeparators
# # boolean settings
# SessionVars.EXTRACT_FEAT = bool(s[1])
# SessionVars.REMOVE_PROD = bool(s[2])
# SessionVars.CLEAN_ALBUM_TITLE = bool(s[3])
# SessionVars.REMOVE_REMASTER_FROM_TRACK = bool(s[4])
# SessionVars.MERGE_ALBUM_VERSIONS = bool(s[5])
# SessionVars.SHOW_ALBUMS_AS_SINGLES = bool(s[6])
-135
View File
@@ -1,135 +0,0 @@
"""
Contains the SQLiteTrackMethods class which contains methods for
interacting with the tracks table.
"""
from collections import OrderedDict
from sqlite3 import Cursor
from app.db.sqlite.utils import tuple_to_track, tuples_to_tracks
from .utils import SQLiteManager
from app.utils.unicode import handle_unicode
class SQLiteTrackMethods:
"""
This class contains all methods for interacting with the tracks table.
"""
@classmethod
def insert_one_track(cls, track: dict, cur: Cursor):
"""
Inserts a single track into the database.
"""
sql = """INSERT OR REPLACE INTO tracks(
album,
albumartist,
albumhash,
artist,
bitrate,
copyright,
date,
disc,
duration,
filepath,
folder,
genre,
last_mod,
title,
track,
trackhash
) VALUES(:album, :albumartist, :albumhash, :artist, :bitrate, :copyright,
:date, :disc, :duration, :filepath, :folder, :genre, :last_mod, :title, :track, :trackhash)
"""
track = OrderedDict(sorted(track.items()))
track["artist"] = track["artists"]
track["albumartist"] = track["albumartists"]
del track["artists"]
del track["albumartists"]
try:
cur.execute(sql, track)
except UnicodeEncodeError:
# for each of the values in the track, call handle_unicode on it
for key, value in track.items():
track[key] = handle_unicode(value)
cur.execute(sql, track)
@classmethod
def insert_many_tracks(cls, tracks: list[dict]):
"""
Inserts a list of tracks into the database.
"""
with SQLiteManager() as cur:
for track in tracks:
cls.insert_one_track(track, cur)
@staticmethod
def get_all_tracks():
"""
Get all tracks from the database and return a generator of Track objects
or an empty list.
"""
with SQLiteManager() as cur:
cur.execute("SELECT * FROM tracks")
rows = cur.fetchall()
if rows is not None:
return tuples_to_tracks(rows)
return []
@staticmethod
def get_track_by_trackhash(trackhash: str):
"""
Gets a track using its trackhash. Returns a Track object or None.
"""
with SQLiteManager() as cur:
cur.execute("SELECT * FROM tracks WHERE trackhash=?", (trackhash,))
row = cur.fetchone()
if row is not None:
return tuple_to_track(row)
return None
@staticmethod
def get_track_by_albumhash(albumhash: str):
"""
Gets a track using its albumhash. Returns a Track object or None.
"""
with SQLiteManager() as cur:
cur.execute("SELECT * FROM tracks WHERE albumhash=?", (albumhash,))
row = cur.fetchone()
if row is not None:
return tuple_to_track(row)
return None
@staticmethod
def remove_tracks_by_filepaths(filepaths: str | set[str]):
"""
Removes a track or tracks from the database using their filepaths.
"""
if isinstance(filepaths, str):
filepaths = {filepaths}
with SQLiteManager() as cur:
for filepath in filepaths:
cur.execute("DELETE FROM tracks WHERE filepath=?", (filepath,))
@staticmethod
def remove_tracks_not_in_folders(folders: set[str]):
sql = "DELETE FROM tracks WHERE folder NOT IN ({})".format(
",".join("?" * len(folders))
)
with SQLiteManager() as cur:
cur.execute(sql, tuple(folders))