2023-12-12 06:22:43 +00:00
|
|
|
//
|
|
|
|
// JellyfinClientController.swift
|
|
|
|
// Jel
|
|
|
|
//
|
|
|
|
// Created by zerocool on 12/12/23.
|
|
|
|
//
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
import Get
|
|
|
|
import JellyfinKit
|
2023-12-13 00:51:54 +00:00
|
|
|
import Pulse
|
2023-12-12 06:22:43 +00:00
|
|
|
|
2023-12-12 22:09:15 +00:00
|
|
|
struct AuthHeaders: Codable {
|
|
|
|
var Client: String
|
|
|
|
var Device: String
|
|
|
|
var DeviceId: String
|
|
|
|
var Version: String
|
|
|
|
var Token: String
|
|
|
|
}
|
|
|
|
|
|
|
|
enum JellyfinClientError: Error {
|
|
|
|
case badResponseCode
|
|
|
|
}
|
|
|
|
|
|
|
|
extension AuthHeaders {
|
|
|
|
func format() -> String {
|
|
|
|
return "MediaBrowser Client=\(self.Client), Device=\(self.Device), DeviceId=\(self.DeviceId), Version=\(self.Version), Token=\(self.Token)"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class JellyfinClientController: ObservableObject {
|
|
|
|
private var api: APIClient
|
|
|
|
|
|
|
|
private var authHeaders: AuthHeaders
|
|
|
|
private var authState: AuthStateController
|
2023-12-12 06:22:43 +00:00
|
|
|
|
2023-12-12 22:09:15 +00:00
|
|
|
init(authHeaders: AuthHeaders, serverUrl: URL? = nil, authState: AuthStateController = AuthStateController.shared) {
|
|
|
|
self.authHeaders = authHeaders
|
|
|
|
self.authState = authState
|
|
|
|
|
|
|
|
self.api = APIClient(baseURL: serverUrl)
|
|
|
|
self.setUrl(url: serverUrl)
|
2023-12-22 22:14:21 +00:00
|
|
|
|
|
|
|
self.setToken(token: self.authState.authToken ?? "")
|
2023-12-12 22:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func setToken(token: String) {
|
|
|
|
self.authHeaders.Token = token
|
2023-12-22 22:14:21 +00:00
|
|
|
self.setUrl(url: self.authState.serverUrl)
|
2023-12-12 22:09:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func setUrl(url: URL?) {
|
|
|
|
if url == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
self.api = APIClient(baseURL: url, {
|
|
|
|
$0.sessionConfiguration.httpAdditionalHeaders = ["Authorization": self.authHeaders.format()]
|
|
|
|
|
|
|
|
let decoder = JSONDecoder()
|
|
|
|
decoder.dateDecodingStrategy = .iso8601withFractionalSeconds
|
|
|
|
$0.decoder = decoder
|
2023-12-13 00:51:54 +00:00
|
|
|
|
|
|
|
$0.sessionDelegate = Pulse.URLSessionProxyDelegate()
|
2023-12-12 22:09:15 +00:00
|
|
|
})
|
2023-12-12 06:22:43 +00:00
|
|
|
}
|
|
|
|
|
2023-12-22 22:14:21 +00:00
|
|
|
func getUrl() -> URL? {
|
|
|
|
return self.api.configuration.baseURL
|
|
|
|
}
|
|
|
|
|
2023-12-15 16:06:36 +00:00
|
|
|
@discardableResult func send<T>(
|
|
|
|
_ request: Request<T>,
|
|
|
|
delegate: URLSessionDataDelegate? = nil,
|
|
|
|
configure: ((inout URLRequest) throws -> Void)? = nil
|
|
|
|
) async throws -> Response<T> where T : Decodable {
|
|
|
|
return try await self.api.send(request, delegate: delegate, configure: configure)
|
|
|
|
}
|
|
|
|
|
|
|
|
@discardableResult func send(
|
|
|
|
_ request: Request<Void>,
|
|
|
|
delegate: URLSessionDataDelegate? = nil,
|
|
|
|
configure: ((inout URLRequest) throws -> Void)? = nil
|
|
|
|
) async throws -> Response<Void> {
|
|
|
|
return try await self.api.send(request, delegate: delegate, configure: configure)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
extension JellyfinClientController {
|
2023-12-15 15:41:00 +00:00
|
|
|
func getPublicServerInfo() async -> PublicSystemInfo? {
|
2023-12-12 22:12:58 +00:00
|
|
|
let request = Paths.getPublicSystemInfo
|
2023-12-12 06:22:43 +00:00
|
|
|
do {
|
2023-12-12 22:09:15 +00:00
|
|
|
let res = try await api.send(request)
|
|
|
|
if res.statusCode != 200 {
|
|
|
|
throw JellyfinClientError.badResponseCode
|
|
|
|
}
|
2023-12-15 15:41:00 +00:00
|
|
|
|
|
|
|
return res.value
|
2023-12-12 06:22:43 +00:00
|
|
|
} catch {
|
2023-12-15 15:41:00 +00:00
|
|
|
return nil
|
2023-12-12 06:22:43 +00:00
|
|
|
}
|
|
|
|
}
|
2023-12-12 22:09:15 +00:00
|
|
|
|
|
|
|
func signIn(username: String, pw: String) async throws {
|
|
|
|
let request = Paths.authenticateUserByName(AuthenticateUserByName(pw: pw, username: username))
|
|
|
|
let res = try await self.api.send(request)
|
2023-12-15 15:41:00 +00:00
|
|
|
DispatchQueue.main.async {
|
|
|
|
self.authState.loggedIn = true
|
|
|
|
self.authState.authToken = res.value.accessToken
|
2023-12-22 22:14:21 +00:00
|
|
|
self.authState.userId = res.value.user?.id
|
2024-01-07 21:58:38 +00:00
|
|
|
self.authState.username = username
|
2023-12-15 15:41:00 +00:00
|
|
|
self.authState.save()
|
2023-12-22 22:14:21 +00:00
|
|
|
|
|
|
|
self.setToken(token: self.authState.authToken ?? "")
|
2023-12-15 15:41:00 +00:00
|
|
|
}
|
2023-12-12 22:09:15 +00:00
|
|
|
}
|
2023-12-25 05:41:45 +00:00
|
|
|
|
|
|
|
func search(parameters: Paths.GetParameters) async -> SearchHintResult? {
|
|
|
|
let request = Paths.get(parameters: parameters)
|
|
|
|
do {
|
|
|
|
let res = try await self.api.send(request)
|
|
|
|
return res.value
|
|
|
|
} catch {
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2023-12-12 06:22:43 +00:00
|
|
|
}
|
2023-12-15 16:06:36 +00:00
|
|
|
|