import path from 'path' import fs from 'fs' import Database from 'better-sqlite3' const CONFIG_PATH = process.env.CONFIG_PATH ?? process.cwd() const DB_PATH = path.resolve(CONFIG_PATH, 'medialore.db') let _db: Database.Database | null = null export function getDb(): Database.Database { if (_db) return _db _db = new Database(DB_PATH) _db.pragma('journal_mode = WAL') _db.pragma('foreign_keys = ON') initDb(_db) return _db } function initDb(db: Database.Database): void { db.exec(` CREATE TABLE IF NOT EXISTS tag_categories ( id TEXT PRIMARY KEY, name TEXT NOT NULL UNIQUE ); CREATE TABLE IF NOT EXISTS tags ( id TEXT PRIMARY KEY, name TEXT NOT NULL, category_id TEXT NOT NULL REFERENCES tag_categories(id) ON DELETE CASCADE ); CREATE UNIQUE INDEX IF NOT EXISTS tags_name_category ON tags(name, category_id); CREATE TABLE IF NOT EXISTS media_tags ( media_key TEXT NOT NULL, tag_id TEXT NOT NULL REFERENCES tags(id) ON DELETE CASCADE, PRIMARY KEY (media_key, tag_id) ); CREATE TABLE IF NOT EXISTS libraries ( id TEXT PRIMARY KEY, name TEXT NOT NULL, path TEXT NOT NULL, type TEXT NOT NULL CHECK(type IN ('games', 'mixed', 'movies', 'tv')), cover_ext TEXT NULL ); CREATE TABLE IF NOT EXISTS users ( id TEXT PRIMARY KEY, username TEXT NOT NULL UNIQUE, password_hash TEXT NOT NULL, role TEXT NOT NULL CHECK(role IN ('admin', 'user')), created_at INTEGER NOT NULL ); CREATE TABLE IF NOT EXISTS library_permissions ( user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, library_id TEXT NOT NULL REFERENCES libraries(id) ON DELETE CASCADE, PRIMARY KEY (user_id, library_id) ); CREATE TABLE IF NOT EXISTS user_settings ( user_id TEXT PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE, mixed_autoplay INTEGER NOT NULL DEFAULT 1, mixed_loop INTEGER NOT NULL DEFAULT 1, mixed_muted INTEGER NOT NULL DEFAULT 1, movies_autoplay INTEGER NOT NULL DEFAULT 1, movies_loop INTEGER NOT NULL DEFAULT 0, movies_muted INTEGER NOT NULL DEFAULT 0, tv_autoplay INTEGER NOT NULL DEFAULT 1, tv_loop INTEGER NOT NULL DEFAULT 0, tv_muted INTEGER NOT NULL DEFAULT 0 ); `) migrateLibrariesType(db) } function migrateLibrariesType(db: Database.Database): void { const row = db .prepare("SELECT sql FROM sqlite_master WHERE type='table' AND name='libraries'") .get() as { sql: string } | undefined if (row && !row.sql.includes("'movies'")) { db.exec(` BEGIN TRANSACTION; CREATE TABLE libraries_new ( id TEXT PRIMARY KEY, name TEXT NOT NULL, path TEXT NOT NULL, type TEXT NOT NULL CHECK(type IN ('games', 'mixed', 'movies', 'tv')), cover_ext TEXT NULL ); INSERT INTO libraries_new SELECT * FROM libraries; DROP TABLE libraries; ALTER TABLE libraries_new RENAME TO libraries; COMMIT; `) } }