mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-31 15:19:34 +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
|
@ -10,12 +10,16 @@
|
||||||
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
2FAD9763203C412B000D30F8 /* config.xml in Resources */ = {isa = PBXBuildFile; fileRef = 2FAD9762203C412B000D30F8 /* config.xml */; };
|
||||||
3A200C1527D64D7E00CBF02E /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */; };
|
3A200C1527D64D7E00CBF02E /* AudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */; };
|
||||||
3ABF580928059BAE005DFBE5 /* PlaybackSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */; };
|
3ABF580928059BAE005DFBE5 /* PlaybackSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */; };
|
||||||
|
3ABF580B2805A837005DFBE5 /* PlaybackReport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABF580A2805A837005DFBE5 /* PlaybackReport.swift */; };
|
||||||
3ABF618F2804325C0070250E /* PlayerHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABF618E2804325C0070250E /* PlayerHandler.swift */; };
|
3ABF618F2804325C0070250E /* PlayerHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3ABF618E2804325C0070250E /* PlayerHandler.swift */; };
|
||||||
3AD4FCE528043E50006DB301 /* AbsDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCE428043E50006DB301 /* AbsDatabase.swift */; };
|
3AD4FCE528043E50006DB301 /* AbsDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCE428043E50006DB301 /* AbsDatabase.swift */; };
|
||||||
3AD4FCE728043E72006DB301 /* AbsDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCE628043E72006DB301 /* AbsDatabase.m */; };
|
3AD4FCE728043E72006DB301 /* AbsDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCE628043E72006DB301 /* AbsDatabase.m */; };
|
||||||
3AD4FCE928043FD7006DB301 /* ServerConnectionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCE828043FD7006DB301 /* ServerConnectionConfig.swift */; };
|
3AD4FCE928043FD7006DB301 /* ServerConnectionConfig.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCE828043FD7006DB301 /* ServerConnectionConfig.swift */; };
|
||||||
3AD4FCEB280443DD006DB301 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCEA280443DD006DB301 /* Database.swift */; };
|
3AD4FCEB280443DD006DB301 /* Database.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCEA280443DD006DB301 /* Database.swift */; };
|
||||||
3AD4FCED28044E6C006DB301 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCEC28044E6C006DB301 /* Store.swift */; };
|
3AD4FCED28044E6C006DB301 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AD4FCEC28044E6C006DB301 /* Store.swift */; };
|
||||||
|
3AF1970C2806E2590096F747 /* ApiClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF1970B2806E2590096F747 /* ApiClient.swift */; };
|
||||||
|
3AF1970E2806E3CA0096F747 /* AbsAudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AF1970D2806E3CA0096F747 /* AbsAudioPlayer.swift */; };
|
||||||
|
3AF197102806E3DC0096F747 /* AbsAudioPlayer.m in Sources */ = {isa = PBXBuildFile; fileRef = 3AF1970F2806E3DC0096F747 /* AbsAudioPlayer.m */; };
|
||||||
3AFCB5E827EA240D00ECCC05 /* NowPlayingInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AFCB5E727EA240D00ECCC05 /* NowPlayingInfo.swift */; };
|
3AFCB5E827EA240D00ECCC05 /* NowPlayingInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3AFCB5E727EA240D00ECCC05 /* NowPlayingInfo.swift */; };
|
||||||
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
50379B232058CBB4000EE86E /* capacitor.config.json in Resources */ = {isa = PBXBuildFile; fileRef = 50379B222058CBB4000EE86E /* capacitor.config.json */; };
|
||||||
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
504EC3081FED79650016851F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 504EC3071FED79650016851F /* AppDelegate.swift */; };
|
||||||
|
@ -30,12 +34,16 @@
|
||||||
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
2FAD9762203C412B000D30F8 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = config.xml; sourceTree = "<group>"; };
|
||||||
3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = "<group>"; };
|
3A200C1427D64D7E00CBF02E /* AudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayer.swift; sourceTree = "<group>"; };
|
||||||
3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackSession.swift; sourceTree = "<group>"; };
|
3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackSession.swift; sourceTree = "<group>"; };
|
||||||
|
3ABF580A2805A837005DFBE5 /* PlaybackReport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackReport.swift; sourceTree = "<group>"; };
|
||||||
3ABF618E2804325C0070250E /* PlayerHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerHandler.swift; sourceTree = "<group>"; };
|
3ABF618E2804325C0070250E /* PlayerHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlayerHandler.swift; sourceTree = "<group>"; };
|
||||||
3AD4FCE428043E50006DB301 /* AbsDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbsDatabase.swift; sourceTree = "<group>"; };
|
3AD4FCE428043E50006DB301 /* AbsDatabase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbsDatabase.swift; sourceTree = "<group>"; };
|
||||||
3AD4FCE628043E72006DB301 /* AbsDatabase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AbsDatabase.m; sourceTree = "<group>"; };
|
3AD4FCE628043E72006DB301 /* AbsDatabase.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AbsDatabase.m; sourceTree = "<group>"; };
|
||||||
3AD4FCE828043FD7006DB301 /* ServerConnectionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionConfig.swift; sourceTree = "<group>"; };
|
3AD4FCE828043FD7006DB301 /* ServerConnectionConfig.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectionConfig.swift; sourceTree = "<group>"; };
|
||||||
3AD4FCEA280443DD006DB301 /* Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = "<group>"; };
|
3AD4FCEA280443DD006DB301 /* Database.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database.swift; sourceTree = "<group>"; };
|
||||||
3AD4FCEC28044E6C006DB301 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = "<group>"; };
|
3AD4FCEC28044E6C006DB301 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = "<group>"; };
|
||||||
|
3AF1970B2806E2590096F747 /* ApiClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ApiClient.swift; sourceTree = "<group>"; };
|
||||||
|
3AF1970D2806E3CA0096F747 /* AbsAudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AbsAudioPlayer.swift; sourceTree = "<group>"; };
|
||||||
|
3AF1970F2806E3DC0096F747 /* AbsAudioPlayer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AbsAudioPlayer.m; sourceTree = "<group>"; };
|
||||||
3AFCB5E727EA240D00ECCC05 /* NowPlayingInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingInfo.swift; sourceTree = "<group>"; };
|
3AFCB5E727EA240D00ECCC05 /* NowPlayingInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NowPlayingInfo.swift; sourceTree = "<group>"; };
|
||||||
4D8D412C26E187E400BA5F0D /* App-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "App-Bridging-Header.h"; sourceTree = "<group>"; };
|
4D8D412C26E187E400BA5F0D /* App-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "App-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||||
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
50379B222058CBB4000EE86E /* capacitor.config.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = capacitor.config.json; sourceTree = "<group>"; };
|
||||||
|
@ -95,6 +103,8 @@
|
||||||
children = (
|
children = (
|
||||||
3AD4FCE428043E50006DB301 /* AbsDatabase.swift */,
|
3AD4FCE428043E50006DB301 /* AbsDatabase.swift */,
|
||||||
3AD4FCE628043E72006DB301 /* AbsDatabase.m */,
|
3AD4FCE628043E72006DB301 /* AbsDatabase.m */,
|
||||||
|
3AF1970D2806E3CA0096F747 /* AbsAudioPlayer.swift */,
|
||||||
|
3AF1970F2806E3DC0096F747 /* AbsAudioPlayer.m */,
|
||||||
);
|
);
|
||||||
path = plugins;
|
path = plugins;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -104,6 +114,7 @@
|
||||||
children = (
|
children = (
|
||||||
3AD4FCE828043FD7006DB301 /* ServerConnectionConfig.swift */,
|
3AD4FCE828043FD7006DB301 /* ServerConnectionConfig.swift */,
|
||||||
3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */,
|
3ABF580828059BAE005DFBE5 /* PlaybackSession.swift */,
|
||||||
|
3ABF580A2805A837005DFBE5 /* PlaybackReport.swift */,
|
||||||
);
|
);
|
||||||
path = models;
|
path = models;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -114,6 +125,7 @@
|
||||||
3AFCB5E727EA240D00ECCC05 /* NowPlayingInfo.swift */,
|
3AFCB5E727EA240D00ECCC05 /* NowPlayingInfo.swift */,
|
||||||
3AD4FCEA280443DD006DB301 /* Database.swift */,
|
3AD4FCEA280443DD006DB301 /* Database.swift */,
|
||||||
3AD4FCEC28044E6C006DB301 /* Store.swift */,
|
3AD4FCEC28044E6C006DB301 /* Store.swift */,
|
||||||
|
3AF1970B2806E2590096F747 /* ApiClient.swift */,
|
||||||
);
|
);
|
||||||
path = util;
|
path = util;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
|
@ -281,11 +293,15 @@
|
||||||
3ABF580928059BAE005DFBE5 /* PlaybackSession.swift in Sources */,
|
3ABF580928059BAE005DFBE5 /* PlaybackSession.swift in Sources */,
|
||||||
3ABF618F2804325C0070250E /* PlayerHandler.swift in Sources */,
|
3ABF618F2804325C0070250E /* PlayerHandler.swift in Sources */,
|
||||||
3AD4FCED28044E6C006DB301 /* Store.swift in Sources */,
|
3AD4FCED28044E6C006DB301 /* Store.swift in Sources */,
|
||||||
|
3ABF580B2805A837005DFBE5 /* PlaybackReport.swift in Sources */,
|
||||||
|
3AF1970E2806E3CA0096F747 /* AbsAudioPlayer.swift in Sources */,
|
||||||
3AD4FCE928043FD7006DB301 /* ServerConnectionConfig.swift in Sources */,
|
3AD4FCE928043FD7006DB301 /* ServerConnectionConfig.swift in Sources */,
|
||||||
3A200C1527D64D7E00CBF02E /* AudioPlayer.swift in Sources */,
|
3A200C1527D64D7E00CBF02E /* AudioPlayer.swift in Sources */,
|
||||||
3AFCB5E827EA240D00ECCC05 /* NowPlayingInfo.swift in Sources */,
|
3AFCB5E827EA240D00ECCC05 /* NowPlayingInfo.swift in Sources */,
|
||||||
3AD4FCEB280443DD006DB301 /* Database.swift in Sources */,
|
3AD4FCEB280443DD006DB301 /* Database.swift in Sources */,
|
||||||
3AD4FCE528043E50006DB301 /* AbsDatabase.swift in Sources */,
|
3AD4FCE528043E50006DB301 /* AbsDatabase.swift in Sources */,
|
||||||
|
3AF197102806E3DC0096F747 /* AbsAudioPlayer.m in Sources */,
|
||||||
|
3AF1970C2806E2590096F747 /* ApiClient.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
|
|
14
ios/App/App/plugins/AbsAudioPlayer.m
Normal file
14
ios/App/App/plugins/AbsAudioPlayer.m
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//
|
||||||
|
// AbsAudioPlayer.m
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
// Created by Rasmus Krämer on 13.04.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <Capacitor/Capacitor.h>
|
||||||
|
|
||||||
|
CAP_PLUGIN(AbsAudioPlayer, "AbsAudioPlayer",
|
||||||
|
CAP_PLUGIN_METHOD(prepareLibraryItem, CAPPluginReturnPromise);
|
||||||
|
)
|
||||||
|
|
32
ios/App/App/plugins/AbsAudioPlayer.swift
Normal file
32
ios/App/App/plugins/AbsAudioPlayer.swift
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
//
|
||||||
|
// AbsAudioPlayer.swift
|
||||||
|
// App
|
||||||
|
//
|
||||||
|
// Created by Rasmus Krämer on 13.04.22.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import Capacitor
|
||||||
|
|
||||||
|
@objc(AbsAudioPlayer)
|
||||||
|
public class AbsAudioPlayer: CAPPlugin {
|
||||||
|
@objc func prepareLibraryItem(_ call: CAPPluginCall) {
|
||||||
|
let libraryItemId = call.getString("libraryItemId")
|
||||||
|
let episodeId = call.getString("episodeId")
|
||||||
|
let playWhenReady = call.getBool("playWhenReady", true)
|
||||||
|
|
||||||
|
if libraryItemId == nil {
|
||||||
|
NSLog("provide library item id")
|
||||||
|
return call.resolve()
|
||||||
|
}
|
||||||
|
if libraryItemId!.starts(with: "local") {
|
||||||
|
NSLog("local items are not implemnted")
|
||||||
|
return call.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
ApiClient.startPlaybackSession(libraryItemId: libraryItemId!, episodeId: episodeId) { session in
|
||||||
|
NSLog(OperationQueue.current)
|
||||||
|
PlayerHandler.startPlayback(session: session, playWhenReady: playWhenReady)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,47 +28,43 @@ extension String {
|
||||||
@objc(AbsDatabase)
|
@objc(AbsDatabase)
|
||||||
public class AbsDatabase: CAPPlugin {
|
public class AbsDatabase: CAPPlugin {
|
||||||
@objc func setCurrentServerConnectionConfig(_ call: CAPPluginCall) {
|
@objc func setCurrentServerConnectionConfig(_ call: CAPPluginCall) {
|
||||||
Database.realmQueue.sync {
|
var id = call.getString("id")
|
||||||
var id = call.getString("id")
|
let address = call.getString("address", "")
|
||||||
let address = call.getString("address", "")
|
let userId = call.getString("userId", "")
|
||||||
let userId = call.getString("userId", "")
|
let username = call.getString("username", "")
|
||||||
let username = call.getString("username", "")
|
let token = call.getString("token", "")
|
||||||
let token = call.getString("token", "")
|
|
||||||
|
let name = "\(address) (\(username))"
|
||||||
let name = "\(address) (\(username))"
|
let config = ServerConnectionConfig()
|
||||||
let config = ServerConnectionConfig()
|
|
||||||
|
if id == nil {
|
||||||
if id == nil {
|
id = "\(address)@\(username)".toBase64()
|
||||||
id = "\(address)@\(username)".toBase64()
|
|
||||||
}
|
|
||||||
|
|
||||||
config.id = id!
|
|
||||||
config.name = name
|
|
||||||
config.address = address
|
|
||||||
config.userId = userId
|
|
||||||
config.username = username
|
|
||||||
config.token = token
|
|
||||||
|
|
||||||
Store.serverConfig = config
|
|
||||||
call.resolve(convertServerConnectionConfigToJSON(config: config))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config.id = id!
|
||||||
|
config.name = name
|
||||||
|
config.address = address
|
||||||
|
config.userId = userId
|
||||||
|
config.username = username
|
||||||
|
config.token = token
|
||||||
|
|
||||||
|
Store.serverConfig = config
|
||||||
|
call.resolve(convertServerConnectionConfigToJSON(config: config))
|
||||||
}
|
}
|
||||||
@objc func getDeviceData(_ call: CAPPluginCall) {
|
@objc func getDeviceData(_ call: CAPPluginCall) {
|
||||||
Database.realmQueue.sync {
|
let configs = Database.getServerConnectionConfigs()
|
||||||
let configs = Database.getServerConnectionConfigs()
|
let index = Database.getActiveServerConfigIndex()
|
||||||
let index = Database.getActiveServerConfigIndex()
|
|
||||||
|
call.resolve([
|
||||||
call.resolve([
|
"serverConnectionConfigs": configs.map { config in
|
||||||
"serverConnectionConfigs": configs.map { config in
|
return convertServerConnectionConfigToJSON(config: config)
|
||||||
return convertServerConnectionConfigToJSON(config: config)
|
},
|
||||||
},
|
"lastServerConnectionConfigId": index < 0 ? -1 : configs.first(where: {
|
||||||
"lastServerConnectionConfigId": index < 0 ? -1 : configs.first(where: {
|
(config: ServerConnectionConfig) -> Bool in
|
||||||
(config: ServerConnectionConfig) -> Bool in
|
return config.index == index
|
||||||
return config.index == index
|
})!.id,
|
||||||
})!.id,
|
"currentLocalPlaybackSession": nil, // Luckily this isn't implemented yet
|
||||||
"currentLocalPlaybackSession": nil, // Luckily this isn't implemented yet
|
])
|
||||||
])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to send a empty array or the client will break
|
// We have to send a empty array or the client will break
|
||||||
|
|
|
@ -23,4 +23,5 @@ target 'App' do
|
||||||
# Add your Pods here
|
# Add your Pods here
|
||||||
|
|
||||||
pod 'RealmSwift', '~>10'
|
pod 'RealmSwift', '~>10'
|
||||||
|
pod 'Alamofire', '~> 5.5'
|
||||||
end
|
end
|
||||||
|
|
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
|
import Foundation
|
||||||
|
|
||||||
struct PlaybackSession {
|
struct PlaybackSession: Decodable {
|
||||||
var id: String
|
var id: String
|
||||||
var userId: String?
|
var userId: String?
|
||||||
var libraryItemId: String?
|
var libraryItemId: String?
|
||||||
|
@ -20,8 +20,8 @@ struct PlaybackSession {
|
||||||
var coverPath: String?
|
var coverPath: String?
|
||||||
var duration: Double
|
var duration: Double
|
||||||
var playMethod: Int
|
var playMethod: Int
|
||||||
var startedAt: Double
|
var startedAt: Double?
|
||||||
var updatedAt: Double
|
var updatedAt: Double?
|
||||||
var timeListening: Double
|
var timeListening: Double
|
||||||
var audioTracks: [AudioTrack]
|
var audioTracks: [AudioTrack]
|
||||||
var currentTime: Double
|
var currentTime: Double
|
||||||
|
@ -30,14 +30,14 @@ struct PlaybackSession {
|
||||||
var serverConnectionConfigId: String?
|
var serverConnectionConfigId: String?
|
||||||
var serverAddress: String?
|
var serverAddress: String?
|
||||||
}
|
}
|
||||||
struct Chapter {
|
struct Chapter: Decodable {
|
||||||
var id: Int
|
var id: Int
|
||||||
var start: Double
|
var start: Double
|
||||||
var end: Double
|
var end: Double
|
||||||
var title: String?
|
var title: String?
|
||||||
}
|
}
|
||||||
struct AudioTrack {
|
struct AudioTrack: Decodable {
|
||||||
var index: Int
|
var index: Int?
|
||||||
var startOffset: Double
|
var startOffset: Double
|
||||||
var duration: Double
|
var duration: Double
|
||||||
var title: String
|
var title: String
|
||||||
|
@ -46,10 +46,10 @@ struct AudioTrack {
|
||||||
var metadata: FileMetadata?
|
var metadata: FileMetadata?
|
||||||
// var isLocal: Bool
|
// var isLocal: Bool
|
||||||
// var localFileId: String?
|
// var localFileId: String?
|
||||||
// var audioProbeResult: AudioProbeResult? Need for local playback
|
// var audioProbeResult: AudioProbeResult? Needed for local playback
|
||||||
var serverIndex: Int?
|
var serverIndex: Int?
|
||||||
}
|
}
|
||||||
struct FileMetadata {
|
struct FileMetadata: Decodable {
|
||||||
var filename: String
|
var filename: String
|
||||||
var ext: String
|
var ext: String
|
||||||
var path: String
|
var path: String
|
||||||
|
|
|
@ -19,13 +19,15 @@ class ServerConnectionConfig: Object {
|
||||||
}
|
}
|
||||||
|
|
||||||
func convertServerConnectionConfigToJSON(config: ServerConnectionConfig) -> Dictionary<String, Any> {
|
func convertServerConnectionConfigToJSON(config: ServerConnectionConfig) -> Dictionary<String, Any> {
|
||||||
return [
|
return Database.realmQueue.sync {
|
||||||
"id": config.id,
|
return [
|
||||||
"name": config.name,
|
"id": config.id,
|
||||||
"index": config.index,
|
"name": config.name,
|
||||||
"address": config.address,
|
"index": config.index,
|
||||||
"userId": config.userId,
|
"address": config.address,
|
||||||
"username": config.username,
|
"userId": config.userId,
|
||||||
"token": config.token,
|
"username": config.username,
|
||||||
]
|
"token": config.token,
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,10 +11,14 @@ class PlayerHandler {
|
||||||
private static var player: AudioPlayer?
|
private static var player: AudioPlayer?
|
||||||
private static var session: PlaybackSession?
|
private static var session: PlaybackSession?
|
||||||
|
|
||||||
public static func startPlayback(session: PlaybackSession) {
|
public static func startPlayback(session: PlaybackSession, playWhenReady: Bool) {
|
||||||
if player != nil {
|
if player != nil {
|
||||||
player?.destroy()
|
player?.destroy()
|
||||||
player = nil
|
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 Foundation
|
||||||
import RealmSwift
|
import RealmSwift
|
||||||
|
|
||||||
|
extension String: Error {}
|
||||||
|
|
||||||
class Database {
|
class Database {
|
||||||
public static let realmQueue = DispatchQueue(label: "realm-queue")
|
public static let realmQueue = DispatchQueue(label: "realm-queue")
|
||||||
|
|
||||||
|
@ -18,28 +20,64 @@ class Database {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
public static func getActiveServerConfigIndex() -> Int {
|
public static func getActiveServerConfigIndex() -> Int {
|
||||||
guard let config = instance.objects(ServerConnectionConfig.self).first else {
|
return realmQueue.sync {
|
||||||
return -1
|
guard let config = instance.objects(ServerConnectionConfig.self).first else {
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return config.index
|
||||||
}
|
}
|
||||||
return config.index
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func setServerConnectionConfig(config: ServerConnectionConfig) {
|
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 {
|
realmQueue.sync {
|
||||||
if existing != nil {
|
let existing: ServerConnectionConfig? = instance.object(ofType: ServerConnectionConfig.self, forPrimaryKey: config.id)
|
||||||
instance.delete(existing!)
|
|
||||||
|
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] {
|
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 []
|
||||||
}
|
}
|
||||||
return Array(configs)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ struct NowPlayingMetadata {
|
||||||
class NowPlayingInfo {
|
class NowPlayingInfo {
|
||||||
private static var nowPlayingInfo: [String: Any] = [:]
|
private static var nowPlayingInfo: [String: Any] = [:]
|
||||||
|
|
||||||
public static func setAudiobook(metadata: NowPlayingMetadata) {
|
public static func setSessionMetadata(metadata: NowPlayingMetadata) {
|
||||||
setMetadata(artwork: nil, metadata: nil)
|
setMetadata(artwork: nil, metadata: nil)
|
||||||
|
|
||||||
if !shouldFetchCover(id: metadata.id) || metadata.artworkUrl == nil {
|
if !shouldFetchCover(id: metadata.id) || metadata.artworkUrl == nil {
|
||||||
|
|
|
@ -9,7 +9,7 @@ import Foundation
|
||||||
import RealmSwift
|
import RealmSwift
|
||||||
|
|
||||||
class Store {
|
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
|
// ONLY USE REALM IN Database.realmQueue OR ELSE THE APP WILL CRASH
|
||||||
public static var serverConfig: ServerConnectionConfig {
|
public static var serverConfig: ServerConnectionConfig {
|
||||||
get {
|
get {
|
||||||
|
@ -25,7 +25,7 @@ class Store {
|
||||||
}
|
}
|
||||||
set(updated) {
|
set(updated) {
|
||||||
Database.setServerConnectionConfig(config: updated)
|
Database.setServerConnectionConfig(config: updated)
|
||||||
_serverConfig = updated
|
_serverConfig = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
16
package-lock.json
generated
16
package-lock.json
generated
|
@ -26,7 +26,8 @@
|
||||||
"libarchive.js": "^1.3.0",
|
"libarchive.js": "^1.3.0",
|
||||||
"nuxt": "^2.15.7",
|
"nuxt": "^2.15.7",
|
||||||
"socket.io-client": "^4.1.3",
|
"socket.io-client": "^4.1.3",
|
||||||
"vue-toastification": "^1.7.11"
|
"vue-toastification": "^1.7.11",
|
||||||
|
"vuedraggable": "^2.24.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "7.13.15",
|
"@babel/core": "7.13.15",
|
||||||
|
@ -15482,6 +15483,11 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sortablejs": {
|
||||||
|
"version": "1.10.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.10.2.tgz",
|
||||||
|
"integrity": "sha512-YkPGufevysvfwn5rfdlGyrGjt7/CRHwvRPogD/lC+TnvcN29jDpCifKP+rBqf+LRldfXSTh+0CGLcSg0VIxq3A=="
|
||||||
|
},
|
||||||
"node_modules/source-list-map": {
|
"node_modules/source-list-map": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz",
|
||||||
|
@ -17325,6 +17331,14 @@
|
||||||
"vue": "^2.0.0"
|
"vue": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vuedraggable": {
|
||||||
|
"version": "2.24.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/vuedraggable/-/vuedraggable-2.24.3.tgz",
|
||||||
|
"integrity": "sha512-6/HDXi92GzB+Hcs9fC6PAAozK1RLt1ewPTLjK0anTYguXLAeySDmcnqE8IC0xa7shvSzRjQXq3/+dsZ7ETGF3g==",
|
||||||
|
"dependencies": {
|
||||||
|
"sortablejs": "1.10.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vuex": {
|
"node_modules/vuex": {
|
||||||
"version": "3.6.2",
|
"version": "3.6.2",
|
||||||
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/vuex/-/vuex-3.6.2.tgz",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue