From 9cfe9964c23b5e88215cbe567a9c5d33c8c349ee Mon Sep 17 00:00:00 2001 From: wakamex Date: Mon, 29 Jun 2026 16:57:44 -0400 Subject: [PATCH] Fix book duration to exclude disabled audio tracks Add Book.updateDuration() which sums the included (non-excluded) audio files, and call it from updateTracks before saving so disabling a track updates the stored duration. Fixes #5311 Co-Authored-By: Claude Opus 4.8 (1M context) --- server/controllers/LibraryItemController.js | 2 ++ server/models/Book.js | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/server/controllers/LibraryItemController.js b/server/controllers/LibraryItemController.js index 07b4ee67f..ddfe2fa34 100644 --- a/server/controllers/LibraryItemController.js +++ b/server/controllers/LibraryItemController.js @@ -507,6 +507,8 @@ class LibraryItemController { req.libraryItem.media.audioFiles = updatedAudioFiles req.libraryItem.media.changed('audioFiles', true) + // Recompute duration so disabled (excluded) tracks no longer count toward the total + req.libraryItem.media.updateDuration() await req.libraryItem.media.save() SocketAuthority.libraryItemEmitter('item_updated', req.libraryItem) diff --git a/server/models/Book.js b/server/models/Book.js index d9f2ff132..2e4d59bee 100644 --- a/server/models/Book.js +++ b/server/models/Book.js @@ -261,6 +261,19 @@ class Book extends Model { return this.audioFiles.filter((af) => !af.exclude) } + /** + * Recalculate the book duration from the included (non-excluded) audio files. + * Sets `this.duration` and returns whether it changed. + * + * @returns {boolean} + */ + updateDuration() { + const newDuration = this.includedAudioFiles.reduce((total, af) => total + (isNaN(af.duration) ? 0 : Number(af.duration)), 0) + if (this.duration === newDuration) return false + this.duration = newDuration + return true + } + get hasMediaFiles() { return !!this.hasAudioTracks || !!this.ebookFile }