diff --git a/server/models/BookAuthor.js b/server/models/BookAuthor.js index f2cbf60f0..d7d65728e 100644 --- a/server/models/BookAuthor.js +++ b/server/models/BookAuthor.js @@ -1,4 +1,4 @@ -const { DataTypes, Model, fn, col } = require('sequelize') +const { DataTypes, Model } = require('sequelize') class BookAuthor extends Model { constructor(values, options) { @@ -37,32 +37,6 @@ class BookAuthor extends Model { }) } - /** - * Get number of books for each author - * - * @param {string[]} authorIds - * @returns {Promise>} - */ - static async getCountsForAuthors(authorIds) { - if (!authorIds.length) return {} - - const rows = await this.findAll({ - attributes: ['authorId', [fn('COUNT', col('id')), 'count']], - where: { - authorId: authorIds - }, - group: ['authorId'], - raw: true - }) - - /** @type {Record} */ - const counts = {} - for (const row of rows) { - counts[row.authorId] = Number(row.count) - } - return counts - } - /** * Initialize model * @param {import('../Database').sequelize} sequelize diff --git a/server/scanner/BookScanner.js b/server/scanner/BookScanner.js index 2b106cdc8..8ae616fe8 100644 --- a/server/scanner/BookScanner.js +++ b/server/scanner/BookScanner.js @@ -228,7 +228,6 @@ class BookScanner { bookId: media.id, authorId: existingAuthorId }) - libraryScan.authorsNumBooksChangedIds.add(existingAuthorId) libraryScan.addLog(LogLevel.DEBUG, `Updating book "${bookMetadata.title}" added author "${authorName}"`) authorsUpdated = true } else { @@ -239,7 +238,6 @@ class BookScanner { }) await media.addAuthor(newAuthor) Database.addAuthorToFilterData(libraryItemData.libraryId, newAuthor.name, newAuthor.id) - SocketAuthority.emitter('author_added', newAuthor.toOldJSON()) libraryScan.addLog(LogLevel.DEBUG, `Updating book "${bookMetadata.title}" added new author "${authorName}"`) authorsUpdated = true } @@ -249,7 +247,6 @@ class BookScanner { for (const author of media.authors) { if (!bookMetadata.authors.includes(author.name)) { await author.bookAuthor.destroy() - libraryScan.authorsNumBooksChangedIds.add(author.id) libraryScan.addLog(LogLevel.DEBUG, `Updating book "${bookMetadata.title}" removed author "${author.name}"`) authorsUpdated = true bookAuthorsRemoved.push(author.id) @@ -481,7 +478,6 @@ class BookScanner { } const createdAtTimestamp = new Date().getTime() - const newAuthorNames = new Set() if (bookMetadata.authors.length) { for (const authorName of bookMetadata.authors) { const matchingAuthorId = await Database.getAuthorIdByName(libraryItemData.libraryId, authorName) @@ -489,8 +485,6 @@ class BookScanner { bookObject.bookAuthors.push({ authorId: matchingAuthorId }) - // Existing author — only numBooks changes; batch emit at scan end - libraryScan.authorsNumBooksChangedIds.add(matchingAuthorId) } else { // New author bookObject.bookAuthors.push({ @@ -502,7 +496,6 @@ class BookScanner { lastFirst: Database.authorModel.getLastFirst(authorName) } }) - newAuthorNames.add(authorName) } } } @@ -600,9 +593,6 @@ class BookScanner { for (const ba of libraryItem.book.bookAuthors) { if (ba.author) { Database.addAuthorToFilterData(libraryItemData.libraryId, ba.author.name, ba.author.id) - if (newAuthorNames.has(ba.author.name)) { - SocketAuthority.emitter('author_added', ba.author.toOldJSON()) - } } } } @@ -901,34 +891,6 @@ class BookScanner { }) } - /** - * Emit authors_num_books_updated for authors whose book count changed during a scan (linked or unlinked). - * Authors with no book links are omitted — orphans are handled by author_removed. - * @param {string} libraryId - * @param {import('./LibraryScan')|import('./ScanLogger')} scanLogger - * @returns {Promise} - */ - async emitAuthorsNumBooksUpdated(libraryId, scanLogger) { - if (!scanLogger.authorsNumBooksChangedIds?.size) return - - const authorIds = [...scanLogger.authorsNumBooksChangedIds] - scanLogger.authorsNumBooksChangedIds.clear() - - const countsByAuthorId = await Database.bookAuthorModel.getCountsForAuthors(authorIds) - - const authors = Object.entries(countsByAuthorId).map(([id, numBooks]) => ({ - id, - numBooks - })) - - if (!authors.length) return - - SocketAuthority.emitter('authors_num_books_updated', { - libraryId, - authors - }) - } - /** * Check authors that were removed from a book and remove them if they no longer have any books * keep authors without books that have a asin, description or imagePath diff --git a/server/scanner/LibraryItemScanner.js b/server/scanner/LibraryItemScanner.js index de95c9a09..501df4274 100644 --- a/server/scanner/LibraryItemScanner.js +++ b/server/scanner/LibraryItemScanner.js @@ -66,7 +66,7 @@ class LibraryItemScanner { if (libraryItemDataUpdated || wasUpdated) { SocketAuthority.libraryItemEmitter('item_updated', expandedLibraryItem) - await this.finalizeAuthorsAndSeriesFromScan(library.id, scanLogger) + await this.checkAuthorsAndSeriesRemovedFromBooks(library.id, scanLogger) return ScanResult.UPDATED } @@ -76,13 +76,12 @@ class LibraryItemScanner { } /** - * Emit author book count updates, then remove empty authors/series left after the scan + * Remove empty authors and series * @param {string} libraryId * @param {ScanLogger} scanLogger * @returns {Promise} */ - async finalizeAuthorsAndSeriesFromScan(libraryId, scanLogger) { - await BookScanner.emitAuthorsNumBooksUpdated(libraryId, scanLogger) + async checkAuthorsAndSeriesRemovedFromBooks(libraryId, scanLogger) { if (scanLogger.authorsRemovedFromBooks.length) { await BookScanner.checkAuthorsRemovedFromBooks(libraryId, scanLogger) } @@ -216,10 +215,7 @@ class LibraryItemScanner { scanLogger.verbose = true scanLogger.setData('libraryItem', libraryItemScanData.relPath) - const newLibraryItem = await this.scanNewLibraryItem(libraryItemScanData, library.settings, scanLogger) - // Watcher path does not go through full-library scan cleanup — emit author book count updates here - await BookScanner.emitAuthorsNumBooksUpdated(library.id, scanLogger) - return newLibraryItem + return this.scanNewLibraryItem(libraryItemScanData, library.settings, scanLogger) } } module.exports = new LibraryItemScanner() diff --git a/server/scanner/LibraryScan.js b/server/scanner/LibraryScan.js index 0366addba..e77f30ba6 100644 --- a/server/scanner/LibraryScan.js +++ b/server/scanner/LibraryScan.js @@ -24,8 +24,6 @@ class LibraryScan { /** @type {string[]} */ this.authorsRemovedFromBooks = [] - /** @type {Set} */ - this.authorsNumBooksChangedIds = new Set() /** @type {string[]} */ this.seriesRemovedFromBooks = [] diff --git a/server/scanner/LibraryScanner.js b/server/scanner/LibraryScanner.js index 73cb51553..640c82d76 100644 --- a/server/scanner/LibraryScanner.js +++ b/server/scanner/LibraryScanner.js @@ -234,7 +234,8 @@ class LibraryScanner { SocketAuthority.libraryItemsEmitter('items_updated', libraryItemsUpdated) } - if (this.shouldCancelScan(libraryScan)) return true + // Authors and series that were removed from books should be removed if they are now empty + await LibraryItemScanner.checkAuthorsAndSeriesRemovedFromBooks(libraryScan.libraryId, libraryScan) // Update missing library items if (libraryItemIdsMissing.length) { @@ -280,9 +281,6 @@ class LibraryScanner { } } - // Author book count updates and empty authors/series cleanup after all items are processed - await LibraryItemScanner.finalizeAuthorsAndSeriesFromScan(libraryScan.libraryId, libraryScan) - libraryScan.addLog(LogLevel.INFO, `Scan completed. ${libraryScan.resultStats}`) return false } diff --git a/server/scanner/ScanLogger.js b/server/scanner/ScanLogger.js index 2748f1f3b..7aed21f13 100644 --- a/server/scanner/ScanLogger.js +++ b/server/scanner/ScanLogger.js @@ -14,8 +14,6 @@ class ScanLogger { /** @type {string[]} */ this.authorsRemovedFromBooks = [] - /** @type {Set} */ - this.authorsNumBooksChangedIds = new Set() /** @type {string[]} */ this.seriesRemovedFromBooks = []