comic library improvements
This commit is contained in:
@@ -552,6 +552,36 @@ async function scanComics(library: Library, libraryRoot: string): Promise<void>
|
||||
const db = getDb()
|
||||
const now = Date.now()
|
||||
|
||||
// Save ComicInfo metadata for issues that were already imported so we can
|
||||
// restore it after the clear+upsert without re-reading any CBZ files.
|
||||
type SavedInfo = { title: string | null; year: number | null; genres: string | null; comicFields: Record<string, unknown> }
|
||||
const savedComicInfo = new Map<string, SavedInfo>()
|
||||
{
|
||||
const rows = db
|
||||
.prepare(
|
||||
`SELECT item_key, title, year, genres, metadata FROM media_items
|
||||
WHERE library_id = ? AND item_type = 'comic_issue'
|
||||
AND (year IS NOT NULL OR genres IS NOT NULL)`
|
||||
)
|
||||
.all(library.id) as { item_key: string; title: string | null; year: number | null; genres: string | null; metadata: string | null }[]
|
||||
for (const row of rows) {
|
||||
const meta: Record<string, unknown> = row.metadata ? (JSON.parse(row.metadata) as Record<string, unknown>) : {}
|
||||
savedComicInfo.set(row.item_key, {
|
||||
title: row.title,
|
||||
year: row.year,
|
||||
genres: row.genres,
|
||||
comicFields: {
|
||||
writer: meta.writer,
|
||||
publisher: meta.publisher,
|
||||
translator: meta.translator,
|
||||
web: meta.web,
|
||||
month: meta.month,
|
||||
day: meta.day,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
clearLibraryItems(db, library.id)
|
||||
|
||||
const upsertSeries = db.prepare(`
|
||||
@@ -648,6 +678,18 @@ async function scanComics(library: Library, libraryRoot: string): Promise<void>
|
||||
}
|
||||
}
|
||||
|
||||
// Build a map of item_key → fresh scan metadata (needed for ComicInfo restore below).
|
||||
const freshMetaMap = new Map<string, Record<string, unknown>>()
|
||||
for (const entry of allRecords) {
|
||||
if (entry.type === 'issue') {
|
||||
const rec = entry.rec as { item_key: unknown; metadata: unknown }
|
||||
freshMetaMap.set(
|
||||
String(rec.item_key),
|
||||
JSON.parse(String(rec.metadata)) as Record<string, unknown>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Insert in batches of 500, yielding the event loop between batches so the app
|
||||
// remains responsive to HTTP requests during a large scan.
|
||||
const BATCH_SIZE = 500
|
||||
@@ -662,6 +704,23 @@ async function scanComics(library: Library, libraryRoot: string): Promise<void>
|
||||
await new Promise<void>((r) => setImmediate(r))
|
||||
}
|
||||
|
||||
// Restore previously-imported ComicInfo data for issues that still exist on disk.
|
||||
// Merges scan-derived fields (pageCount, coverUrl) with the saved ComicInfo fields
|
||||
// so neither set of data is lost. Title from ComicInfo is also preserved.
|
||||
if (savedComicInfo.size > 0) {
|
||||
const restoreStmt = db.prepare(
|
||||
'UPDATE media_items SET title = @title, year = @year, genres = @genres, metadata = @metadata WHERE item_key = @item_key'
|
||||
)
|
||||
db.transaction(() => {
|
||||
for (const [item_key, saved] of savedComicInfo) {
|
||||
const freshMeta = freshMetaMap.get(item_key)
|
||||
if (!freshMeta) continue // file was removed from disk
|
||||
const merged = { ...freshMeta, ...saved.comicFields }
|
||||
restoreStmt.run({ item_key, title: saved.title, year: saved.year, genres: saved.genres, metadata: JSON.stringify(merged) })
|
||||
}
|
||||
})()
|
||||
}
|
||||
|
||||
// Prewarm CBZ cover thumbnails — fire-and-forget so they don't block scan completion.
|
||||
for (const item of items) {
|
||||
const issuesToWarm: ComicIssue[] = 'issues' in item
|
||||
|
||||
Reference in New Issue
Block a user