feat(library): add MOBI file metadata writing and Kindle library settings

Add server support for writing metadata, covers, and EXTH records directly into MOBI/AZW format files. Introduce migration 0057 to persist Kindle file write preferences per library, and update the library creation UI and locale catalogs.
This commit is contained in:
neon
2026-07-28 05:48:15 +00:00
parent e4e20f89e3
commit f7716bdbdb
46 changed files with 18103 additions and 9 deletions
+4 -1
View File
@@ -5,8 +5,11 @@ import type { ComicMetadataFields } from "./metadata-fetch";
import type { BookFileWriteField, WriteResult } from "./file-write";
import type { CustomMetadataBookValue } from "./custom-metadata";
import type { CoverAspectRatio } from "./library";
import { DEFAULT_FORMAT_PRIORITY } from "./library";
export const BOOK_FORMATS = ["epub", "pdf", "mobi", "azw3", "cbz", "cbr", "cb7", "fb2", "m4b", "mp3", "m4a", "opus", "ogg", "flac"] as const;
// Derived rather than duplicated: these two lists describe the same set of formats,
// and maintaining them separately let BOOK_FORMATS fall behind on azw and kepub.
export const BOOK_FORMATS = DEFAULT_FORMAT_PRIORITY;
export type BookFormat = (typeof BOOK_FORMATS)[number];
const AUDIO_FORMATS = new Set<string>(["m4b", "mp3", "m4a", "opus", "ogg", "flac"]);
+20
View File
@@ -121,6 +121,23 @@ export const CBX_BOOK_FILE_WRITE_FIELDS = [
...COMIC_BOOK_FILE_WRITE_FIELDS,
] as const satisfies readonly BookFileWriteField[];
// MOBI EXTH records are keyed by number and have no extensible string-keyed
// namespace, so fields without a standard EXTH slot (series, rating, page count,
// subtitle, provider IDs, comic fields, narrators) cannot be represented at all.
export const MOBI_BOOK_FILE_WRITE_FIELDS = [
"title",
"description",
"publisher",
"publishedDate",
"language",
"isbn10",
"isbn13",
"authors",
"genres",
"tags",
"coverBytes",
] as const satisfies readonly BookFileWriteField[];
export const AUDIO_BOOK_FILE_WRITE_FIELDS = [
"title",
"subtitle",
@@ -144,6 +161,9 @@ export const BOOK_FILE_WRITE_FORMAT_FIELDS = {
pdf: PDF_BOOK_FILE_WRITE_FIELDS,
cbz: CBX_BOOK_FILE_WRITE_FIELDS,
cb7: CBX_BOOK_FILE_WRITE_FIELDS,
mobi: MOBI_BOOK_FILE_WRITE_FIELDS,
azw3: MOBI_BOOK_FILE_WRITE_FIELDS,
azw: MOBI_BOOK_FILE_WRITE_FIELDS,
m4b: AUDIO_BOOK_FILE_WRITE_FIELDS,
m4a: AUDIO_BOOK_FILE_WRITE_FIELDS,
mp3: AUDIO_BOOK_FILE_WRITE_FIELDS,
+2
View File
@@ -74,6 +74,8 @@ export interface Library {
fileWritePdfMaxFileSizeMb: number;
fileWriteCbxEnabled: boolean;
fileWriteCbxMaxFileSizeMb: number;
fileWriteKindleEnabled: boolean;
fileWriteKindleMaxFileSizeMb: number;
fileWriteAudioEnabled: boolean;
fileWriteAudioMaxFileSizeMb: number;
fileRenameEnabled: boolean;