Last active
December 27, 2025 07:49
-
-
Save soundslikeinfo/c6bdb16ce34e0b7e78d6ecb4e29fb1db to your computer and use it in GitHub Desktop.
Screen Grab Router v.0.0.9 - System message confirming frame creation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <?xml version="1.0" encoding="UTF-8"?> | |
| <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> | |
| <plist version="1.0"> | |
| <array> | |
| <dict> | |
| <key>Activate</key> | |
| <string>Normal</string> | |
| <key>CreationDate</key> | |
| <real>788350637.77395296</real> | |
| <key>Macros</key> | |
| <array> | |
| <dict> | |
| <key>Actions</key> | |
| <array> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Yellow</string> | |
| <key>ActionUID</key> | |
| <integer>7100</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>Comment</string> | |
| <key>StyledText</key> | |
| <data> | |
| cnRmZAAAAAADAAAAAgAAAAcAAABU | |
| WFQucnRmAQAAAC7hAgAAKwAAAAEA | |
| AADZAgAAe1xydGYxXGFuc2lcYW5z | |
| aWNwZzEyNTJcY29jb2FydGYyODY3 | |
| Clxjb2NvYXRleHRzY2FsaW5nMFxj | |
| b2NvYXBsYXRmb3JtMHtcZm9udHRi | |
| bFxmMFxmc3dpc3NcZmNoYXJzZXQw | |
| IEhlbHZldGljYTt9CntcY29sb3J0 | |
| Ymw7XHJlZDI1NVxncmVlbjI1NVxi | |
| bHVlMjU1O1xyZWQwXGdyZWVuMFxi | |
| bHVlMDt9CntcKlxleHBhbmRlZGNv | |
| bG9ydGJsOztcY3NzcmdiXGMwXGMw | |
| XGMwXGM4NDcwNlxjbmFtZSBjb250 | |
| cm9sVGV4dENvbG9yO30KXHBhcmRc | |
| dHg1NjBcdHgxMTIwXHR4MTY4MFx0 | |
| eDIyNDBcdHgyODAwXHR4MzM2MFx0 | |
| eDM5MjBcdHg0NDgwXHR4NTA0MFx0 | |
| eDU2MDBcdHg2MTYwXHR4NjcyMFxw | |
| YXJkaXJuYXR1cmFsXHBhcnRpZ2h0 | |
| ZW5mYWN0b3IwCgpcZjBcZnMyNiBc | |
| Y2YyICoqRnJlZSB0byBVc2UqKlwK | |
| VGhpcyB3b3JrZmxvdyBpcyBmcmVl | |
| IHRvIHVzZSwgbW9kaWZ5LCBhbmQg | |
| cmVkaXN0cmlidXRlLlwKXApZb3Ug | |
| YXJlIHdlbGNvbWUgdG8gc2hhcmUg | |
| dGhpcyB3aXRoIG90aGVycyBvciBh | |
| ZGFwdCBpdCBmb3IgeW91ciBvd24g | |
| bmVlZHMuIEF0dHJpYnV0aW9uIGlz | |
| IGFwcHJlY2lhdGVkIGJ1dCBub3Qg | |
| cmVxdWlyZWQuXApcClByb3ZpZGVk | |
| IGFzLWlzIHdpdGggbm8gd2FycmFu | |
| dGllcy4gUGxlYXNlIGNoZWNrIHRo | |
| ZSBjb2RlIGJlZm9yZSBydW5uaW5n | |
| IHRvIGVuc3VyZSBpdCBmaXRzIHlv | |
| dXIgc2VjdXJpdHkgbmVlZHMuXApc | |
| Ci0gdS9zb3VuZHNsaWtlaW5mb1wK | |
| LSBncnJzdGluZUBnbWFpbC5jb219 | |
| AQAAACMAAAABAAAABwAAAFRYVC5y | |
| dGYQAAAAfUpPabYBAAAAAAAAAAAA | |
| AA== | |
| </data> | |
| <key>Title</key> | |
| <string>Read before using: Free to Use Agreement</string> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Yellow</string> | |
| <key>ActionUID</key> | |
| <integer>6707</integer> | |
| <key>MacroActionType</key> | |
| <string>Comment</string> | |
| <key>StyledText</key> | |
| <data> | |
| cnRmZAAAAAADAAAAAgAAAAcAAABU | |
| WFQucnRmAQAAAC5pAgAAKwAAAAEA | |
| AABhAgAAe1xydGYxXGFuc2lcYW5z | |
| aWNwZzEyNTJcY29jb2FydGYyODY3 | |
| Clxjb2NvYXRleHRzY2FsaW5nMFxj | |
| b2NvYXBsYXRmb3JtMHtcZm9udHRi | |
| bFxmMFxmc3dpc3NcZmNoYXJzZXQw | |
| IEhlbHZldGljYTt9CntcY29sb3J0 | |
| Ymw7XHJlZDI1NVxncmVlbjI1NVxi | |
| bHVlMjU1O1xyZWQwXGdyZWVuMFxi | |
| bHVlMDt9CntcKlxleHBhbmRlZGNv | |
| bG9ydGJsOztcY3NzcmdiXGMwXGMw | |
| XGMwXGM4NDcwNlxjbmFtZSBjb250 | |
| cm9sVGV4dENvbG9yO30KXHBhcmRc | |
| dHg1NjBcdHgxMTIwXHR4MTY4MFx0 | |
| eDIyNDBcdHgyODAwXHR4MzM2MFx0 | |
| eDM5MjBcdHg0NDgwXHR4NTA0MFx0 | |
| eDU2MDBcdHg2MTYwXHR4NjcyMFxw | |
| YXJkaXJuYXR1cmFsXHBhcnRpZ2h0 | |
| ZW5mYWN0b3IwCgpcZjBcZnMyNiBc | |
| Y2YyIC0gdjAuMC45IC0gU3lzdGVt | |
| IHByb2Nlc3NpbmcgbWVzc2FnZSBk | |
| dXJpbmcgZnJhbWUgY3JlYXRpb25c | |
| ClxwYXJkXHR4NTYwXHR4MTEyMFx0 | |
| eDE2ODBcdHgyMjQwXHR4MjgwMFx0 | |
| eDMzNjBcdHgzOTIwXHR4NDQ4MFx0 | |
| eDUwNDBcdHg1NjAwXHR4NjE2MFx0 | |
| eDY3MjBccGFyZGlybmF0dXJhbFxw | |
| YXJ0aWdodGVuZmFjdG9yMApcY2Yy | |
| IC0gdjAuMC44IC0gSW50cm9kdWNl | |
| IENIQU5HRUxPRy4gTmV3IE1hY3Jv | |
| IEljb259AQAAACMAAAABAAAABwAA | |
| AFRYVC5ydGYQAAAAMo9PabYBAAAA | |
| AAAAAAAAAA== | |
| </data> | |
| <key>Title</key> | |
| <string>CHANGELOG</string> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Yellow</string> | |
| <key>ActionUID</key> | |
| <integer>6709</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>Comment</string> | |
| <key>StyledText</key> | |
| <data> | |
| cnRmZAAAAAADAAAAAgAAAAcAAABU | |
| WFQucnRmAQAAAC7eAgAAKwAAAAEA | |
| AADWAgAAe1xydGYxXGFuc2lcYW5z | |
| aWNwZzEyNTJcY29jb2FydGYyODY3 | |
| Clxjb2NvYXRleHRzY2FsaW5nMFxj | |
| b2NvYXBsYXRmb3JtMHtcZm9udHRi | |
| bFxmMFxmc3dpc3NcZmNoYXJzZXQw | |
| IEhlbHZldGljYTt9CntcY29sb3J0 | |
| Ymw7XHJlZDI1NVxncmVlbjI1NVxi | |
| bHVlMjU1O1xyZWQwXGdyZWVuMFxi | |
| bHVlMDt9CntcKlxleHBhbmRlZGNv | |
| bG9ydGJsOztcY3NzcmdiXGMwXGMw | |
| XGMwXGM4NDcwNlxjbmFtZSBjb250 | |
| cm9sVGV4dENvbG9yO30KXHBhcmRc | |
| dHg1NjBcdHgxMTIwXHR4MTY4MFx0 | |
| eDIyNDBcdHgyODAwXHR4MzM2MFx0 | |
| eDM5MjBcdHg0NDgwXHR4NTA0MFx0 | |
| eDU2MDBcdHg2MTYwXHR4NjcyMFxw | |
| YXJkaXJuYXR1cmFsXHBhcnRpZ2h0 | |
| ZW5mYWN0b3IwCgpcZjBcZnMyNiBc | |
| Y2YyIC0gQ2hhbmdlIExvY2FsIFZh | |
| cmlhYmxlOiBNYWluRm9sZGVyIHRv | |
| IHlvdXIgc2NyZWVuc2hvdHMgZGly | |
| ZWN0b3J5IFtEZWZhdWx0OiBUaGUg | |
| UHJldmlldy5hcHBcJzkycyBkYXRh | |
| IGRpcmVjdG9yeSBvbiBpQ2xvdWRd | |
| XApcCk5vdGU6IFwnOTN+XCc5NCBh | |
| bmQgXCc5MyRIT01FXCc5NCBzaG91 | |
| bGQgYmUgc2FmZSB0byB1c2UgZm9y | |
| IHlvdXIgdmFyaWFibGUsIHNpbmNl | |
| IHRoZXJlIGlzIGFuIGV4cGFuZGVy | |
| IGZvciB0aGlzIGluIHRoZSBtYWlu | |
| IHNjcmlwdC5cCi0gVGhlIG1haW4g | |
| IHNjcmlwdCBpcyBpbiBcJzkzU2hl | |
| bGwgU2NyaXB0IChNb3ZlIEZpbGUp | |
| XCc5NCBpbnNpZGUgXCc5M1Byb2Nl | |
| c3Mgc2NyZWVuc2hvdFwnOTR9AQAA | |
| ACMAAAABAAAABwAAAFRYVC5ydGYQ | |
| AAAAXuxOabYBAAAAAAAAAAAAAA== | |
| </data> | |
| <key>Title</key> | |
| <string>How to Customize</string> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Yellow</string> | |
| <key>ActionName</key> | |
| <string>Set Local Variable: MainFolder</string> | |
| <key>ActionUID</key> | |
| <integer>6281</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>$HOME/Library/Mobile Documents/com~apple~Preview/Documents/Screen Shots</string> | |
| <key>Variable</key> | |
| <string>Local__MainFolder</string> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Red</string> | |
| <key>ActionUID</key> | |
| <integer>6708</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>Comment</string> | |
| <key>StyledText</key> | |
| <data> | |
| cnRmZAAAAAADAAAAAgAAAAcAAABU | |
| WFQucnRmAQAAAC4WAgAAKwAAAAEA | |
| AAAOAgAAe1xydGYxXGFuc2lcYW5z | |
| aWNwZzEyNTJcY29jb2FydGYyODY3 | |
| Clxjb2NvYXRleHRzY2FsaW5nMFxj | |
| b2NvYXBsYXRmb3JtMHtcZm9udHRi | |
| bFxmMFxmc3dpc3NcZmNoYXJzZXQw | |
| IEhlbHZldGljYTt9CntcY29sb3J0 | |
| Ymw7XHJlZDI1NVxncmVlbjI1NVxi | |
| bHVlMjU1O1xyZWQwXGdyZWVuMFxi | |
| bHVlMDt9CntcKlxleHBhbmRlZGNv | |
| bG9ydGJsOztcY3NzcmdiXGMwXGMw | |
| XGMwXGM4NDcwNlxjbmFtZSBjb250 | |
| cm9sVGV4dENvbG9yO30KXHBhcmRc | |
| dHg1NjBcdHgxMTIwXHR4MTY4MFx0 | |
| eDIyNDBcdHgyODAwXHR4MzM2MFx0 | |
| eDM5MjBcdHg0NDgwXHR4NTA0MFx0 | |
| eDU2MDBcdHg2MTYwXHR4NjcyMFxw | |
| YXJkaXJuYXR1cmFsXHBhcnRpZ2h0 | |
| ZW5mYWN0b3IwCgpcZjBcZnMyNiBc | |
| Y2YyIC0gKipOb3QgeWV0IGF2YWls | |
| YWJsZSBmb3IgY3VzdG9taXppbmcg | |
| R2xvYmFsX19DYXRlZ29yeUxpc3Qq | |
| KlwKLSBLTSBWYXJpYWJsZTogR2xv | |
| YmFsX19DYXRlZ29yeUxpc3QgIHRv | |
| IHRoZSBmb2xkZXIgbmFtZXMgb2Yg | |
| eW91ciBjaG9pY2UuIChIYXJkIGNv | |
| ZGVkKVwKfQEAAAAjAAAAAQAAAAcA | |
| AABUWFQucnRmEAAAAFnqTmm2AQAA | |
| AAAAAAAAAAA= | |
| </data> | |
| <key>Title</key> | |
| <string>@TODO</string> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Red</string> | |
| <key>ActionName</key> | |
| <string>Set Global Variable: CategoryList</string> | |
| <key>ActionUID</key> | |
| <integer>6282</integer> | |
| <key>Conditions</key> | |
| <dict> | |
| <key>ConditionList</key> | |
| <array> | |
| <dict> | |
| <key>ConditionType</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Global__CategoryList</string> | |
| <key>VariableConditionType</key> | |
| <string>IsEmpty</string> | |
| <key>VariableValue</key> | |
| <string>value</string> | |
| </dict> | |
| </array> | |
| <key>ConditionListMatch</key> | |
| <string>All</string> | |
| </dict> | |
| <key>ElseActions</key> | |
| <array/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>IfThenElse</string> | |
| <key>ThenActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6283</integer> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>Copy only (Do not save) | |
| + Add Frame | |
| + New category | |
| - Delete category | |
| General | |
| AI Project | |
| Meme</string> | |
| <key>Variable</key> | |
| <string>Global__CategoryList</string> | |
| </dict> | |
| </array> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionName</key> | |
| <string>Set Local Variable: LoopStatus="Active"</string> | |
| <key>ActionUID</key> | |
| <integer>6279</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>Active</string> | |
| <key>Variable</key> | |
| <string>Local__LoopStatus</string> | |
| </dict> | |
| <dict> | |
| <key>ActionName</key> | |
| <string>Set Local Variable: Timestamp</string> | |
| <key>ActionUID</key> | |
| <integer>6280</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>%ICUDateTime%yyyyMMdd_HHmmss%</string> | |
| <key>Variable</key> | |
| <string>Local__Timestamp</string> | |
| </dict> | |
| <dict> | |
| <key>ActionName</key> | |
| <string>Set Local Variable: FrameAdded="No"</string> | |
| <key>ActionUID</key> | |
| <integer>6315</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>No</string> | |
| <key>Variable</key> | |
| <string>Local__FrameAdded</string> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Purple</string> | |
| <key>ActionName</key> | |
| <string>Shell: screencapture command</string> | |
| <key>ActionUID</key> | |
| <integer>6284</integer> | |
| <key>DisplayKind</key> | |
| <string>Window</string> | |
| <key>HonourFailureSettings</key> | |
| <true/> | |
| <key>IncludeStdErr</key> | |
| <false/> | |
| <key>IncludedVariables</key> | |
| <array> | |
| <string>9999</string> | |
| </array> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>ExecuteShellScript</string> | |
| <key>Path</key> | |
| <string></string> | |
| <key>Source</key> | |
| <string>Nothing</string> | |
| <key>Text</key> | |
| <string>screencapture -i /tmp/temp_screenshot.png</string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>TrimResults</key> | |
| <true/> | |
| <key>TrimResultsNew</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Yellow</string> | |
| <key>ActionName</key> | |
| <string>Process screenshot</string> | |
| <key>ActionUID</key> | |
| <integer>6285</integer> | |
| <key>Conditions</key> | |
| <dict> | |
| <key>ConditionList</key> | |
| <array> | |
| <dict> | |
| <key>ConditionType</key> | |
| <string>FileAttribute</string> | |
| <key>ConditionValue</key> | |
| <string>NOW()-86400</string> | |
| <key>FileAttribute</key> | |
| <string>Name</string> | |
| <key>FileAttrtibuteConditionType</key> | |
| <string>IsNotEmpty</string> | |
| <key>Path</key> | |
| <string>/tmp/temp_screenshot.png</string> | |
| </dict> | |
| </array> | |
| <key>ConditionListMatch</key> | |
| <string>All</string> | |
| </dict> | |
| <key>ElseActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6307</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>Notification</string> | |
| <key>SoundName</key> | |
| <string>Funk</string> | |
| <key>Subtitle</key> | |
| <string></string> | |
| <key>Text</key> | |
| <string>Your screenshot was not taken properl</string> | |
| <key>Title</key> | |
| <string>Failed to take a Screenshot </string> | |
| </dict> | |
| </array> | |
| <key>MacroActionType</key> | |
| <string>IfThenElse</string> | |
| <key>ThenActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Teal</string> | |
| <key>ActionName</key> | |
| <string>While Loop to handle category deletions</string> | |
| <key>ActionUID</key> | |
| <integer>6286</integer> | |
| <key>Actions</key> | |
| <array> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Purple</string> | |
| <key>ActionName</key> | |
| <string>Prompt (Folder List)</string> | |
| <key>ActionUID</key> | |
| <integer>6287</integer> | |
| <key>Floating</key> | |
| <true/> | |
| <key>HasTitle</key> | |
| <false/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>CustomPrompt</string> | |
| <key>Text</key> | |
| <string><!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <style> | |
| /* 1. NEON SCROLLBAR */ | |
| ::-webkit-scrollbar { width: 5px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { background: rgba(0, 255, 255, 0.2); border-radius: 4px; } | |
| ::-webkit-scrollbar-thumb:hover { background: rgba(0, 255, 255, 0.6); } | |
| /* 2. THE SHELL */ | |
| html, body { | |
| margin: 0; padding: 0; | |
| width: 100%; | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| body { | |
| min-height: 300px; | |
| background-color: rgba(5, 5, 10, 0.90); | |
| backdrop-filter: blur(20px) saturate(150%); | |
| -webkit-backdrop-filter: blur(20px) saturate(150%); | |
| border: 1px solid rgba(0, 255, 255, 0.25); | |
| box-shadow: 0 0 25px rgba(0, 0, 0, 0.8); | |
| color: #d0d0d0; | |
| font-family: "Menlo", "Consolas", "Monaco", monospace; | |
| box-sizing: border-box; | |
| user-select: none; | |
| cursor: default; | |
| padding: 2px; | |
| } | |
| /* 3. SCROLL CONTAINER */ | |
| #scroll-view { | |
| height: 100%; | |
| width: 100%; | |
| overflow-y: auto; | |
| padding: 6px; | |
| box-sizing: border-box; | |
| } | |
| .item { | |
| padding: 10px 14px; | |
| margin-bottom: 2px; | |
| border-radius: 4px; | |
| font-size: 14px; | |
| letter-spacing: 0.5px; | |
| transition: all 0.1s ease-out; | |
| border: 1px solid transparent; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| .item:hover, .selected { | |
| background-color: rgba(0, 255, 255, 0.1); | |
| border: 1px solid rgba(0, 255, 255, 0.5); | |
| color: #00ffff; | |
| box-shadow: 0 0 15px rgba(0, 255, 255, 0.2); | |
| text-shadow: 0 0 8px rgba(0, 255, 255, 0.6); | |
| } | |
| /* SPECIAL COMMANDS (Copy, New, Delete) */ | |
| .special-command { | |
| color: #ff00ff; /* Neon Magenta */ | |
| font-weight: bold; | |
| font-size: 13px; | |
| opacity: 0.9; | |
| } | |
| .special-command:hover, .special-command.selected { | |
| background-color: rgba(255, 0, 255, 0.1); | |
| border: 1px solid rgba(255, 0, 255, 0.6); | |
| color: #ff00ff; | |
| box-shadow: 0 0 15px rgba(255, 0, 255, 0.3); | |
| text-shadow: 0 0 8px rgba(255, 0, 255, 0.8); | |
| opacity: 1; | |
| } | |
| /* Divider */ | |
| .separator { | |
| height: 1px; | |
| background: linear-gradient(90deg, transparent, rgba(0, 255, 255, 0.3), transparent); | |
| margin: 6px 0 6px 0; | |
| } | |
| </style> | |
| </head> | |
| <body data-kmwindow="SCREEN(Main,MidX)-150,SCREEN(Main,MidY)-200,300,300"> | |
| <div id="scroll-view"> | |
| <div id="list"> | |
| </div> | |
| </div> | |
| <script> | |
| const WINDOW_WIDTH = 300; | |
| const MIN_HEIGHT = 300; | |
| const MAX_HEIGHT = 500; | |
| function KMInit() { | |
| // 1. GET VARIABLES | |
| var rawList = window.KeyboardMaestro.GetVariable('Global__CategoryList'); | |
| var frameStatus = window.KeyboardMaestro.GetVariable('Local__FrameAdded'); | |
| if (!rawList) rawList = ""; | |
| // --- THE FIX: CLEANING CREW --- | |
| // We filter out any lines that look like commands so we don't duplicate them | |
| var folderLines = rawList.split(/\r\n|\r|\n/).filter(function(line) { | |
| var t = line.trim(); | |
| // Keep the line ONLY if it is NOT one of our special commands | |
| return t !== "" && | |
| !t.includes("Copy only") && | |
| !t.includes("+ Add Frame") && | |
| !t.includes("+ New") && | |
| !t.includes("- Delete"); | |
| }); | |
| var cleanFolderList = folderLines.join("\n"); | |
| // ------------------------------ | |
| // 2. BUILD MENU DYNAMICALLY | |
| var menuItems = "Copy only (Do not save)\n"; | |
| // LOGIC: Only show "Add Frame" if variable is NOT "Yes" | |
| if (frameStatus !== "Yes") { | |
| menuItems += "+ Add Frame\n"; | |
| } | |
| // Add the rest + the CLEAN folder list | |
| menuItems += "+ New Category\n- Delete Category\n" + cleanFolderList; | |
| // 3. RENDER THE LIST | |
| var lines = menuItems.split(/\r\n|\r|\n/); | |
| var container = document.getElementById('list'); | |
| container.innerHTML = ''; | |
| lines.forEach(function(line, index) { | |
| if (line && line.trim() !== "") { | |
| var div = document.createElement('div'); | |
| div.className = 'item'; | |
| div.textContent = line.trim(); | |
| // Highlight commands | |
| if (line.includes('Copy only') || line.includes('+') || line.includes('- Delete')) { | |
| div.classList.add('special-command'); | |
| } | |
| div.onclick = function() { submit(line.trim()); }; | |
| container.appendChild(div); | |
| } | |
| }); | |
| // 4. SMART DIVIDER | |
| var children = container.children; | |
| for (var i = 0; i < children.length; i++) { | |
| if (children[i].textContent.includes('- Delete')) { | |
| var sep = document.createElement('div'); | |
| sep.className = 'separator'; | |
| if (children[i].nextSibling) { | |
| container.insertBefore(sep, children[i].nextSibling); | |
| } else { | |
| container.appendChild(sep); | |
| } | |
| break; | |
| } | |
| } | |
| // 5. RESIZE WINDOW | |
| var contentHeight = container.offsetHeight + 20; | |
| var finalHeight = contentHeight; | |
| if (finalHeight < MIN_HEIGHT) finalHeight = MIN_HEIGHT; | |
| if (finalHeight > MAX_HEIGHT) finalHeight = MAX_HEIGHT; | |
| window.KeyboardMaestro.ResizeWindow(WINDOW_WIDTH, finalHeight); | |
| initNavigation(); | |
| } | |
| function submit(val) { | |
| window.KeyboardMaestro.SetVariable('Local__Category', val); | |
| window.KeyboardMaestro.Submit('OK'); | |
| } | |
| function initNavigation() { | |
| let index = 0; | |
| const items = document.querySelectorAll('.item'); | |
| if (items.length > 0) items[0].classList.add('selected'); | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'ArrowDown') { | |
| e.preventDefault(); | |
| items[index].classList.remove('selected'); | |
| index = (index + 1) % items.length; | |
| items[index].classList.add('selected'); | |
| items[index].scrollIntoView({block: "nearest"}); | |
| } else if (e.key === 'ArrowUp') { | |
| e.preventDefault(); | |
| items[index].classList.remove('selected'); | |
| index = (index - 1 + items.length) % items.length; | |
| items[index].classList.add('selected'); | |
| items[index].scrollIntoView({block: "nearest"}); | |
| } else if (e.key === 'Enter') { | |
| e.preventDefault(); | |
| items[index].click(); | |
| } else if (e.key === 'Escape') { | |
| submit('Copy only (Do not save)'); | |
| } | |
| }); | |
| } | |
| window.addEventListener('load', function() { setTimeout(KMInit, 50); }); | |
| </script> | |
| </body> | |
| </html></string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>Transparent</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionName</key> | |
| <string>If (Copy) → Exit</string> | |
| <key>ActionUID</key> | |
| <integer>6288</integer> | |
| <key>Conditions</key> | |
| <dict> | |
| <key>ConditionList</key> | |
| <array> | |
| <dict> | |
| <key>ConditionType</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Local__Category</string> | |
| <key>VariableConditionType</key> | |
| <string>Contains</string> | |
| <key>VariableValue</key> | |
| <string>Copy only</string> | |
| </dict> | |
| </array> | |
| <key>ConditionListMatch</key> | |
| <string>All</string> | |
| </dict> | |
| <key>ElseActions</key> | |
| <array/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>IfThenElse</string> | |
| <key>ThenActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6289</integer> | |
| <key>Destination</key> | |
| <string>Clipboard</string> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>ReadFile</string> | |
| <key>Source</key> | |
| <string>/tmp/temp_screenshot.png</string> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6290</integer> | |
| <key>Destination</key> | |
| <string></string> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>File</string> | |
| <key>Operation</key> | |
| <string>Delete</string> | |
| <key>Source</key> | |
| <string>/tmp/temp_screenshot.png</string> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6291</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>Notification</string> | |
| <key>SoundName</key> | |
| <string></string> | |
| <key>Subtitle</key> | |
| <string>Screenshot copied to clipboard.</string> | |
| <key>Text</key> | |
| <string></string> | |
| <key>Title</key> | |
| <string>Copied!</string> | |
| </dict> | |
| <dict> | |
| <key>Action</key> | |
| <string>CancelThisMacro</string> | |
| <key>ActionUID</key> | |
| <integer>6292</integer> | |
| <key>MacroActionType</key> | |
| <string>Cancel</string> | |
| </dict> | |
| </array> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Red</string> | |
| <key>ActionName</key> | |
| <string>If (Delete) → Delete Folder</string> | |
| <key>ActionUID</key> | |
| <integer>6293</integer> | |
| <key>Conditions</key> | |
| <dict> | |
| <key>ConditionList</key> | |
| <array> | |
| <dict> | |
| <key>ConditionType</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Local__Category</string> | |
| <key>VariableConditionType</key> | |
| <string>Contains</string> | |
| <key>VariableValue</key> | |
| <string>- Delete Category</string> | |
| </dict> | |
| </array> | |
| <key>ConditionListMatch</key> | |
| <string>All</string> | |
| </dict> | |
| <key>ElseActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6299</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>Done</string> | |
| <key>Variable</key> | |
| <string>Local__LoopStatus</string> | |
| </dict> | |
| </array> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>IfThenElse</string> | |
| <key>ThenActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Purple</string> | |
| <key>ActionName</key> | |
| <string>Prompt (Select Folder to Delete From List)</string> | |
| <key>ActionUID</key> | |
| <integer>6294</integer> | |
| <key>Floating</key> | |
| <true/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>CustomPrompt</string> | |
| <key>Text</key> | |
| <string><!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <style> | |
| /* 1. NEON SCROLLBAR (Red Tint for Delete) */ | |
| ::-webkit-scrollbar { width: 5px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { background: rgba(255, 50, 50, 0.2); border-radius: 4px; } | |
| ::-webkit-scrollbar-thumb:hover { background: rgba(255, 50, 50, 0.6); } | |
| /* 2. THE SHELL */ | |
| html, body { | |
| margin: 0; padding: 0; | |
| width: 100%; | |
| overflow: hidden; | |
| } | |
| body { | |
| /* RED/PINK TINTED GLASS for "Danger Mode" */ | |
| background-color: rgba(15, 5, 5, 0.90); | |
| backdrop-filter: blur(20px) saturate(150%); | |
| -webkit-backdrop-filter: blur(20px) saturate(150%); | |
| /* Red Border */ | |
| border: 1px solid rgba(255, 50, 50, 0.25); | |
| box-shadow: 0 0 25px rgba(0, 0, 0, 0.8), inset 0 0 50px rgba(255, 0, 0, 0.05); | |
| color: #d0d0d0; | |
| font-family: "Menlo", "Consolas", "Monaco", monospace; | |
| box-sizing: border-box; | |
| user-select: none; | |
| cursor: default; | |
| padding: 2px; | |
| } | |
| /* HEADER */ | |
| #header { | |
| padding: 12px 14px 4px 14px; | |
| text-align: center; | |
| border-bottom: 1px solid rgba(255, 50, 50, 0.15); | |
| margin-bottom: 4px; | |
| background: rgba(50, 0, 0, 0.2); | |
| } | |
| .title { | |
| font-size: 13px; | |
| font-weight: 700; | |
| color: #ff5050; /* Red Text */ | |
| text-shadow: 0 0 10px rgba(255, 50, 50, 0.3); | |
| margin-bottom: 4px; | |
| text-transform: uppercase; | |
| letter-spacing: 1px; | |
| } | |
| /* LIST CONTAINER */ | |
| #scroll-view { | |
| height: 100%; | |
| width: 100%; | |
| overflow-y: auto; | |
| padding: 6px; | |
| box-sizing: border-box; | |
| } | |
| .item { | |
| padding: 10px 14px; | |
| margin-bottom: 2px; | |
| border-radius: 4px; | |
| font-size: 14px; | |
| letter-spacing: 0.5px; | |
| transition: all 0.1s ease-out; | |
| border: 1px solid transparent; | |
| white-space: nowrap; | |
| overflow: hidden; | |
| text-overflow: ellipsis; | |
| } | |
| /* DANGER HOVER STATE (Red) */ | |
| .item:hover, .selected { | |
| background-color: rgba(255, 50, 50, 0.1); | |
| border: 1px solid rgba(255, 50, 50, 0.5); | |
| color: #ff5050; | |
| box-shadow: 0 0 15px rgba(255, 50, 50, 0.2); | |
| text-shadow: 0 0 8px rgba(255, 50, 50, 0.6); | |
| } | |
| </style> | |
| </head> | |
| <body data-kmwindow="SCREEN(Main,MidX)-150,SCREEN(Main,MidY)-200,300,300"> | |
| <div id="header"> | |
| <div class="title">Select to Delete</div> | |
| </div> | |
| <div id="scroll-view"> | |
| <div id="list"> | |
| </div> | |
| </div> | |
| <script> | |
| const WINDOW_WIDTH = 300; | |
| const MIN_HEIGHT = 200; | |
| const MAX_HEIGHT = 500; | |
| function KMInit() { | |
| var rawList = window.KeyboardMaestro.GetVariable('Global__CategoryList'); | |
| if (!rawList) rawList = ""; | |
| var lines = rawList.split(/\r\n|\r|\n/); | |
| var container = document.getElementById('list'); | |
| container.innerHTML = ''; | |
| var validItemCount = 0; | |
| lines.forEach(function(line) { | |
| // CLEANUP: We ignore lines that are commands (+ New / - Delete) | |
| if (line && line.trim() !== "" && !line.includes('+') && !line.includes('- Delete')) { | |
| validItemCount++; | |
| var div = document.createElement('div'); | |
| div.className = 'item'; | |
| div.textContent = line.trim(); | |
| div.onclick = function() { submit(line.trim()); }; | |
| container.appendChild(div); | |
| } | |
| }); | |
| // If list is empty (user deleted everything?) | |
| if (validItemCount === 0) { | |
| var div = document.createElement('div'); | |
| div.className = 'item'; | |
| div.style.color = '#666'; | |
| div.style.fontStyle = 'italic'; | |
| div.textContent = "(No folders to delete)"; | |
| div.onclick = function() { window.KeyboardMaestro.Cancel(); }; | |
| container.appendChild(div); | |
| } | |
| // AUTO-RESIZE CALCULATION | |
| var header = document.getElementById('header'); | |
| var contentHeight = container.offsetHeight + header.offsetHeight + 20; | |
| var finalHeight = contentHeight; | |
| if (finalHeight < MIN_HEIGHT) finalHeight = MIN_HEIGHT; | |
| if (finalHeight > MAX_HEIGHT) finalHeight = MAX_HEIGHT; | |
| window.KeyboardMaestro.ResizeWindow(WINDOW_WIDTH, finalHeight); | |
| initNavigation(); | |
| } | |
| function submit(val) { | |
| // IMPORTANT: Saves to 'Local__ItemToDelete' to match your flow | |
| window.KeyboardMaestro.SetVariable('Local__ItemToDelete', val); | |
| window.KeyboardMaestro.Submit('OK'); | |
| } | |
| function initNavigation() { | |
| let index = 0; | |
| const items = document.querySelectorAll('.item'); | |
| if (items.length > 0) items[0].classList.add('selected'); | |
| document.addEventListener('keydown', (e) => { | |
| if (e.key === 'ArrowDown') { | |
| e.preventDefault(); | |
| items[index].classList.remove('selected'); | |
| index = (index + 1) % items.length; | |
| items[index].classList.add('selected'); | |
| items[index].scrollIntoView({block: "nearest"}); | |
| } else if (e.key === 'ArrowUp') { | |
| e.preventDefault(); | |
| items[index].classList.remove('selected'); | |
| index = (index - 1 + items.length) % items.length; | |
| items[index].classList.add('selected'); | |
| items[index].scrollIntoView({block: "nearest"}); | |
| } else if (e.key === 'Enter') { | |
| items[index].click(); | |
| } else if (e.key === 'Escape') { | |
| window.KeyboardMaestro.Cancel(); | |
| } | |
| }); | |
| } | |
| window.addEventListener('load', function() { setTimeout(KMInit, 50); }); | |
| </script> | |
| </body> | |
| </html></string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>Action</key> | |
| <string>IgnoreCaseRegEx</string> | |
| <key>ActionUID</key> | |
| <integer>6295</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SearchReplace</string> | |
| <key>Replace</key> | |
| <string></string> | |
| <key>Search</key> | |
| <string>(?m)^%Variable%Local__ItemToDelete%\R?</string> | |
| <key>Source</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Global__CategoryList</string> | |
| <key>Which</key> | |
| <string>All</string> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6296</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>Notification</string> | |
| <key>SoundName</key> | |
| <string></string> | |
| <key>Subtitle</key> | |
| <string>Deleted %Variable%Local__ItemToDelete% from list.</string> | |
| <key>Text</key> | |
| <string></string> | |
| <key>Title</key> | |
| <string>Deleted Item</string> | |
| </dict> | |
| <dict> | |
| <key>Action</key> | |
| <string>IgnoreCaseRegEx</string> | |
| <key>ActionUID</key> | |
| <integer>6297</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SearchReplace</string> | |
| <key>Replace</key> | |
| <string>%Return%</string> | |
| <key>Search</key> | |
| <string>\n+</string> | |
| <key>Source</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Global__CategoryList</string> | |
| <key>Which</key> | |
| <string>All</string> | |
| </dict> | |
| </array> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Magenta</string> | |
| <key>ActionName</key> | |
| <string>If (Add Frame) → Add Frame</string> | |
| <key>ActionUID</key> | |
| <integer>6311</integer> | |
| <key>Conditions</key> | |
| <dict> | |
| <key>ConditionList</key> | |
| <array> | |
| <dict> | |
| <key>ConditionType</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Local__Category</string> | |
| <key>VariableConditionType</key> | |
| <string>Contains</string> | |
| <key>VariableValue</key> | |
| <string>Add Frame</string> | |
| </dict> | |
| </array> | |
| <key>ConditionListMatch</key> | |
| <string>All</string> | |
| </dict> | |
| <key>ElseActions</key> | |
| <array/> | |
| <key>MacroActionType</key> | |
| <string>IfThenElse</string> | |
| <key>ThenActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionName</key> | |
| <string>Confirmation Modal</string> | |
| <key>ActionUID</key> | |
| <integer>7491</integer> | |
| <key>Floating</key> | |
| <true/> | |
| <key>HasTitle</key> | |
| <false/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>CustomPrompt</string> | |
| <key>Text</key> | |
| <string><!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <style> | |
| html, body { | |
| margin: 0; padding: 0; | |
| width: 100%; height: 100%; | |
| overflow: hidden; | |
| background: transparent; /* Allows KM to render true transparency */ | |
| } | |
| /* The Card Container */ | |
| .notification-card { | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| height: 100%; | |
| /* GLASS EFFECT */ | |
| background-color: rgba(5, 5, 10, 0.85); | |
| backdrop-filter: blur(12px); | |
| -webkit-backdrop-filter: blur(12px); | |
| /* NEON BORDER */ | |
| border: 1px solid rgba(0, 255, 100, 0.3); | |
| border-radius: 12px; | |
| box-shadow: 0 0 25px rgba(0, 0, 0, 0.6), | |
| inset 0 0 20px rgba(0, 255, 100, 0.05); | |
| /* Animation: Fade In/Out handled by KM usually, but we can pulse */ | |
| animation: pulse 2s infinite ease-in-out; | |
| } | |
| .title { | |
| font-family: "Menlo", "Consolas", monospace; | |
| font-size: 16px; | |
| font-weight: 800; | |
| color: #ffffff; | |
| text-transform: uppercase; | |
| letter-spacing: 2px; | |
| margin-bottom: 8px; | |
| text-shadow: 0 0 10px rgba(255, 255, 255, 0.5); | |
| } | |
| .subtitle { | |
| font-family: "Menlo", monospace; | |
| font-size: 12px; | |
| color: #50ff80; /* Neon Green */ | |
| text-shadow: 0 0 8px rgba(0, 255, 100, 0.6); | |
| } | |
| /* Loading Bar (Optional Aesthetic) */ | |
| .loader { | |
| margin-top: 15px; | |
| width: 150px; | |
| height: 2px; | |
| background: rgba(255,255,255,0.1); | |
| border-radius: 2px; | |
| overflow: hidden; | |
| position: relative; | |
| } | |
| .loader::after { | |
| content: ''; | |
| position: absolute; | |
| top: 0; left: 0; | |
| height: 100%; | |
| width: 0%; | |
| background: #50ff80; | |
| box-shadow: 0 0 10px #50ff80; | |
| animation: load 2.25s linear forwards; | |
| } | |
| @keyframes load { | |
| 0% { width: 0%; } | |
| 100% { width: 100%; } | |
| } | |
| @keyframes pulse { | |
| 0% { box-shadow: 0 0 25px rgba(0,0,0,0.6), inset 0 0 20px rgba(0,255,100,0.05); } | |
| 50% { box-shadow: 0 0 35px rgba(0,0,0,0.8), inset 0 0 30px rgba(0,255,100,0.15); } | |
| 100% { box-shadow: 0 0 25px rgba(0,0,0,0.6), inset 0 0 20px rgba(0,255,100,0.05); } | |
| } | |
| </style> | |
| </head> | |
| <body data-kmwindow="SCREEN(Main,MidX)-150,SCREEN(Main,MidY)-300,300,100"> | |
| <div class="notification-card"> | |
| <div class="title">System Active</div> | |
| <div class="subtitle">Processing Capture...</div> | |
| <div class="loader"></div> | |
| </div> | |
| <script> | |
| // AUTO-CLOSE TIMER | |
| setTimeout(function() { | |
| // 'Cancel' closes it without "Submitting" data, which is fine for a notification. | |
| // Use 'OK' if you want to trigger the next step explicitly, but Cancel is cleaner for a splash. | |
| window.KeyboardMaestro.Cancel(); | |
| }, 2250); | |
| </script> | |
| </body> | |
| </html></string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>Transparent</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6308</integer> | |
| <key>DisplayKind</key> | |
| <string>Variable</string> | |
| <key>HonourFailureSettings</key> | |
| <true/> | |
| <key>IncludeStdErr</key> | |
| <false/> | |
| <key>IncludedVariables</key> | |
| <array> | |
| <string>9999</string> | |
| </array> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>ExecuteAppleScript</string> | |
| <key>Path</key> | |
| <string></string> | |
| <key>Text</key> | |
| <string>tell application "Finder" | |
| try | |
| -- Get the wallpaper of the primary monitor | |
| get POSIX path of (desktop picture as alias) | |
| on error | |
| -- Fallback if something goes wrong | |
| return "" | |
| end try | |
| end tell</string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>TrimResults</key> | |
| <true/> | |
| <key>TrimResultsNew</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| <key>Variable</key> | |
| <string>Local__WallpaperPath</string> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6309</integer> | |
| <key>DisplayKind</key> | |
| <string>None</string> | |
| <key>HonourFailureSettings</key> | |
| <true/> | |
| <key>IncludeStdErr</key> | |
| <false/> | |
| <key>IncludedVariables</key> | |
| <array> | |
| <string>9999</string> | |
| </array> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>ExecuteSwift</string> | |
| <key>Path</key> | |
| <string></string> | |
| <key>Text</key> | |
| <string>#!/usr/bin/swift | |
| import AppKit | |
| // --- CONFIGURATION --- | |
| // 1. Inputs | |
| let env = ProcessInfo.processInfo.environment | |
| let screenshotPath = "/tmp/temp_screenshot.png" | |
| // Default to a system wallpaper if the variable is missing | |
| let wallpaperPath = env["KMVAR_Local__WallpaperPath"] ?? "/System/Library/CoreServices/DefaultDesktop.heic" | |
| // 2. Styling | |
| let border: CGFloat = 80 // Thickness of the wallpaper frame | |
| let shadowBlur: CGFloat = 20 // Softness of the shadow | |
| let shadowOffset: CGFloat = -10 // Distance of shadow (Downwards) | |
| let shadowOpacity: CGFloat = 0.5 | |
| // --- LOGIC --- | |
| // Load Images | |
| guard let fg = NSImage(contentsOfFile: screenshotPath) else { exit(0) } | |
| // Fallback if wallpaper is missing | |
| var bg = NSImage(contentsOfFile: wallpaperPath) | |
| if bg == nil { | |
| bg = NSImage(size: NSSize(width: 1920, height: 1080)) | |
| bg?.lockFocus() | |
| NSColor.darkGray.set() | |
| NSRect(x: 0, y: 0, width: 1920, height: 1080).fill() | |
| bg?.unlockFocus() | |
| } | |
| // Calculate Dimensions | |
| let fgSize = fg.size | |
| let newSize = NSSize(width: fgSize.width + (border * 2), height: fgSize.height + (border * 2)) | |
| // --- NEW: ASPECT FILL CALCULATION --- | |
| // We calculate a crop rectangle (fromRect) so the wallpaper fills the frame without stretching | |
| let targetAspect = newSize.width / newSize.height | |
| let bgSize = bg!.size | |
| let bgAspect = bgSize.width / bgSize.height | |
| var fromRect = NSRect.zero | |
| if targetAspect > bgAspect { | |
| // Target is wider than wallpaper -> Crop Top & Bottom | |
| let newHeight = bgSize.width / targetAspect | |
| let y = (bgSize.height - newHeight) / 2 | |
| fromRect = NSRect(x: 0, y: y, width: bgSize.width, height: newHeight) | |
| } else { | |
| // Target is taller than wallpaper -> Crop Sides (This fixes your vertical screenshot issue) | |
| let newWidth = bgSize.height * targetAspect | |
| let x = (bgSize.width - newWidth) / 2 | |
| fromRect = NSRect(x: x, y: 0, width: newWidth, height: bgSize.height) | |
| } | |
| // ------------------------------------ | |
| // Create Canvas | |
| let newImage = NSImage(size: newSize) | |
| newImage.lockFocus() | |
| // Draw Background (Using the Smart Crop) | |
| bg!.draw(in: NSRect(origin: .zero, size: newSize), | |
| from: fromRect, | |
| operation: .copy, | |
| fraction: 1.0) | |
| // Draw Shadow | |
| NSGraphicsContext.saveGraphicsState() | |
| let shadow = NSShadow() | |
| shadow.shadowOffset = NSSize(width: 0, height: shadowOffset) | |
| shadow.shadowBlurRadius = shadowBlur | |
| shadow.shadowColor = NSColor.black.withAlphaComponent(shadowOpacity) | |
| shadow.set() | |
| // Draw Foreground | |
| let x = (newSize.width - fgSize.width) / 2 | |
| let y = (newSize.height - fgSize.height) / 2 | |
| fg.draw(in: NSRect(x: x, y: y, width: fgSize.width, height: fgSize.height), | |
| from: NSRect(origin: .zero, size: fgSize), | |
| operation: .sourceOver, | |
| fraction: 1.0) | |
| NSGraphicsContext.restoreGraphicsState() | |
| newImage.unlockFocus() | |
| // Save in Place | |
| if let tiffData = newImage.tiffRepresentation, | |
| let bitmap = NSBitmapImageRep(data: tiffData), | |
| let pngData = bitmap.representation(using: .png, properties: [:]) { | |
| try? pngData.write(to: URL(fileURLWithPath: screenshotPath)) | |
| } | |
| exit(0)</string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>TrimResults</key> | |
| <true/> | |
| <key>TrimResultsNew</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6312</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>Notification</string> | |
| <key>SoundName</key> | |
| <string></string> | |
| <key>Subtitle</key> | |
| <string>Frame Added!</string> | |
| <key>Text</key> | |
| <string></string> | |
| <key>Title</key> | |
| <string>%ExecutingMacro%</string> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6314</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>Yes</string> | |
| <key>Variable</key> | |
| <string>Local__FrameAdded</string> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6313</integer> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>Active</string> | |
| <key>Variable</key> | |
| <string>Local__LoopStatus</string> | |
| </dict> | |
| </array> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| </array> | |
| <key>Conditions</key> | |
| <dict> | |
| <key>ConditionList</key> | |
| <array> | |
| <dict> | |
| <key>ConditionType</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Local__LoopStatus</string> | |
| <key>VariableConditionType</key> | |
| <string>Is</string> | |
| <key>VariableValue</key> | |
| <string>Active</string> | |
| </dict> | |
| </array> | |
| <key>ConditionListMatch</key> | |
| <string>All</string> | |
| </dict> | |
| <key>MacroActionType</key> | |
| <string>While</string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionName</key> | |
| <string>Copy the screen grab</string> | |
| <key>ActionUID</key> | |
| <integer>6300</integer> | |
| <key>Destination</key> | |
| <string>Clipboard</string> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>ReadFile</string> | |
| <key>Source</key> | |
| <string>/tmp/temp_screenshot.png</string> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Green</string> | |
| <key>ActionName</key> | |
| <string>If (New) → Create Folder</string> | |
| <key>ActionUID</key> | |
| <integer>6301</integer> | |
| <key>Conditions</key> | |
| <dict> | |
| <key>ConditionList</key> | |
| <array> | |
| <dict> | |
| <key>ConditionType</key> | |
| <string>Variable</string> | |
| <key>Variable</key> | |
| <string>Local__Category</string> | |
| <key>VariableConditionType</key> | |
| <string>Contains</string> | |
| <key>VariableValue</key> | |
| <string>+ New Category</string> | |
| </dict> | |
| </array> | |
| <key>ConditionListMatch</key> | |
| <string>All</string> | |
| </dict> | |
| <key>ElseActions</key> | |
| <array/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>IfThenElse</string> | |
| <key>ThenActions</key> | |
| <array> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6302</integer> | |
| <key>Buttons</key> | |
| <array> | |
| <dict> | |
| <key>Button</key> | |
| <string>OK</string> | |
| </dict> | |
| <dict> | |
| <key>Button</key> | |
| <string>Cancel</string> | |
| <key>Cancel</key> | |
| <true/> | |
| </dict> | |
| </array> | |
| <key>MacroActionType</key> | |
| <string>PromptForUserInput</string> | |
| <key>Prompt</key> | |
| <string>Please enter the details for these variables.</string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>Title</key> | |
| <string>New Folder Name</string> | |
| <key>Variables</key> | |
| <array> | |
| <dict> | |
| <key>Default</key> | |
| <string></string> | |
| <key>Type</key> | |
| <string>Automatic</string> | |
| <key>Variable</key> | |
| <string>Local__Category</string> | |
| </dict> | |
| </array> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6303</integer> | |
| <key>MacroActionType</key> | |
| <string>SetVariableToText</string> | |
| <key>Text</key> | |
| <string>%Variable%Global__CategoryList%%Return%%Variable%Local__Category%</string> | |
| <key>Variable</key> | |
| <string>Global__CategoryList</string> | |
| </dict> | |
| </array> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Purple</string> | |
| <key>ActionName</key> | |
| <string>Prompt (Final Action)</string> | |
| <key>ActionUID</key> | |
| <integer>6304</integer> | |
| <key>Floating</key> | |
| <true/> | |
| <key>HasTitle</key> | |
| <false/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>CustomPrompt</string> | |
| <key>Text</key> | |
| <string><!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <style> | |
| /* --- CYBERPUNK THEME RESTORED --- */ | |
| /* SCROLLBAR (Green Tint) */ | |
| ::-webkit-scrollbar { width: 5px; } | |
| ::-webkit-scrollbar-track { background: transparent; } | |
| ::-webkit-scrollbar-thumb { background: rgba(0, 255, 100, 0.2); border-radius: 4px; } | |
| ::-webkit-scrollbar-thumb:hover { background: rgba(0, 255, 100, 0.6); } | |
| html, body { | |
| margin: 0; padding: 0; | |
| width: 100%; | |
| height: 100%; | |
| overflow: hidden; | |
| } | |
| body { | |
| /* Deep Black Background */ | |
| background-color: rgba(5, 5, 8, 0.95); | |
| backdrop-filter: blur(20px) saturate(150%); | |
| -webkit-backdrop-filter: blur(20px) saturate(150%); | |
| /* Subtle border */ | |
| border: 1px solid rgba(100, 255, 100, 0.15); | |
| box-shadow: 0 0 30px rgba(0, 0, 0, 0.9); | |
| color: #d0d0d0; | |
| font-family: "Menlo", "Consolas", "Monaco", monospace; | |
| box-sizing: border-box; | |
| user-select: none; | |
| cursor: default; | |
| /* Layout */ | |
| display: flex; | |
| flex-direction: column; | |
| padding: 2px; | |
| } | |
| /* HEADER SECTION */ | |
| #header { | |
| padding: 14px 10px 10px 10px; | |
| text-align: center; | |
| border-bottom: 1px solid rgba(255, 255, 255, 0.05); | |
| background: linear-gradient(to bottom, rgba(255,255,255,0.02), transparent); | |
| margin-bottom: 6px; | |
| } | |
| .title { | |
| font-size: 13px; | |
| font-weight: 800; | |
| color: #ffffff; /* WHITE Header */ | |
| text-transform: uppercase; | |
| letter-spacing: 1.5px; | |
| text-shadow: 0 0 10px rgba(255, 255, 255, 0.2); | |
| } | |
| .subtitle { | |
| font-size: 13px; | |
| font-weight: 500; | |
| color: #ff00ff; /* MAGENTA Subtitle */ | |
| margin-top: 4px; | |
| text-shadow: 0 0 8px rgba(255, 0, 255, 0.4); | |
| } | |
| /* LIST AREA */ | |
| #scroll-view { | |
| flex-grow: 1; | |
| overflow-y: auto; | |
| padding: 6px 10px; | |
| } | |
| /* LIST ITEMS */ | |
| .item { | |
| padding: 10px 14px; | |
| margin-bottom: 4px; | |
| border-radius: 6px; | |
| font-size: 14px; | |
| letter-spacing: 0.5px; | |
| transition: all 0.1s ease-out; | |
| border: 1px solid transparent; | |
| text-align: left; /* Aligned Left */ | |
| color: #aaaaaa; | |
| } | |
| /* THE GREEN GLOW (Matches your Screenshot) */ | |
| .item:hover, .selected { | |
| background-color: rgba(0, 255, 100, 0.05); | |
| border: 1px solid rgba(50, 255, 100, 0.6); | |
| color: #50ff80; /* GREEN Text */ | |
| box-shadow: 0 0 15px rgba(0, 255, 100, 0.15), inset 0 0 10px rgba(0, 255, 100, 0.05); | |
| text-shadow: 0 0 5px rgba(50, 255, 100, 0.5); | |
| font-weight: 600; | |
| } | |
| /* DIVIDER */ | |
| .separator { | |
| height: 1px; | |
| background: rgba(255, 255, 255, 0.1); | |
| margin: 8px 0 8px 0; | |
| } | |
| /* DO NOTHING (Dimmed) */ | |
| .cancel-item { | |
| color: #666; | |
| } | |
| .cancel-item:hover, .cancel-item.selected { | |
| border-color: rgba(150, 150, 150, 0.3); | |
| color: #ccc; | |
| box-shadow: none; | |
| background-color: rgba(255, 255, 255, 0.05); | |
| } | |
| </style> | |
| </head> | |
| <body data-kmwindow="SCREEN(Main,MidX)-150,SCREEN(Main,MidY)-200,300,320"> | |
| <div id="header"> | |
| <div class="title">Screenshot Saved</div> | |
| <div class="subtitle" id="sub-text">Saved to...</div> | |
| </div> | |
| <div id="scroll-view"> | |
| <div id="list"> | |
| <div class="item" onclick="submit('Open File')">Open File</div> | |
| <div class="item" onclick="submit('Open in FlowVision')">Open in FlowVision | |
| </div> | |
| <div class="item" onclick="submit('Open in qView')">Open in qView</div> | |
| <div class="item" onclick="submit('Show in Finder')">Show in Finder</div> | |
| <div class="separator"></div> | |
| <div class="item cancel-item" onclick="submit('Do Nothing')">Do Nothing</div> | |
| </div> | |
| </div> | |
| <script> | |
| // Update subtitle | |
| const category = window.KeyboardMaestro.GetVariable('Local__Category'); | |
| if (category) { | |
| document.getElementById('sub-text').textContent = "Saved to " + category; | |
| } | |
| function submit(val) { | |
| window.KeyboardMaestro.SetVariable('Local__NextStep', val); | |
| window.KeyboardMaestro.Submit('OK'); | |
| } | |
| function initNavigation() { | |
| let index = 0; | |
| const items = document.querySelectorAll('.item'); | |
| if (items.length > 0) items[0].classList.add('selected'); | |
| // Focus Lock | |
| window.focus(); | |
| if(document.body) document.body.focus(); | |
| document.addEventListener('keydown', (e) => { | |
| // --- BEEP KILLER --- | |
| if (e.key === 'ArrowDown') { | |
| e.preventDefault(); | |
| items[index].classList.remove('selected'); | |
| index = (index + 1) % items.length; | |
| items[index].classList.add('selected'); | |
| items[index].scrollIntoView({block: "nearest"}); | |
| } | |
| else if (e.key === 'ArrowUp') { | |
| e.preventDefault(); | |
| items[index].classList.remove('selected'); | |
| index = (index - 1 + items.length) % items.length; | |
| items[index].classList.add('selected'); | |
| items[index].scrollIntoView({block: "nearest"}); | |
| } | |
| else if (e.key === 'Enter') { | |
| e.preventDefault(); | |
| items[index].click(); | |
| } | |
| else if (e.key === 'Escape') { | |
| submit('Do Nothing'); | |
| } | |
| }); | |
| } | |
| window.addEventListener('load', function() { setTimeout(initNavigation, 50); }); | |
| </script> | |
| </body> | |
| </html></string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>Transparent</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionColor</key> | |
| <string>Magenta</string> | |
| <key>ActionName</key> | |
| <string>Shell Script (Move File)</string> | |
| <key>ActionUID</key> | |
| <integer>6305</integer> | |
| <key>DisplayKind</key> | |
| <string>Asynchronously</string> | |
| <key>HonourFailureSettings</key> | |
| <true/> | |
| <key>IncludeStdErr</key> | |
| <false/> | |
| <key>IncludedVariables</key> | |
| <array> | |
| <string>9999</string> | |
| </array> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>ExecuteShellScript</string> | |
| <key>Path</key> | |
| <string></string> | |
| <key>Source</key> | |
| <string>Nothing</string> | |
| <key>Text</key> | |
| <string>#!/bin/bash | |
| # 1. SETUP PATHS | |
| # Use your specific path here | |
| ROOT="$KMVAR_Local__MainFolder" | |
| CATEGORY="$KMVAR_Local__Category" | |
| ACTION="$KMVAR_Local__NextStep" | |
| # If ROOT starts with "~", replace it with the actual Home Directory | |
| if [[ "$ROOT" == \~* ]]; then | |
| ROOT="${ROOT/#\~/$HOME}" | |
| fi | |
| # If ROOT is literally "$HOME...", try to fix that too (rare but possible) | |
| if [[ "$ROOT" == \$HOME* ]]; then | |
| ROOT="${ROOT/\$HOME/$HOME}" | |
| fi | |
| # 2. CALCULATE FILENAME | |
| TIMESTAMP="$KMVAR_Local__Timestamp" | |
| FILENAME="${CATEGORY}_${TIMESTAMP}.png" | |
| FOLDER="$ROOT/$CATEGORY" | |
| FULL_PATH="$FOLDER/$FILENAME" | |
| # 3. MOVE THE FILE | |
| mkdir -p "$FOLDER" | |
| mv "/tmp/temp_screenshot.png" "$FULL_PATH" | |
| # 4. HANDLE THE UI ACTION (Open/Show) | |
| # We use the full path to the 'open' command to be safe | |
| if [ "$ACTION" == "Open File" ]; then | |
| /usr/bin/open "$FULL_PATH" | |
| elif [ "$ACTION" == "Open in qView" ]; then | |
| # -a opens a specific application | |
| /usr/bin/open -a "qView" "$FULL_PATH" | |
| elif [ "$ACTION" == "Open in FlowVision" ]; then | |
| # -a opens a specific application | |
| /usr/bin/open -a "FlowVision" "$FULL_PATH" | |
| elif [ "$ACTION" == "Show in Finder" ]; then | |
| /usr/bin/open -R "$FULL_PATH" | |
| fi</string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| <key>TrimResults</key> | |
| <true/> | |
| <key>TrimResultsNew</key> | |
| <true/> | |
| <key>UseText</key> | |
| <true/> | |
| </dict> | |
| <dict> | |
| <key>ActionUID</key> | |
| <integer>6306</integer> | |
| <key>DeviceID</key> | |
| <string>SOUNDEFFECTS</string> | |
| <key>IsActive</key> | |
| <false/> | |
| <key>IsDisclosed</key> | |
| <false/> | |
| <key>MacroActionType</key> | |
| <string>PlaySound</string> | |
| <key>Path</key> | |
| <string>/System/Library/Sounds/Glass.aiff</string> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| </array> | |
| <key>TimeOutAbortsMacro</key> | |
| <true/> | |
| </dict> | |
| </array> | |
| <key>CreationDate</key> | |
| <real>788434180.73563695</real> | |
| <key>CustomIconData</key> | |
| <string>KMEP-GenericApplication-/Applications/Spaces.app</string> | |
| <key>ModificationDate</key> | |
| <real>788514481.32022905</real> | |
| <key>Name</key> | |
| <string>Screen Grab Router</string> | |
| <key>Triggers</key> | |
| <array> | |
| <dict> | |
| <key>FireType</key> | |
| <string>Pressed</string> | |
| <key>KeyCode</key> | |
| <integer>21</integer> | |
| <key>MacroTriggerType</key> | |
| <string>HotKey</string> | |
| <key>Modifiers</key> | |
| <integer>768</integer> | |
| </dict> | |
| </array> | |
| <key>UID</key> | |
| <string>58AFC0BF-CD76-4756-9A75-01904921689D</string> | |
| </dict> | |
| </array> | |
| <key>Name</key> | |
| <string>Screen Grabber Routing</string> | |
| <key>ToggleMacroUID</key> | |
| <string>DDFF254E-3D18-4A02-A2CE-928E8FA3B9B5</string> | |
| <key>UID</key> | |
| <string>BB511681-3DBB-417C-A366-41D315949357</string> | |
| </dict> | |
| </array> | |
| </plist> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment