Small improvements

This commit is contained in:
Rasmus Krämer
2022-05-03 12:55:13 +02:00
parent 394363c8cb
commit 9701c767b2
8 changed files with 86 additions and 66 deletions
+4 -5
View File
@@ -53,7 +53,7 @@ public class AbsDatabase: CAPPlugin {
} }
@objc func removeServerConnectionConfig(_ call: CAPPluginCall) { @objc func removeServerConnectionConfig(_ call: CAPPluginCall) {
let id = call.getString("serverConnectionConfigId", "") let id = call.getString("serverConnectionConfigId", "")
Database.deleteServerConnectionConfig(id: id) Database.shared.deleteServerConnectionConfig(id: id)
call.resolve() call.resolve()
} }
@@ -63,13 +63,12 @@ public class AbsDatabase: CAPPlugin {
} }
@objc func getDeviceData(_ call: CAPPluginCall) { @objc func getDeviceData(_ call: CAPPluginCall) {
let configs = Database.getServerConnectionConfigs() let configs = Database.shared.getServerConnectionConfigs()
let index = Database.getLastActiveConfigIndex() let index = Database.shared.getLastActiveConfigIndex()
call.resolve([ call.resolve([
"serverConnectionConfigs": configs.map { config in convertServerConnectionConfigToJSON(config: config) }, "serverConnectionConfigs": configs.map { config in convertServerConnectionConfigToJSON(config: config) },
"lastServerConnectionConfigId": configs.first { config in config.index == index }?.id, "lastServerConnectionConfigId": configs.first { config in config.index == index }?.id as Any,
// Luckily this isn't implemented yet
// "currentLocalPlaybackSession": nil, // "currentLocalPlaybackSession": nil,
]) ])
} }
+7 -8
View File
@@ -70,6 +70,7 @@ class AudioPlayer: NSObject {
public func destroy() { public func destroy() {
// Pause is not synchronous causing this error on below lines: // Pause is not synchronous causing this error on below lines:
// AVAudioSession_iOS.mm:1206 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session // AVAudioSession_iOS.mm:1206 Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session
// It is related to L79 `AVAudioSession.sharedInstance().setActive(false)`
pause() pause()
audioPlayer.replaceCurrentItem(with: nil) audioPlayer.replaceCurrentItem(with: nil)
@@ -80,11 +81,9 @@ class AudioPlayer: NSObject {
print(error) print(error)
} }
// Throws error Possibly related to the error above DispatchQueue.runOnMainQueue {
// DispatchQueue.main.sync { UIApplication.shared.endReceivingRemoteControlEvents()
// UIApplication.shared.endReceivingRemoteControlEvents() }
// }
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.closed.rawValue), object: nil) NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.closed.rawValue), object: nil)
} }
@@ -186,9 +185,9 @@ class AudioPlayer: NSObject {
// MARK: - Now playing // MARK: - Now playing
private func setupRemoteTransportControls() { private func setupRemoteTransportControls() {
// DispatchQueue.main.sync { DispatchQueue.runOnMainQueue {
UIApplication.shared.beginReceivingRemoteControlEvents() UIApplication.shared.beginReceivingRemoteControlEvents()
// } }
let commandCenter = MPRemoteCommandCenter.shared() let commandCenter = MPRemoteCommandCenter.shared()
commandCenter.playCommand.isEnabled = true commandCenter.playCommand.isEnabled = true
@@ -246,7 +245,7 @@ class AudioPlayer: NSObject {
} }
private func updateNowPlaying() { private func updateNowPlaying() {
NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.update.rawValue), object: nil) NotificationCenter.default.post(name: NSNotification.Name(PlayerEvents.update.rawValue), object: nil)
NowPlayingInfo.update(duration: getDuration(), currentTime: getCurrentTime(), rate: rate) NowPlayingInfo.shared.update(duration: getDuration(), currentTime: getCurrentTime(), rate: rate)
} }
// MARK: - Observer // MARK: - Observer
+18 -15
View File
@@ -20,16 +20,16 @@ class PlayerHandler {
player = nil player = nil
} }
NowPlayingInfo.setSessionMetadata(metadata: NowPlayingMetadata(id: session.id, itemId: session.libraryItemId!, artworkUrl: session.coverPath, title: session.displayTitle ?? "Unknown title", author: session.displayAuthor, series: nil)) NowPlayingInfo.shared.setSessionMetadata(metadata: NowPlayingMetadata(id: session.id, itemId: session.libraryItemId!, artworkUrl: session.coverPath, title: session.displayTitle ?? "Unknown title", author: session.displayAuthor, series: nil))
self.session = session self.session = session
player = AudioPlayer(playbackSession: session, playWhenReady: playWhenReady, playbackRate: playbackRate) player = AudioPlayer(playbackSession: session, playWhenReady: playWhenReady, playbackRate: playbackRate)
// DispatchQueue.main.sync { DispatchQueue.runOnMainQueue {
timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
self.tick() self.tick()
}
} }
// }
} }
public static func stopPlayback() { public static func stopPlayback() {
player?.destroy() player?.destroy()
@@ -38,7 +38,7 @@ class PlayerHandler {
timer?.invalidate() timer?.invalidate()
timer = nil timer = nil
NowPlayingInfo.reset() NowPlayingInfo.shared.reset()
} }
public static func getCurrentTime() -> Double? { public static func getCurrentTime() -> Double? {
@@ -63,20 +63,20 @@ class PlayerHandler {
} }
public static func seekForward(amount: Double) { public static func seekForward(amount: Double) {
if player == nil { guard let player = player else {
return return
} }
let destinationTime = player!.getCurrentTime() + amount let destinationTime = player.getCurrentTime() + amount
player!.seek(destinationTime) player.seek(destinationTime)
} }
public static func seekBackward(amount: Double) { public static func seekBackward(amount: Double) {
if player == nil { guard let player = player else {
return return
} }
let destinationTime = player!.getCurrentTime() - amount let destinationTime = player.getCurrentTime() - amount
player!.seek(destinationTime) player.seek(destinationTime)
} }
public static func seek(amount: Double) { public static func seek(amount: Double) {
player?.seek(amount) player?.seek(amount)
@@ -109,13 +109,16 @@ class PlayerHandler {
} }
} }
public static func syncProgress() { public static func syncProgress() {
if player == nil || session == nil { if session == nil {
return
}
guard let player = player else {
return return
} }
let report = PlaybackReport(currentTime: player!.getCurrentTime(), duration: player!.getDuration(), timeListened: listeningTimePassedSinceLastSync) let report = PlaybackReport(currentTime: player.getCurrentTime(), duration: player.getDuration(), timeListened: listeningTimePassedSinceLastSync)
session!.currentTime = player!.getCurrentTime() session!.currentTime = player.getCurrentTime()
listeningTimePassedSinceLastSync = 0 listeningTimePassedSinceLastSync = 0
// TODO: check if online // TODO: check if online
+8 -1
View File
@@ -9,6 +9,14 @@ import Foundation
import Alamofire import Alamofire
class ApiClient { class ApiClient {
public static func getData(from url: URL, completion: @escaping (UIImage?) -> Void) {
URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in
if let data = data {
completion(UIImage(data:data))
}
}).resume()
}
public static func postResource<T: Decodable>(endpoint: String, parameters: [String: String], decodable: T.Type = T.self, callback: ((_ param: T) -> Void)?) { public static func postResource<T: Decodable>(endpoint: String, parameters: [String: String], decodable: T.Type = T.self, callback: ((_ param: T) -> Void)?) {
if (Store.serverConfig == nil) { if (Store.serverConfig == nil) {
NSLog("Server config not set") NSLog("Server config not set")
@@ -54,7 +62,6 @@ class ApiClient {
} }
public static func startPlaybackSession(libraryItemId: String, episodeId: String?, callback: @escaping (_ param: PlaybackSession) -> Void) { public static func startPlaybackSession(libraryItemId: String, episodeId: String?, callback: @escaping (_ param: PlaybackSession) -> Void) {
var endpoint = "api/items/\(libraryItemId)/play" var endpoint = "api/items/\(libraryItemId)/play"
if episodeId != nil { if episodeId != nil {
endpoint += "/\(episodeId!)" endpoint += "/\(episodeId!)"
+22 -13
View File
@@ -10,16 +10,25 @@ import RealmSwift
class Database { class Database {
// All DB releated actions must be executed on "realm-queue" // All DB releated actions must be executed on "realm-queue"
public static let realmQueue = DispatchQueue(label: "realm-queue") public static let realmQueue: DispatchQueue = DispatchQueue(label: "realm-queue")
private static var instance: Realm = try! Realm(queue: realmQueue) public static var shared = {
realmQueue.sync {
return Database()
}
}()
private var instance: Realm
private init() {
self.instance = try! Realm(queue: Database.realmQueue)
}
public static func setServerConnectionConfig(config: ServerConnectionConfig) { public func setServerConnectionConfig(config: ServerConnectionConfig) {
var refrence: ThreadSafeReference<ServerConnectionConfig>? var refrence: ThreadSafeReference<ServerConnectionConfig>?
if config.realm != nil { if config.realm != nil {
refrence = ThreadSafeReference(to: config) refrence = ThreadSafeReference(to: config)
} }
realmQueue.sync { Database.realmQueue.sync {
let existing: ServerConnectionConfig? = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: config.id) let existing: ServerConnectionConfig? = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: config.id)
if config.index == 0 { if config.index == 0 {
@@ -55,8 +64,8 @@ class Database {
setLastActiveConfigIndex(index: config.index) setLastActiveConfigIndex(index: config.index)
} }
} }
public static func deleteServerConnectionConfig(id: String) { public func deleteServerConnectionConfig(id: String) {
realmQueue.sync { Database.realmQueue.sync {
let config = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: id) let config = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: id)
do { do {
@@ -71,10 +80,10 @@ class Database {
} }
} }
} }
public static func getServerConnectionConfigs() -> [ServerConnectionConfig] { public func getServerConnectionConfigs() -> [ServerConnectionConfig] {
var refrences: [ThreadSafeReference<ServerConnectionConfig>] = [] var refrences: [ThreadSafeReference<ServerConnectionConfig>] = []
realmQueue.sync { Database.realmQueue.sync {
let configs = instance.objects(ServerConnectionConfig.self) let configs = instance.objects(ServerConnectionConfig.self)
refrences = configs.map { config in refrences = configs.map { config in
return ThreadSafeReference(to: config) return ThreadSafeReference(to: config)
@@ -94,12 +103,12 @@ class Database {
} }
} }
public static func setLastActiveConfigIndexToNil() { public func setLastActiveConfigIndexToNil() {
realmQueue.sync { Database.realmQueue.sync {
setLastActiveConfigIndex(index: nil) setLastActiveConfigIndex(index: nil)
} }
} }
public static func setLastActiveConfigIndex(index: Int?) { public func setLastActiveConfigIndex(index: Int?) {
let existing = instance.objects(ServerConnectionConfigActiveIndex.self) let existing = instance.objects(ServerConnectionConfigActiveIndex.self)
let obj = ServerConnectionConfigActiveIndex() let obj = ServerConnectionConfigActiveIndex()
obj.index = index obj.index = index
@@ -114,8 +123,8 @@ class Database {
debugPrint(exception) debugPrint(exception)
} }
} }
public static func getLastActiveConfigIndex() -> Int? { public func getLastActiveConfigIndex() -> Int? {
return realmQueue.sync { return Database.realmQueue.sync {
return instance.objects(ServerConnectionConfigActiveIndex.self).first?.index ?? nil return instance.objects(ServerConnectionConfigActiveIndex.self).first?.index ?? nil
} }
} }
+11
View File
@@ -18,3 +18,14 @@ extension Encodable {
return dictionary return dictionary
} }
} }
extension DispatchQueue {
static func runOnMainQueue(callback: @escaping (() -> Void)) {
if Thread.isMainThread {
callback()
} else {
DispatchQueue.main.sync {
callback()
}
}
}
}
+14 -22
View File
@@ -8,14 +8,6 @@
import Foundation import Foundation
import MediaPlayer import MediaPlayer
func getData(from url: URL, completion: @escaping (UIImage?) -> Void) {
URLSession.shared.dataTask(with: url, completionHandler: {(data, response, error) in
if let data = data {
completion(UIImage(data:data))
}
}).resume()
}
struct NowPlayingMetadata { struct NowPlayingMetadata {
var id: String var id: String
var itemId: String var itemId: String
@@ -26,22 +18,22 @@ struct NowPlayingMetadata {
} }
class NowPlayingInfo { class NowPlayingInfo {
private static var nowPlayingInfo: [String: Any] = [:] static var shared = {
return NowPlayingInfo()
}()
public static func setSessionMetadata(metadata: NowPlayingMetadata) { private var nowPlayingInfo: [String: Any]
private init() {
self.nowPlayingInfo = [:]
}
public func setSessionMetadata(metadata: NowPlayingMetadata) {
setMetadata(artwork: nil, metadata: metadata) setMetadata(artwork: nil, metadata: metadata)
/*
if !shouldFetchCover(id: metadata.id) || metadata.artworkUrl == nil {
return
}
*/
guard let url = URL(string: "\(Store.serverConfig!.address)/api/items/\(metadata.itemId)/cover?token=\(Store.serverConfig!.token)") else { guard let url = URL(string: "\(Store.serverConfig!.address)/api/items/\(metadata.itemId)/cover?token=\(Store.serverConfig!.token)") else {
return return
} }
ApiClient.getData(from: url) { [self] image in
getData(from: url) { [self] image in
guard let downloadedImage = image else { guard let downloadedImage = image else {
return return
} }
@@ -52,7 +44,7 @@ class NowPlayingInfo {
self.setMetadata(artwork: artwork, metadata: metadata) self.setMetadata(artwork: artwork, metadata: metadata)
} }
} }
public static func update(duration: Double, currentTime: Double, rate: Float) { public func update(duration: Double, currentTime: Double, rate: Float) {
nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = duration nowPlayingInfo[MPMediaItemPropertyPlaybackDuration] = duration
nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentTime nowPlayingInfo[MPNowPlayingInfoPropertyElapsedPlaybackTime] = currentTime
nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = rate nowPlayingInfo[MPNowPlayingInfoPropertyPlaybackRate] = rate
@@ -60,12 +52,12 @@ class NowPlayingInfo {
MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo
} }
public static func reset() { public func reset() {
nowPlayingInfo = [:] nowPlayingInfo = [:]
MPNowPlayingInfoCenter.default().nowPlayingInfo = nil MPNowPlayingInfoCenter.default().nowPlayingInfo = nil
} }
private static func setMetadata(artwork: MPMediaItemArtwork?, metadata: NowPlayingMetadata?) { private func setMetadata(artwork: MPMediaItemArtwork?, metadata: NowPlayingMetadata?) {
if metadata == nil { if metadata == nil {
return return
} }
@@ -84,7 +76,7 @@ class NowPlayingInfo {
nowPlayingInfo[MPMediaItemPropertyArtist] = metadata!.author ?? "unknown" nowPlayingInfo[MPMediaItemPropertyArtist] = metadata!.author ?? "unknown"
nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = metadata!.series nowPlayingInfo[MPMediaItemPropertyAlbumTitle] = metadata!.series
} }
private static func shouldFetchCover(id: String) -> Bool { private func shouldFetchCover(id: String) -> Bool {
nowPlayingInfo[MPNowPlayingInfoPropertyExternalContentIdentifier] as? String != id || nowPlayingInfo[MPMediaItemPropertyArtwork] == nil nowPlayingInfo[MPNowPlayingInfoPropertyExternalContentIdentifier] as? String != id || nowPlayingInfo[MPMediaItemPropertyArtwork] == nil
} }
} }
+2 -2
View File
@@ -16,9 +16,9 @@ class Store {
} }
set(updated) { set(updated) {
if updated != nil { if updated != nil {
Database.setServerConnectionConfig(config: updated!) Database.shared.setServerConnectionConfig(config: updated!)
} else { } else {
Database.setLastActiveConfigIndexToNil() Database.shared.setLastActiveConfigIndexToNil()
} }
Database.realmQueue.sync { Database.realmQueue.sync {