mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-05 10:35:42 +02:00
Improved realm thread and added http client
This commit is contained in:
parent
4abd1c8b49
commit
736af85855
14 changed files with 253 additions and 71 deletions
13
ios/App/Shared/models/PlaybackReport.swift
Normal file
13
ios/App/Shared/models/PlaybackReport.swift
Normal file
|
@ -0,0 +1,13 @@
|
|||
//
|
||||
// PlaybackReport.swift
|
||||
// App
|
||||
//
|
||||
// Created by Rasmus Krämer on 12.04.22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RealmSwift
|
||||
|
||||
class PlaybackReport: Object {
|
||||
@Persisted var token: String
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
struct PlaybackSession {
|
||||
struct PlaybackSession: Decodable {
|
||||
var id: String
|
||||
var userId: String?
|
||||
var libraryItemId: String?
|
||||
|
@ -20,8 +20,8 @@ struct PlaybackSession {
|
|||
var coverPath: String?
|
||||
var duration: Double
|
||||
var playMethod: Int
|
||||
var startedAt: Double
|
||||
var updatedAt: Double
|
||||
var startedAt: Double?
|
||||
var updatedAt: Double?
|
||||
var timeListening: Double
|
||||
var audioTracks: [AudioTrack]
|
||||
var currentTime: Double
|
||||
|
@ -30,14 +30,14 @@ struct PlaybackSession {
|
|||
var serverConnectionConfigId: String?
|
||||
var serverAddress: String?
|
||||
}
|
||||
struct Chapter {
|
||||
struct Chapter: Decodable {
|
||||
var id: Int
|
||||
var start: Double
|
||||
var end: Double
|
||||
var title: String?
|
||||
}
|
||||
struct AudioTrack {
|
||||
var index: Int
|
||||
struct AudioTrack: Decodable {
|
||||
var index: Int?
|
||||
var startOffset: Double
|
||||
var duration: Double
|
||||
var title: String
|
||||
|
@ -46,10 +46,10 @@ struct AudioTrack {
|
|||
var metadata: FileMetadata?
|
||||
// var isLocal: Bool
|
||||
// var localFileId: String?
|
||||
// var audioProbeResult: AudioProbeResult? Need for local playback
|
||||
// var audioProbeResult: AudioProbeResult? Needed for local playback
|
||||
var serverIndex: Int?
|
||||
}
|
||||
struct FileMetadata {
|
||||
struct FileMetadata: Decodable {
|
||||
var filename: String
|
||||
var ext: String
|
||||
var path: String
|
||||
|
|
|
@ -19,13 +19,15 @@ class ServerConnectionConfig: Object {
|
|||
}
|
||||
|
||||
func convertServerConnectionConfigToJSON(config: ServerConnectionConfig) -> Dictionary<String, Any> {
|
||||
return [
|
||||
"id": config.id,
|
||||
"name": config.name,
|
||||
"index": config.index,
|
||||
"address": config.address,
|
||||
"userId": config.userId,
|
||||
"username": config.username,
|
||||
"token": config.token,
|
||||
]
|
||||
return Database.realmQueue.sync {
|
||||
return [
|
||||
"id": config.id,
|
||||
"name": config.name,
|
||||
"index": config.index,
|
||||
"address": config.address,
|
||||
"userId": config.userId,
|
||||
"username": config.username,
|
||||
"token": config.token,
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,10 +11,14 @@ class PlayerHandler {
|
|||
private static var player: AudioPlayer?
|
||||
private static var session: PlaybackSession?
|
||||
|
||||
public static func startPlayback(session: PlaybackSession) {
|
||||
public static func startPlayback(session: PlaybackSession, playWhenReady: Bool) {
|
||||
if player != nil {
|
||||
player?.destroy()
|
||||
player = nil
|
||||
}
|
||||
|
||||
NowPlayingInfo.setSessionMetadata(metadata: NowPlayingMetadata(id: session.id, artworkUrl: "\(Store.serverConfig.address)/api/items/\(String(describing: session.libraryItemId))/cover?token=\(Store.serverConfig.token)", title: session.displayTitle ?? "Unknown title", author: session.displayAuthor, series: nil))
|
||||
self.session = session
|
||||
player = AudioPlayer(playbackSession: session, playWhenReady: playWhenReady)
|
||||
}
|
||||
}
|
||||
|
|
52
ios/App/Shared/util/ApiClient.swift
Normal file
52
ios/App/Shared/util/ApiClient.swift
Normal file
|
@ -0,0 +1,52 @@
|
|||
//
|
||||
// ApiClient.swift
|
||||
// App
|
||||
//
|
||||
// Created by Rasmus Krämer on 13.04.22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Alamofire
|
||||
|
||||
class ApiClient {
|
||||
/*
|
||||
public static func getResource<T: Decodable>(endpoint: String, decodable: T.Type = T.self, callback: ((_ param: DataRequest) -> Void)?) {
|
||||
let headers: HTTPHeaders = [
|
||||
"Authorization": "Bearer \(Store.serverConfig.token)"
|
||||
]
|
||||
|
||||
AF.request("\(Store.serverConfig.address)/\(endpoint)", headers: headers).responseDecodable(of: decodable) { response in
|
||||
// callback(response)
|
||||
debugPrint("Response: \(response)")
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
public static func postResource<T: Decodable>(endpoint: String, parameters: [String: String], decodable: T.Type = T.self, callback: ((_ param: T) -> Void)?) {
|
||||
let headers: HTTPHeaders = [
|
||||
"Authorization": "Bearer \(Store.serverConfig.token)"
|
||||
]
|
||||
|
||||
AF.request("\(Store.serverConfig.address)/\(endpoint)", method: .post, parameters: parameters, encoder: JSONParameterEncoder.default, headers: headers).responseDecodable(of: decodable) { response in
|
||||
switch response.result {
|
||||
case .success(let obj):
|
||||
callback?(obj)
|
||||
case .failure(let error):
|
||||
NSLog("api request to \(endpoint) failed")
|
||||
print(error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static func startPlaybackSession(libraryItemId: String, episodeId: String?, callback: @escaping (_ param: PlaybackSession) -> Void) {
|
||||
var endpoint = "api/items/\(libraryItemId)/play"
|
||||
if episodeId != nil {
|
||||
endpoint += "/\(episodeId!)"
|
||||
}
|
||||
|
||||
ApiClient.postResource(endpoint: endpoint, parameters: [
|
||||
"forceTranscode": "true", // TODO: direct play
|
||||
"mediaPlayer": "AVPlayer",
|
||||
], decodable: PlaybackSession.self, callback: callback)
|
||||
}
|
||||
}
|
|
@ -8,6 +8,8 @@
|
|||
import Foundation
|
||||
import RealmSwift
|
||||
|
||||
extension String: Error {}
|
||||
|
||||
class Database {
|
||||
public static let realmQueue = DispatchQueue(label: "realm-queue")
|
||||
|
||||
|
@ -18,28 +20,64 @@ class Database {
|
|||
}()
|
||||
|
||||
public static func getActiveServerConfigIndex() -> Int {
|
||||
guard let config = instance.objects(ServerConnectionConfig.self).first else {
|
||||
return -1
|
||||
return realmQueue.sync {
|
||||
guard let config = instance.objects(ServerConnectionConfig.self).first else {
|
||||
return -1
|
||||
}
|
||||
return config.index
|
||||
}
|
||||
return config.index
|
||||
}
|
||||
|
||||
public static func setServerConnectionConfig(config: ServerConnectionConfig) {
|
||||
let existing: ServerConnectionConfig? = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: config.id)
|
||||
var refrence: ThreadSafeReference<ServerConnectionConfig>?
|
||||
if config.realm != nil {
|
||||
refrence = ThreadSafeReference(to: config)
|
||||
}
|
||||
|
||||
try! instance.write {
|
||||
if existing != nil {
|
||||
instance.delete(existing!)
|
||||
realmQueue.sync {
|
||||
let existing: ServerConnectionConfig? = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: config.id)
|
||||
|
||||
do {
|
||||
try instance.write {
|
||||
if existing != nil {
|
||||
instance.delete(existing!)
|
||||
}
|
||||
if refrence == nil {
|
||||
instance.add(config)
|
||||
} else {
|
||||
guard let resolved = instance.resolve(refrence!) else {
|
||||
throw "unable to resolve refrence"
|
||||
}
|
||||
|
||||
instance.add(resolved);
|
||||
}
|
||||
}
|
||||
} catch(let exception) {
|
||||
NSLog("failed to save server config")
|
||||
debugPrint(exception)
|
||||
}
|
||||
instance.add(config)
|
||||
}
|
||||
}
|
||||
public static func getServerConnectionConfigs() -> [ServerConnectionConfig] {
|
||||
let configs = instance.objects(ServerConnectionConfig.self)
|
||||
var refrences: [ThreadSafeReference<ServerConnectionConfig>] = []
|
||||
|
||||
if configs.count <= 0 {
|
||||
realmQueue.sync {
|
||||
let configs = instance.objects(ServerConnectionConfig.self)
|
||||
refrences = configs.map { config in
|
||||
return ThreadSafeReference(to: config)
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
let realm = try Realm()
|
||||
|
||||
return refrences.map { refrence in
|
||||
return realm.resolve(refrence)!
|
||||
}
|
||||
} catch(let exception) {
|
||||
NSLog("error while readling configs")
|
||||
debugPrint(exception)
|
||||
return []
|
||||
}
|
||||
return Array(configs)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ struct NowPlayingMetadata {
|
|||
class NowPlayingInfo {
|
||||
private static var nowPlayingInfo: [String: Any] = [:]
|
||||
|
||||
public static func setAudiobook(metadata: NowPlayingMetadata) {
|
||||
public static func setSessionMetadata(metadata: NowPlayingMetadata) {
|
||||
setMetadata(artwork: nil, metadata: nil)
|
||||
|
||||
if !shouldFetchCover(id: metadata.id) || metadata.artworkUrl == nil {
|
||||
|
|
|
@ -9,7 +9,7 @@ import Foundation
|
|||
import RealmSwift
|
||||
|
||||
class Store {
|
||||
private static var _serverConfig: ServerConnectionConfig?
|
||||
@ThreadSafe private static var _serverConfig: ServerConnectionConfig?
|
||||
// ONLY USE REALM IN Database.realmQueue OR ELSE THE APP WILL CRASH
|
||||
public static var serverConfig: ServerConnectionConfig {
|
||||
get {
|
||||
|
@ -25,7 +25,7 @@ class Store {
|
|||
}
|
||||
set(updated) {
|
||||
Database.setServerConnectionConfig(config: updated)
|
||||
_serverConfig = updated
|
||||
_serverConfig = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue