diff --git a/ios/App/App/plugins/AbsAudioPlayer.swift b/ios/App/App/plugins/AbsAudioPlayer.swift index 2b4197fc..44b3b374 100644 --- a/ios/App/App/plugins/AbsAudioPlayer.swift +++ b/ios/App/App/plugins/AbsAudioPlayer.swift @@ -81,9 +81,9 @@ public class AbsAudioPlayer: CAPPlugin { NSLog("Failed to get local playback session") return call.resolve([:]) } - playbackSession.save() do { + try playbackSession.save() try self.startPlaybackSession(playbackSession, playWhenReady: playWhenReady, playbackRate: playbackRate) call.resolve(try playbackSession.asDictionary()) } catch(let exception) { @@ -93,8 +93,8 @@ public class AbsAudioPlayer: CAPPlugin { } } else { // Playing from the server ApiClient.startPlaybackSession(libraryItemId: libraryItemId!, episodeId: episodeId, forceTranscode: false) { session in - session.save() do { + try session.save() try self.startPlaybackSession(session, playWhenReady: playWhenReady, playbackRate: playbackRate) call.resolve(try session.asDictionary()) } catch(let exception) { @@ -122,7 +122,7 @@ public class AbsAudioPlayer: CAPPlugin { @objc func setPlaybackSpeed(_ call: CAPPluginCall) { let playbackRate = call.getFloat("value", 1.0) let settings = PlayerSettings.main() - settings.update { + try? settings.update { settings.playbackRate = playbackRate } PlayerHandler.setPlaybackSpeed(speed: settings.playbackRate) @@ -244,17 +244,15 @@ public class AbsAudioPlayer: CAPPlugin { // If direct playing then fallback to transcode ApiClient.startPlaybackSession(libraryItemId: libraryItemId, episodeId: episodeId, forceTranscode: true) { session in - session.save() - PlayerHandler.startPlayback(sessionId: session.id, playWhenReady: self.initialPlayWhenReady, playbackRate: PlayerSettings.main().playbackRate) - do { + try session.save() + PlayerHandler.startPlayback(sessionId: session.id, playWhenReady: self.initialPlayWhenReady, playbackRate: PlayerSettings.main().playbackRate) self.sendPlaybackSession(session: try session.asDictionary()) + self.sendMetadata() } catch(let exception) { - NSLog("failed to convert session to json") + NSLog("Failed to start transcoded session") debugPrint(exception) } - - self.sendMetadata() } } else { self.notifyListeners("onPlaybackFailed", data: [ diff --git a/ios/App/App/plugins/AbsDatabase.swift b/ios/App/App/plugins/AbsDatabase.swift index 4a36a1d8..3a281277 100644 --- a/ios/App/App/plugins/AbsDatabase.swift +++ b/ios/App/App/plugins/AbsDatabase.swift @@ -139,7 +139,7 @@ public class AbsDatabase: CAPPlugin { call.reject("localMediaProgressId not specificed") return } - Database.shared.removeLocalMediaProgress(localMediaProgressId: localMediaProgressId) + try? Database.shared.removeLocalMediaProgress(localMediaProgressId: localMediaProgressId) call.resolve() } @@ -171,14 +171,14 @@ public class AbsDatabase: CAPPlugin { return call.reject("localLibraryItemId or localMediaProgressId must be specified") } - let localMediaProgress = LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId) + let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId) guard let localMediaProgress = localMediaProgress else { call.reject("Local media progress not found or created") return } NSLog("syncServerMediaProgressWithLocalMediaProgress: Saving local media progress") - localMediaProgress.updateFromServerMediaProgress(serverMediaProgress) + try localMediaProgress.updateFromServerMediaProgress(serverMediaProgress) call.resolve(try localMediaProgress.asDictionary()) } catch { @@ -195,30 +195,36 @@ public class AbsDatabase: CAPPlugin { NSLog("updateLocalMediaProgressFinished \(localMediaProgressId ?? "Unknown") | Is Finished: \(isFinished)") - let localMediaProgress = LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId) - guard let localMediaProgress = localMediaProgress else { - call.resolve(["error": "Library Item not found"]) - return - } + do { + let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: localMediaProgressId, localLibraryItemId: localLibraryItemId, localEpisodeId: localEpisodeId) + guard let localMediaProgress = localMediaProgress else { + call.resolve(["error": "Library Item not found"]) + return + } - // Update finished status - localMediaProgress.updateIsFinished(isFinished) - - // Build API response - let progressDictionary = try? localMediaProgress.asDictionary() - var response: [String: Any] = ["local": true, "server": false, "localMediaProgress": progressDictionary ?? ""] - - // Send update to the server if logged in - let hasLinkedServer = localMediaProgress.serverConnectionConfigId != nil - let loggedIntoServer = Store.serverConfig?.id == localMediaProgress.serverConnectionConfigId - if hasLinkedServer && loggedIntoServer { - response["server"] = true - let payload = ["isFinished": isFinished] - ApiClient.updateMediaProgress(libraryItemId: localMediaProgress.libraryItemId!, episodeId: localEpisodeId, payload: payload) { + // Update finished status + try localMediaProgress.updateIsFinished(isFinished) + + // Build API response + let progressDictionary = try? localMediaProgress.asDictionary() + var response: [String: Any] = ["local": true, "server": false, "localMediaProgress": progressDictionary ?? ""] + + // Send update to the server if logged in + let hasLinkedServer = localMediaProgress.serverConnectionConfigId != nil + let loggedIntoServer = Store.serverConfig?.id == localMediaProgress.serverConnectionConfigId + if hasLinkedServer && loggedIntoServer { + response["server"] = true + let payload = ["isFinished": isFinished] + ApiClient.updateMediaProgress(libraryItemId: localMediaProgress.libraryItemId!, episodeId: localEpisodeId, payload: payload) { + call.resolve(response) + } + } else { call.resolve(response) } - } else { - call.resolve(response) + } catch { + debugPrint(error) + call.resolve(["error": "Failed to mark as complete"]) + return } } diff --git a/ios/App/App/plugins/AbsDownloader.swift b/ios/App/App/plugins/AbsDownloader.swift index a5dbffa2..d430fd5e 100644 --- a/ios/App/App/plugins/AbsDownloader.swift +++ b/ios/App/App/plugins/AbsDownloader.swift @@ -28,7 +28,7 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { handleDownloadTaskUpdate(downloadTask: downloadTask) { downloadItem, downloadItemPart in - let realm = try! Realm() + let realm = try Realm() try realm.write { downloadItemPart.progress = 100 downloadItemPart.completed = true @@ -139,7 +139,7 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { } self.handleDownloadTaskCompleteFromDownloadItem(item) if let item = Database.shared.getDownloadItem(downloadItemId: item.id!) { - item.delete() + try? item.delete() } } @@ -181,7 +181,7 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { } } else { localLibraryItem = LocalLibraryItem(libraryItem, localUrl: localDirectory, server: Store.serverConfig!, files: files, coverPath: coverFile) - Database.shared.saveLocalLibraryItem(localLibraryItem: localLibraryItem!) + try? Database.shared.saveLocalLibraryItem(localLibraryItem: localLibraryItem!) } statusNotification["localLibraryItem"] = try? localLibraryItem.asDictionary() @@ -189,7 +189,7 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { if let progress = libraryItem.userMediaProgress { let episode = downloadItem.media?.episodes.first(where: { $0.id == downloadItem.episodeId }) let localMediaProgress = LocalMediaProgress(localLibraryItem: localLibraryItem!, episode: episode, progress: progress) - Database.shared.saveLocalMediaProgress(localMediaProgress) + try? localMediaProgress.save() statusNotification["localMediaProgress"] = try? localMediaProgress.asDictionary() } @@ -276,7 +276,7 @@ public class AbsDownloader: CAPPlugin, URLSessionDownloadDelegate { } // Persist in the database before status start coming in - Database.shared.saveDownloadItem(downloadItem) + try Database.shared.saveDownloadItem(downloadItem) // Start all the downloads for task in tasks { diff --git a/ios/App/App/plugins/AbsFileSystem.swift b/ios/App/App/plugins/AbsFileSystem.swift index 928eed64..a96e53c6 100644 --- a/ios/App/App/plugins/AbsFileSystem.swift +++ b/ios/App/App/plugins/AbsFileSystem.swift @@ -70,7 +70,7 @@ public class AbsFileSystem: CAPPlugin { do { if let localLibraryItemId = localLibraryItemId, let item = Database.shared.getLocalLibraryItem(localLibraryItemId: localLibraryItemId) { try FileManager.default.removeItem(at: item.contentDirectory!) - item.delete() + try item.delete() success = true } } catch { @@ -89,24 +89,29 @@ public class AbsFileSystem: CAPPlugin { var success = false if let localLibraryItemId = localLibraryItemId, let trackLocalFileId = trackLocalFileId, let item = Database.shared.getLocalLibraryItem(localLibraryItemId: localLibraryItemId) { - item.update { - do { - if let fileIndex = item.localFiles.firstIndex(where: { $0.id == trackLocalFileId }) { - try FileManager.default.removeItem(at: item.localFiles[fileIndex].contentPath) - item.realm?.delete(item.localFiles[fileIndex]) - if item.isPodcast, let media = item.media { - if let episodeIndex = media.episodes.firstIndex(where: { $0.audioTrack?.localFileId == trackLocalFileId }) { - media.episodes.remove(at: episodeIndex) + do { + try item.update { + do { + if let fileIndex = item.localFiles.firstIndex(where: { $0.id == trackLocalFileId }) { + try FileManager.default.removeItem(at: item.localFiles[fileIndex].contentPath) + item.realm?.delete(item.localFiles[fileIndex]) + if item.isPodcast, let media = item.media { + if let episodeIndex = media.episodes.firstIndex(where: { $0.audioTrack?.localFileId == trackLocalFileId }) { + media.episodes.remove(at: episodeIndex) + } + item.media = media } - item.media = media + call.resolve(try item.asDictionary()) + success = true } - call.resolve(try item.asDictionary()) - success = true + } catch { + NSLog("Failed to delete \(error)") + success = false } - } catch { - NSLog("Failed to delete \(error)") - success = false } + } catch { + NSLog("Failed to delete \(error)") + success = false } } diff --git a/ios/App/Shared/models/download/DownloadItem.swift b/ios/App/Shared/models/download/DownloadItem.swift index 446cadcc..ee30213a 100644 --- a/ios/App/Shared/models/download/DownloadItem.swift +++ b/ios/App/Shared/models/download/DownloadItem.swift @@ -88,8 +88,8 @@ extension DownloadItem { self.downloadItemParts.allSatisfy({ $0.failed == false }) } - func delete() { - try! self.realm?.write { + func delete() throws { + try self.realm?.write { self.realm?.delete(self.downloadItemParts) self.realm?.delete(self) } diff --git a/ios/App/Shared/models/local/LocalLibraryItem.swift b/ios/App/Shared/models/local/LocalLibraryItem.swift index d2ef503c..51d6a8bb 100644 --- a/ios/App/Shared/models/local/LocalLibraryItem.swift +++ b/ios/App/Shared/models/local/LocalLibraryItem.swift @@ -198,8 +198,8 @@ extension LocalLibraryItem { ) } - func delete() { - try! self.realm?.write { + func delete() throws { + try self.realm?.write { self.realm?.delete(self.localFiles) self.realm?.delete(self) } diff --git a/ios/App/Shared/models/local/LocalMediaProgress.swift b/ios/App/Shared/models/local/LocalMediaProgress.swift index c15c38a9..c034ae8d 100644 --- a/ios/App/Shared/models/local/LocalMediaProgress.swift +++ b/ios/App/Shared/models/local/LocalMediaProgress.swift @@ -119,8 +119,8 @@ extension LocalMediaProgress { self.finishedAt = progress.finishedAt } - func updateIsFinished(_ finished: Bool) { - try! self.realm?.write { + func updateIsFinished(_ finished: Bool) throws { + try self.realm?.write { if self.isFinished != finished { self.progress = finished ? 1.0 : 0.0 } @@ -135,8 +135,8 @@ extension LocalMediaProgress { } } - func updateFromPlaybackSession(_ playbackSession: PlaybackSession) { - try! self.realm?.write { + func updateFromPlaybackSession(_ playbackSession: PlaybackSession) throws { + try self.realm?.write { self.currentTime = playbackSession.currentTime self.progress = playbackSession.progress self.lastUpdate = Date().timeIntervalSince1970 * 1000 @@ -145,8 +145,8 @@ extension LocalMediaProgress { } } - func updateFromServerMediaProgress(_ serverMediaProgress: MediaProgress) { - try! self.realm?.write { + func updateFromServerMediaProgress(_ serverMediaProgress: MediaProgress) throws { + try self.realm?.write { self.isFinished = serverMediaProgress.isFinished self.progress = serverMediaProgress.progress self.currentTime = serverMediaProgress.currentTime @@ -157,9 +157,9 @@ extension LocalMediaProgress { } } - static func fetchOrCreateLocalMediaProgress(localMediaProgressId: String?, localLibraryItemId: String?, localEpisodeId: String?) -> LocalMediaProgress? { - let realm = try! Realm() - return try! realm.write { () -> LocalMediaProgress? in + static func fetchOrCreateLocalMediaProgress(localMediaProgressId: String?, localLibraryItemId: String?, localEpisodeId: String?) throws -> LocalMediaProgress? { + let realm = try Realm() + return try realm.write { () -> LocalMediaProgress? in if let localMediaProgressId = localMediaProgressId { // Check if it existing in the database, if not, we need to create it if let progress = Database.shared.getLocalMediaProgress(localMediaProgressId: localMediaProgressId) { diff --git a/ios/App/Shared/models/server/AudioTrack.swift b/ios/App/Shared/models/server/AudioTrack.swift index c0d0ab88..8cd9e50e 100644 --- a/ios/App/Shared/models/server/AudioTrack.swift +++ b/ios/App/Shared/models/server/AudioTrack.swift @@ -37,7 +37,7 @@ class AudioTrack: EmbeddedObject, Codable { contentUrl = try? values.decode(String.self, forKey: .contentUrl) mimeType = try values.decode(String.self, forKey: .mimeType) metadata = try? values.decode(FileMetadata.self, forKey: .metadata) - localFileId = try! values.decodeIfPresent(String.self, forKey: .localFileId) + localFileId = try? values.decodeIfPresent(String.self, forKey: .localFileId) serverIndex = try? values.decode(Int.self, forKey: .serverIndex) } diff --git a/ios/App/Shared/player/AudioPlayer.swift b/ios/App/Shared/player/AudioPlayer.swift index f02b9708..70e334ec 100644 --- a/ios/App/Shared/player/AudioPlayer.swift +++ b/ios/App/Shared/player/AudioPlayer.swift @@ -306,7 +306,7 @@ class AudioPlayer: NSObject { if (self.currentTrackIndex != indexOfSeek) { self.currentTrackIndex = indexOfSeek - playbackSession.update { + try? playbackSession.update { playbackSession.currentTime = to } diff --git a/ios/App/Shared/player/PlayerHandler.swift b/ios/App/Shared/player/PlayerHandler.swift index 0a330f61..505c58b8 100644 --- a/ios/App/Shared/player/PlayerHandler.swift +++ b/ios/App/Shared/player/PlayerHandler.swift @@ -158,16 +158,21 @@ class PlayerHandler { // MARK: - Helper logic private static func cleanupOldSessions(currentSessionId: String?) { - let realm = try! Realm() - let oldSessions = realm.objects(PlaybackSession.self) .where({ - $0.isActiveSession == true && $0.serverConnectionConfigId == Store.serverConfig?.id - }) - try! realm.write { - for s in oldSessions { - if s.id != currentSessionId { - s.isActiveSession = false + do { + let realm = try Realm() + let oldSessions = realm.objects(PlaybackSession.self) .where({ + $0.isActiveSession == true && $0.serverConnectionConfigId == Store.serverConfig?.id + }) + try realm.write { + for s in oldSessions { + if s.id != currentSessionId { + s.isActiveSession = false + } } } + } catch { + debugPrint("Failed to cleanup sessions") + debugPrint(error) } } } diff --git a/ios/App/Shared/player/PlayerProgress.swift b/ios/App/Shared/player/PlayerProgress.swift index 47498a2e..d99a15a4 100644 --- a/ios/App/Shared/player/PlayerProgress.swift +++ b/ios/App/Shared/player/PlayerProgress.swift @@ -21,34 +21,49 @@ class PlayerProgress { public func syncFromPlayer(currentTime: Double, includesPlayProgress: Bool, isStopping: Bool) async { let backgroundToken = await UIApplication.shared.beginBackgroundTask(withName: "ABS:syncFromPlayer") - let session = updateLocalSessionFromPlayer(currentTime: currentTime, includesPlayProgress: includesPlayProgress) - updateLocalMediaProgressFromLocalSession() - if let session = session { - await updateServerSessionFromLocalSession(session, rateLimitSync: !isStopping) + do { + let session = try updateLocalSessionFromPlayer(currentTime: currentTime, includesPlayProgress: includesPlayProgress) + try updateLocalMediaProgressFromLocalSession() + if let session = session { + try await updateServerSessionFromLocalSession(session, rateLimitSync: !isStopping) + } + } catch { + debugPrint("Failed to syncFromPlayer") + debugPrint(error) } await UIApplication.shared.endBackgroundTask(backgroundToken) } public func syncToServer() async { let backgroundToken = await UIApplication.shared.beginBackgroundTask(withName: "ABS:syncToServer") - await updateAllServerSessionFromLocalSession() + do { + try await updateAllServerSessionFromLocalSession() + } catch { + debugPrint("Failed to syncToServer") + debugPrint(error) + } await UIApplication.shared.endBackgroundTask(backgroundToken) } public func syncFromServer() async { let backgroundToken = await UIApplication.shared.beginBackgroundTask(withName: "ABS:syncFromServer") - await updateLocalSessionFromServerMediaProgress() + do { + try await updateLocalSessionFromServerMediaProgress() + } catch { + debugPrint("Failed to syncFromServer") + debugPrint(error) + } await UIApplication.shared.endBackgroundTask(backgroundToken) } // MARK: - SYNC LOGIC - private func updateLocalSessionFromPlayer(currentTime: Double, includesPlayProgress: Bool) -> PlaybackSession? { + private func updateLocalSessionFromPlayer(currentTime: Double, includesPlayProgress: Bool) throws -> PlaybackSession? { guard let session = PlayerHandler.getPlaybackSession() else { return nil } guard !currentTime.isNaN else { return nil } // Prevent bad data on player stop - session.update { + try session.update { session.realm?.refresh() let nowInSeconds = Date().timeIntervalSince1970 @@ -68,18 +83,18 @@ class PlayerProgress { return session.freeze() } - private func updateLocalMediaProgressFromLocalSession() { + private func updateLocalMediaProgressFromLocalSession() throws { guard let session = PlayerHandler.getPlaybackSession() else { return } guard session.isLocal else { return } - let localMediaProgress = LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: session.localMediaProgressId, localLibraryItemId: session.localLibraryItem?.id, localEpisodeId: session.episodeId) + let localMediaProgress = try LocalMediaProgress.fetchOrCreateLocalMediaProgress(localMediaProgressId: session.localMediaProgressId, localLibraryItemId: session.localLibraryItem?.id, localEpisodeId: session.episodeId) guard let localMediaProgress = localMediaProgress else { // Local media progress should have been created // If we're here, it means a library id is invalid return } - localMediaProgress.updateFromPlaybackSession(session) + try localMediaProgress.updateFromPlaybackSession(session) NSLog("Local progress saved to the database") @@ -87,25 +102,25 @@ class PlayerProgress { NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.localProgress.rawValue), object: nil) } - private func updateAllServerSessionFromLocalSession() async { - await withTaskGroup(of: Void.self) { [self] group in - for session in try! await Realm().objects(PlaybackSession.self).where({ $0.serverConnectionConfigId == Store.serverConfig?.id }) { + private func updateAllServerSessionFromLocalSession() async throws { + try await withThrowingTaskGroup(of: Void.self) { [self] group in + for session in try await Realm().objects(PlaybackSession.self).where({ $0.serverConnectionConfigId == Store.serverConfig?.id }) { let session = session.freeze() group.addTask { - await self.updateServerSessionFromLocalSession(session) + try await self.updateServerSessionFromLocalSession(session) } } - await group.waitForAll() + try await group.waitForAll() } } - private func updateServerSessionFromLocalSession(_ session: PlaybackSession, rateLimitSync: Bool = false) async { + private func updateServerSessionFromLocalSession(_ session: PlaybackSession, rateLimitSync: Bool = false) async throws { var safeToSync = true guard var session = session.thaw() else { return } // We need to update and check the server time in a transaction for thread-safety - session.update { + try session.update { session.realm?.refresh() let nowInMilliseconds = Date().timeIntervalSince1970 * 1000 @@ -140,14 +155,14 @@ class PlayerProgress { // Remove old sessions after they synced with the server if success && !session.isActiveSession { if let session = session.thaw() { - session.delete() + try session.delete() } } } - private func updateLocalSessionFromServerMediaProgress() async { + private func updateLocalSessionFromServerMediaProgress() async throws { NSLog("updateLocalSessionFromServerMediaProgress: Checking if local media progress was updated on server") - guard let session = try! await Realm().objects(PlaybackSession.self).last(where: { + guard let session = try await Realm().objects(PlaybackSession.self).last(where: { $0.isActiveSession == true && $0.serverConnectionConfigId == Store.serverConfig?.id })?.freeze() else { NSLog("updateLocalSessionFromServerMediaProgress: Failed to get session") @@ -177,7 +192,7 @@ class PlayerProgress { if serverIsNewerThanLocal && currentTimeIsDifferent { NSLog("updateLocalSessionFromServerMediaProgress: Server has newer time than local serverLastUpdate=\(serverLastUpdate) localLastUpdate=\(localLastUpdate)") guard let session = session.thaw() else { return } - session.update { + try session.update { session.currentTime = serverCurrentTime session.updatedAt = serverLastUpdate } diff --git a/ios/App/Shared/util/ApiClient.swift b/ios/App/Shared/util/ApiClient.swift index 2d5258b0..2c247e35 100644 --- a/ios/App/Shared/util/ApiClient.swift +++ b/ios/App/Shared/util/ApiClient.swift @@ -200,7 +200,12 @@ class ApiClient { if let updates = response.localProgressUpdates { for update in updates { - Database.shared.saveLocalMediaProgress(update) + do { + try update.save() + } catch { + debugPrint("Failed to update local media progress") + debugPrint(error) + } } } diff --git a/ios/App/Shared/util/DaoExtensions.swift b/ios/App/Shared/util/DaoExtensions.swift index f1d61c3a..67c7923a 100644 --- a/ios/App/Shared/util/DaoExtensions.swift +++ b/ios/App/Shared/util/DaoExtensions.swift @@ -9,15 +9,15 @@ import Foundation import RealmSwift extension Object { - func save() { - let realm = try! Realm() - try! realm.write { + func save() throws { + let realm = try Realm() + try realm.write { realm.add(self, update: .modified) } } - func update(handler: () -> Void) { - try! self.realm?.write { + func update(handler: () -> Void) throws { + try self.realm?.write { handler() } } @@ -33,12 +33,12 @@ extension EmbeddedObject { } protocol Deletable { - func delete() + func delete() throws } extension Deletable where Self: Object { - func delete() { - try! self.realm?.write { + func delete() throws { + try self.realm?.write { self.realm?.delete(self) } } diff --git a/ios/App/Shared/util/Database.swift b/ios/App/Shared/util/Database.swift index 396682ae..721f7121 100644 --- a/ios/App/Shared/util/Database.swift +++ b/ios/App/Shared/util/Database.swift @@ -112,48 +112,83 @@ class Database { } public func getLocalLibraryItems(mediaType: MediaType? = nil) -> [LocalLibraryItem] { - let realm = try! Realm() - return Array(realm.objects(LocalLibraryItem.self)) + do { + let realm = try Realm() + return Array(realm.objects(LocalLibraryItem.self)) + } catch { + debugPrint(error) + return [] + } } public func getLocalLibraryItem(byServerLibraryItemId: String) -> LocalLibraryItem? { - let realm = try! Realm() - return realm.objects(LocalLibraryItem.self).first(where: { $0.libraryItemId == byServerLibraryItemId }) + do { + let realm = try Realm() + return realm.objects(LocalLibraryItem.self).first(where: { $0.libraryItemId == byServerLibraryItemId }) + } catch { + debugPrint(error) + return nil + } } public func getLocalLibraryItem(localLibraryItemId: String) -> LocalLibraryItem? { - let realm = try! Realm() - return realm.object(ofType: LocalLibraryItem.self, forPrimaryKey: localLibraryItemId) + do { + let realm = try Realm() + return realm.object(ofType: LocalLibraryItem.self, forPrimaryKey: localLibraryItemId) + } catch { + debugPrint(error) + return nil + } } - public func saveLocalLibraryItem(localLibraryItem: LocalLibraryItem) { - let realm = try! Realm() - try! realm.write { realm.add(localLibraryItem, update: .modified) } + public func saveLocalLibraryItem(localLibraryItem: LocalLibraryItem) throws { + let realm = try Realm() + try realm.write { realm.add(localLibraryItem, update: .modified) } } public func getLocalFile(localFileId: String) -> LocalFile? { - let realm = try! Realm() - return realm.object(ofType: LocalFile.self, forPrimaryKey: localFileId) + do { + let realm = try Realm() + return realm.object(ofType: LocalFile.self, forPrimaryKey: localFileId) + } catch { + debugPrint(error) + return nil + } } public func getDownloadItem(downloadItemId: String) -> DownloadItem? { - let realm = try! Realm() - return realm.object(ofType: DownloadItem.self, forPrimaryKey: downloadItemId) + do { + let realm = try Realm() + return realm.object(ofType: DownloadItem.self, forPrimaryKey: downloadItemId) + } catch { + debugPrint(error) + return nil + } } public func getDownloadItem(libraryItemId: String) -> DownloadItem? { - let realm = try! Realm() - return realm.objects(DownloadItem.self).filter("libraryItemId == %@", libraryItemId).first + do { + let realm = try Realm() + return realm.objects(DownloadItem.self).filter("libraryItemId == %@", libraryItemId).first + } catch { + debugPrint(error) + return nil + } } public func getDownloadItem(downloadItemPartId: String) -> DownloadItem? { - let realm = try! Realm() - return realm.objects(DownloadItem.self).filter("SUBQUERY(downloadItemParts, $part, $part.id == %@) .@count > 0", downloadItemPartId).first + do { + let realm = try Realm() + return realm.objects(DownloadItem.self).filter("SUBQUERY(downloadItemParts, $part, $part.id == %@) .@count > 0", downloadItemPartId).first + } catch { + debugPrint(error) + return nil + } } - public func saveDownloadItem(_ downloadItem: DownloadItem) { - let realm = try! Realm() - return try! realm.write { realm.add(downloadItem, update: .modified) } + public func saveDownloadItem(_ downloadItem: DownloadItem) throws { + let realm = try Realm() + return try realm.write { realm.add(downloadItem, update: .modified) } } public func getDeviceSettings() -> DeviceSettings { @@ -162,31 +197,41 @@ class Database { } public func getAllLocalMediaProgress() -> [LocalMediaProgress] { - let realm = try! Realm() - return Array(realm.objects(LocalMediaProgress.self)) - } - - public func saveLocalMediaProgress(_ mediaProgress: LocalMediaProgress) { - let realm = try! Realm() - try! realm.write { realm.add(mediaProgress, update: .modified) } + do { + let realm = try Realm() + return Array(realm.objects(LocalMediaProgress.self)) + } catch { + debugPrint(error) + return [] + } } // For books this will just be the localLibraryItemId for podcast episodes this will be "{localLibraryItemId}-{episodeId}" public func getLocalMediaProgress(localMediaProgressId: String) -> LocalMediaProgress? { - let realm = try! Realm() - return realm.object(ofType: LocalMediaProgress.self, forPrimaryKey: localMediaProgressId) + do { + let realm = try Realm() + return realm.object(ofType: LocalMediaProgress.self, forPrimaryKey: localMediaProgressId) + } catch { + debugPrint(error) + return nil + } } - public func removeLocalMediaProgress(localMediaProgressId: String) { - let realm = try! Realm() - try! realm.write { + public func removeLocalMediaProgress(localMediaProgressId: String) throws { + let realm = try Realm() + try realm.write { let progress = realm.object(ofType: LocalMediaProgress.self, forPrimaryKey: localMediaProgressId) realm.delete(progress!) } } public func getPlaybackSession(id: String) -> PlaybackSession? { - let realm = try! Realm() - return realm.object(ofType: PlaybackSession.self, forPrimaryKey: id) + do { + let realm = try Realm() + return realm.object(ofType: PlaybackSession.self, forPrimaryKey: id) + } catch { + debugPrint(error) + return nil + } } }