mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-04 18:15:01 +02:00
Update:iOS using new sync local sessions endpoint
- remove local session sync function call on starting playback - Add User model and getCurrentUser api function
This commit is contained in:
parent
ff5a1bb09f
commit
36be91962c
12 changed files with 128 additions and 97 deletions
41
ios/App/Shared/models/server/User.swift
Normal file
41
ios/App/Shared/models/server/User.swift
Normal file
|
@ -0,0 +1,41 @@
|
|||
//
|
||||
// User.swift
|
||||
// Audiobookshelf
|
||||
//
|
||||
// Created by advplyr on 11/12/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import RealmSwift
|
||||
|
||||
class User: EmbeddedObject, Codable {
|
||||
@Persisted var id: String = ""
|
||||
@Persisted var username: String = ""
|
||||
@Persisted var mediaProgress = List<MediaProgress>()
|
||||
|
||||
private enum CodingKeys : String, CodingKey {
|
||||
case id, username, mediaProgress
|
||||
}
|
||||
|
||||
override init() {
|
||||
super.init()
|
||||
}
|
||||
|
||||
required init(from decoder: Decoder) throws {
|
||||
super.init()
|
||||
|
||||
let values = try decoder.container(keyedBy: CodingKeys.self)
|
||||
id = try values.decode(String.self, forKey: .id)
|
||||
username = try values.decode(String.self, forKey: .username)
|
||||
if let progresses = try? values.decode([MediaProgress].self, forKey: .mediaProgress) {
|
||||
mediaProgress.append(objectsIn: progresses)
|
||||
}
|
||||
}
|
||||
|
||||
func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(id, forKey: .id)
|
||||
try container.encode(username, forKey: .username)
|
||||
try container.encode(Array(mediaProgress), forKey: .mediaProgress)
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@ class PlayerHandler {
|
|||
|
||||
// Cleanup and sync old sessions
|
||||
cleanupOldSessions(currentSessionId: sessionId)
|
||||
Task { await PlayerProgress.shared.syncToServer() }
|
||||
|
||||
// Set now playing info
|
||||
NowPlayingInfo.shared.setSessionMetadata(metadata: NowPlayingMetadata(id: session.id, itemId: session.libraryItemId!, title: session.displayTitle ?? "Unknown title", author: session.displayAuthor, series: nil))
|
||||
|
|
|
@ -36,17 +36,6 @@ class PlayerProgress {
|
|||
await UIApplication.shared.endBackgroundTask(backgroundToken)
|
||||
}
|
||||
|
||||
public func syncToServer() async {
|
||||
let backgroundToken = await UIApplication.shared.beginBackgroundTask(withName: "ABS:syncToServer")
|
||||
do {
|
||||
try await updateAllServerSessionFromLocalSession()
|
||||
} catch {
|
||||
logger.error("Failed to syncToServer")
|
||||
logger.error(error)
|
||||
}
|
||||
await UIApplication.shared.endBackgroundTask(backgroundToken)
|
||||
}
|
||||
|
||||
public func syncFromServer() async {
|
||||
let backgroundToken = await UIApplication.shared.beginBackgroundTask(withName: "ABS:syncFromServer")
|
||||
do {
|
||||
|
|
|
@ -189,34 +189,62 @@ class ApiClient {
|
|||
return await postResource(endpoint: "api/session/local", parameters: session)
|
||||
}
|
||||
|
||||
public static func syncMediaProgress(callback: @escaping (_ results: LocalMediaProgressSyncResultsPayload) -> Void) {
|
||||
let localMediaProgressList = Database.shared.getAllLocalMediaProgress().filter {
|
||||
$0.serverConnectionConfigId == Store.serverConfig?.id
|
||||
}.map { $0.freeze() }
|
||||
|
||||
if ( !localMediaProgressList.isEmpty ) {
|
||||
let payload = LocalMediaProgressSyncPayload(localMediaProgress: localMediaProgressList)
|
||||
logger.log("Sending sync local progress request with \(localMediaProgressList.count) progress items")
|
||||
postResource(endpoint: "api/me/sync-local-progress", parameters: payload, decodable: MediaProgressSyncResponsePayload.self) { response in
|
||||
let resultsPayload = LocalMediaProgressSyncResultsPayload(numLocalMediaProgressForServer: localMediaProgressList.count, numServerProgressUpdates: response.numServerProgressUpdates, numLocalProgressUpdates: response.localProgressUpdates?.count)
|
||||
logger.log("Media Progress Sync | \(String(describing: try? resultsPayload.asDictionary()))")
|
||||
|
||||
if let updates = response.localProgressUpdates {
|
||||
for update in updates {
|
||||
do {
|
||||
try update.save()
|
||||
} catch {
|
||||
debugPrint("Failed to update local media progress")
|
||||
debugPrint(error)
|
||||
public static func reportAllLocalPlaybackSessions(_ sessions: [PlaybackSession]) async -> Bool {
|
||||
return await postResource(endpoint: "api/session/local-all", parameters: LocalPlaybackSessionSyncAllPayload(sessions: sessions))
|
||||
}
|
||||
|
||||
public static func syncLocalSessionsWithServer() async {
|
||||
do {
|
||||
// Sync server progress with local media progress
|
||||
let localMediaProgressList = Database.shared.getAllLocalMediaProgress().filter {
|
||||
$0.serverConnectionConfigId == Store.serverConfig?.id
|
||||
}.map { $0.freeze() }
|
||||
logger.log("syncLocalSessionsWithServer: Found \(localMediaProgressList.count) local media progress for server")
|
||||
|
||||
if (localMediaProgressList.isEmpty) {
|
||||
logger.log("syncLocalSessionsWithServer: No local progress to sync")
|
||||
} else {
|
||||
let currentUser = await ApiClient.getCurrentUser()
|
||||
guard let currentUser = currentUser else {
|
||||
logger.log("syncLocalSessionsWithServer: No User")
|
||||
return
|
||||
}
|
||||
try currentUser.mediaProgress.forEach { mediaProgress in
|
||||
let localMediaProgress = localMediaProgressList.first { lmp in
|
||||
if (lmp.episodeId != nil) {
|
||||
return lmp.episodeId == mediaProgress.episodeId
|
||||
} else {
|
||||
return lmp.libraryItemId == mediaProgress.libraryItemId
|
||||
}
|
||||
}
|
||||
if (localMediaProgress != nil && mediaProgress.lastUpdate > localMediaProgress!.lastUpdate) {
|
||||
logger.log("syncLocalSessionsWithServer: Updating local media progress \(localMediaProgress!.id) with server media progress")
|
||||
try localMediaProgress?.updateFromServerMediaProgress(mediaProgress)
|
||||
} else if (localMediaProgress != nil) {
|
||||
logger.log("syncLocalSessionsWithServer: Local progress for \(localMediaProgress!.id) is more recent then server progress")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Send saved playback sessions to server and remove them from db
|
||||
let playbackSessions = Database.shared.getAllPlaybackSessions().filter {
|
||||
$0.serverConnectionConfigId == Store.serverConfig?.id
|
||||
}.map { $0.freeze() }
|
||||
logger.log("syncLocalSessionsWithServer: Found \(playbackSessions.count) playback sessions for server")
|
||||
if (!playbackSessions.isEmpty) {
|
||||
let success = await ApiClient.reportAllLocalPlaybackSessions(playbackSessions)
|
||||
if (success) {
|
||||
// Remove sessions from db
|
||||
try playbackSessions.forEach { session in
|
||||
if let session = session.thaw() {
|
||||
try session.delete()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
callback(resultsPayload)
|
||||
}
|
||||
} else {
|
||||
logger.log("No local media progress to sync")
|
||||
callback(LocalMediaProgressSyncResultsPayload(numLocalMediaProgressForServer: 0, numServerProgressUpdates: 0, numLocalProgressUpdates: 0))
|
||||
} catch {
|
||||
debugPrint(error)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -234,6 +262,11 @@ class ApiClient {
|
|||
return await getResource(endpoint: endpoint, decodable: MediaProgress.self)
|
||||
}
|
||||
|
||||
public static func getCurrentUser() async -> User? {
|
||||
logger.log("getCurrentUser")
|
||||
return await getResource(endpoint: "api/me", decodable: User.self)
|
||||
}
|
||||
|
||||
public static func getLibraryItemWithProgress(libraryItemId:String, episodeId:String?, callback: @escaping (_ param: LibraryItem?) -> Void) {
|
||||
var endpoint = "api/items/\(libraryItemId)?expanded=1&include=progress"
|
||||
if episodeId != nil {
|
||||
|
@ -287,6 +320,10 @@ struct LocalMediaProgressSyncResultsPayload: Codable {
|
|||
var numLocalProgressUpdates: Int?
|
||||
}
|
||||
|
||||
struct LocalPlaybackSessionSyncAllPayload: Codable {
|
||||
var sessions: [PlaybackSession]
|
||||
}
|
||||
|
||||
struct Connectivity {
|
||||
static private let sharedInstance = NetworkReachabilityManager()!
|
||||
static var isConnectedToInternet:Bool {
|
||||
|
|
|
@ -241,6 +241,16 @@ class Database {
|
|||
}
|
||||
}
|
||||
|
||||
public func getAllPlaybackSessions() -> [PlaybackSession] {
|
||||
do {
|
||||
let realm = try Realm()
|
||||
return Array(realm.objects(PlaybackSession.self))
|
||||
} catch {
|
||||
debugPrint(error)
|
||||
return []
|
||||
}
|
||||
}
|
||||
|
||||
public func getPlaybackSession(id: String) -> PlaybackSession? {
|
||||
do {
|
||||
let realm = try Realm()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue