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>
129 lines
5 KiB
Swift
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).")
|
|
}
|
|
}
|
|
}
|