/* Begin PBXBuildFile section */
B5278B172A71528F009F6462 /* HelpPopoverViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B162A71528F009F6462 /* HelpPopoverViewController.swift */; };
B5278B1F2A71BD9B009F6462 /* OutputSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B1E2A71BD9B009F6462 /* OutputSettings.swift */; };
- B5278B212A71BFC3009F6462 /* SettingsStructs.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B202A71BFC3009F6462 /* SettingsStructs.swift */; };
+ B5278B212A71BFC3009F6462 /* OutputFormatSetting.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B202A71BFC3009F6462 /* OutputFormatSetting.swift */; };
B5278B232A71C140009F6462 /* PreferencesWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B222A71C140009F6462 /* PreferencesWindow.swift */; };
B5278B252A71CA80009F6462 /* AdvancedSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B242A71CA80009F6462 /* AdvancedSettings.swift */; };
B5278B282A739871009F6462 /* CGImage+resize.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B272A739871009F6462 /* CGImage+resize.swift */; };
B5278B422A779CDB009F6462 /* BackendResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B412A779CDB009F6462 /* BackendResponse.swift */; };
B5278B452A77D924009F6462 /* CaptureSessionConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B442A77D924009F6462 /* CaptureSessionConfiguration.swift */; };
B5278B472A77E8D7009F6462 /* CapturaURLDecoder.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B462A77E8D7009F6462 /* CapturaURLDecoder.swift */; };
+ B5278B4B2A7995AA009F6462 /* CloudStorage in Frameworks */ = {isa = PBXBuildFile; productRef = B5278B4A2A7995AA009F6462 /* CloudStorage */; };
+ B5278B4E2A799AA3009F6462 /* GetRemoteCaptures.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5278B4D2A799AA3009F6462 /* GetRemoteCaptures.swift */; };
+ B55403E72A79A08C004BCBAB /* CapturaShortcutsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55403E62A79A08C004BCBAB /* CapturaShortcutsProvider.swift */; };
+ B55403EA2A79A434004BCBAB /* ScriptedPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55403E92A79A434004BCBAB /* ScriptedPreferences.swift */; };
+ B55403EB2A7A2AD2004BCBAB /* Captura.sdef in Resources */ = {isa = PBXBuildFile; fileRef = B5278B482A781B78009F6462 /* Captura.sdef */; };
+ B55403ED2A7A388B004BCBAB /* RecordCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55403EC2A7A388B004BCBAB /* RecordCommand.swift */; };
B55DDFCC2A6F0253001A5E76 /* Notification+AppEvents.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55DDFCB2A6F0253001A5E76 /* Notification+AppEvents.swift */; };
B55DDFCE2A6F069D001A5E76 /* RecordingWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = B55DDFCD2A6F069D001A5E76 /* RecordingWindow.swift */; };
B56C70CD2A6EFDF4009B97EB /* CaptureState.swift in Sources */ = {isa = PBXBuildFile; fileRef = B56C70CC2A6EFDF4009B97EB /* CaptureState.swift */; };
/* Begin PBXFileReference section */
B5278B162A71528F009F6462 /* HelpPopoverViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpPopoverViewController.swift; sourceTree = "<group>"; };
B5278B1E2A71BD9B009F6462 /* OutputSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputSettings.swift; sourceTree = "<group>"; };
- B5278B202A71BFC3009F6462 /* SettingsStructs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStructs.swift; sourceTree = "<group>"; };
+ B5278B202A71BFC3009F6462 /* OutputFormatSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputFormatSetting.swift; sourceTree = "<group>"; };
B5278B222A71C140009F6462 /* PreferencesWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindow.swift; sourceTree = "<group>"; };
B5278B242A71CA80009F6462 /* AdvancedSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettings.swift; sourceTree = "<group>"; };
B5278B272A739871009F6462 /* CGImage+resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGImage+resize.swift"; sourceTree = "<group>"; };
B5278B432A77B43A009F6462 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
B5278B442A77D924009F6462 /* CaptureSessionConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptureSessionConfiguration.swift; sourceTree = "<group>"; };
B5278B462A77E8D7009F6462 /* CapturaURLDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapturaURLDecoder.swift; sourceTree = "<group>"; };
+ B5278B482A781B78009F6462 /* Captura.sdef */ = {isa = PBXFileReference; lastKnownFileType = text; path = Captura.sdef; sourceTree = "<group>"; };
+ B5278B4D2A799AA3009F6462 /* GetRemoteCaptures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetRemoteCaptures.swift; sourceTree = "<group>"; };
+ B55403E62A79A08C004BCBAB /* CapturaShortcutsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapturaShortcutsProvider.swift; sourceTree = "<group>"; };
+ B55403E92A79A434004BCBAB /* ScriptedPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptedPreferences.swift; sourceTree = "<group>"; };
+ B55403EC2A7A388B004BCBAB /* RecordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordCommand.swift; sourceTree = "<group>"; };
B55DDFCB2A6F0253001A5E76 /* Notification+AppEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+AppEvents.swift"; sourceTree = "<group>"; };
B55DDFCD2A6F069D001A5E76 /* RecordingWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingWindow.swift; sourceTree = "<group>"; };
B56C70CC2A6EFDF4009B97EB /* CaptureState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptureState.swift; sourceTree = "<group>"; };
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
+ B5278B4B2A7995AA009F6462 /* CloudStorage in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
B5278B1C2A71BD3C009F6462 /* Data */ = {
isa = PBXGroup;
children = (
- B5278B202A71BFC3009F6462 /* SettingsStructs.swift */,
+ B5278B202A71BFC3009F6462 /* OutputFormatSetting.swift */,
B5278B292A73992D009F6462 /* GifRenderer.swift */,
B5278B2B2A739B3A009F6462 /* CapturaFile.swift */,
B5F9155A2A6EF80E007ECE8E /* CapturaRemoteFile+name.swift */,
path = Domain;
sourceTree = "<group>";
};
+ B5278B4C2A799A90009F6462 /* Intents */ = {
+ isa = PBXGroup;
+ children = (
+ B5278B4D2A799AA3009F6462 /* GetRemoteCaptures.swift */,
+ B55403E62A79A08C004BCBAB /* CapturaShortcutsProvider.swift */,
+ );
+ path = Intents;
+ sourceTree = "<group>";
+ };
+ B55403E82A79A3D5004BCBAB /* Scripting */ = {
+ isa = PBXGroup;
+ children = (
+ B5278B482A781B78009F6462 /* Captura.sdef */,
+ B55403E92A79A434004BCBAB /* ScriptedPreferences.swift */,
+ B55403EC2A7A388B004BCBAB /* RecordCommand.swift */,
+ );
+ path = Scripting;
+ sourceTree = "<group>";
+ };
B5F915452A6EF80D007ECE8E = {
isa = PBXGroup;
children = (
B5F915502A6EF80D007ECE8E /* Captura */ = {
isa = PBXGroup;
children = (
+ B55403E82A79A3D5004BCBAB /* Scripting */,
+ B5278B4C2A799A90009F6462 /* Intents */,
B5278B432A77B43A009F6462 /* Info.plist */,
B5F915512A6EF80D007ECE8E /* CapturaApp.swift */,
B5278B262A739862009F6462 /* Core Extensions */,
);
name = Captura;
packageProductDependencies = (
+ B5278B4A2A7995AA009F6462 /* CloudStorage */,
);
productName = Captura;
productReference = B5F9154E2A6EF80D007ECE8E /* Captura.app */;
);
mainGroup = B5F915452A6EF80D007ECE8E;
packageReferences = (
+ B5278B492A7995AA009F6462 /* XCRemoteSwiftPackageReference "CloudStorage" */,
);
productRefGroup = B5F9154F2A6EF80D007ECE8E /* Products */;
projectDirPath = "";
files = (
B5F915592A6EF80E007ECE8E /* Preview Assets.xcassets in Resources */,
B5F915562A6EF80E007ECE8E /* Assets.xcassets in Resources */,
+ B55403EB2A7A2AD2004BCBAB /* Captura.sdef in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
B5278B382A73D1EE009F6462 /* CapturaSettings.swift in Sources */,
B5278B282A739871009F6462 /* CGImage+resize.swift in Sources */,
B5278B422A779CDB009F6462 /* BackendResponse.swift in Sources */,
+ B5278B4E2A799AA3009F6462 /* GetRemoteCaptures.swift in Sources */,
B5278B452A77D924009F6462 /* CaptureSessionConfiguration.swift in Sources */,
B5278B2C2A739B3A009F6462 /* CapturaFile.swift in Sources */,
+ B55403E72A79A08C004BCBAB /* CapturaShortcutsProvider.swift in Sources */,
B5278B1F2A71BD9B009F6462 /* OutputSettings.swift in Sources */,
B5278B2A2A73992D009F6462 /* GifRenderer.swift in Sources */,
- B5278B212A71BFC3009F6462 /* SettingsStructs.swift in Sources */,
+ B5278B212A71BFC3009F6462 /* OutputFormatSetting.swift in Sources */,
B55DDFCE2A6F069D001A5E76 /* RecordingWindow.swift in Sources */,
+ B55403ED2A7A388B004BCBAB /* RecordCommand.swift in Sources */,
B5278B402A744297009F6462 /* Persistence.swift in Sources */,
B55DDFCC2A6F0253001A5E76 /* Notification+AppEvents.swift in Sources */,
B5F9155B2A6EF80E007ECE8E /* CapturaRemoteFile+name.swift in Sources */,
B5278B252A71CA80009F6462 /* AdvancedSettings.swift in Sources */,
B5278B362A73B3AA009F6462 /* CapturaCaptureSession.swift in Sources */,
B5278B3E2A74420F009F6462 /* Captura.xcdatamodeld in Sources */,
+ B55403EA2A79A434004BCBAB /* ScriptedPreferences.swift in Sources */,
B5F915522A6EF80D007ECE8E /* CapturaApp.swift in Sources */,
B5278B472A77E8D7009F6462 /* CapturaURLDecoder.swift in Sources */,
);
};
/* End XCConfigurationList section */
+/* Begin XCRemoteSwiftPackageReference section */
+ B5278B492A7995AA009F6462 /* XCRemoteSwiftPackageReference "CloudStorage" */ = {
+ isa = XCRemoteSwiftPackageReference;
+ repositoryURL = "https://github.com/nonstrict-hq/CloudStorage";
+ requirement = {
+ kind = upToNextMajorVersion;
+ minimumVersion = 0.4.0;
+ };
+ };
+/* End XCRemoteSwiftPackageReference section */
+
+/* Begin XCSwiftPackageProductDependency section */
+ B5278B4A2A7995AA009F6462 /* CloudStorage */ = {
+ isa = XCSwiftPackageProductDependency;
+ package = B5278B492A7995AA009F6462 /* XCRemoteSwiftPackageReference "CloudStorage" */;
+ productName = CloudStorage;
+ };
+/* End XCSwiftPackageProductDependency section */
+
/* Begin XCVersionGroup section */
B5278B3C2A74420F009F6462 /* Captura.xcdatamodeld */ = {
isa = XCVersionGroup;
--- /dev/null
+{
+ "pins" : [
+ {
+ "identity" : "cloudstorage",
+ "kind" : "remoteSourceControl",
+ "location" : "https://github.com/nonstrict-hq/CloudStorage",
+ "state" : {
+ "revision" : "35700218d35579df091974b6e7765db94c83448b",
+ "version" : "0.4.0"
+ }
+ }
+ ],
+ "version" : 2
+}
<array>
<string>CloudKit</string>
</array>
+ <key>com.apple.developer.ubiquity-kvstore-identifier</key>
+ <string>$(TeamIdentifierPrefix)$(CFBundleIdentifier)</string>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.assets.pictures.read-write</key>
var remoteFiles: [CapturaRemoteFile] = []
var captureSessionConfiguration: CaptureSessionConfiguration = CaptureSessionConfiguration()
+ @objc var scriptedPreferences: ScriptedPreferences?
+
func applicationDidFinishLaunching(_ notification: Notification) {
setupStatusBar()
NotificationCenter.default.addObserver(
object: nil)
closeWindow()
fetchRemoteItems()
+
+ scriptedPreferences = ScriptedPreferences()
}
// MARK: - Setup Functions
case let .configure(config):
CapturaSettings.apply(config)
case let .record(config):
- captureSessionConfiguration = CaptureSessionConfiguration(from: config)
+ let config = CaptureSessionConfiguration(from: config)
+ NotificationCenter.default.post(name: .startAreaSelection, object: nil, userInfo: [
+ "config": config
+ ])
NotificationCenter.default.post(name: .startAreaSelection, object: nil, userInfo: nil)
}
}
if let frame = notification.userInfo?["frame"] {
receivedFrame(frame as! CVImageBuffer)
}
+ case .reloadConfiguration:
+ reloadConfiguration()
+ case .setCaptureSessionConfiguration:
+ if let userInfo = notification.userInfo {
+ if let config = userInfo["config"] as? RecordAction {
+ setCaptureSessionConfiguration(config)
+ }
+ }
case .NSManagedObjectContextObjectsDidChange:
DispatchQueue.main.async {
self.fetchRemoteItems()
}
}
+ func reloadConfiguration() {
+ self.captureSessionConfiguration = CaptureSessionConfiguration()
+ }
+
+ func setCaptureSessionConfiguration(_ config: RecordAction) {
+ self.captureSessionConfiguration = CaptureSessionConfiguration(from: config)
+ }
+
// MARK: - CoreData
private func fetchRemoteItems() {
static let failedToStart = Notification.Name("failedToStart")
static let receivedFrame = Notification.Name("receivedFrame")
static let failedtoUpload = Notification.Name("failedToUpload")
+ static let reloadConfiguration = Notification.Name("reloadConfiguration")
+ static let setCaptureSessionConfiguration = Notification.Name("setCaptureSessionConfiguration")
}
struct CapturaSettings {
static var frameRate: Int {
get {
- UserDefaults.standard.integer(forKey: "frameRate")
+ if NSUbiquitousKeyValueStore.default.object(forKey: "frameRate") == nil {
+ return 10
+ } else {
+ return min(10, max(4, Int(NSUbiquitousKeyValueStore.default.longLong(forKey: "frameRate"))))
+ }
}
set {
- UserDefaults.standard.setValue(newValue, forKey: "frameRate")
+ NSUbiquitousKeyValueStore.default.setValue(newValue, forKey: "frameRate")
}
}
static var outputFormats: OutputFormatSetting {
get {
- OutputFormatSetting(rawValue: UserDefaults.standard.integer(forKey: "outputFormats")) ?? .all
+ OutputFormatSetting(rawValue: Int(NSUbiquitousKeyValueStore.default.longLong(forKey: "outputFormats"))) ?? .all
}
set {
- UserDefaults.standard.setValue(newValue.rawValue, forKey: "outputFormats")
+ NSUbiquitousKeyValueStore.default.setValue(newValue.rawValue, forKey: "outputFormats")
}
}
static var backend: URL? {
get {
- if let url = UserDefaults.standard.string(forKey: "backendUrl") {
+ if let url = NSUbiquitousKeyValueStore.default.string(forKey: "backendUrl") {
return URL(string: url)
}
return nil
}
set {
- UserDefaults.standard.setValue(newValue?.absoluteString, forKey: "backendUrl")
+ NSUbiquitousKeyValueStore.default.setValue(newValue?.absoluteString, forKey: "backendUrl")
}
}
static var backendFormat: OutputFormatSetting {
get {
- OutputFormatSetting(rawValue: UserDefaults.standard.integer(forKey: "backendFormat")) ?? .gifOnly
+ OutputFormatSetting(rawValue: Int(NSUbiquitousKeyValueStore.default.longLong(forKey: "backendFormat"))) ?? .gifOnly
}
set {
- UserDefaults.standard.setValue(newValue.rawValue, forKey: "backendFormat")
+ NSUbiquitousKeyValueStore.default.setValue(newValue.rawValue, forKey: "backendFormat")
}
}
static var shouldKeepLocalFiles: Bool {
get {
- UserDefaults.standard.bool(forKey: "keepFiles")
+ if NSUbiquitousKeyValueStore.default.object(forKey: "keepFiles") == nil {
+ return true
+ } else {
+ return NSUbiquitousKeyValueStore.default.bool(forKey: "keepFiles")
+ }
}
set {
- UserDefaults.standard.set(newValue, forKey: "keepFiles")
+ NSUbiquitousKeyValueStore.default.set(newValue, forKey: "keepFiles")
}
}
static var shouldAllowURLAutomation: Bool {
- UserDefaults.standard.bool(forKey: "allowURLAutomation")
+ get {
+ NSUbiquitousKeyValueStore.default.bool(forKey: "allowURLAutomation")
+ }
+ set {
+ NSUbiquitousKeyValueStore.default.setValue(newValue, forKey: "allowURLAutomation")
+ }
}
static func apply(_ config: ConfigureAction) {
func shouldSaveMp4() -> Bool {
return self == .mp4Only || self == .all
}
+
+ func toString() -> String {
+ switch(self) {
+ case .gifOnly:
+ return "gif"
+ case .mp4Only:
+ return "mp4"
+ case .all:
+ return "all"
+ }
+ }
}
</array>
</dict>
</array>
+ <key>NSAppleScriptEnabled</key>
+ <true/>
+ <key>OSAScriptingDefinition</key>
+ <string>Captura.sdef</string>
</dict>
</plist>
--- /dev/null
+import AppIntents
+
+struct CapturaShortcutsProvider: AppShortcutsProvider {
+
+ static var appShortcuts: [AppShortcut] {
+
+ AppShortcut(intent: GetRemoteCaptures(), phrases: ["Get \(.applicationName) remote captures"])
+
+ }
+}
--- /dev/null
+import AppIntents
+import CoreData
+
+struct GetRemoteCaptures: AppIntent {
+ static var title: LocalizedStringResource = "Get remote captures"
+
+ static var description =
+ IntentDescription("Return a list of remote captures")
+
+ @Parameter(title: "Count") var count: Int?
+
+ static var parameterSummary: some ParameterSummary {
+ Summary("Get \(\.$count) latest captures.")
+ }
+
+ func perform() async throws -> some IntentResult & ReturnsValue {
+ let viewContext = PersistenceController.shared.container.viewContext
+ let fetchRequest = NSFetchRequest<CapturaRemoteFile>(entityName: "CapturaRemoteFile")
+ fetchRequest.fetchLimit = min(10, max(1, count ?? 5))
+ fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: false)]
+
+ let results = await viewContext.perform {
+ return try? viewContext.fetch(fetchRequest)
+ }
+
+ let finalResults = results?.compactMap { URL(string: $0.url ?? "")} ?? []
+ return .result(value: finalResults)
+ }
+}
import SwiftUI
+import CloudStorage
struct AdvancedSettings: View {
- @AppStorage("backendUrl") var backendUrl: String = ""
- @AppStorage("backendFormat") var outputFormats: OutputFormatSetting = .gifOnly
- @AppStorage("keepFiles") var keepFiles = true
- @AppStorage("allowURLAutomation") var allowURLAutomation = false
+ @CloudStorage("backendUrl") var backendUrl: String = ""
+ @CloudStorage("backendFormat") var backendFormat: OutputFormatSetting = .gifOnly
+ @CloudStorage("keepFiles") var keepFiles = true
+ @CloudStorage("allowURLAutomation") var allowURLAutomation = false
@State var showConfirmation = false
+ private var anyState: String { "\(backendUrl), \(backendFormat), \(keepFiles), \(allowURLAutomation)" }
+
var parsedBackendUrl: URL? {
URL(string: backendUrl)
}
TextField("", text: $backendUrl).font(.body)
}.font(.headline)
.help("The Backend URL to use. If this is empty, no backend will be used and the options below won't have an effect.")
- Picker(selection: $outputFormats, label: Text("Backend Format").font(.headline)) {
+ Picker(selection: $backendFormat, label: Text("Backend Format").font(.headline)) {
Text("GIF")
.tag(OutputFormatSetting.gifOnly)
.padding(.horizontal, 4.0)
Spacer()
}
}
+ .onChange(of: anyState) { _ in
+ NotificationCenter.default.post(name: .reloadConfiguration, object: nil, userInfo: nil)
+ }
}
}
import SwiftUI
+import CloudStorage
struct OutputSettings: View {
- @AppStorage("outputFormats") var outputFormats: OutputFormatSetting = .all
- @AppStorage("frameRate") var frameRate = 10.0
+ @CloudStorage("outputFormats") var outputFormats: OutputFormatSetting = .all
+ @CloudStorage("frameRate") var frameRate = 10.0
+
+ private var anyState: String { "\(outputFormats), \(frameRate)" }
var body: some View {
Form {
}
Spacer()
}
+ .onChange(of: anyState) { _ in
+ NotificationCenter.default.post(name: .reloadConfiguration, object: nil, userInfo: nil)
+ }
}
}
--- /dev/null
+<!DOCTYPE dictionary SYSTEM "file://localhost/System/Library/DTDs/sdef.dtd">
+<dictionary title="CapturaScripting">
+ <suite name="Captura Suite" code="CAPT" description="Controls Captura">
+ <class name="application" code="Capp" description="The application's top-level scripting object.">
+ <cocoa class="NSApplication"/>
+ <property name="preferences" code="Cprp" type="preferences" access="r">
+ <cocoa key="scriptedPreferences"/>
+ </property>
+ </class>
+ <class name="preferences" code="Cprf" description="The application preferences">
+ <cocoa class="ScriptedPreferences"/>
+ <property name="fps" code="Cpfp" type="integer" description="Sets the FPS of the recording" access="rw" />
+ <property name="outputs" code="Cpou" type="text" description="Which outputs get generated locally" access="rw" />
+ <property name="backend" code="Cpbk" type="file url" description="Updates the backend URL that will be used" access="rw" />
+ <property name="backend_output" code="Cpbo" type="text" description="Which output should be sent to the backend" access="rw" />
+ <property name="keep_local_files" code="Cplf" type="boolean" description="Whether to keep local files after a successful backend upload." access="rw"/>
+ </class>
+ <record-type code="CCRr" name="recording_configuration">
+ <property name="x" code="CCrx" type="integer" description="Sets the starting horizontal position of the recording frame from the left of the screen. Defaults to the center of the screen." />
+ <property name="y" code="CCry" type="integer" description="Sets the starting vertical position of the recording frame from the bottom of the screen. Defaults to the center of the screen." />
+ <property name="width" code="CCrw" type="integer" description="Sets the width of the recording frame. Defaults to 400" />
+ <property name="height" code="CCrh" type="integer" description="Sets the height of the recording frame. Defaults to 400" />
+ <property name="prevent_resize" code="CCRz" type="boolean" description="Prevents the recording frame from being resized. Defaults to false." />
+ <property name="prevent_move" code="CCRm" type="boolean" description="Prevents the recording frame from being moved. Defaults to false." />
+ <property name="fps" code="CCrf" type="integer" description="Sets the FPS of the recording" />
+ <property name="outputs" code="CCRo" type="text" description="Which outputs get generated locally" />
+ <property name="backend" code="CCRb" type="file url" description="Updates the backend URL that will be used" />
+ <property name="backend_output" code="CCRp" type="text" description="Which output should be sent to the backend" />
+ <property name="keep_local_files" code="CCRk" type="boolean" description="Whether to keep local files after a successful backend upload." />
+ <property name="auto_start" code="CCRa" type="boolean" description="Whether the recording session should start automatically or not. It takes 3 seconds to start." />
+ <property name="max_length" code="CCrl" type="integer" description="The max length for the recording in seconds, default and max is 300." />
+ </record-type>
+ <command name="start_recording" code="CCCMStRc">
+ <cocoa class="RecordCommand" />
+ <direct-parameter description="The settings to be configured">
+ <type type="recording_configuration" />
+ </direct-parameter>
+ </command>
+ </suite>
+</dictionary>
--- /dev/null
+import Foundation
+
+@objc(RecordCommand)
+class RecordCommand: NSScriptCommand {
+ override func performDefaultImplementation() -> Any? {
+ print("AAAH \(self.directParameter)")
+
+ guard let args = self.directParameter as? [String: Any] else {
+ return nil
+ }
+
+ print("AAH COMMANDS \(args)")
+
+ // Here you can extract the parameters from the args dictionary and configure your settings
+ let x = args["x"] as? Int
+ let y = args["y"] as? Int
+ let width = args["width"] as? Int
+ let height = args["height"] as? Int
+ let preventResize = args["prevent_resize"] as? Bool
+ let preventMove = args["prevent_move"] as? Bool
+ let fps = args["fps"] as? Int
+ let outputs = OutputFormatSetting(args["outputs"] as? String ?? "")
+ let backend = URL(string: args["backend"] as? String ?? "")
+ let backendOutput = OutputFormatSetting(args["backend_output"] as? String ?? "")
+ let keepLocalFiles = args["keep_local_files"] as? Bool
+ let autoStart = args["auto_start"] as? Bool
+ let maxLength = args["max_length"] as? Int
+
+ print("AAH WIDTH \(width)")
+
+ var skipBackend = false
+ if let backendString = args["backend"] as? String {
+ if backendString == "" {
+ skipBackend = true
+ }
+ }
+
+ let config = RecordAction(
+ action: "record",
+ 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
+ )
+
+ NotificationCenter.default.post(name: .setCaptureSessionConfiguration, object: nil, userInfo: [
+ "config": config
+ ])
+ NotificationCenter.default.post(name: .startAreaSelection, object: nil, userInfo: nil)
+
+ // Return a result if needed
+ return nil
+ }
+}
--- /dev/null
+import Foundation
+
+class ScriptedPreferences: NSObject {
+ @objc dynamic var fps: Int {
+ get {
+ CapturaSettings.frameRate
+ }
+ set {
+ CapturaSettings.frameRate = newValue
+ }
+ }
+ @objc dynamic var outputs: String {
+ get {
+ CapturaSettings.outputFormats.toString()
+ }
+ set {
+ CapturaSettings.outputFormats = OutputFormatSetting(newValue) ?? .gifOnly
+ }
+ }
+
+ @objc dynamic var backend: String {
+ get {
+ CapturaSettings.backend?.absoluteString ?? ""
+ }
+ set {
+ CapturaSettings.backend = URL(string: newValue)
+ }
+ }
+
+ @objc dynamic var backend_output: String {
+ get {
+ CapturaSettings.backendFormat.toString()
+ }
+ set {
+ CapturaSettings.backendFormat = OutputFormatSetting(newValue) ?? .gifOnly
+ }
+ }
+
+ @objc dynamic var keep_local_files: Bool {
+ get {
+ CapturaSettings.shouldKeepLocalFiles
+ }
+ set {
+ CapturaSettings.shouldKeepLocalFiles = newValue
+ }
+ }
+}