From 04e1edb77c187ca6c5f6c699c5eb28e15c7f8104 Mon Sep 17 00:00:00 2001 From: David C Date: Sat, 1 Aug 2026 15:24:57 -0700 Subject: [PATCH 1/4] Use precise timing extraction for opus, ogg, and mp3 during import --- Shared/Services/AudioMetadataService.swift | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Shared/Services/AudioMetadataService.swift b/Shared/Services/AudioMetadataService.swift index 8cc30c6c4..f500bcd0e 100644 --- a/Shared/Services/AudioMetadataService.swift +++ b/Shared/Services/AudioMetadataService.swift @@ -93,7 +93,9 @@ public class AudioMetadataService: BPLogger, AudioMetadataServiceProtocol { public init() {} public func extractMetadata(from fileURL: URL) async -> AudioMetadata? { - let asset = AVURLAsset(url: fileURL) + let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) + let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil + let asset = AVURLAsset(url: fileURL, options: options) return await extractMetadata(from: asset) } @@ -232,7 +234,9 @@ public class AudioMetadataService: BPLogger, AudioMetadataServiceProtocol { } public func extractManualChapters(from fileURL: URL) async -> [ChapterMetadata]? { - let asset = AVURLAsset(url: fileURL) + let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) + let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil + let asset = AVURLAsset(url: fileURL, options: options) do { let metadata = try await asset.load(.metadata) let duration = CMTimeGetSeconds(try await asset.load(.duration)) From 4419e6808bee918ab1a20cffb5ee0386c5d9aff4 Mon Sep 17 00:00:00 2001 From: David C Date: Sat, 1 Aug 2026 15:25:13 -0700 Subject: [PATCH 2/4] Use precise timing extraction for opus, ogg, and mp3 during sync chapters load --- Shared/Services/LibraryService+Sync.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Shared/Services/LibraryService+Sync.swift b/Shared/Services/LibraryService+Sync.swift index 7e03fa99d..654159785 100644 --- a/Shared/Services/LibraryService+Sync.swift +++ b/Shared/Services/LibraryService+Sync.swift @@ -424,6 +424,10 @@ extension LibraryService: LibrarySyncProtocol { public func loadChaptersIfNeeded(relativePath: String) async { let fileURL = DataManager.getProcessedFolderURL().appendingPathComponent(relativePath) - await loadChaptersIfNeeded(relativePath: relativePath, asset: AVAsset(url: fileURL)) + let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) + let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil + let asset = AVURLAsset(url: fileURL, options: options) + + await loadChaptersIfNeeded(relativePath: relativePath, asset: asset) } } From 33538a2aac24e3d2df7577c039114fce66e8802d Mon Sep 17 00:00:00 2001 From: David C Date: Sat, 1 Aug 2026 15:25:27 -0700 Subject: [PATCH 3/4] Use precise timing extraction for opus, ogg, and mp3 during sync download verification --- Shared/Services/Sync/SyncService.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Shared/Services/Sync/SyncService.swift b/Shared/Services/Sync/SyncService.swift index 5622c8a38..bb80b5e81 100644 --- a/Shared/Services/Sync/SyncService.swift +++ b/Shared/Services/Sync/SyncService.swift @@ -816,7 +816,9 @@ extension SyncService { let actualDuration: Double do { - let asset = AVURLAsset(url: fileURL) + let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) + let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil + let asset = AVURLAsset(url: fileURL, options: options) actualDuration = CMTimeGetSeconds(try await asset.load(.duration)) } catch { /// We have a trustworthy synced duration, so this is a format we can play — From fdaecc35fbb06b2ce53f4c06c7751f0d12036e3a Mon Sep 17 00:00:00 2001 From: David C Date: Sat, 1 Aug 2026 15:32:09 -0700 Subject: [PATCH 4/4] Add concise code comments explaining precise duration necessity for MP3 and Ogg --- Shared/Services/AudioMetadataService.swift | 4 ++++ Shared/Services/LibraryService+Sync.swift | 2 ++ Shared/Services/Sync/SyncService.swift | 2 ++ 3 files changed, 8 insertions(+) diff --git a/Shared/Services/AudioMetadataService.swift b/Shared/Services/AudioMetadataService.swift index f500bcd0e..5178eb682 100644 --- a/Shared/Services/AudioMetadataService.swift +++ b/Shared/Services/AudioMetadataService.swift @@ -93,6 +93,8 @@ public class AudioMetadataService: BPLogger, AudioMetadataServiceProtocol { public init() {} public func extractMetadata(from fileURL: URL) async -> AudioMetadata? { + // MP3 and Ogg lack global duration headers. We request precise timing to prevent + // inaccurate duration estimates for VBR files by forcing a full stream scan. let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil let asset = AVURLAsset(url: fileURL, options: options) @@ -234,6 +236,8 @@ public class AudioMetadataService: BPLogger, AudioMetadataServiceProtocol { } public func extractManualChapters(from fileURL: URL) async -> [ChapterMetadata]? { + // MP3 and Ogg lack global duration headers. We request precise timing to prevent + // inaccurate duration estimates for VBR files by forcing a full stream scan. let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil let asset = AVURLAsset(url: fileURL, options: options) diff --git a/Shared/Services/LibraryService+Sync.swift b/Shared/Services/LibraryService+Sync.swift index 654159785..a119b9d5c 100644 --- a/Shared/Services/LibraryService+Sync.swift +++ b/Shared/Services/LibraryService+Sync.swift @@ -424,6 +424,8 @@ extension LibraryService: LibrarySyncProtocol { public func loadChaptersIfNeeded(relativePath: String) async { let fileURL = DataManager.getProcessedFolderURL().appendingPathComponent(relativePath) + // MP3 and Ogg lack global duration headers. We request precise timing to prevent + // inaccurate duration estimates for VBR files by forcing a full stream scan. let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil let asset = AVURLAsset(url: fileURL, options: options) diff --git a/Shared/Services/Sync/SyncService.swift b/Shared/Services/Sync/SyncService.swift index bb80b5e81..375dbd15b 100644 --- a/Shared/Services/Sync/SyncService.swift +++ b/Shared/Services/Sync/SyncService.swift @@ -816,6 +816,8 @@ extension SyncService { let actualDuration: Double do { + // MP3 and Ogg lack global duration headers. We request precise timing to prevent + // inaccurate duration estimates for VBR files by forcing a full stream scan. let requiresPreciseDuration = ["opus", "ogg", "mp3"].contains(fileURL.pathExtension.lowercased()) let options: [String: Any]? = requiresPreciseDuration ? [AVURLAssetPreferPreciseDurationAndTimingKey: true] : nil let asset = AVURLAsset(url: fileURL, options: options)