diff --git a/ios/App/Shared/player/AudioPlayer.swift b/ios/App/Shared/player/AudioPlayer.swift index e46b0da7..ae1e5db2 100644 --- a/ios/App/Shared/player/AudioPlayer.swift +++ b/ios/App/Shared/player/AudioPlayer.swift @@ -561,8 +561,15 @@ class AudioPlayer: NSObject { guard let playbackSession = self.getPlaybackSession() else { return nil } if (playbackSession.playMethod == PlayMethod.directplay.rawValue) { - let urlstr = "\(Store.serverConfig!.address)/api/items/\(itemId)/file/\(ino)?token=\(Store.serverConfig!.token)" - let url = URL(string: urlstr)! + // As of v2.22.0 tracks use a different endpoint + // See: https://github.com/advplyr/audiobookshelf/pull/4263 + let contentUrl: String + if Store.isServerVersionGreaterThanOrEqualTo("2.22.0") { + contentUrl = "\(Store.serverConfig!.address)/public/session/\(playbackSession.id)/track/\(track.index ?? 1)" + } else { + contentUrl = "\(Store.serverConfig!.address)/api/items/\(itemId)/file/\(ino)?token=\(Store.serverConfig!.token)" + } + let url = URL(string: contentUrl)! return AVURLAsset(url: url) } else if (playbackSession.playMethod == PlayMethod.local.rawValue) { guard let localFile = track.getLocalFile() else { @@ -577,7 +584,9 @@ class AudioPlayer: NSObject { let headers: [String: String] = [ "Authorization": "Bearer \(Store.serverConfig!.token)" ] - return AVURLAsset(url: URL(string: "\(Store.serverConfig!.address)\(track.contentUrl ?? "")")!, options: ["AVURLAssetHTTPHeaderFieldsKey": headers]) + + let contentUrl = "\(Store.serverConfig!.address)\(track.contentUrl ?? "")" + return AVURLAsset(url: URL(string: contentUrl)!, options: ["AVURLAssetHTTPHeaderFieldsKey": headers]) } } diff --git a/ios/App/Shared/util/NowPlayingInfo.swift b/ios/App/Shared/util/NowPlayingInfo.swift index 69443fbe..5369cbca 100644 --- a/ios/App/Shared/util/NowPlayingInfo.swift +++ b/ios/App/Shared/util/NowPlayingInfo.swift @@ -22,8 +22,16 @@ struct NowPlayingMetadata { return item.coverUrl } else { guard let config = Store.serverConfig else { return nil } - guard let url = URL(string: "\(config.address)/api/items/\(itemId)/cover?token=\(config.token)") else { return nil } - return url + + // As of v2.17.0 token is not needed with cover image requests + let coverUrlString: String + if Store.isServerVersionGreaterThanOrEqualTo("2.17.0") { + coverUrlString = "\(config.address)/api/items/\(itemId)/cover" + } else { + coverUrlString = "\(config.address)/api/items/\(itemId)/cover?token=\(config.token)" + } + + return URL(string: coverUrlString) } } } diff --git a/ios/App/Shared/util/Store.swift b/ios/App/Shared/util/Store.swift index 6073f2d7..b0b991d1 100644 --- a/ios/App/Shared/util/Store.swift +++ b/ios/App/Shared/util/Store.swift @@ -29,4 +29,46 @@ class Store { } } } + + /** + * Check if the currently connected server version is >= compareVersion + * Abs server only uses major.minor.patch + * Note: Version is returned in Abs auth payloads starting v2.6.0 + * Note: Version is saved with the server connection config starting after v0.9.81 + * + * @example + * serverVersion=2.25.1 + * isServerVersionGreaterThanOrEqualTo("2.26.0") = false + * + * serverVersion=2.26.1 + * isServerVersionGreaterThanOrEqualTo("2.26.0") = true + */ + public static func isServerVersionGreaterThanOrEqualTo(_ compareVersion: String) -> Bool { + guard let serverConfig = serverConfig, !serverConfig.version.isEmpty else { + return false + } + + if compareVersion.isEmpty { + return true + } + + let serverVersionParts = serverConfig.version.split(separator: ".").compactMap { Int($0) } + let compareVersionParts = compareVersion.split(separator: ".").compactMap { Int($0) } + + // Compare major, minor, and patch components + let maxLength = max(serverVersionParts.count, compareVersionParts.count) + + for i in 0.. compareVersionComponent { + return true // Server version is greater than compareVersion + } + } + + return true // versions are equal in major, minor, and patch + } }