@@ -12,9 +12,11 @@ import Foundation
1212
1313final class ChaptersViewModel : ChaptersView . Model {
1414 private let playerManager : PlayerManagerProtocol
15+ private let libraryService : LibraryServiceProtocol
1516
16- init ( playerManager: PlayerManagerProtocol ) {
17+ init ( playerManager: PlayerManagerProtocol , libraryService : LibraryServiceProtocol ) {
1718 self . playerManager = playerManager
19+ self . libraryService = libraryService
1820 super. init (
1921 chapters: playerManager. currentItem? . chapters ?? [ ] ,
2022 currentChapter: playerManager. currentItem? . currentChapter
@@ -24,4 +26,48 @@ final class ChaptersViewModel: ChaptersView.Model {
2426 override func handleChapterSelected( _ chapter: PlayableChapter ) {
2527 self . playerManager. jumpToChapter ( chapter)
2628 }
29+
30+ /// Re-parsing only applies to single-file books; bound books and folders derive their
31+ /// chapters from constituent files, so there's no embedded chapter track to re-read.
32+ override var canReloadChapters : Bool {
33+ playerManager. currentItem? . isBoundBook == false
34+ }
35+
36+ @MainActor
37+ override func reloadChapters( ) async {
38+ guard let currentItem = playerManager. currentItem, currentItem. isBoundBook == false else {
39+ return
40+ }
41+
42+ let relativePath = currentItem. relativePath
43+ let fileURL = DataManager . getProcessedFolderURL ( ) . appendingPathComponent ( relativePath)
44+ guard FileManager . default. fileExists ( atPath: fileURL. path) else {
45+ // The file must be downloaded first, through the usual library download flow.
46+ currentAlert = Self . infoAlert ( message: " reparse_chapters_download_description " . localized)
47+ return
48+ }
49+
50+ isReloadingChapters = true
51+ defer { isReloadingChapters = false }
52+
53+ guard let newCount = await libraryService. reloadChapters ( relativePath: relativePath) else {
54+ currentAlert = Self . infoAlert ( message: " reparse_chapters_none_description " . localized)
55+ return
56+ }
57+
58+ // Rebuild the player's item so the new chapters take effect everywhere (scrubber, now
59+ // playing, end-of-chapter sleep timer), then refresh this screen's list from it.
60+ playerManager. reloadCurrentItem ( )
61+ chapters = playerManager. currentItem? . chapters ?? [ ]
62+ currentChapter = playerManager. currentItem? . currentChapter
63+
64+ currentAlert = Self . infoAlert (
65+ title: " reparse_chapters_found_title " . localized,
66+ message: String . localizedStringWithFormat ( " reparse_chapters_found_description " . localized, newCount)
67+ )
68+ }
69+
70+ private static func infoAlert( title: String ? = nil , message: String ) -> BPAlertContent {
71+ BPAlertContent ( title: title, message: message, style: . alert, actionItems: [ . okAction] )
72+ }
2773}
0 commit comments