feat(api,web): support CBZ — scan, métadonnées, lecteur d'albums
- api: cbz utilitaire commun, scanner/métadonnées (+ tests), books, schéma et migrations - web: CbzReader, ReaderPage/locators (+ tests), types et client API - shared: types formats Refs: #16
This commit is contained in:
@ -59,7 +59,7 @@ export class DatabaseService implements OnModuleDestroy {
|
||||
language TEXT,
|
||||
publisher TEXT,
|
||||
published_date TEXT,
|
||||
format TEXT NOT NULL CHECK (format IN ('epub','pdf')),
|
||||
format TEXT NOT NULL CHECK (format IN ('epub','pdf','cbz')),
|
||||
file_path TEXT NOT NULL UNIQUE,
|
||||
cover_path TEXT,
|
||||
file_size INTEGER NOT NULL,
|
||||
@ -119,6 +119,78 @@ export class DatabaseService implements OnModuleDestroy {
|
||||
VALUES (new.id, new.title, new.author, new.description, new.isbn);
|
||||
END;
|
||||
`);
|
||||
this.ensureBooksSupportsCbz();
|
||||
this.sqlite.exec("INSERT INTO book_fts(book_fts) VALUES('rebuild')");
|
||||
}
|
||||
|
||||
private ensureBooksSupportsCbz(): void {
|
||||
const table = this.sqlite
|
||||
.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'books'")
|
||||
.get() as { sql?: string } | undefined;
|
||||
if (!table?.sql || table.sql.includes("'cbz'")) return;
|
||||
|
||||
this.sqlite.exec(`
|
||||
PRAGMA foreign_keys = OFF;
|
||||
PRAGMA legacy_alter_table = ON;
|
||||
|
||||
DROP TRIGGER IF EXISTS books_ai;
|
||||
DROP TRIGGER IF EXISTS books_ad;
|
||||
DROP TRIGGER IF EXISTS books_au;
|
||||
|
||||
BEGIN;
|
||||
ALTER TABLE books RENAME TO books_legacy_format;
|
||||
CREATE TABLE books (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
library_id INTEGER NOT NULL REFERENCES libraries(id) ON DELETE CASCADE,
|
||||
title TEXT NOT NULL,
|
||||
author TEXT,
|
||||
description TEXT,
|
||||
isbn TEXT,
|
||||
language TEXT,
|
||||
publisher TEXT,
|
||||
published_date TEXT,
|
||||
format TEXT NOT NULL CHECK (format IN ('epub','pdf','cbz')),
|
||||
file_path TEXT NOT NULL UNIQUE,
|
||||
cover_path TEXT,
|
||||
file_size INTEGER NOT NULL,
|
||||
file_mtime TEXT NOT NULL,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
INSERT INTO books (
|
||||
id, library_id, title, author, description, isbn, language, publisher, published_date,
|
||||
format, file_path, cover_path, file_size, file_mtime, created_at, updated_at
|
||||
)
|
||||
SELECT
|
||||
id, library_id, title, author, description, isbn, language, publisher, published_date,
|
||||
format, file_path, cover_path, file_size, file_mtime, created_at, updated_at
|
||||
FROM books_legacy_format;
|
||||
DROP TABLE books_legacy_format;
|
||||
COMMIT;
|
||||
|
||||
PRAGMA legacy_alter_table = OFF;
|
||||
PRAGMA foreign_keys = ON;
|
||||
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS books_file_path_unique ON books(file_path);
|
||||
CREATE INDEX IF NOT EXISTS books_library_idx ON books(library_id);
|
||||
CREATE INDEX IF NOT EXISTS books_title_idx ON books(title);
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS books_ai AFTER INSERT ON books BEGIN
|
||||
INSERT INTO book_fts(rowid, title, author, description, isbn)
|
||||
VALUES (new.id, new.title, new.author, new.description, new.isbn);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS books_ad AFTER DELETE ON books BEGIN
|
||||
INSERT INTO book_fts(book_fts, rowid, title, author, description, isbn)
|
||||
VALUES('delete', old.id, old.title, old.author, old.description, old.isbn);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER IF NOT EXISTS books_au AFTER UPDATE ON books BEGIN
|
||||
INSERT INTO book_fts(book_fts, rowid, title, author, description, isbn)
|
||||
VALUES('delete', old.id, old.title, old.author, old.description, old.isbn);
|
||||
INSERT INTO book_fts(rowid, title, author, description, isbn)
|
||||
VALUES (new.id, new.title, new.author, new.description, new.isbn);
|
||||
END;
|
||||
`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user