├── README.md
├── python-automation.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcshareddata
│ │ ├── WorkspaceSettings.xcsettings
│ │ └── swiftpm
│ │ │ └── Package.resolved
│ └── xcuserdata
│ │ └── angel.xcuserdatad
│ │ ├── UserInterfaceState.xcuserstate
│ │ └── WorkspaceSettings.xcsettings
└── xcuserdata
│ └── angel.xcuserdatad
│ └── xcschemes
│ └── xcschememanagement.plist
└── python-automation
├── Assets.xcassets
├── AccentColor.colorset
│ └── Contents.json
├── AppIcon.appiconset
│ └── Contents.json
└── Contents.json
├── ContentView.swift
├── Preview Content
└── Preview Assets.xcassets
│ └── Contents.json
├── PythonController.swift
├── QuoteController.swift
├── QuoteViewModel.swift
├── Scripts
├── __pycache__
│ └── sort_downloads.cpython-313.pyc
└── sort_downloads.py
├── __pycache__
└── AutomationScript.cpython-313.pyc
├── python_automation.entitlements
└── python_automationApp.swift
/README.md:
--------------------------------------------------------------------------------
1 | A simple, open-source macOS menu bar application for effortlessly
2 | running Python scripts with an extra of motivation.
3 |
4 |
5 |
6 | ## Setting Up
7 |
8 | 1. Clone Repository on XCode
9 | 2. On _PythonControler.swift_ update Script's path
10 |
11 | ```SwiftUI
12 | sys.path.append("{/Users/...}/python-automation/python-automation/Scripts")
13 | ```
14 |
15 | 4. Build the app and locate apps's folder
16 | 5. Drag app to Application folder
17 |
18 |
19 | ## Configuration
20 |
21 | 1. Place your Python scripts in the designated ./Scripts directory on the projects repository.
22 | 2. Create a new Button and reorganize to your needs.
23 |
24 | ```SwiftUI
25 | Button(action: {}){
26 | VStack(spacing: 12) {
27 | AutomationButton(icon: "arrow.clockwise.square", title: "organize", subtitle: "/Downloads", custom: false)
28 | .onTapGesture {
29 | let _ = PythonController().self.runSortDownloads(script: "DownloadsSorter")
30 | }
31 | }
32 | .frame(width: 111, height: 30)
33 | .padding(12)
34 | .background {
35 | RoundedRectangle(cornerRadius: 12, style: .continuous)
36 | .fill(.ultraThinMaterial)
37 | }
38 | }
39 | .buttonStyle(.plain)
40 | ```
41 |
--------------------------------------------------------------------------------
/python-automation.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 77;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 0BB36C222CBBF471000D036A /* PythonKit in Frameworks */ = {isa = PBXBuildFile; productRef = 0BB36C212CBBF471000D036A /* PythonKit */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXFileReference section */
14 | 0BB36C0E2CBBF3C8000D036A /* python-automation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "python-automation.app"; sourceTree = BUILT_PRODUCTS_DIR; };
15 | /* End PBXFileReference section */
16 |
17 | /* Begin PBXFileSystemSynchronizedRootGroup section */
18 | 0BB36C102CBBF3C8000D036A /* python-automation */ = {
19 | isa = PBXFileSystemSynchronizedRootGroup;
20 | path = "python-automation";
21 | sourceTree = "";
22 | };
23 | /* End PBXFileSystemSynchronizedRootGroup section */
24 |
25 | /* Begin PBXFrameworksBuildPhase section */
26 | 0BB36C0B2CBBF3C8000D036A /* Frameworks */ = {
27 | isa = PBXFrameworksBuildPhase;
28 | buildActionMask = 2147483647;
29 | files = (
30 | 0BB36C222CBBF471000D036A /* PythonKit in Frameworks */,
31 | );
32 | runOnlyForDeploymentPostprocessing = 0;
33 | };
34 | /* End PBXFrameworksBuildPhase section */
35 |
36 | /* Begin PBXGroup section */
37 | 0BB36C052CBBF3C8000D036A = {
38 | isa = PBXGroup;
39 | children = (
40 | 0BB36C102CBBF3C8000D036A /* python-automation */,
41 | 0BB36C0F2CBBF3C8000D036A /* Products */,
42 | );
43 | sourceTree = "";
44 | };
45 | 0BB36C0F2CBBF3C8000D036A /* Products */ = {
46 | isa = PBXGroup;
47 | children = (
48 | 0BB36C0E2CBBF3C8000D036A /* python-automation.app */,
49 | );
50 | name = Products;
51 | sourceTree = "";
52 | };
53 | /* End PBXGroup section */
54 |
55 | /* Begin PBXNativeTarget section */
56 | 0BB36C0D2CBBF3C8000D036A /* python-automation */ = {
57 | isa = PBXNativeTarget;
58 | buildConfigurationList = 0BB36C1D2CBBF3C9000D036A /* Build configuration list for PBXNativeTarget "python-automation" */;
59 | buildPhases = (
60 | 0BB36C0A2CBBF3C8000D036A /* Sources */,
61 | 0BB36C0B2CBBF3C8000D036A /* Frameworks */,
62 | 0BB36C0C2CBBF3C8000D036A /* Resources */,
63 | );
64 | buildRules = (
65 | );
66 | dependencies = (
67 | );
68 | fileSystemSynchronizedGroups = (
69 | 0BB36C102CBBF3C8000D036A /* python-automation */,
70 | );
71 | name = "python-automation";
72 | packageProductDependencies = (
73 | 0BB36C212CBBF471000D036A /* PythonKit */,
74 | );
75 | productName = "python-automation";
76 | productReference = 0BB36C0E2CBBF3C8000D036A /* python-automation.app */;
77 | productType = "com.apple.product-type.application";
78 | };
79 | /* End PBXNativeTarget section */
80 |
81 | /* Begin PBXProject section */
82 | 0BB36C062CBBF3C8000D036A /* Project object */ = {
83 | isa = PBXProject;
84 | attributes = {
85 | BuildIndependentTargetsInParallel = 1;
86 | LastSwiftUpdateCheck = 1600;
87 | LastUpgradeCheck = 1600;
88 | TargetAttributes = {
89 | 0BB36C0D2CBBF3C8000D036A = {
90 | CreatedOnToolsVersion = 16.0;
91 | };
92 | };
93 | };
94 | buildConfigurationList = 0BB36C092CBBF3C8000D036A /* Build configuration list for PBXProject "python-automation" */;
95 | developmentRegion = en;
96 | hasScannedForEncodings = 0;
97 | knownRegions = (
98 | en,
99 | Base,
100 | );
101 | mainGroup = 0BB36C052CBBF3C8000D036A;
102 | minimizedProjectReferenceProxies = 1;
103 | packageReferences = (
104 | 0BB36C202CBBF471000D036A /* XCRemoteSwiftPackageReference "PythonKit" */,
105 | );
106 | preferredProjectObjectVersion = 77;
107 | productRefGroup = 0BB36C0F2CBBF3C8000D036A /* Products */;
108 | projectDirPath = "";
109 | projectRoot = "";
110 | targets = (
111 | 0BB36C0D2CBBF3C8000D036A /* python-automation */,
112 | );
113 | };
114 | /* End PBXProject section */
115 |
116 | /* Begin PBXResourcesBuildPhase section */
117 | 0BB36C0C2CBBF3C8000D036A /* Resources */ = {
118 | isa = PBXResourcesBuildPhase;
119 | buildActionMask = 2147483647;
120 | files = (
121 | );
122 | runOnlyForDeploymentPostprocessing = 0;
123 | };
124 | /* End PBXResourcesBuildPhase section */
125 |
126 | /* Begin PBXSourcesBuildPhase section */
127 | 0BB36C0A2CBBF3C8000D036A /* Sources */ = {
128 | isa = PBXSourcesBuildPhase;
129 | buildActionMask = 2147483647;
130 | files = (
131 | );
132 | runOnlyForDeploymentPostprocessing = 0;
133 | };
134 | /* End PBXSourcesBuildPhase section */
135 |
136 | /* Begin XCBuildConfiguration section */
137 | 0BB36C1B2CBBF3C9000D036A /* Debug */ = {
138 | isa = XCBuildConfiguration;
139 | buildSettings = {
140 | ALWAYS_SEARCH_USER_PATHS = NO;
141 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
142 | CLANG_ANALYZER_NONNULL = YES;
143 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
144 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
145 | CLANG_ENABLE_MODULES = YES;
146 | CLANG_ENABLE_OBJC_ARC = YES;
147 | CLANG_ENABLE_OBJC_WEAK = YES;
148 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
149 | CLANG_WARN_BOOL_CONVERSION = YES;
150 | CLANG_WARN_COMMA = YES;
151 | CLANG_WARN_CONSTANT_CONVERSION = YES;
152 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
153 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
154 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
155 | CLANG_WARN_EMPTY_BODY = YES;
156 | CLANG_WARN_ENUM_CONVERSION = YES;
157 | CLANG_WARN_INFINITE_RECURSION = YES;
158 | CLANG_WARN_INT_CONVERSION = YES;
159 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
160 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
161 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
162 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
163 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
164 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
165 | CLANG_WARN_STRICT_PROTOTYPES = YES;
166 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
167 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
168 | CLANG_WARN_UNREACHABLE_CODE = YES;
169 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
170 | COPY_PHASE_STRIP = NO;
171 | DEBUG_INFORMATION_FORMAT = dwarf;
172 | ENABLE_STRICT_OBJC_MSGSEND = YES;
173 | ENABLE_TESTABILITY = YES;
174 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
175 | GCC_C_LANGUAGE_STANDARD = gnu17;
176 | GCC_DYNAMIC_NO_PIC = NO;
177 | GCC_NO_COMMON_BLOCKS = YES;
178 | GCC_OPTIMIZATION_LEVEL = 0;
179 | GCC_PREPROCESSOR_DEFINITIONS = (
180 | "DEBUG=1",
181 | "$(inherited)",
182 | );
183 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
184 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
185 | GCC_WARN_UNDECLARED_SELECTOR = YES;
186 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
187 | GCC_WARN_UNUSED_FUNCTION = YES;
188 | GCC_WARN_UNUSED_VARIABLE = YES;
189 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
190 | MACOSX_DEPLOYMENT_TARGET = 15.0;
191 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
192 | MTL_FAST_MATH = YES;
193 | ONLY_ACTIVE_ARCH = YES;
194 | SDKROOT = macosx;
195 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
196 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
197 | };
198 | name = Debug;
199 | };
200 | 0BB36C1C2CBBF3C9000D036A /* Release */ = {
201 | isa = XCBuildConfiguration;
202 | buildSettings = {
203 | ALWAYS_SEARCH_USER_PATHS = NO;
204 | ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
205 | CLANG_ANALYZER_NONNULL = YES;
206 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
207 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
208 | CLANG_ENABLE_MODULES = YES;
209 | CLANG_ENABLE_OBJC_ARC = YES;
210 | CLANG_ENABLE_OBJC_WEAK = YES;
211 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
212 | CLANG_WARN_BOOL_CONVERSION = YES;
213 | CLANG_WARN_COMMA = YES;
214 | CLANG_WARN_CONSTANT_CONVERSION = YES;
215 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
216 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
217 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
218 | CLANG_WARN_EMPTY_BODY = YES;
219 | CLANG_WARN_ENUM_CONVERSION = YES;
220 | CLANG_WARN_INFINITE_RECURSION = YES;
221 | CLANG_WARN_INT_CONVERSION = YES;
222 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
223 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
224 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
225 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
226 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
227 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
228 | CLANG_WARN_STRICT_PROTOTYPES = YES;
229 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
230 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
231 | CLANG_WARN_UNREACHABLE_CODE = YES;
232 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
233 | COPY_PHASE_STRIP = NO;
234 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
235 | ENABLE_NS_ASSERTIONS = NO;
236 | ENABLE_STRICT_OBJC_MSGSEND = YES;
237 | ENABLE_USER_SCRIPT_SANDBOXING = YES;
238 | GCC_C_LANGUAGE_STANDARD = gnu17;
239 | GCC_NO_COMMON_BLOCKS = YES;
240 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
241 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
242 | GCC_WARN_UNDECLARED_SELECTOR = YES;
243 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
244 | GCC_WARN_UNUSED_FUNCTION = YES;
245 | GCC_WARN_UNUSED_VARIABLE = YES;
246 | LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
247 | MACOSX_DEPLOYMENT_TARGET = 15.0;
248 | MTL_ENABLE_DEBUG_INFO = NO;
249 | MTL_FAST_MATH = YES;
250 | SDKROOT = macosx;
251 | SWIFT_COMPILATION_MODE = wholemodule;
252 | };
253 | name = Release;
254 | };
255 | 0BB36C1E2CBBF3C9000D036A /* Debug */ = {
256 | isa = XCBuildConfiguration;
257 | buildSettings = {
258 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
259 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
260 | CODE_SIGN_ENTITLEMENTS = "python-automation/python_automation.entitlements";
261 | CODE_SIGN_STYLE = Automatic;
262 | COMBINE_HIDPI_IMAGES = YES;
263 | CURRENT_PROJECT_VERSION = 1;
264 | DEVELOPMENT_ASSET_PATHS = "\"python-automation/Preview Content\"";
265 | ENABLE_HARDENED_RUNTIME = YES;
266 | ENABLE_PREVIEWS = YES;
267 | GENERATE_INFOPLIST_FILE = YES;
268 | INFOPLIST_KEY_LSUIElement = YES;
269 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
270 | LD_RUNPATH_SEARCH_PATHS = (
271 | "$(inherited)",
272 | "@executable_path/../Frameworks",
273 | );
274 | MARKETING_VERSION = 1.0;
275 | PRODUCT_BUNDLE_IDENTIFIER = "ahrm-vision.python-automation";
276 | PRODUCT_NAME = "$(TARGET_NAME)";
277 | SWIFT_EMIT_LOC_STRINGS = YES;
278 | SWIFT_VERSION = 5.0;
279 | };
280 | name = Debug;
281 | };
282 | 0BB36C1F2CBBF3C9000D036A /* Release */ = {
283 | isa = XCBuildConfiguration;
284 | buildSettings = {
285 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
286 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
287 | CODE_SIGN_ENTITLEMENTS = "python-automation/python_automation.entitlements";
288 | CODE_SIGN_STYLE = Automatic;
289 | COMBINE_HIDPI_IMAGES = YES;
290 | CURRENT_PROJECT_VERSION = 1;
291 | DEVELOPMENT_ASSET_PATHS = "\"python-automation/Preview Content\"";
292 | ENABLE_HARDENED_RUNTIME = YES;
293 | ENABLE_PREVIEWS = YES;
294 | GENERATE_INFOPLIST_FILE = YES;
295 | INFOPLIST_KEY_LSUIElement = YES;
296 | INFOPLIST_KEY_NSHumanReadableCopyright = "";
297 | LD_RUNPATH_SEARCH_PATHS = (
298 | "$(inherited)",
299 | "@executable_path/../Frameworks",
300 | );
301 | MARKETING_VERSION = 1.0;
302 | PRODUCT_BUNDLE_IDENTIFIER = "ahrm-vision.python-automation";
303 | PRODUCT_NAME = "$(TARGET_NAME)";
304 | SWIFT_EMIT_LOC_STRINGS = YES;
305 | SWIFT_VERSION = 5.0;
306 | };
307 | name = Release;
308 | };
309 | /* End XCBuildConfiguration section */
310 |
311 | /* Begin XCConfigurationList section */
312 | 0BB36C092CBBF3C8000D036A /* Build configuration list for PBXProject "python-automation" */ = {
313 | isa = XCConfigurationList;
314 | buildConfigurations = (
315 | 0BB36C1B2CBBF3C9000D036A /* Debug */,
316 | 0BB36C1C2CBBF3C9000D036A /* Release */,
317 | );
318 | defaultConfigurationIsVisible = 0;
319 | defaultConfigurationName = Release;
320 | };
321 | 0BB36C1D2CBBF3C9000D036A /* Build configuration list for PBXNativeTarget "python-automation" */ = {
322 | isa = XCConfigurationList;
323 | buildConfigurations = (
324 | 0BB36C1E2CBBF3C9000D036A /* Debug */,
325 | 0BB36C1F2CBBF3C9000D036A /* Release */,
326 | );
327 | defaultConfigurationIsVisible = 0;
328 | defaultConfigurationName = Release;
329 | };
330 | /* End XCConfigurationList section */
331 |
332 | /* Begin XCRemoteSwiftPackageReference section */
333 | 0BB36C202CBBF471000D036A /* XCRemoteSwiftPackageReference "PythonKit" */ = {
334 | isa = XCRemoteSwiftPackageReference;
335 | repositoryURL = "http://github.com/pvieito/PythonKit.git";
336 | requirement = {
337 | branch = master;
338 | kind = branch;
339 | };
340 | };
341 | /* End XCRemoteSwiftPackageReference section */
342 |
343 | /* Begin XCSwiftPackageProductDependency section */
344 | 0BB36C212CBBF471000D036A /* PythonKit */ = {
345 | isa = XCSwiftPackageProductDependency;
346 | package = 0BB36C202CBBF471000D036A /* XCRemoteSwiftPackageReference "PythonKit" */;
347 | productName = PythonKit;
348 | };
349 | /* End XCSwiftPackageProductDependency section */
350 | };
351 | rootObject = 0BB36C062CBBF3C8000D036A /* Project object */;
352 | }
353 |
--------------------------------------------------------------------------------
/python-automation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/python-automation.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/python-automation.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "originHash" : "545d5544303551a60f9c5953d36b31e23d8aee95be1dfd101f5cd7b228b4f5ee",
3 | "pins" : [
4 | {
5 | "identity" : "pythonkit",
6 | "kind" : "remoteSourceControl",
7 | "location" : "http://github.com/pvieito/PythonKit.git",
8 | "state" : {
9 | "branch" : "master",
10 | "revision" : "6fee7617cfa910fbac7035276e295ba967adbbb4"
11 | }
12 | }
13 | ],
14 | "version" : 3
15 | }
16 |
--------------------------------------------------------------------------------
/python-automation.xcodeproj/project.xcworkspace/xcuserdata/angel.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angx1/automation-clipper/bfc116f8e8f0f94a955ebe04293ab9908a40ca4d/python-automation.xcodeproj/project.xcworkspace/xcuserdata/angel.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/python-automation.xcodeproj/project.xcworkspace/xcuserdata/angel.xcuserdatad/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BuildLocationStyle
6 | UseAppPreferences
7 | CustomBuildLocationType
8 | RelativeToDerivedData
9 | DerivedDataLocationStyle
10 | Default
11 | ShowSharedSchemesAutomaticallyEnabled
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/python-automation.xcodeproj/xcuserdata/angel.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | python-automation.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 0
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/python-automation/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/python-automation/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "mac",
5 | "scale" : "1x",
6 | "size" : "16x16"
7 | },
8 | {
9 | "idiom" : "mac",
10 | "scale" : "2x",
11 | "size" : "16x16"
12 | },
13 | {
14 | "idiom" : "mac",
15 | "scale" : "1x",
16 | "size" : "32x32"
17 | },
18 | {
19 | "idiom" : "mac",
20 | "scale" : "2x",
21 | "size" : "32x32"
22 | },
23 | {
24 | "idiom" : "mac",
25 | "scale" : "1x",
26 | "size" : "128x128"
27 | },
28 | {
29 | "idiom" : "mac",
30 | "scale" : "2x",
31 | "size" : "128x128"
32 | },
33 | {
34 | "idiom" : "mac",
35 | "scale" : "1x",
36 | "size" : "256x256"
37 | },
38 | {
39 | "idiom" : "mac",
40 | "scale" : "2x",
41 | "size" : "256x256"
42 | },
43 | {
44 | "idiom" : "mac",
45 | "scale" : "1x",
46 | "size" : "512x512"
47 | },
48 | {
49 | "idiom" : "mac",
50 | "scale" : "2x",
51 | "size" : "512x512"
52 | }
53 | ],
54 | "info" : {
55 | "author" : "xcode",
56 | "version" : 1
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/python-automation/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/python-automation/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // python-automation
4 | //
5 | // Created by Angel Rodriguez Moran on 13/10/24.
6 | //
7 |
8 |
9 | import SwiftUI
10 |
11 | struct ContentView: View {
12 | @State var showResult: Bool = false
13 | var body: some View {
14 |
15 | /*
16 | Button(action: {
17 | PythonController()
18 | showResult.toggle()
19 | }){
20 | Text("Run Python Script")
21 | }
22 |
23 | if showResult {
24 | Text(String("\(PythonController())"))
25 | }
26 |
27 | */
28 |
29 | Text("auto-py")
30 | .padding(64)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/python-automation/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/python-automation/PythonController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PythonController.swift
3 | // python-automation
4 | //
5 | // Created by Angel Rodriguez Moran on 13/10/24.
6 | //
7 |
8 | import Foundation
9 | import PythonKit
10 |
11 | class PythonController {
12 | func runSortDownloads(script: String) -> PythonObject {
13 | let sys = Python.import("sys")
14 | sys.path.append("/Users/angel/Documents/dev/swift/automation-clipper/python-automation/Scripts/") // Complete with your global path to ./Scripts
15 | let file = Python.import(script)
16 | let response = file.sort_downloads()
17 |
18 | return response
19 |
20 | }
21 | }
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/python-automation/QuoteController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // QuoteViewModel.swift
3 | // python-automation
4 | //
5 | // Created by Angel Rodriguez Moran on 13/10/24.
6 | //
7 |
8 |
9 |
10 | import Foundation
11 |
12 | struct QuoteResponse: Decodable {
13 | let results: [Quote]
14 | }
15 |
16 | struct Quote: Decodable {
17 | let text: String
18 | let author: String
19 | }
20 |
21 | class APIService {
22 | static let shared = APIService()
23 | private init() {}
24 |
25 | func fetchQuote() async throws -> Quote {
26 | guard let url = URL(string: "https://stoic-quotes.com/api/quote") else {
27 | throw URLError(.badURL)
28 | }
29 |
30 | let (data, _) = try await URLSession.shared.data(from: url)
31 | let quote = try JSONDecoder().decode(Quote.self, from: data)
32 | return quote
33 |
34 | }
35 | }
36 |
37 |
--------------------------------------------------------------------------------
/python-automation/QuoteViewModel.swift:
--------------------------------------------------------------------------------
1 | //
2 | // QuoteViewModel.swift
3 | // python-automation
4 | //
5 | // Created by Angel Rodriguez Moran on 13/10/24.
6 | //
7 |
8 |
9 |
10 | import Foundation
11 |
12 | @MainActor
13 | class QuoteViewModel: ObservableObject {
14 | @Published var quote: Quote?
15 | @Published var errorMessage: String?
16 |
17 | func fetchQuote() {
18 | Task {
19 | do {
20 | let fetchedQuote = try await APIService.shared.fetchQuote()
21 | self.quote = fetchedQuote
22 | self.errorMessage = nil
23 | } catch {
24 | self.errorMessage = error.localizedDescription
25 | self.quote = nil
26 | }
27 | }
28 | }
29 | }
30 |
31 |
32 |
--------------------------------------------------------------------------------
/python-automation/Scripts/__pycache__/sort_downloads.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angx1/automation-clipper/bfc116f8e8f0f94a955ebe04293ab9908a40ca4d/python-automation/Scripts/__pycache__/sort_downloads.cpython-313.pyc
--------------------------------------------------------------------------------
/python-automation/Scripts/sort_downloads.py:
--------------------------------------------------------------------------------
1 |
2 | import os
3 | import shutil
4 |
5 | def sort_downloads():
6 | downloads_path = os.path.join(os.path.expanduser("~"), "Downloads")
7 | target = downloads_path
8 | extensions = {item.split('.')[-1] for item in os.listdir(target)}
9 |
10 |
11 | # create folder for each extension type
12 | for extension in extensions:
13 | if not os.path.exists(os.path.join(target, extension)):
14 | os.mkdir(os.path.join(target, extension))
15 |
16 |
17 | # move files to their respective folders
18 | for item in os.listdir(target):
19 | if os.path.isfile(os.path.join(target, item)):
20 | file_extension = item.split('.')[-1]
21 | shutil.move(os.path.join(target, item), os.path.join(target, file_extension, item))
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/python-automation/__pycache__/AutomationScript.cpython-313.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/angx1/automation-clipper/bfc116f8e8f0f94a955ebe04293ab9908a40ca4d/python-automation/__pycache__/AutomationScript.cpython-313.pyc
--------------------------------------------------------------------------------
/python-automation/python_automation.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.cs.disable-library-validation
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/python-automation/python_automationApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // python-automation
3 | //
4 | // Created by Angel Rodriguez Moran on 13/10/24.
5 | //
6 |
7 |
8 |
9 | import SwiftUI
10 |
11 | @main
12 | struct python_automationApp: App {
13 | @StateObject private var viewModel = QuoteViewModel()
14 |
15 | var body: some Scene {
16 | MenuBarExtra("auto-py", systemImage: "circle") {
17 | QuoteControlCentreView()
18 | .environmentObject(viewModel)
19 | .onAppear {
20 | viewModel.fetchQuote()
21 | }
22 | .frame(width: 300)
23 | .clipped()
24 | .background {
25 | RoundedRectangle(cornerRadius: 12, style: .continuous)
26 | .fill(.ultraThinMaterial)
27 | .frame(maxWidth: .greatestFiniteMagnitude, alignment: .center)
28 | }
29 | .padding(12)
30 |
31 | AutomationsControlCentreView()
32 |
33 | }
34 | .menuBarExtraStyle(.window)
35 |
36 | }
37 |
38 |
39 |
40 |
41 |
42 |
43 | @ViewBuilder
44 | func AutomationsControlCentreView() -> some View {
45 | VStack(alignment: .leading){
46 | HStack{
47 | Button(action: {}){
48 | VStack(spacing: 12) {
49 | AutomationButton(icon: "arrow.clockwise.square", title: "organize", subtitle: "/Downloads", custom: false)
50 | .onTapGesture {
51 | let _ = PythonController().self.runSortDownloads(script: "sort_downloads")
52 | }
53 | }
54 | .frame(width: 111, height: 30)
55 | .padding(12)
56 | .background {
57 | RoundedRectangle(cornerRadius: 12, style: .continuous)
58 | .fill(.ultraThinMaterial)
59 | }
60 | }
61 | .buttonStyle(.plain)
62 | }
63 | .padding([.horizontal], 12)
64 | .padding([.bottom, .top], 3)
65 |
66 |
67 |
68 | }
69 | .padding([.top], -20)
70 | .padding([.bottom, .top], 12)
71 | .frame(maxWidth: .infinity, alignment: .leading)
72 |
73 | }
74 |
75 |
76 |
77 | @ViewBuilder
78 | func AutomationButton(icon: String, title: String, subtitle: String, custom: Bool) -> some View {
79 | HStack(spacing: 5) {
80 | if custom {
81 | Image(systemName: icon)
82 | .font(.largeTitle)
83 | .symbolRenderingMode(.palette)
84 | .foregroundStyle(.white, .white)
85 | }else{
86 | Image(systemName: icon)
87 | .font(.largeTitle)
88 | .symbolRenderingMode(.palette)
89 | .foregroundStyle(.white, .orange)
90 | }
91 |
92 |
93 | VStack(alignment: .leading, spacing: 1) {
94 | Text(title)
95 | .font(.callout)
96 | .foregroundStyle(.primary)
97 |
98 | Text(subtitle)
99 | .font(.caption2)
100 | .foregroundStyle(.primary)
101 | .opacity(0.7)
102 |
103 |
104 | }
105 | }
106 |
107 | .frame(maxWidth: .infinity, alignment: .leading)
108 |
109 | }
110 |
111 | }
112 |
113 | struct QuoteControlCentreView: View {
114 | @EnvironmentObject var viewModel: QuoteViewModel
115 |
116 | var body: some View {
117 | VStack {
118 | if let quote = viewModel.quote {
119 | Text(quote.text)
120 | .font(.system(size: 12))
121 | .padding(10)
122 |
123 | Text("- \(quote.author)")
124 | .font(.system(size: 10))
125 | .foregroundColor(.secondary)
126 | .padding([.top], -10)
127 | .padding([.bottom], 10)
128 |
129 | } else if let errorMessage = viewModel.errorMessage {
130 | Text("Error: \(errorMessage)")
131 | .foregroundColor(.red)
132 | } else {
133 | Text("Loading...")
134 | .font(.title)
135 | .padding()
136 | }
137 | }
138 |
139 | }
140 | }
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
--------------------------------------------------------------------------------