Régression worker PDF : le worker pdf.js est désormais instancié une seule fois via un port dédié (?worker&url) et reconfiguré à chaque montage, au lieu d'un workerSrc recalculé qui cassait le rendu. - ReaderShell : chrome commun aux lecteurs (toolbar, zones de tap, statut) et contrat ReaderControls pour EPUB/PDF/CBZ - préférences de lecture par livre (mode horizontal/vertical, fit) : table reader_preferences + migrations idempotentes, module API, DTO partagés, client web avec fallback localStorage hors-ligne Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
48 lines
1.7 KiB
TypeScript
48 lines
1.7 KiB
TypeScript
import { Injectable, NotFoundException } from "@nestjs/common";
|
|
import { eq, sql } from "drizzle-orm";
|
|
import { UpdateReaderPreferencesDto } from "@readabook/shared";
|
|
import { DatabaseService } from "../database/database.service.js";
|
|
import { books, readerPreferences } from "../database/schema.js";
|
|
|
|
@Injectable()
|
|
export class ReaderPreferencesService {
|
|
constructor(private readonly database: DatabaseService) {}
|
|
|
|
find(userId: number, bookId: number) {
|
|
const row = this.database.db
|
|
.select({
|
|
mode: readerPreferences.mode,
|
|
fit: readerPreferences.fit,
|
|
updatedAt: readerPreferences.updatedAt
|
|
})
|
|
.from(readerPreferences)
|
|
.where(sql`${readerPreferences.userId} = ${userId} AND ${readerPreferences.bookId} = ${bookId}`)
|
|
.get();
|
|
return row ?? { mode: "paged", fit: null };
|
|
}
|
|
|
|
upsert(userId: number, bookId: number, input: UpdateReaderPreferencesDto) {
|
|
const book = this.database.db.select({ id: books.id }).from(books).where(eq(books.id, bookId)).get();
|
|
if (!book) throw new NotFoundException("Book not found");
|
|
|
|
const current = this.find(userId, bookId);
|
|
const now = this.database.now();
|
|
const mode = input.mode ?? current.mode;
|
|
const fit = input.fit === undefined ? current.fit : input.fit;
|
|
|
|
this.database.sqlite
|
|
.prepare(
|
|
`
|
|
INSERT INTO reader_preferences(user_id, book_id, mode, fit, created_at, updated_at)
|
|
VALUES (?, ?, ?, ?, ?, ?)
|
|
ON CONFLICT(user_id, book_id) DO UPDATE SET
|
|
mode = excluded.mode,
|
|
fit = excluded.fit,
|
|
updated_at = excluded.updated_at
|
|
`
|
|
)
|
|
.run(userId, bookId, mode, fit, now, now);
|
|
return this.find(userId, bookId);
|
|
}
|
|
}
|