// // JellyfinClientController.swift // Jel // // Created by zerocool on 12/12/23. // import Foundation import Get import JellyfinKit import Pulse 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 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) self.setToken(token: self.authState.authToken ?? "") } func setToken(token: String) { self.authHeaders.Token = token self.setUrl(url: self.authState.serverUrl) } 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 $0.sessionDelegate = Pulse.URLSessionProxyDelegate() }) } func getUrl() -> URL? { return self.api.configuration.baseURL } @discardableResult func send( _ request: Request, delegate: URLSessionDataDelegate? = nil, configure: ((inout URLRequest) throws -> Void)? = nil ) async throws -> Response where T : Decodable { return try await self.api.send(request, delegate: delegate, configure: configure) } @discardableResult func send( _ request: Request, delegate: URLSessionDataDelegate? = nil, configure: ((inout URLRequest) throws -> Void)? = nil ) async throws -> Response { return try await self.api.send(request, delegate: delegate, configure: configure) } } extension JellyfinClientController { func getPublicServerInfo() async -> PublicSystemInfo? { let request = Paths.getPublicSystemInfo do { let res = try await api.send(request) if res.statusCode != 200 { throw JellyfinClientError.badResponseCode } return res.value } catch { return nil } } 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) DispatchQueue.main.async { self.authState.loggedIn = true self.authState.authToken = res.value.accessToken self.authState.userId = res.value.user?.id self.authState.username = username self.authState.save() self.setToken(token: self.authState.authToken ?? "") } } 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 } }