Ferrite-backup/Ferrite/API/KodiWrapper.swift
kingbri ecdd0199f6 Tree: Cleanup access levels
Public should not be used in an app since it declares public to
additional modules. However, an app is one module. Some structs/
classes need to be left public to conform to CoreData's generation.

Signed-off-by: kingbri <bdashore3@proton.me>
2024-06-16 15:00:35 -05:00

129 lines
5 KiB
Swift

//
// KodiWrapper.swift
// Ferrite
//
// Created by Brian Dashore on 3/4/23.
//
import Foundation
class Kodi {
private let encoder = JSONEncoder()
// Used to add server to CoreData. Not part of API
func addServer(urlString: String,
friendlyName: String?,
username: String?,
password: String?,
existingServer: KodiServer? = nil) throws
{
let backgroundContext = PersistenceController.shared.backgroundContext
if !urlString.starts(with: "http://"), !urlString.starts(with: "https://") {
throw KodiError.ServerAddition(description: "Could not add Kodi server because the URL is invalid.")
}
var name = ""
if let friendlyName {
name = friendlyName
} else {
var components = URLComponents(string: urlString)
components?.scheme = nil
components?.path = ""
guard let cleanedName = components?.url?.description.dropFirst(2) else {
throw KodiError.ServerAddition(description: "An invalid friendly name for this Kodi server was generated.")
}
name = String(cleanedName)
}
if existingServer == nil {
let existingServerRequest = KodiServer.fetchRequest()
existingServerRequest.fetchLimit = 1
// If a server with the same name or URL exists, error out
let namePredicate = NSPredicate(format: "name == %@", name)
let urlPredicate = NSPredicate(format: "urlString == %@", urlString)
existingServerRequest.predicate = NSCompoundPredicate(type: .or, subpredicates: [namePredicate, urlPredicate])
if (try? backgroundContext.fetch(existingServerRequest).first) != nil {
throw KodiError.ServerAddition(description: "An existing kodi server with the same name or URL was found. Please try editing an existing server instead.")
}
}
let newServerObject = existingServer ?? KodiServer(context: backgroundContext)
newServerObject.urlString = urlString
newServerObject.name = name
if let username, let password {
newServerObject.username = username
newServerObject.password = password
}
try backgroundContext.save()
}
func ping(server: KodiServer) async throws {
var request = URLRequest(url: URL(string: "\(server.urlString)/jsonrpc")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
let requestBody = RPCPayload(
method: "JSONRPC.Ping",
params: nil
)
if let username = server.username, let password = server.password {
request.setValue("Basic \(Data("\(username):\(password)".utf8).base64EncodedString())", forHTTPHeaderField: "Authorization")
}
request.httpBody = try encoder.encode(requestBody)
let (_, response) = try await URLSession.shared.data(for: request)
guard let response = response as? HTTPURLResponse else {
throw KodiError.FailedRequest(description: "No HTTP response given")
}
if response.statusCode == 401 {
throw KodiError.FailedRequest(description: "Your Kodi account details for server \(server.name) are invalid. Please check your credentials in Settings > Kodi.")
} else if response.statusCode <= 200, response.statusCode >= 299 {
throw KodiError.FailedRequest(description: "The Kodi request failed with status code \(response.statusCode).")
}
}
func sendVideoUrl(urlString: String, server: KodiServer) async throws {
if URL(string: urlString) == nil {
throw KodiError.InvalidPlaybackUrl
}
let requestBody = RPCPayload(
method: "Player.Open",
params: Params(item: Item(file: urlString))
)
var request = URLRequest(url: URL(string: "\(server.urlString)/jsonrpc")!)
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
if let username = server.username, let password = server.password {
request.setValue("Basic \(Data("\(username):\(password)".utf8).base64EncodedString())", forHTTPHeaderField: "Authorization")
}
request.httpBody = try encoder.encode(requestBody)
let (_, response) = try await URLSession.shared.data(for: request)
guard let response = response as? HTTPURLResponse else {
throw KodiError.FailedRequest(description: "No HTTP response given")
}
if response.statusCode == 401 {
throw KodiError.FailedRequest(description: "Your Kodi account details are invalid. Please check your credentials in Settings > Kodi.")
} else if response.statusCode <= 200, response.statusCode >= 299 {
throw KodiError.FailedRequest(description: "The Kodi request failed with status code \(response.statusCode).")
}
}
}