From: Ruben Beltran del Rio Date: Wed, 2 Aug 2023 08:30:51 +0000 (+0200) Subject: Add AppleScript support X-Git-Tag: 1.0.0~6 X-Git-Url: https://git.r.bdr.sh/rbdr/captura/commitdiff_plain/377442f2f1f0f08bc525393c9bd1c84f159c5159 Add AppleScript support --- diff --git a/Captura.xcodeproj/project.pbxproj b/Captura.xcodeproj/project.pbxproj index 4c6ba9a..35a5e10 100644 --- a/Captura.xcodeproj/project.pbxproj +++ b/Captura.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* 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 */; }; @@ -23,6 +23,12 @@ 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 */; }; @@ -56,7 +62,7 @@ /* Begin PBXFileReference section */ B5278B162A71528F009F6462 /* HelpPopoverViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HelpPopoverViewController.swift; sourceTree = ""; }; B5278B1E2A71BD9B009F6462 /* OutputSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputSettings.swift; sourceTree = ""; }; - B5278B202A71BFC3009F6462 /* SettingsStructs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsStructs.swift; sourceTree = ""; }; + B5278B202A71BFC3009F6462 /* OutputFormatSetting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OutputFormatSetting.swift; sourceTree = ""; }; B5278B222A71C140009F6462 /* PreferencesWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesWindow.swift; sourceTree = ""; }; B5278B242A71CA80009F6462 /* AdvancedSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedSettings.swift; sourceTree = ""; }; B5278B272A739871009F6462 /* CGImage+resize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGImage+resize.swift"; sourceTree = ""; }; @@ -71,6 +77,11 @@ B5278B432A77B43A009F6462 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; B5278B442A77D924009F6462 /* CaptureSessionConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptureSessionConfiguration.swift; sourceTree = ""; }; B5278B462A77E8D7009F6462 /* CapturaURLDecoder.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapturaURLDecoder.swift; sourceTree = ""; }; + B5278B482A781B78009F6462 /* Captura.sdef */ = {isa = PBXFileReference; lastKnownFileType = text; path = Captura.sdef; sourceTree = ""; }; + B5278B4D2A799AA3009F6462 /* GetRemoteCaptures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetRemoteCaptures.swift; sourceTree = ""; }; + B55403E62A79A08C004BCBAB /* CapturaShortcutsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CapturaShortcutsProvider.swift; sourceTree = ""; }; + B55403E92A79A434004BCBAB /* ScriptedPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScriptedPreferences.swift; sourceTree = ""; }; + B55403EC2A7A388B004BCBAB /* RecordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordCommand.swift; sourceTree = ""; }; B55DDFCB2A6F0253001A5E76 /* Notification+AppEvents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+AppEvents.swift"; sourceTree = ""; }; B55DDFCD2A6F069D001A5E76 /* RecordingWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RecordingWindow.swift; sourceTree = ""; }; B56C70CC2A6EFDF4009B97EB /* CaptureState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CaptureState.swift; sourceTree = ""; }; @@ -93,6 +104,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B5278B4B2A7995AA009F6462 /* CloudStorage in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -152,7 +164,7 @@ B5278B1C2A71BD3C009F6462 /* Data */ = { isa = PBXGroup; children = ( - B5278B202A71BFC3009F6462 /* SettingsStructs.swift */, + B5278B202A71BFC3009F6462 /* OutputFormatSetting.swift */, B5278B292A73992D009F6462 /* GifRenderer.swift */, B5278B2B2A739B3A009F6462 /* CapturaFile.swift */, B5F9155A2A6EF80E007ECE8E /* CapturaRemoteFile+name.swift */, @@ -194,6 +206,25 @@ path = Domain; sourceTree = ""; }; + B5278B4C2A799A90009F6462 /* Intents */ = { + isa = PBXGroup; + children = ( + B5278B4D2A799AA3009F6462 /* GetRemoteCaptures.swift */, + B55403E62A79A08C004BCBAB /* CapturaShortcutsProvider.swift */, + ); + path = Intents; + sourceTree = ""; + }; + B55403E82A79A3D5004BCBAB /* Scripting */ = { + isa = PBXGroup; + children = ( + B5278B482A781B78009F6462 /* Captura.sdef */, + B55403E92A79A434004BCBAB /* ScriptedPreferences.swift */, + B55403EC2A7A388B004BCBAB /* RecordCommand.swift */, + ); + path = Scripting; + sourceTree = ""; + }; B5F915452A6EF80D007ECE8E = { isa = PBXGroup; children = ( @@ -217,6 +248,8 @@ B5F915502A6EF80D007ECE8E /* Captura */ = { isa = PBXGroup; children = ( + B55403E82A79A3D5004BCBAB /* Scripting */, + B5278B4C2A799A90009F6462 /* Intents */, B5278B432A77B43A009F6462 /* Info.plist */, B5F915512A6EF80D007ECE8E /* CapturaApp.swift */, B5278B262A739862009F6462 /* Core Extensions */, @@ -272,6 +305,7 @@ ); name = Captura; packageProductDependencies = ( + B5278B4A2A7995AA009F6462 /* CloudStorage */, ); productName = Captura; productReference = B5F9154E2A6EF80D007ECE8E /* Captura.app */; @@ -346,6 +380,7 @@ ); mainGroup = B5F915452A6EF80D007ECE8E; packageReferences = ( + B5278B492A7995AA009F6462 /* XCRemoteSwiftPackageReference "CloudStorage" */, ); productRefGroup = B5F9154F2A6EF80D007ECE8E /* Products */; projectDirPath = ""; @@ -365,6 +400,7 @@ files = ( B5F915592A6EF80E007ECE8E /* Preview Assets.xcassets in Resources */, B5F915562A6EF80E007ECE8E /* Assets.xcassets in Resources */, + B55403EB2A7A2AD2004BCBAB /* Captura.sdef in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -393,12 +429,15 @@ 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 */, @@ -409,6 +448,7 @@ 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 */, ); @@ -738,6 +778,25 @@ }; /* 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; diff --git a/Captura.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/Captura.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved new file mode 100644 index 0000000..c5bc2ce --- /dev/null +++ b/Captura.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -0,0 +1,14 @@ +{ + "pins" : [ + { + "identity" : "cloudstorage", + "kind" : "remoteSourceControl", + "location" : "https://github.com/nonstrict-hq/CloudStorage", + "state" : { + "revision" : "35700218d35579df091974b6e7765db94c83448b", + "version" : "0.4.0" + } + } + ], + "version" : 2 +} diff --git a/Captura/Captura.entitlements b/Captura/Captura.entitlements index 2391ad2..f6cc65e 100644 --- a/Captura/Captura.entitlements +++ b/Captura/Captura.entitlements @@ -12,6 +12,8 @@ CloudKit + com.apple.developer.ubiquity-kvstore-identifier + $(TeamIdentifierPrefix)$(CFBundleIdentifier) com.apple.security.app-sandbox com.apple.security.assets.pictures.read-write diff --git a/Captura/CapturaApp.swift b/Captura/CapturaApp.swift index eb6f02e..c6ec9f0 100644 --- a/Captura/CapturaApp.swift +++ b/Captura/CapturaApp.swift @@ -39,6 +39,8 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { var remoteFiles: [CapturaRemoteFile] = [] var captureSessionConfiguration: CaptureSessionConfiguration = CaptureSessionConfiguration() + @objc var scriptedPreferences: ScriptedPreferences? + func applicationDidFinishLaunching(_ notification: Notification) { setupStatusBar() NotificationCenter.default.addObserver( @@ -48,6 +50,8 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { object: nil) closeWindow() fetchRemoteItems() + + scriptedPreferences = ScriptedPreferences() } // MARK: - Setup Functions @@ -108,7 +112,10 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { 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) } } @@ -196,6 +203,14 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { 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() @@ -324,6 +339,14 @@ class CapturaAppDelegate: NSObject, NSApplicationDelegate, NSMenuDelegate { } } + func reloadConfiguration() { + self.captureSessionConfiguration = CaptureSessionConfiguration() + } + + func setCaptureSessionConfiguration(_ config: RecordAction) { + self.captureSessionConfiguration = CaptureSessionConfiguration(from: config) + } + // MARK: - CoreData private func fetchRemoteItems() { diff --git a/Captura/Core Extensions/Notification+AppEvents.swift b/Captura/Core Extensions/Notification+AppEvents.swift index 0a0f820..82b46e1 100644 --- a/Captura/Core Extensions/Notification+AppEvents.swift +++ b/Captura/Core Extensions/Notification+AppEvents.swift @@ -9,4 +9,6 @@ extension Notification.Name { 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") } diff --git a/Captura/Data/CapturaSettings.swift b/Captura/Data/CapturaSettings.swift index 85368ea..2d0e70b 100644 --- a/Captura/Data/CapturaSettings.swift +++ b/Captura/Data/CapturaSettings.swift @@ -3,19 +3,23 @@ import Foundation 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") } } @@ -41,36 +45,45 @@ struct CapturaSettings { 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) { diff --git a/Captura/Data/SettingsStructs.swift b/Captura/Data/OutputFormatSetting.swift similarity index 73% rename from Captura/Data/SettingsStructs.swift rename to Captura/Data/OutputFormatSetting.swift index 16172ca..211a08e 100644 --- a/Captura/Data/SettingsStructs.swift +++ b/Captura/Data/OutputFormatSetting.swift @@ -25,4 +25,15 @@ enum OutputFormatSetting: Int { 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" + } + } } diff --git a/Captura/Info.plist b/Captura/Info.plist index 6110e45..1789155 100644 --- a/Captura/Info.plist +++ b/Captura/Info.plist @@ -11,5 +11,9 @@ + NSAppleScriptEnabled + + OSAScriptingDefinition + Captura.sdef diff --git a/Captura/Intents/CapturaShortcutsProvider.swift b/Captura/Intents/CapturaShortcutsProvider.swift new file mode 100644 index 0000000..2727325 --- /dev/null +++ b/Captura/Intents/CapturaShortcutsProvider.swift @@ -0,0 +1,10 @@ +import AppIntents + +struct CapturaShortcutsProvider: AppShortcutsProvider { + + static var appShortcuts: [AppShortcut] { + + AppShortcut(intent: GetRemoteCaptures(), phrases: ["Get \(.applicationName) remote captures"]) + + } +} diff --git a/Captura/Intents/GetRemoteCaptures.swift b/Captura/Intents/GetRemoteCaptures.swift new file mode 100644 index 0000000..58d9583 --- /dev/null +++ b/Captura/Intents/GetRemoteCaptures.swift @@ -0,0 +1,29 @@ +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(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) + } +} diff --git a/Captura/Presentation/Settings/AdvancedSettings.swift b/Captura/Presentation/Settings/AdvancedSettings.swift index 8799436..66314b4 100644 --- a/Captura/Presentation/Settings/AdvancedSettings.swift +++ b/Captura/Presentation/Settings/AdvancedSettings.swift @@ -1,13 +1,16 @@ 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) } @@ -21,7 +24,7 @@ struct AdvancedSettings: View { 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) @@ -72,6 +75,9 @@ struct AdvancedSettings: View { Spacer() } } + .onChange(of: anyState) { _ in + NotificationCenter.default.post(name: .reloadConfiguration, object: nil, userInfo: nil) + } } } diff --git a/Captura/Presentation/Settings/OutputSettings.swift b/Captura/Presentation/Settings/OutputSettings.swift index df12541..cce34ea 100644 --- a/Captura/Presentation/Settings/OutputSettings.swift +++ b/Captura/Presentation/Settings/OutputSettings.swift @@ -1,9 +1,12 @@ 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 { @@ -35,6 +38,9 @@ struct OutputSettings: View { } Spacer() } + .onChange(of: anyState) { _ in + NotificationCenter.default.post(name: .reloadConfiguration, object: nil, userInfo: nil) + } } } diff --git a/Captura/Scripting/Captura.sdef b/Captura/Scripting/Captura.sdef new file mode 100644 index 0000000..82cf06f --- /dev/null +++ b/Captura/Scripting/Captura.sdef @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Captura/Scripting/RecordCommand.swift b/Captura/Scripting/RecordCommand.swift new file mode 100644 index 0000000..8db2656 --- /dev/null +++ b/Captura/Scripting/RecordCommand.swift @@ -0,0 +1,64 @@ +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 + } +} diff --git a/Captura/Scripting/ScriptedPreferences.swift b/Captura/Scripting/ScriptedPreferences.swift new file mode 100644 index 0000000..b6aa719 --- /dev/null +++ b/Captura/Scripting/ScriptedPreferences.swift @@ -0,0 +1,47 @@ +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 + } + } +}