diff --git a/ios/App/App/plugins/AbsAudioPlayer.swift b/ios/App/App/plugins/AbsAudioPlayer.swift index d7f00e28..a66d3b36 100644 --- a/ios/App/App/plugins/AbsAudioPlayer.swift +++ b/ios/App/App/plugins/AbsAudioPlayer.swift @@ -36,30 +36,36 @@ public class AbsAudioPlayer: CAPPlugin { NSLog("provide library item id") return call.resolve() } - if libraryItemId!.starts(with: "local") { - NSLog("local items are not implemnted") - return call.resolve() - } initialPlayWhenReady = playWhenReady initialPlaybackRate = playbackRate PlayerHandler.stopPlayback() - sendPrepareMetadataEvent(itemId: libraryItemId!, playWhenReady: playWhenReady) - ApiClient.startPlaybackSession(libraryItemId: libraryItemId!, episodeId: episodeId, forceTranscode: false) { session in - do { - self.sendPlaybackSession(session: try session.asDictionary()) - call.resolve(try session.asDictionary()) - } catch(let exception) { - NSLog("failed to convert session to json") - debugPrint(exception) - call.resolve([:]) - } - - - PlayerHandler.startPlayback(session: session, playWhenReady: playWhenReady, playbackRate: playbackRate) + let isLocalItem = libraryItemId?.starts(with: "local_") ?? false + if (isLocalItem) { + let item = Database.shared.getLocalLibraryItem(localLibraryItem: libraryItemId!) + // TODO: Logic required for podcasts here + let playbackSession = item?.getPlaybackSession(episode: nil) + PlayerHandler.startPlayback(session: playbackSession!, playWhenReady: playWhenReady, playbackRate: playbackRate) self.sendMetadata() + call.resolve() + } else { // Playing from the server + sendPrepareMetadataEvent(itemId: libraryItemId!, playWhenReady: playWhenReady) + ApiClient.startPlaybackSession(libraryItemId: libraryItemId!, episodeId: episodeId, forceTranscode: false) { session in + do { + self.sendPlaybackSession(session: try session.asDictionary()) + call.resolve(try session.asDictionary()) + } catch(let exception) { + NSLog("failed to convert session to json") + debugPrint(exception) + call.resolve([:]) + } + + + PlayerHandler.startPlayback(session: session, playWhenReady: playWhenReady, playbackRate: playbackRate) + self.sendMetadata() + } } } @objc func closePlayback(_ call: CAPPluginCall) { diff --git a/ios/App/Shared/models/LocalLibrary.swift b/ios/App/Shared/models/LocalLibrary.swift index 52d908c3..fb5c4f36 100644 --- a/ios/App/Shared/models/LocalLibrary.swift +++ b/ios/App/Shared/models/LocalLibrary.swift @@ -125,7 +125,7 @@ class LocalFile: Object, Encodable { } class LocalMediaProgress: Object, Encodable { - @Persisted var id: String = UUID().uuidString + @Persisted(primaryKey: true) var id: String = UUID().uuidString @Persisted var localLibraryItemId: String @Persisted var localEpisodeId: String? = "" @Persisted var duration: Double diff --git a/ios/App/Shared/models/LocalLibraryExtensions.swift b/ios/App/Shared/models/LocalLibraryExtensions.swift index 0a72f9ff..c08337ce 100644 --- a/ios/App/Shared/models/LocalLibraryExtensions.swift +++ b/ios/App/Shared/models/LocalLibraryExtensions.swift @@ -58,6 +58,53 @@ extension LocalLibraryItem { self.serverAddress = server.address self.serverUserId = server.userId } + + func getDuration() -> Double { + var total = 0.0 + self.media?.tracks.forEach { track in total += track.duration } + return total + } + + func getPlaybackSession(episode: LocalPodcastEpisode?) -> PlaybackSession { + let localEpisodeId = episode?.id + let sessionId = "play_local_\(UUID().uuidString)" + + // Get current progress from local media + let mediaProgressId = (localEpisodeId != nil) ? "\(self.id)-\(localEpisodeId!)" : self.id + let mediaProgress = Database.shared.getLocalMediaProgress(localMediaProgressId: mediaProgressId) + + // TODO: Clean up add mediaType methods for displayTitle and displayAuthor + let mediaMetadata = self.media?.metadata + let audioTracks = self.media?.tracks + let authorName = mediaMetadata?.authorName + + if let episode = episode { + // TODO: Implement podcast + } + + let dateNow = Date().timeIntervalSince1970 + return PlaybackSession( + id: sessionId, + userId: self.serverUserId, + libraryItemId: self.libraryItemId, + episodeId: episode?.serverEpisodeId, + mediaType: self.mediaType, + chapters: [], + displayTitle: mediaMetadata?.title, + displayAuthor: authorName, + coverPath: nil, + duration: self.getDuration(), + playMethod: 3, + startedAt: dateNow, + updatedAt: 0, + timeListening: 0.0, + audioTracks: [], + currentTime: mediaProgress?.currentTime ?? 0.0, + libraryItem: nil, + serverConnectionConfigId: self.serverConnectionConfigId, + serverAddress: self.serverAddress + ) + } } extension LocalMediaType { diff --git a/ios/App/Shared/models/PlaybackSession.swift b/ios/App/Shared/models/PlaybackSession.swift index 483da125..d5b75293 100644 --- a/ios/App/Shared/models/PlaybackSession.swift +++ b/ios/App/Shared/models/PlaybackSession.swift @@ -25,8 +25,8 @@ struct PlaybackSession: Decodable, Encodable { var timeListening: Double var audioTracks: [AudioTrack] var currentTime: Double - var libraryItem: LibraryItem - // var localLibraryItem: LocalLibraryItem? + var libraryItem: LibraryItem? + //var localLibraryItem: LocalLibraryItem? var serverConnectionConfigId: String? var serverAddress: String? } diff --git a/ios/App/Shared/util/Database.swift b/ios/App/Shared/util/Database.swift index 58274b14..0ec073d9 100644 --- a/ios/App/Shared/util/Database.swift +++ b/ios/App/Shared/util/Database.swift @@ -229,4 +229,26 @@ class Database { } } } + + public func saveLocalMediaProgress(_ mediaProgress: LocalMediaProgress) { + Database.realmQueue.sync { + try! instance.write { instance.add(mediaProgress) } + } + } + + // For books this will just be the localLibraryItemId for podcast episodes this will be "{localLibraryItemId}-{episodeId}" + public func getLocalMediaProgress(localMediaProgressId: String) -> LocalMediaProgress? { + Database.realmQueue.sync { + instance.object(ofType: LocalMediaProgress.self, forPrimaryKey: localMediaProgressId) + } + } + + public func removeLocalMediaProgress(localMediaProgressId: String) { + Database.realmQueue.sync { + try! instance.write { + let progress = instance.object(ofType: LocalMediaProgress.self, forPrimaryKey: localMediaProgressId) + instance.delete(progress!) + } + } + } }