+import Foundation
+
+
+protocol ConfigureActionProtocol {
+ var action: String { get }
+ var fps: Int? { get }
+ var outputs: OutputFormatSetting? { get }
+ var backend: URL? { get }
+ var backendOutput: OutputFormatSetting? { get }
+ var keepLocalFiles: Bool? { get }
+}
+
+protocol RecordActionProtocol {
+ var action: String { get }
+
+ var x: Int? { get }
+ var y: Int? { get }
+ var width: Int? { get }
+ var height: Int? { get }
+ var preventResize: Bool? { get }
+ var preventMove: Bool? { get }
+ var fps: Int? { get }
+ var backend: URL? { get }
+ var outputs: OutputFormatSetting? { get }
+ var backendOutput: OutputFormatSetting? { get }
+ var keepLocalFiles: Bool? { get }
+ var autoStart: Bool? { get }
+}
+
+// The concrete implementations
+struct ConfigureAction: ConfigureActionProtocol {
+ let action: String
+ var fps: Int?
+ var outputs: OutputFormatSetting?
+ var backend: URL?
+ var backendOutput: OutputFormatSetting?
+ var keepLocalFiles: Bool?
+}
+
+struct RecordAction: RecordActionProtocol {
+ let action: String
+ var x: Int?
+ var y: Int?
+ var width: Int?
+ var height: Int?
+ var preventResize: Bool?
+ var preventMove: Bool?
+ var fps: Int?
+ var outputs: OutputFormatSetting?
+ var backend: URL?
+ var backendOutput: OutputFormatSetting?
+ var keepLocalFiles: Bool?
+ var autoStart: Bool?
+}
+
+enum CapturaAction {
+ case record(RecordAction)
+ case configure(ConfigureAction)
+}
+
+struct CapturaURLDecoder {
+
+ static func decodeParams(url: URL) -> CapturaAction? {
+ guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
+ let params = components.queryItems else {
+ return nil
+ }
+
+ var paramsDict = [String: Any]()
+
+ params.forEach { item in
+ paramsDict[item.name] = item.value
+ }
+
+ guard let action = paramsDict["action"] as? String else {
+ return nil
+ }
+
+ switch action {
+ case "configure":
+ var fps = Int(paramsDict["fps"] as? String ?? "")
+ let backend = URL(string: paramsDict["backend"] as? String ?? "")
+ let keepLocalFiles = Bool(paramsDict["keep_local_files"] as? String ?? "")
+ let outputs = OutputFormatSetting(paramsDict["outputs"] as? String ?? "")
+ var backendOutput = OutputFormatSetting(paramsDict["backend_output"] as? String ?? "")
+
+ if fps != nil {
+ fps = min(10, max(4, fps!))
+ }
+
+ if backendOutput == .all {
+ backendOutput = .gifOnly
+ }
+
+ return .configure(ConfigureAction(
+ action: action,
+ fps: fps,
+ outputs: outputs,
+ backend: backend,
+ backendOutput: backendOutput,
+ keepLocalFiles: keepLocalFiles
+ ))
+
+ case "record":
+ let x = Int(paramsDict["x"] as? String ?? "")
+ let y = Int(paramsDict["y"] as? String ?? "")
+ let width = Int(paramsDict["width"] as? String ?? "")
+ let height = Int(paramsDict["height"] as? String ?? "")
+ let preventResize = Bool(paramsDict["prevent_resize"] as? String ?? "")
+ let preventMove = Bool(paramsDict["prevent_move"] as? String ?? "")
+ var fps = Int(paramsDict["fps"] as? String ?? "")
+ let backend = URL(string: paramsDict["backend"] as? String ?? "")
+ let keepLocalFiles = Bool(paramsDict["keep_local_files"] as? String ?? "")
+ let outputs = OutputFormatSetting(paramsDict["outputs"] as? String ?? "")
+ var backendOutput = OutputFormatSetting(paramsDict["backend_output"] as? String ?? "")
+
+ if fps != nil {
+ fps = min(10, max(4, fps!))
+ }
+
+ if backendOutput == .all {
+ backendOutput = .gifOnly
+ }
+
+ return .record(RecordAction(
+ action: action,
+ x: x,
+ y: y,
+ width: width,
+ height: height,
+ preventResize: preventResize,
+ preventMove: preventMove,
+ fps: fps,
+ outputs: outputs,
+ backend: backend,
+ backendOutput: backendOutput,
+ keepLocalFiles: keepLocalFiles
+ ))
+
+ default:
+ return nil
+ }
+ }
+}