/* Copyright (C) 2024 Rubén Beltrán del Río This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see https://captura.tranquil.systems. */ 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 } var skipBackend: Bool { get } var maxLength: Int? { 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? var skipBackend: Bool var maxLength: Int? } 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 ?? "") let autoStart = Bool(paramsDict["auto_start"] as? String ?? "") var maxLength = Int(paramsDict["max_length"] as? String ?? "") if fps != nil { fps = min(10, max(4, fps!)) } if maxLength != nil { maxLength = min(300, max(1, fps!)) } if backendOutput == .all { backendOutput = .gifOnly } var skipBackend = false if let backendString = paramsDict["backend"] as? String { if backendString == "" { skipBackend = true } } 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, autoStart: autoStart, skipBackend: skipBackend, maxLength: maxLength )) default: return nil } } }