├── .gitignore ├── LICENSE ├── README.md ├── public ├── alfred_buffer.webp ├── icon_dark_mode.webp ├── icon_light_mode.webp ├── log_detail.webp ├── types.webp └── universal_action.webp └── src ├── compress.sh ├── entry.js ├── icon.png ├── icons ├── delete.webp ├── info.webp ├── manual.webp ├── new.webp ├── presets.webp ├── return.webp ├── run.webp └── web.webp ├── info.plist ├── json └── presets.json ├── notificator ├── options.js └── presets.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | **/.DS_Store 3 | src/prefs.plist -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-present Benjamin Oddou 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | logo-dark 2 | logo-light 3 | 4 | [![made with heart by Benjamin Oddou](https://img.shields.io/badge/made%20with%20%E2%99%A5%20by-benjamin%20oddou-62D895.svg?style=flat)](https://github.com/BenjaminOddou) 5 | [![saythanks](https://img.shields.io/badge/say-thanks-469C2C.svg?style=flat)](https://saythanks.io/to/BenjaminOddou) 6 | 7 | Welcome to the Alfred Smart WebP repository: **An Alfred Workflow** ✨ 8 | 9 | ## ✅ Prerequisites 10 | 11 | * MacOS 12 | * Alfred 5. Note that the [Alfred Powerpack](https://www.alfredapp.com/powerpack/) is required to use workflows. 13 | 14 | ## 🏎️ cwebp 15 | 16 | Under the hood, the compression is made with [cwebp](https://developers.google.com/speed/webp/docs/cwebp) (made by Google), a tool that allows to compress images into the WebP format, which is generally lighter, and broadly used to share images on the web. 17 | 18 | ## ⬇️ Installation 19 | 20 | 1. [Download the workflow](https://github.com/BenjaminOddou/alfred-smart-webp-compression/releases/latest) 21 | 2. Double click the `.alfredworkflow` file to install 22 | 23 | ## 🧰 Setup the workflow 24 | 25 | #### Open the Terminal of you Mac and run the following command: 26 | 27 | Install cwebp (using [Homebrew](https://brew.sh)): 28 | 29 | ```shell 30 | brew install webp 31 | ``` 32 | 33 | ## 🧙‍♂️ Invoke the workflow 34 | 35 | You can invoke the workflow by writing `webp` into the Alfred search box. You can change this value by changing the `🕹️ Trigger` variable in workflow configuration panel. 36 | 37 | ## 🤖 Usage of the workflow 38 | 39 | ### Handling presets 40 | 41 | #### Create a preset 42 | 43 | Go under the `presets section` and click on `Add a new preset`. 44 | 45 | Add your preset by putting a `value`, press ⏎ and input a `title` and a `subtitle` separated by a `/`. 46 | 47 | #### Modify a preset 48 | 49 | Go under the `presets section` and click on the preset you want to modify. 50 | 51 | Select wether you want to modify the `title/subtitle` or the `value` and press ⏎. Input the new title/subtitle or value and press ⏎. 52 | 53 | #### Remove a preset 54 | 55 | Under the `presets section`, click on `Remove a preset`. 56 | 57 | Select the preset you want to remove and press ⏎. 58 | 59 | ### Start the compression 60 | 61 | #### Using Workflow File Filter 62 | 63 | Under the home menu, click on `Start the compression`. 64 | 65 | Select the folder with images or directly the image you want to compress and press enter ⏎. 66 | 67 | > Note that when selecting a folder, images within subdirectories aren't selected if `🔍 Depth of the search` is 1. If you want images in subdirectories, increase this value. Only images with `png|jpg|jpeg|tif|tiff|webp` file extensions are selected. In addition, they aren't case sensitive, meaning that the image extension can be `PNG|JpG|tifF...` 68 | 69 | Here is an example where the user selected a folder and put `Level 2` in `🔍 Depth of the search` : 70 | ```shell 71 | . 72 | ├── selected folder # Level 1 73 | │ ├── subdirectory # Level 2 74 | │ │ ├── image.PnG # selected ✅ 75 | │ │ ├── a nested folder # Level 3 76 | │ │ │ ├── one image.webp # not selected ❌ 77 | │ │ │ └── a second image.tiff # not selected ❌ 78 | │ │ └── file.doc # not selected ❌ 79 | │ └── first-image.jpeg # selected ✅ 80 | ``` 81 | 82 | Alternatively, use the `Alfred Buffer` to select folder(s) and image(s) at the same time !! Basic commands are : 83 | 84 | * ⌥↑ to add a file to the buffer from Alfred's results. 85 | * ⌥↓ to add a file and move to the next item in your list of results. 86 | * ⌥← to remove the last item from the buffer. 87 | * ⌥→ to action all items in the buffer. 88 | * ⌥⌫ to remove all items from the buffer. 89 | 90 | To know more on how to use `Alfred Buffer`, follow this [link](https://www.alfredapp.com/help/features/file-search/#file-buffer). 91 | 92 | > Note that `Alfred Buffer` is preferred compare to the `{query}`, meaning that if you select a folder/image (by clicking on it or by pressing enter ⏎) that is not included in the buffer, **it will not be compressed**. 93 | 94 | ![alfred_buffer](public/alfred_buffer.webp) 95 | 96 | Choose the cwebp options by selecting a preset or input it manually by pressing `Manual options`. 97 | 98 | #### Using Alfred Universal Actions 99 | 100 | Select the folder(s) / image(s) you want to compress within alfred using `Quick Search` and run `Universal Actions` with → or ⌥→ if you used the `Alfred buffer`. Select "Compress images to WebP". 101 | 102 | ![universal_action](public/universal_action.webp) 103 | 104 | > Note that the workflow is type sensitive, meaning that if you select a file that is not part of the following types, the action "Compress images to WebP" will not be available 105 | 106 | ![types](public/types.webp) 107 | 108 | If you want to know more on how to use Alfred Universal Actions, follow this [link](https://www.alfredapp.com/help/features/universal-actions/). 109 | 110 | #### Logs output 111 | 112 | Check the logs of your compression under the `Data folder`. The log file contains the 2 parts. 113 | 114 | 1. In the orange box there is : 115 | * Date of the compression with a `YYYY/MM/dd` pattern. 116 | * Exact time of the compression with a `HH:mm:ss` pattern. 117 | * Folder(s) + image(s) path(s) selected with a tab ⇥ separator. 118 | * Preset or manual input. Preset will be displayed as `preset_name,preset_detail` whereas manual input will be displayed raw. 119 | * The selected level of variable `🔍 Depth of the search` 120 | 2. In the green box there is the cwebp output. 121 | 122 | > Note that each compression is separated by a line. 123 | 124 | ![log_detail](public/log_detail.webp) 125 | 126 | ## ⚖️ License 127 | 128 | [MIT License](LICENSE) © Benjamin Oddou 129 | -------------------------------------------------------------------------------- /public/alfred_buffer.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/public/alfred_buffer.webp -------------------------------------------------------------------------------- /public/icon_dark_mode.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/public/icon_dark_mode.webp -------------------------------------------------------------------------------- /public/icon_light_mode.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/public/icon_light_mode.webp -------------------------------------------------------------------------------- /public/log_detail.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/public/log_detail.webp -------------------------------------------------------------------------------- /public/types.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/public/types.webp -------------------------------------------------------------------------------- /public/universal_action.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/public/universal_action.webp -------------------------------------------------------------------------------- /src/compress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | function handle_error { 4 | source ./notificator --title "🚨 Error" --message "An error occurred! Exiting script.." --sound "$sound" 5 | exit 1 6 | } 7 | 8 | trap "handle_error" ERR 9 | 10 | (source ./notificator --title "⏳ Please wait..." --message "The workflow is generating images" --sound "$sound") & 11 | 12 | echo "🔍 Depth of the search : Level ${level}\n" 13 | 14 | LINKS=(${(s/ /)_links_list}) # split by tab 15 | IMAGES=() 16 | IFS=$'\n' 17 | 18 | for LINK in "${LINKS[@]}"; do 19 | if [ -d "$LINK" ]; then 20 | IMAGES+=($(find -E "$LINK" -maxdepth "$level" -iregex '.*\.(png|jpg|jpeg|tif|tiff|webp)')) 21 | else 22 | IMAGES+=("$LINK") 23 | fi 24 | done 25 | 26 | for IMAGE in "${IMAGES[@]}"; do 27 | 2>&1 eval "cwebp $_the_preset \"$IMAGE\" -o \"${IMAGE%.*}.webp\"" 28 | done 29 | 30 | if [[ $workflow_action = "_notif" ]];then 31 | sleep 0.5 32 | source ./notificator --title "⌛ Finished" --message "Process completed. You can check the log file" --sound "$sound" 33 | fi -------------------------------------------------------------------------------- /src/entry.js: -------------------------------------------------------------------------------- 1 | ObjC.import('stdlib') 2 | const app = Application.currentApplication() 3 | app.includeStandardAdditions = true 4 | const PWD = $.getenv("PWD") 5 | const fm = $.NSFileManager.defaultManager 6 | const encoding = $.NSUTF8StringEncoding 7 | const level = $.NSProcessInfo.processInfo.environment.objectForKey('split2')?.js || 0 8 | const type = $.NSProcessInfo.processInfo.environment.objectForKey('split3')?.js || null 9 | const action = $.NSProcessInfo.processInfo.environment.objectForKey('split4')?.js || null 10 | const key = $.NSProcessInfo.processInfo.environment.objectForKey('split5')?.js || null 11 | const data_folder = $.NSProcessInfo.processInfo.environment.objectForKey('data_folder')?.js || $.NSProcessInfo.processInfo.environment.objectForKey('alfred_workflow_data').js 12 | const cmd = "which cwebp"; 13 | let items = [] 14 | 15 | function readFile(path) { 16 | if (fm.fileExistsAtPath(path)) { 17 | return $.NSString.stringWithContentsOfFileEncodingError(path, encoding, null).js 18 | } else { 19 | const sourcePath = `${PWD}/json/presets.json` 20 | fm.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(data_folder, true, $(), null) 21 | fm.copyItemAtPathToPathError(sourcePath, path, null) 22 | return $.NSString.stringWithContentsOfFileEncodingError(path, encoding, null).js 23 | } 24 | } 25 | 26 | try { 27 | app.doShellScript(cmd) 28 | if (level == 0){ 29 | items.push( 30 | { 31 | title: 'Start the compression', 32 | subtitle: 'Run the cwebp compression with your parameters', 33 | arg: '_compress', 34 | icon: { path: 'icons/run.webp' }, 35 | }, 36 | { 37 | title: 'Presets', 38 | subtitle: 'Create, modify or remove presets', 39 | arg: '_rerun;1;presets', 40 | icon: { path: 'icons/presets.webp' }, 41 | }, 42 | { 43 | title: 'Online documentation', 44 | subtitle: 'Show cwebp documentation', 45 | quicklookurl: 'https://developers.google.com/speed/webp/docs/cwebp', 46 | arg: '_web;https://developers.google.com/speed/webp/docs/cwebp', 47 | icon: { path: 'icons/web.webp' }, 48 | }, 49 | ) 50 | } else { 51 | items.push({ 52 | title: 'Return', 53 | subtitle: 'Back to previous state', 54 | arg: `_rerun;${level - 1};${type}`, 55 | icon: { path: 'icons/return.webp' }, 56 | }) 57 | if (level == 1) { 58 | if (type == 'presets') { 59 | items.push( 60 | { 61 | title: 'Add a new preset', 62 | subtitle: 'Create a new preset with custom cwebp options', 63 | arg: '_presets;new', 64 | icon: { path: 'icons/new.webp' }, 65 | }, 66 | { 67 | title: 'Delete a preset', 68 | subtitle: 'Erase a preset from the list below', 69 | arg: '_rerun;2;presets;delete', 70 | icon: { path: 'icons/delete.webp' }, 71 | } 72 | ) 73 | content = JSON.parse(readFile(`${data_folder}/presets.json`)) 74 | content.items.forEach(item => { 75 | item.arg = `_rerun;2;presets;modify;${item.id}` 76 | items.push(item) 77 | }) 78 | } 79 | } else if (level == 2) { 80 | if (type == 'presets') { 81 | if (action == 'delete') { 82 | content = JSON.parse(readFile(`${data_folder}/presets.json`)) 83 | content.items.forEach(item => { 84 | item.arg = `_presets;delete;${item.id}` 85 | items.push(item) 86 | }) 87 | } else if (action == 'modify') { 88 | content = JSON.parse(readFile(`${data_folder}/presets.json`)) 89 | content.items.forEach(item => { 90 | if (item.id == key) { 91 | items.push( 92 | { 93 | title: 'Modify the Preset\'s Title/Subtitle', 94 | subtitle: `Current Title: ${item.title} ǀ Current Subtitle: ${item.subtitle}`, 95 | arg: `_presets;modify;tl&sb;Title and/or Subtitle;${item.title}/${item.subtitle};${key}`, 96 | icon: { path: 'icons/presets.webp' }, 97 | }, 98 | { 99 | title: 'Modify the Preset\'s Value', 100 | subtitle: `Current Value: ${item.arg}`, 101 | arg: `_presets;modify;arg;Value;${item.arg};${key}`, 102 | icon: { path: 'icons/presets.webp' }, 103 | } 104 | ) 105 | } 106 | }) 107 | } 108 | } 109 | } 110 | } 111 | JSON.stringify({ items }) 112 | } catch { 113 | items = [] 114 | items.push( 115 | { 116 | title: 'Something went wrong...', 117 | subtitle: 'Press ⏎ to check the docs online', 118 | arg: '_web;https://github.com/BenjaminOddou/alfred-smart-webp-compression', 119 | quicklookurl: 'https://github.com/BenjaminOddou/alfred-smart-webp-compression', 120 | icon: { path: 'icons/info.webp' }, 121 | }, 122 | ) 123 | JSON.stringify({ items }) 124 | } -------------------------------------------------------------------------------- /src/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icon.png -------------------------------------------------------------------------------- /src/icons/delete.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/delete.webp -------------------------------------------------------------------------------- /src/icons/info.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/info.webp -------------------------------------------------------------------------------- /src/icons/manual.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/manual.webp -------------------------------------------------------------------------------- /src/icons/new.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/new.webp -------------------------------------------------------------------------------- /src/icons/presets.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/presets.webp -------------------------------------------------------------------------------- /src/icons/return.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/return.webp -------------------------------------------------------------------------------- /src/icons/run.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/run.webp -------------------------------------------------------------------------------- /src/icons/web.webp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BenjaminOddou/alfred-smart-webp-compression/0c2c10e882d5739de7d9871901b31aea84bfb87e/src/icons/web.webp -------------------------------------------------------------------------------- /src/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | com.benjamino.smart_webp_compression 7 | connections 8 | 9 | 045C5FE6-9D9A-4C6E-BB9F-73E732480CB9 10 | 11 | 12 | destinationuid 13 | 1F5239EB-3ECF-4E0E-8431-A65EB2327A19 14 | modifiers 15 | 0 16 | modifiersubtext 17 | 18 | vitoclose 19 | 20 | 21 | 22 | 0BC6A292-B409-4DAC-8EA9-2C8604D1F303 23 | 24 | 25 | destinationuid 26 | 42AF05BF-C545-42DF-AC3B-9F81F851C963 27 | modifiers 28 | 0 29 | modifiersubtext 30 | 31 | vitoclose 32 | 33 | 34 | 35 | 13DDCB6C-9438-4C2B-B386-867F758EEDAF 36 | 37 | 38 | destinationuid 39 | 38FEF466-6198-4D50-AA90-D70C13B216F4 40 | modifiers 41 | 0 42 | modifiersubtext 43 | 44 | vitoclose 45 | 46 | 47 | 48 | 1F5239EB-3ECF-4E0E-8431-A65EB2327A19 49 | 50 | 51 | destinationuid 52 | 13DDCB6C-9438-4C2B-B386-867F758EEDAF 53 | modifiers 54 | 0 55 | modifiersubtext 56 | 57 | sourceoutputuid 58 | 82863E01-18CA-4A51-B90A-43A845142D62 59 | vitoclose 60 | 61 | 62 | 63 | destinationuid 64 | A5FB494F-4E88-47A0-879E-401294A7C6D4 65 | modifiers 66 | 0 67 | modifiersubtext 68 | 69 | sourceoutputuid 70 | 1891A02A-6CF8-4BBC-B8F9-97BD1B09BF5B 71 | vitoclose 72 | 73 | 74 | 75 | destinationuid 76 | FDEDA57C-C351-4AA4-B0D2-BA3A16A2125F 77 | modifiers 78 | 0 79 | modifiersubtext 80 | 81 | sourceoutputuid 82 | F94A9936-1BF8-45BE-AFB3-BED2285C65FD 83 | vitoclose 84 | 85 | 86 | 87 | destinationuid 88 | E059706B-E9CB-457B-A984-1F96041A300B 89 | modifiers 90 | 0 91 | modifiersubtext 92 | 93 | sourceoutputuid 94 | 3E3E8353-8D8A-4CFD-B5B3-BDD74E9917F5 95 | vitoclose 96 | 97 | 98 | 99 | 2308696E-54E9-47F6-BFAD-BE577F5EA33C 100 | 101 | 102 | destinationuid 103 | 94DB40C4-AE8A-4383-B916-29465859AAF9 104 | modifiers 105 | 0 106 | modifiersubtext 107 | 108 | vitoclose 109 | 110 | 111 | 112 | 24C70ED0-81F4-484E-841F-032B110455CA 113 | 114 | 115 | destinationuid 116 | 6C3B838B-C528-449D-B058-3836F59421EA 117 | modifiers 118 | 0 119 | modifiersubtext 120 | 121 | vitoclose 122 | 123 | 124 | 125 | 2594B231-AB96-474F-A44E-2C733F045144 126 | 127 | 128 | destinationuid 129 | 3FEE47AA-2088-45F6-B112-EC2794BD9397 130 | modifiers 131 | 0 132 | modifiersubtext 133 | 134 | vitoclose 135 | 136 | 137 | 138 | 29E00EF6-FC86-4DE7-83BC-A4D225269C5E 139 | 140 | 141 | destinationuid 142 | 3B719F83-111C-42AA-A4F0-3858F6AEBDF8 143 | modifiers 144 | 0 145 | modifiersubtext 146 | 147 | vitoclose 148 | 149 | 150 | 151 | 29FE5492-8E67-4F8F-87A3-159939E6A097 152 | 153 | 154 | destinationuid 155 | 8CA4509B-0219-4AD8-9C45-13EC464FF9DF 156 | modifiers 157 | 0 158 | modifiersubtext 159 | 160 | vitoclose 161 | 162 | 163 | 164 | 312ACF3E-422C-4D71-B4C8-524DD7FA8B12 165 | 166 | 167 | destinationuid 168 | 3FEE47AA-2088-45F6-B112-EC2794BD9397 169 | modifiers 170 | 0 171 | modifiersubtext 172 | 173 | vitoclose 174 | 175 | 176 | 177 | 38FEF466-6198-4D50-AA90-D70C13B216F4 178 | 179 | 180 | destinationuid 181 | 69BA9B7D-DD02-4970-AF06-8266F95388C9 182 | modifiers 183 | 0 184 | modifiersubtext 185 | 186 | vitoclose 187 | 188 | 189 | 190 | 3B719F83-111C-42AA-A4F0-3858F6AEBDF8 191 | 192 | 193 | destinationuid 194 | E05259B6-5B68-46E1-B5E3-A2955ACC4A3A 195 | modifiers 196 | 0 197 | modifiersubtext 198 | 199 | vitoclose 200 | 201 | 202 | 203 | 3BC14125-DD5B-4FA9-9AD5-A3A69F183B2F 204 | 205 | 206 | destinationuid 207 | 6C3B838B-C528-449D-B058-3836F59421EA 208 | modifiers 209 | 0 210 | modifiersubtext 211 | 212 | vitoclose 213 | 214 | 215 | 216 | 3F40E4A0-B574-41EF-B31C-49AF88E9DEA3 217 | 218 | 219 | destinationuid 220 | ECEF6C22-D209-4F02-8240-FFF192BCD9B9 221 | modifiers 222 | 0 223 | modifiersubtext 224 | 225 | vitoclose 226 | 227 | 228 | 229 | 3FEE47AA-2088-45F6-B112-EC2794BD9397 230 | 231 | 232 | destinationuid 233 | 3F40E4A0-B574-41EF-B31C-49AF88E9DEA3 234 | modifiers 235 | 0 236 | modifiersubtext 237 | 238 | vitoclose 239 | 240 | 241 | 242 | 42AF05BF-C545-42DF-AC3B-9F81F851C963 243 | 244 | 245 | destinationuid 246 | 24C70ED0-81F4-484E-841F-032B110455CA 247 | modifiers 248 | 0 249 | modifiersubtext 250 | 251 | vitoclose 252 | 253 | 254 | 255 | 69BA9B7D-DD02-4970-AF06-8266F95388C9 256 | 257 | 258 | destinationuid 259 | CF9124F1-C2EF-4BBE-B066-A2CCC6C1149B 260 | modifiers 261 | 0 262 | modifiersubtext 263 | 264 | vitoclose 265 | 266 | 267 | 268 | 7587F5D4-DC06-4411-BDC1-EA1FD81363D6 269 | 270 | 271 | destinationuid 272 | 3BC14125-DD5B-4FA9-9AD5-A3A69F183B2F 273 | modifiers 274 | 0 275 | modifiersubtext 276 | 277 | vitoclose 278 | 279 | 280 | 281 | 8CA4509B-0219-4AD8-9C45-13EC464FF9DF 282 | 283 | 284 | destinationuid 285 | F2BF7B8C-1591-4877-AFF5-0EAFDFB59178 286 | modifiers 287 | 0 288 | modifiersubtext 289 | 290 | vitoclose 291 | 292 | 293 | 294 | 94DB40C4-AE8A-4383-B916-29465859AAF9 295 | 296 | 297 | destinationuid 298 | 3B719F83-111C-42AA-A4F0-3858F6AEBDF8 299 | modifiers 300 | 0 301 | modifiersubtext 302 | 303 | vitoclose 304 | 305 | 306 | 307 | C4C284CD-55E1-41E9-867A-B48CA7AB5D47 308 | 309 | 310 | destinationuid 311 | 2594B231-AB96-474F-A44E-2C733F045144 312 | modifiers 313 | 0 314 | modifiersubtext 315 | 316 | vitoclose 317 | 318 | 319 | 320 | CF9124F1-C2EF-4BBE-B066-A2CCC6C1149B 321 | 322 | 323 | destinationuid 324 | 29E00EF6-FC86-4DE7-83BC-A4D225269C5E 325 | modifiers 326 | 0 327 | modifiersubtext 328 | 329 | sourceoutputuid 330 | 40F21FC1-5AB6-4DD3-BBB7-CDD2D7B59B8F 331 | vitoclose 332 | 333 | 334 | 335 | destinationuid 336 | 94DB40C4-AE8A-4383-B916-29465859AAF9 337 | modifiers 338 | 0 339 | modifiersubtext 340 | 341 | vitoclose 342 | 343 | 344 | 345 | E05259B6-5B68-46E1-B5E3-A2955ACC4A3A 346 | 347 | 348 | destinationuid 349 | C4C284CD-55E1-41E9-867A-B48CA7AB5D47 350 | modifiers 351 | 0 352 | modifiersubtext 353 | 354 | sourceoutputuid 355 | B04F7F98-F4C6-4E61-986D-68F6986FEA93 356 | vitoclose 357 | 358 | 359 | 360 | destinationuid 361 | 312ACF3E-422C-4D71-B4C8-524DD7FA8B12 362 | modifiers 363 | 0 364 | modifiersubtext 365 | 366 | vitoclose 367 | 368 | 369 | 370 | E059706B-E9CB-457B-A984-1F96041A300B 371 | 372 | 373 | destinationuid 374 | 0BC6A292-B409-4DAC-8EA9-2C8604D1F303 375 | modifiers 376 | 0 377 | modifiersubtext 378 | 379 | sourceoutputuid 380 | 40F21FC1-5AB6-4DD3-BBB7-CDD2D7B59B8F 381 | vitoclose 382 | 383 | 384 | 385 | destinationuid 386 | 6C3B838B-C528-449D-B058-3836F59421EA 387 | modifiers 388 | 0 389 | modifiersubtext 390 | 391 | sourceoutputuid 392 | 9A4468F5-CA10-41FA-9110-3FEAA5816577 393 | vitoclose 394 | 395 | 396 | 397 | destinationuid 398 | 7587F5D4-DC06-4411-BDC1-EA1FD81363D6 399 | modifiers 400 | 0 401 | modifiersubtext 402 | 403 | sourceoutputuid 404 | 8EE14863-8E4A-47BE-9D21-B6624353D444 405 | vitoclose 406 | 407 | 408 | 409 | ECEF6C22-D209-4F02-8240-FFF192BCD9B9 410 | 411 | 412 | destinationuid 413 | 58F33492-15F5-46AB-A362-CA56E17F396D 414 | modifiers 415 | 0 416 | modifiersubtext 417 | 418 | sourceoutputuid 419 | 858CBA9A-76BF-4F4E-AB3A-16789D3C48CF 420 | vitoclose 421 | 422 | 423 | 424 | destinationuid 425 | C498F126-D109-47CE-9C8D-C1439C5F5B30 426 | modifiers 427 | 0 428 | modifiersubtext 429 | 430 | sourceoutputuid 431 | E483B0E6-5E1E-4F8E-BE08-F61FB4E857AB 432 | vitoclose 433 | 434 | 435 | 436 | F2BF7B8C-1591-4877-AFF5-0EAFDFB59178 437 | 438 | 439 | destinationuid 440 | 045C5FE6-9D9A-4C6E-BB9F-73E732480CB9 441 | modifiers 442 | 0 443 | modifiersubtext 444 | 445 | sourceoutputuid 446 | 1891A02A-6CF8-4BBC-B8F9-97BD1B09BF5B 447 | vitoclose 448 | 449 | 450 | 451 | 452 | createdby 453 | Benjamin Oddou 454 | description 455 | 🧙‍♂️ Transform your images into WebP format with ease 456 | disabled 457 | 458 | name 459 | Smart WebP 460 | objects 461 | 462 | 463 | config 464 | 465 | openwith 466 | 467 | sourcefile 468 | {var:data_folder}/logs.txt 469 | 470 | type 471 | alfred.workflow.action.openfile 472 | uid 473 | 58F33492-15F5-46AB-A362-CA56E17F396D 474 | version 475 | 3 476 | 477 | 478 | config 479 | 480 | addfilestobuffer 481 | 482 | clearbuffer 483 | 484 | outputtype 485 | 0 486 | 487 | type 488 | alfred.workflow.action.buffer 489 | uid 490 | 69BA9B7D-DD02-4970-AF06-8266F95388C9 491 | version 492 | 1 493 | 494 | 495 | config 496 | 497 | anchorfields 498 | 499 | argumenttrimmode 500 | 0 501 | argumenttype 502 | 0 503 | daterange 504 | 0 505 | fields 506 | 507 | 508 | field 509 | kMDItemDisplayName 510 | not 511 | 512 | split 513 | 514 | value 515 | {query} 516 | words 517 | 518 | 519 | 520 | field 521 | kMDItemAlternateNames 522 | not 523 | 524 | split 525 | 526 | value 527 | {query} 528 | words 529 | 530 | 531 | 532 | field 533 | kMDItemFinderComment 534 | not 535 | 536 | split 537 | 538 | value 539 | {query} 540 | words 541 | 542 | 543 | 544 | includesystem 545 | 546 | limit 547 | 0 548 | runningsubtext 549 | 550 | scopes 551 | 552 | sortmode 553 | 0 554 | subtext 555 | Start writing to find images and folders 556 | title 557 | Choose images / folders for compression 558 | types 559 | 560 | org.webmproject.webp 561 | public.folder 562 | public.jpeg 563 | public.png 564 | public.tiff 565 | 566 | withspace 567 | 568 | 569 | inboundconfig 570 | 571 | externalid 572 | {query} 573 | usecustominputarg 574 | 575 | 576 | type 577 | alfred.workflow.input.filefilter 578 | uid 579 | 13DDCB6C-9438-4C2B-B386-867F758EEDAF 580 | version 581 | 2 582 | 583 | 584 | config 585 | 586 | argumenttype 587 | 0 588 | subtext 589 | Write the cwebp options and press ⏎ 590 | text 591 | Input your cwebp options 592 | withspace 593 | 594 | 595 | inboundconfig 596 | 597 | externalid 598 | {query} 599 | usecustominputarg 600 | 601 | 602 | type 603 | alfred.workflow.input.keyword 604 | uid 605 | C4C284CD-55E1-41E9-867A-B48CA7AB5D47 606 | version 607 | 1 608 | 609 | 610 | config 611 | 612 | argument 613 | 614 | passthroughargument 615 | 616 | variables 617 | 618 | _links_list 619 | {var:_link_no_buffer} 620 | 621 | 622 | type 623 | alfred.workflow.utility.argument 624 | uid 625 | 29E00EF6-FC86-4DE7-83BC-A4D225269C5E 626 | version 627 | 1 628 | 629 | 630 | config 631 | 632 | conditions 633 | 634 | 635 | inputstring 636 | 637 | matchcasesensitive 638 | 639 | matchmode 640 | 0 641 | matchstring 642 | 643 | outputlabel 644 | 645 | uid 646 | 40F21FC1-5AB6-4DD3-BBB7-CDD2D7B59B8F 647 | 648 | 649 | elselabel 650 | else 651 | hideelse 652 | 653 | 654 | type 655 | alfred.workflow.utility.conditional 656 | uid 657 | CF9124F1-C2EF-4BBE-B066-A2CCC6C1149B 658 | version 659 | 1 660 | 661 | 662 | config 663 | 664 | argument 665 | 666 | passthroughargument 667 | 668 | variables 669 | 670 | _link_no_buffer 671 | {query} 672 | 673 | 674 | type 675 | alfred.workflow.utility.argument 676 | uid 677 | 38FEF466-6198-4D50-AA90-D70C13B216F4 678 | version 679 | 1 680 | 681 | 682 | config 683 | 684 | argument 685 | 686 | passthroughargument 687 | 688 | variables 689 | 690 | _the_preset 691 | {query} 692 | 693 | 694 | type 695 | alfred.workflow.utility.argument 696 | uid 697 | 2594B231-AB96-474F-A44E-2C733F045144 698 | version 699 | 1 700 | 701 | 702 | config 703 | 704 | concurrently 705 | 706 | escaping 707 | 102 708 | script 709 | ./compress.sh 710 | scriptargtype 711 | 1 712 | scriptfile 713 | 714 | type 715 | 5 716 | 717 | type 718 | alfred.workflow.action.script 719 | uid 720 | 3FEE47AA-2088-45F6-B112-EC2794BD9397 721 | version 722 | 2 723 | 724 | 725 | config 726 | 727 | adduuid 728 | 729 | allowemptyfiles 730 | 731 | createintermediatefolders 732 | 733 | filename 734 | {var:data_folder}/logs.txt 735 | filetext 736 | {date:YYYY/MM/dd} 737 | {time:HH:mm:ss} 738 | user input : {var:_links_list} 739 | cwebp options : {var:_the_preset} 740 | {query} 741 | ______________________ 742 | 743 | ignoredynamicplaceholders 744 | 745 | relativepathmode 746 | 0 747 | type 748 | 3 749 | 750 | type 751 | alfred.workflow.output.writefile 752 | uid 753 | 3F40E4A0-B574-41EF-B31C-49AF88E9DEA3 754 | version 755 | 1 756 | 757 | 758 | config 759 | 760 | alfredfiltersresults 761 | 762 | alfredfiltersresultsmatchmode 763 | 0 764 | argumenttreatemptyqueryasnil 765 | 766 | argumenttrimmode 767 | 0 768 | argumenttype 769 | 1 770 | escaping 771 | 102 772 | queuedelaycustom 773 | 3 774 | queuedelayimmediatelyinitially 775 | 776 | queuedelaymode 777 | 0 778 | queuemode 779 | 1 780 | runningsubtext 781 | Loading elements... 782 | script 783 | osascript -l JavaScript options.js 784 | scriptargtype 785 | 1 786 | scriptfile 787 | menu.sh 788 | subtext 789 | 790 | title 791 | Select a preset or input your options 792 | type 793 | 5 794 | withspace 795 | 796 | 797 | type 798 | alfred.workflow.input.scriptfilter 799 | uid 800 | 3B719F83-111C-42AA-A4F0-3858F6AEBDF8 801 | version 802 | 3 803 | 804 | 805 | config 806 | 807 | conditions 808 | 809 | 810 | inputstring 811 | {var:workflow_action} 812 | matchcasesensitive 813 | 814 | matchmode 815 | 0 816 | matchstring 817 | _open 818 | outputlabel 819 | open 820 | uid 821 | 858CBA9A-76BF-4F4E-AB3A-16789D3C48CF 822 | 823 | 824 | inputstring 825 | {var:workflow_action} 826 | matchcasesensitive 827 | 828 | matchmode 829 | 0 830 | matchstring 831 | _reveal 832 | outputlabel 833 | reveal 834 | uid 835 | E483B0E6-5E1E-4F8E-BE08-F61FB4E857AB 836 | 837 | 838 | elselabel 839 | else 840 | hideelse 841 | 842 | 843 | type 844 | alfred.workflow.utility.conditional 845 | uid 846 | ECEF6C22-D209-4F02-8240-FFF192BCD9B9 847 | version 848 | 1 849 | 850 | 851 | config 852 | 853 | conditions 854 | 855 | 856 | inputstring 857 | 858 | matchcasesensitive 859 | 860 | matchmode 861 | 0 862 | matchstring 863 | manual 864 | outputlabel 865 | 866 | uid 867 | B04F7F98-F4C6-4E61-986D-68F6986FEA93 868 | 869 | 870 | elselabel 871 | else 872 | hideelse 873 | 874 | 875 | type 876 | alfred.workflow.utility.conditional 877 | uid 878 | E05259B6-5B68-46E1-B5E3-A2955ACC4A3A 879 | version 880 | 1 881 | 882 | 883 | config 884 | 885 | path 886 | {var:data_folder}/logs.txt 887 | 888 | type 889 | alfred.workflow.action.revealfile 890 | uid 891 | C498F126-D109-47CE-9C8D-C1439C5F5B30 892 | version 893 | 1 894 | 895 | 896 | config 897 | 898 | argument 899 | 900 | passthroughargument 901 | 902 | variables 903 | 904 | _the_preset 905 | {query} 906 | 907 | 908 | type 909 | alfred.workflow.utility.argument 910 | uid 911 | 312ACF3E-422C-4D71-B4C8-524DD7FA8B12 912 | version 913 | 1 914 | 915 | 916 | config 917 | 918 | acceptsmulti 919 | 1 920 | filetypes 921 | 922 | org.webmproject.webp 923 | public.folder 924 | public.jpeg 925 | public.png 926 | public.tiff 927 | 928 | name 929 | Compress images to WebP 930 | 931 | type 932 | alfred.workflow.trigger.action 933 | uid 934 | 2308696E-54E9-47F6-BFAD-BE577F5EA33C 935 | version 936 | 1 937 | 938 | 939 | config 940 | 941 | argument 942 | 943 | passthroughargument 944 | 945 | variables 946 | 947 | _links_list 948 | {query} 949 | 950 | 951 | type 952 | alfred.workflow.utility.argument 953 | uid 954 | 94DB40C4-AE8A-4383-B916-29465859AAF9 955 | version 956 | 1 957 | 958 | 959 | config 960 | 961 | externaltriggerid 962 | _reruncwebp 963 | passinputasargument 964 | 965 | passvariables 966 | 967 | workflowbundleid 968 | self 969 | 970 | type 971 | alfred.workflow.output.callexternaltrigger 972 | uid 973 | A5FB494F-4E88-47A0-879E-401294A7C6D4 974 | version 975 | 1 976 | 977 | 978 | config 979 | 980 | conditions 981 | 982 | 983 | inputstring 984 | {var:split1} 985 | matchcasesensitive 986 | 987 | matchmode 988 | 0 989 | matchstring 990 | _compress 991 | outputlabel 992 | compress 993 | uid 994 | 82863E01-18CA-4A51-B90A-43A845142D62 995 | 996 | 997 | inputstring 998 | {var:split1} 999 | matchcasesensitive 1000 | 1001 | matchmode 1002 | 0 1003 | matchstring 1004 | _rerun 1005 | outputlabel 1006 | rerun 1007 | uid 1008 | 1891A02A-6CF8-4BBC-B8F9-97BD1B09BF5B 1009 | 1010 | 1011 | inputstring 1012 | {var:split1} 1013 | matchcasesensitive 1014 | 1015 | matchmode 1016 | 0 1017 | matchstring 1018 | _web 1019 | outputlabel 1020 | web 1021 | uid 1022 | F94A9936-1BF8-45BE-AFB3-BED2285C65FD 1023 | 1024 | 1025 | inputstring 1026 | {var:split1} 1027 | matchcasesensitive 1028 | 1029 | matchmode 1030 | 0 1031 | matchstring 1032 | _presets 1033 | outputlabel 1034 | preset 1035 | uid 1036 | 3E3E8353-8D8A-4CFD-B5B3-BDD74E9917F5 1037 | 1038 | 1039 | elselabel 1040 | else 1041 | hideelse 1042 | 1043 | 1044 | type 1045 | alfred.workflow.utility.conditional 1046 | uid 1047 | 1F5239EB-3ECF-4E0E-8431-A65EB2327A19 1048 | version 1049 | 1 1050 | 1051 | 1052 | config 1053 | 1054 | alfredfiltersresults 1055 | 1056 | alfredfiltersresultsmatchmode 1057 | 0 1058 | argumenttreatemptyqueryasnil 1059 | 1060 | argumenttrimmode 1061 | 0 1062 | argumenttype 1063 | 1 1064 | escaping 1065 | 102 1066 | keyword 1067 | {var:trigger} 1068 | queuedelaycustom 1069 | 3 1070 | queuedelayimmediatelyinitially 1071 | 1072 | queuedelaymode 1073 | 0 1074 | queuemode 1075 | 1 1076 | runningsubtext 1077 | Loading elements... 1078 | script 1079 | osascript -l JavaScript entry.js "$1" 1080 | scriptargtype 1081 | 1 1082 | scriptfile 1083 | menu.sh 1084 | subtext 1085 | Compress images to webp format easily 1086 | title 1087 | Smart webp compression 1088 | type 1089 | 5 1090 | withspace 1091 | 1092 | 1093 | type 1094 | alfred.workflow.input.scriptfilter 1095 | uid 1096 | 8CA4509B-0219-4AD8-9C45-13EC464FF9DF 1097 | version 1098 | 3 1099 | 1100 | 1101 | config 1102 | 1103 | availableviaurlhandler 1104 | 1105 | triggerid 1106 | _reruncwebp 1107 | 1108 | type 1109 | alfred.workflow.trigger.external 1110 | uid 1111 | 29FE5492-8E67-4F8F-87A3-159939E6A097 1112 | version 1113 | 1 1114 | 1115 | 1116 | config 1117 | 1118 | delimiter 1119 | ; 1120 | discardemptyarguments 1121 | 1122 | outputas 1123 | 0 1124 | trimarguments 1125 | 1126 | variableprefix 1127 | split 1128 | 1129 | type 1130 | alfred.workflow.utility.split 1131 | uid 1132 | 045C5FE6-9D9A-4C6E-BB9F-73E732480CB9 1133 | version 1134 | 1 1135 | 1136 | 1137 | config 1138 | 1139 | conditions 1140 | 1141 | 1142 | inputstring 1143 | 1144 | matchcasesensitive 1145 | 1146 | matchmode 1147 | 1 1148 | matchstring 1149 | 1150 | outputlabel 1151 | 1152 | uid 1153 | 1891A02A-6CF8-4BBC-B8F9-97BD1B09BF5B 1154 | 1155 | 1156 | elselabel 1157 | else 1158 | hideelse 1159 | 1160 | 1161 | type 1162 | alfred.workflow.utility.conditional 1163 | uid 1164 | F2BF7B8C-1591-4877-AFF5-0EAFDFB59178 1165 | version 1166 | 1 1167 | 1168 | 1169 | config 1170 | 1171 | browser 1172 | 1173 | skipqueryencode 1174 | 1175 | skipvarencode 1176 | 1177 | spaces 1178 | 1179 | url 1180 | {var:split2} 1181 | 1182 | type 1183 | alfred.workflow.action.openurl 1184 | uid 1185 | FDEDA57C-C351-4AA4-B0D2-BA3A16A2125F 1186 | version 1187 | 1 1188 | 1189 | 1190 | config 1191 | 1192 | argumenttype 1193 | 0 1194 | subtext 1195 | Input valid cwebp options, check the documentation 1196 | text 1197 | Preset Value 1198 | withspace 1199 | 1200 | 1201 | inboundconfig 1202 | 1203 | externalid 1204 | {query} 1205 | usecustominputarg 1206 | 1207 | 1208 | type 1209 | alfred.workflow.input.keyword 1210 | uid 1211 | 0BC6A292-B409-4DAC-8EA9-2C8604D1F303 1212 | version 1213 | 1 1214 | 1215 | 1216 | config 1217 | 1218 | argumenttype 1219 | 0 1220 | subtext 1221 | Input a title and a description for the preset ǀ Example: 'My Preset/Some description' 1222 | text 1223 | Preset Title/Subtitle 1224 | withspace 1225 | 1226 | 1227 | type 1228 | alfred.workflow.input.keyword 1229 | uid 1230 | 24C70ED0-81F4-484E-841F-032B110455CA 1231 | version 1232 | 1 1233 | 1234 | 1235 | config 1236 | 1237 | argument 1238 | 1239 | passthroughargument 1240 | 1241 | variables 1242 | 1243 | _new_preset 1244 | {query} 1245 | 1246 | 1247 | type 1248 | alfred.workflow.utility.argument 1249 | uid 1250 | 42AF05BF-C545-42DF-AC3B-9F81F851C963 1251 | version 1252 | 1 1253 | 1254 | 1255 | config 1256 | 1257 | concurrently 1258 | 1259 | escaping 1260 | 102 1261 | script 1262 | osascript -l JavaScript presets.js "$1" 1263 | scriptargtype 1264 | 1 1265 | scriptfile 1266 | 1267 | type 1268 | 5 1269 | 1270 | type 1271 | alfred.workflow.action.script 1272 | uid 1273 | 6C3B838B-C528-449D-B058-3836F59421EA 1274 | version 1275 | 2 1276 | 1277 | 1278 | config 1279 | 1280 | conditions 1281 | 1282 | 1283 | inputstring 1284 | {var:split2} 1285 | matchcasesensitive 1286 | 1287 | matchmode 1288 | 0 1289 | matchstring 1290 | new 1291 | outputlabel 1292 | new 1293 | uid 1294 | 40F21FC1-5AB6-4DD3-BBB7-CDD2D7B59B8F 1295 | 1296 | 1297 | inputstring 1298 | {var:split2} 1299 | matchcasesensitive 1300 | 1301 | matchmode 1302 | 0 1303 | matchstring 1304 | delete 1305 | outputlabel 1306 | delete 1307 | uid 1308 | 9A4468F5-CA10-41FA-9110-3FEAA5816577 1309 | 1310 | 1311 | inputstring 1312 | {var:split2} 1313 | matchcasesensitive 1314 | 1315 | matchmode 1316 | 0 1317 | matchstring 1318 | modify 1319 | outputlabel 1320 | modify 1321 | uid 1322 | 8EE14863-8E4A-47BE-9D21-B6624353D444 1323 | 1324 | 1325 | elselabel 1326 | else 1327 | hideelse 1328 | 1329 | 1330 | type 1331 | alfred.workflow.utility.conditional 1332 | uid 1333 | E059706B-E9CB-457B-A984-1F96041A300B 1334 | version 1335 | 1 1336 | 1337 | 1338 | config 1339 | 1340 | argumenttype 1341 | 0 1342 | subtext 1343 | Don't forget to use a '/' to separate elements 1344 | text 1345 | Modify the {var:modif4} 1346 | withspace 1347 | 1348 | 1349 | inboundconfig 1350 | 1351 | custominputarg 1352 | {var:modif5} 1353 | externalid 1354 | {query} 1355 | usecustominputarg 1356 | 1357 | 1358 | type 1359 | alfred.workflow.input.keyword 1360 | uid 1361 | 3BC14125-DD5B-4FA9-9AD5-A3A69F183B2F 1362 | version 1363 | 1 1364 | 1365 | 1366 | config 1367 | 1368 | delimiter 1369 | ; 1370 | discardemptyarguments 1371 | 1372 | outputas 1373 | 0 1374 | trimarguments 1375 | 1376 | variableprefix 1377 | modif 1378 | 1379 | type 1380 | alfred.workflow.utility.split 1381 | uid 1382 | 7587F5D4-DC06-4411-BDC1-EA1FD81363D6 1383 | version 1384 | 1 1385 | 1386 | 1387 | readme 1388 | # 🎩 Alfred Smart WebP 1389 | 1390 | ✨ *Transform your images into WebP format with ease* ✨ 1391 | 1392 | ## ✅ Prerequisites 1393 | 1394 | * MacOS. 1395 | * Alfred 5. Note that the [Alfred Powerpack](https://www.alfredapp.com/powerpack/) is required to use workflows. 1396 | 1397 | ## 🏎️ cwebp 1398 | 1399 | Under the hood, the compression is made with [cwebp](https://developers.google.com/speed/webp/docs/cwebp) (made by Google), a tool that allows to compress images into the WebP format, which is generally lighter, and broadly used to share images on the web. 1400 | 1401 | ## 🧰 Setup the workflow 1402 | 1403 | #### Open the Terminal of you Mac and run the following command: 1404 | 1405 | Install cwebp (using [Homebrew](https://brew.sh)): 1406 | 1407 | `brew install webp` 1408 | 1409 | ## 🧙‍♂️ Invoke the workflow 1410 | 1411 | You can invoke the workflow by writing `webp` into the Alfred search box. You can change this value by changing the `🕹️ Trigger` variable in workflow configuration panel. 1412 | 1413 | ## 🤖 Usage of the workflow 1414 | 1415 | Go to the dedicated [GitHub repository](https://github.com/BenjaminOddou/alfred-smart-webp-compression) page to check the documentation 1416 | 1417 | © Benjamin Oddou 1418 | uidata 1419 | 1420 | 045C5FE6-9D9A-4C6E-BB9F-73E732480CB9 1421 | 1422 | xpos 1423 | 535 1424 | ypos 1425 | 435 1426 | 1427 | 0BC6A292-B409-4DAC-8EA9-2C8604D1F303 1428 | 1429 | xpos 1430 | 950 1431 | ypos 1432 | 635 1433 | 1434 | 13DDCB6C-9438-4C2B-B386-867F758EEDAF 1435 | 1436 | xpos 1437 | 950 1438 | ypos 1439 | 145 1440 | 1441 | 1F5239EB-3ECF-4E0E-8431-A65EB2327A19 1442 | 1443 | xpos 1444 | 620 1445 | ypos 1446 | 395 1447 | 1448 | 2308696E-54E9-47F6-BFAD-BE577F5EA33C 1449 | 1450 | xpos 1451 | 950 1452 | ypos 1453 | 265 1454 | 1455 | 24C70ED0-81F4-484E-841F-032B110455CA 1456 | 1457 | xpos 1458 | 1235 1459 | ypos 1460 | 635 1461 | 1462 | 2594B231-AB96-474F-A44E-2C733F045144 1463 | 1464 | xpos 1465 | 2005 1466 | ypos 1467 | 180 1468 | 1469 | 29E00EF6-FC86-4DE7-83BC-A4D225269C5E 1470 | 1471 | xpos 1472 | 1480 1473 | ypos 1474 | 160 1475 | 1476 | 29FE5492-8E67-4F8F-87A3-159939E6A097 1477 | 1478 | xpos 1479 | 95 1480 | ypos 1481 | 405 1482 | 1483 | 312ACF3E-422C-4D71-B4C8-524DD7FA8B12 1484 | 1485 | xpos 1486 | 2005 1487 | ypos 1488 | 245 1489 | 1490 | 38FEF466-6198-4D50-AA90-D70C13B216F4 1491 | 1492 | xpos 1493 | 1130 1494 | ypos 1495 | 175 1496 | 1497 | 3B719F83-111C-42AA-A4F0-3858F6AEBDF8 1498 | 1499 | xpos 1500 | 1560 1501 | ypos 1502 | 200 1503 | 1504 | 3BC14125-DD5B-4FA9-9AD5-A3A69F183B2F 1505 | 1506 | xpos 1507 | 1235 1508 | ypos 1509 | 795 1510 | 1511 | 3F40E4A0-B574-41EF-B31C-49AF88E9DEA3 1512 | 1513 | xpos 1514 | 2300 1515 | ypos 1516 | 185 1517 | 1518 | 3FEE47AA-2088-45F6-B112-EC2794BD9397 1519 | 1520 | colorindex 1521 | 11 1522 | xpos 1523 | 2135 1524 | ypos 1525 | 185 1526 | 1527 | 42AF05BF-C545-42DF-AC3B-9F81F851C963 1528 | 1529 | xpos 1530 | 1130 1531 | ypos 1532 | 665 1533 | 1534 | 58F33492-15F5-46AB-A362-CA56E17F396D 1535 | 1536 | xpos 1537 | 2595 1538 | ypos 1539 | 125 1540 | 1541 | 69BA9B7D-DD02-4970-AF06-8266F95388C9 1542 | 1543 | xpos 1544 | 1235 1545 | ypos 1546 | 145 1547 | 1548 | 6C3B838B-C528-449D-B058-3836F59421EA 1549 | 1550 | colorindex 1551 | 8 1552 | xpos 1553 | 1465 1554 | ypos 1555 | 715 1556 | 1557 | 7587F5D4-DC06-4411-BDC1-EA1FD81363D6 1558 | 1559 | xpos 1560 | 1130 1561 | ypos 1562 | 825 1563 | 1564 | 8CA4509B-0219-4AD8-9C45-13EC464FF9DF 1565 | 1566 | xpos 1567 | 305 1568 | ypos 1569 | 405 1570 | 1571 | 94DB40C4-AE8A-4383-B916-29465859AAF9 1572 | 1573 | xpos 1574 | 1480 1575 | ypos 1576 | 295 1577 | 1578 | A5FB494F-4E88-47A0-879E-401294A7C6D4 1579 | 1580 | xpos 1581 | 950 1582 | ypos 1583 | 390 1584 | 1585 | C498F126-D109-47CE-9C8D-C1439C5F5B30 1586 | 1587 | xpos 1588 | 2595 1589 | ypos 1590 | 245 1591 | 1592 | C4C284CD-55E1-41E9-867A-B48CA7AB5D47 1593 | 1594 | xpos 1595 | 1825 1596 | ypos 1597 | 150 1598 | 1599 | CF9124F1-C2EF-4BBE-B066-A2CCC6C1149B 1600 | 1601 | xpos 1602 | 1385 1603 | ypos 1604 | 165 1605 | 1606 | E05259B6-5B68-46E1-B5E3-A2955ACC4A3A 1607 | 1608 | xpos 1609 | 1740 1610 | ypos 1611 | 220 1612 | 1613 | E059706B-E9CB-457B-A984-1F96041A300B 1614 | 1615 | xpos 1616 | 775 1617 | ypos 1618 | 720 1619 | 1620 | ECEF6C22-D209-4F02-8240-FFF192BCD9B9 1621 | 1622 | xpos 1623 | 2465 1624 | ypos 1625 | 205 1626 | 1627 | F2BF7B8C-1591-4877-AFF5-0EAFDFB59178 1628 | 1629 | xpos 1630 | 465 1631 | ypos 1632 | 435 1633 | 1634 | FDEDA57C-C351-4AA4-B0D2-BA3A16A2125F 1635 | 1636 | xpos 1637 | 950 1638 | ypos 1639 | 510 1640 | 1641 | 1642 | userconfigurationconfig 1643 | 1644 | 1645 | config 1646 | 1647 | default 1648 | ~/Library/Application Support/Alfred/Workflow Data/com.benjamino.smart_webp_compression 1649 | filtermode 1650 | 1 1651 | placeholder 1652 | 1653 | required 1654 | 1655 | 1656 | description 1657 | this folder contains presets and logs outputs. 1658 | label 1659 | 📂 Data folder 1660 | type 1661 | filepicker 1662 | variable 1663 | data_folder 1664 | 1665 | 1666 | config 1667 | 1668 | default 1669 | webp 1670 | placeholder 1671 | 1672 | required 1673 | 1674 | trim 1675 | 1676 | 1677 | description 1678 | keyword that launches the workflow. 1679 | label 1680 | 🕹️ Trigger 1681 | type 1682 | textfield 1683 | variable 1684 | trigger 1685 | 1686 | 1687 | config 1688 | 1689 | default 1690 | 1 1691 | placeholder 1692 | 1693 | required 1694 | 1695 | trim 1696 | 1697 | 1698 | description 1699 | input a value between 1 and ∞. allows to compress images in nested folders. 1700 | label 1701 | 🔍 Depth of the search 1702 | type 1703 | textfield 1704 | variable 1705 | level 1706 | 1707 | 1708 | config 1709 | 1710 | default 1711 | _open 1712 | pairs 1713 | 1714 | 1715 | Open log file 🟢 1716 | _open 1717 | 1718 | 1719 | Reveal log file in finder 🔵 1720 | _reveal 1721 | 1722 | 1723 | Display a notification 🟡 1724 | _notif 1725 | 1726 | 1727 | Do nothing 🔴 1728 | 1729 | 1730 | 1731 | 1732 | description 1733 | choose output action. 1734 | label 1735 | 🔫 Workflow action 1736 | type 1737 | popupbutton 1738 | variable 1739 | workflow_action 1740 | 1741 | 1742 | config 1743 | 1744 | default 1745 | Submarine 1746 | pairs 1747 | 1748 | 1749 | Mute 🔕 1750 | 1751 | 1752 | 1753 | Submarine 🤿 1754 | Submarine 1755 | 1756 | 1757 | Pop 🎉 1758 | Pop 1759 | 1760 | 1761 | Ping ✨ 1762 | Ping 1763 | 1764 | 1765 | Purr 🐯 1766 | Purr 1767 | 1768 | 1769 | Hero ⚔️ 1770 | Hero 1771 | 1772 | 1773 | Funk 🕺 1774 | Funk 1775 | 1776 | 1777 | Basso 🎧 1778 | Basso 1779 | 1780 | 1781 | Sosumi 📻 1782 | Sosumi 1783 | 1784 | 1785 | Glass 🍸 1786 | Glass 1787 | 1788 | 1789 | Blow 💨 1790 | Blow 1791 | 1792 | 1793 | Bottle 🍼 1794 | Bottle 1795 | 1796 | 1797 | Frog 🐸 1798 | Frog 1799 | 1800 | 1801 | Tink 🛎️ 1802 | Tink 1803 | 1804 | 1805 | Morse ♨️ 1806 | Morse 1807 | 1808 | 1809 | Classic 😃 1810 | default 1811 | 1812 | 1813 | 1814 | description 1815 | workflow notification sound. 1816 | label 1817 | 🎷 Notification sound 1818 | type 1819 | popupbutton 1820 | variable 1821 | sound 1822 | 1823 | 1824 | variablesdontexport 1825 | 1826 | version 1827 | 3.0.2 1828 | webaddress 1829 | https://github.com/BenjaminOddou/alfred-smart-webp-compression 1830 | 1831 | 1832 | -------------------------------------------------------------------------------- /src/json/presets.json: -------------------------------------------------------------------------------- 1 | { 2 | "items": [ 3 | { 4 | "title": "Example of presets ↓", 5 | "subtitle": "Press ⏎ to modify the preset. These are just examples, you can remove them", 6 | "arg": "remove me", 7 | "id": "9563BA83-6322-4392-9B39-93FE9A13CE47", 8 | "icon": { 9 | "path": "icons/presets.webp" 10 | } 11 | }, 12 | { 13 | "title": "Classic", 14 | "subtitle": "Good quality (80) with slow compression and multithread", 15 | "arg": "-v -print_psnr -print_ssim -print_lsim -m 6 -q 70 -mt -af", 16 | "id": "C9536D8E-79E1-4E51-B94B-65FD313BC32E", 17 | "icon": { 18 | "path": "icons/presets.webp" 19 | } 20 | }, 21 | { 22 | "title": "Crop 64px", 23 | "subtitle": "Crop image to 64px height + medium quality (60)", 24 | "arg": "-q 60 -resize 64 0", 25 | "id": "4F77F996-0B86-4036-9B8D-9104DA5A523F", 26 | "icon": { 27 | "path": "icons/presets.webp" 28 | } 29 | } 30 | ] 31 | } -------------------------------------------------------------------------------- /src/notificator: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | #################################################### 4 | ### Created by Vítor Galvão ### 5 | ### Find the latest version at: ### 6 | ### https://github.com/vitorgalvao/notificator ### 7 | #################################################### 8 | 9 | readonly program="$(basename "${0}")" 10 | 11 | # Helpers 12 | function show_notification { 13 | /usr/bin/open "${app}" --args "${notificator_message}" "${notificator_title}" "${notificator_subtitle}" "${notificator_sound}" 14 | } 15 | 16 | function make_icns { 17 | # Setup 18 | local -r file="${1}" 19 | local -r tmp_dir="$(/usr/bin/mktemp -d)" 20 | local -r icon="${tmp_dir}/icon.icns" 21 | local -r iconset="${tmp_dir}/icon.iconset" 22 | /bin/mkdir "${iconset}" 23 | 24 | # Create iconset 25 | for size in {16,32,64,128,256,512}; do 26 | /usr/bin/sips --resampleHeightWidth "${size}" "${size}" "${file}" --out "${iconset}/icon_${size}x${size}.png" &> /dev/null 27 | /usr/bin/sips --resampleHeightWidth "$((size * 2))" "$((size * 2))" "${file}" --out "${iconset}/icon_${size}x${size}@2x.png" &> /dev/null 28 | done 29 | 30 | # Convert to icns 31 | /usr/bin/iconutil --convert icns "${iconset}" --output "${icon}" 32 | 33 | # Clean up and return path to icns 34 | /bin/rm -rf "${iconset}" 35 | echo "${icon}" 36 | } 37 | 38 | function usage { 39 | echo " 40 | Trigger macOS notifications from Alfred, using the Workflow icon 41 | 42 | Usage: 43 | ${program} --message [options] 44 | 45 | Options: 46 | -m, --message Message text 47 | -t, --title Title text 48 | -s, --subtitle Subtitle text 49 | -p, --sound Sound name (from /System/Library/Sounds) 50 | -h, --help Show this help 51 | " | sed -E 's/^ {4}//' 52 | } 53 | 54 | # Options 55 | args=() 56 | while [[ "${1}" ]]; do 57 | case "${1}" in 58 | -h | --help) 59 | usage 60 | exit 0 61 | ;; 62 | -m | --message) 63 | readonly notificator_message="${2}" 64 | shift 65 | ;; 66 | -t | --title) 67 | readonly notificator_title="${2}" 68 | shift 69 | ;; 70 | -s | --subtitle) 71 | readonly notificator_subtitle="${2}" 72 | shift 73 | ;; 74 | -p | --sound) 75 | readonly notificator_sound="${2}" 76 | shift 77 | ;; 78 | --) 79 | shift 80 | args+=("${@}") 81 | break 82 | ;; 83 | -*) 84 | echo "Unrecognised option: ${1}" 85 | exit 1 86 | ;; 87 | *) 88 | args+=("${1}") 89 | ;; 90 | esac 91 | shift 92 | done 93 | set -- "${args[@]}" 94 | 95 | # Check for required arguments 96 | if [[ -z "${notificator_message}" ]]; then 97 | echo 'A message is mandatory! Aborting…' >&2 98 | exit 1 99 | fi 100 | 101 | readonly bundle_id="$(tr -cd '[:alnum:]._-' <<< "${alfred_workflow_bundleid}")" 102 | readonly name="$(tr -cd '[:alnum:]._- ' <<< "${alfred_workflow_name}")" 103 | readonly icon="${alfred_preferences}/workflows/${alfred_workflow_uid}/icon.png" 104 | readonly app="${alfred_workflow_cache}/Notificator for ${name}.app" 105 | readonly plist="${app}/Contents/Info.plist" 106 | 107 | # Exit early if Notificator exists and was modified fewer than 30 days ago 108 | if [[ -e "${app}" && -n "$(find "${app}" -depth 0 -mtime -30)" ]]; then 109 | show_notification 110 | exit 0 111 | fi 112 | 113 | # Pre-build checks 114 | if [[ -z "${bundle_id}" ]]; then 115 | echo "Workflow is missing the bundle identifier! Aborting…" >&2 116 | exit 1 117 | fi 118 | 119 | if [[ -z "${name}" ]]; then 120 | echo "Workflow is missing the name! Aborting…" >&2 121 | exit 1 122 | fi 123 | 124 | if [[ ! -f "${icon}" ]]; then 125 | echo "Workflow is missing the icon! Aborting…" >&2 126 | exit 1 127 | fi 128 | 129 | # Build Notificator 130 | readonly jxa_script=' 131 | // Build argv/argc in a way that can be used from the applet inside the app bundle 132 | ObjC.import("Foundation") 133 | const args = $.NSProcessInfo.processInfo.arguments 134 | const argv = [] 135 | const argc = args.count 136 | for (let i = 0; i < argc; i++) { argv.push(ObjC.unwrap(args.objectAtIndex(i))) } 137 | 138 | // Notification script 139 | const app = Application.currentApplication() 140 | app.includeStandardAdditions = true 141 | 142 | if (argv.length < 2) { // We use "2" because the script will always see at least one argument: the applet itself 143 | argv[1] = "Opening usage instructions…" 144 | argv[2] = "Notificator is a command-line app" 145 | argv[4] = "Funk" 146 | 147 | app.openLocation("https://github.com/vitorgalvao/notificator#usage") 148 | } 149 | 150 | const message = argv[1] 151 | const title = argv[2] 152 | const subtitle = argv[3] 153 | const sound = argv[4] 154 | 155 | const options = {} 156 | if (title) options.withTitle = title 157 | if (subtitle) options.subtitle = subtitle 158 | if (sound) options.soundName = sound 159 | 160 | app.displayNotification(message, options) 161 | ' 162 | 163 | [[ -d "${app}" ]] && rm -r "${app}" 164 | /bin/mkdir -p "${alfred_workflow_cache}" 165 | /usr/bin/osacompile -l JavaScript -o "${app}" -e "${jxa_script}" 2> /dev/null 166 | 167 | # Modify Notificator 168 | /usr/libexec/PlistBuddy -c "add :CFBundleIdentifier string ${bundle_id}.notificator" "${plist}" 169 | /usr/libexec/PlistBuddy -c 'add :LSUIElement string 1' "${plist}" 170 | mv "$(make_icns "${icon}")" "${app}/Contents/Resources/applet.icns" 171 | 172 | # Redo signature 173 | codesign --remove-signature "${app}" 174 | codesign --sign - "${app}" 175 | 176 | show_notification -------------------------------------------------------------------------------- /src/options.js: -------------------------------------------------------------------------------- 1 | ObjC.import('stdlib') 2 | const app = Application.currentApplication() 3 | app.includeStandardAdditions = true 4 | const PWD = $.getenv("PWD") 5 | const fm = $.NSFileManager.defaultManager 6 | const encoding = $.NSUTF8StringEncoding 7 | const data_folder = $.NSProcessInfo.processInfo.environment.objectForKey('data_folder')?.js || $.NSProcessInfo.processInfo.environment.objectForKey('alfred_workflow_data').js 8 | let items = [] 9 | 10 | function readFile(path) { 11 | if (fm.fileExistsAtPath(path)) { 12 | return $.NSString.stringWithContentsOfFileEncodingError(path, encoding, null).js 13 | } else { 14 | const sourcePath = `${PWD}/json/presets.json` 15 | fm.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(data_folder, true, $(), null) 16 | fm.copyItemAtPathToPathError(sourcePath, path, null) 17 | return $.NSString.stringWithContentsOfFileEncodingError(path, encoding, null).js 18 | } 19 | } 20 | 21 | items.push( 22 | { 23 | title: 'Manual options', 24 | subtitle: 'Run the cwebp compression with your manual input', 25 | arg: 'manual', 26 | icon: { path: 'icons/manual.webp' }, 27 | }, 28 | ) 29 | try { 30 | content = JSON.parse(readFile(`${data_folder}/presets.json`)) 31 | content.items.forEach(item => { items.push(item) }) 32 | } catch {} 33 | 34 | JSON.stringify({ items }) -------------------------------------------------------------------------------- /src/presets.js: -------------------------------------------------------------------------------- 1 | ObjC.import('stdlib') 2 | ObjC.import('Cocoa') 3 | const app = Application.currentApplication() 4 | app.includeStandardAdditions = true 5 | const fm = $.NSFileManager.defaultManager 6 | const encoding = $.NSUTF8StringEncoding 7 | const sound = $.NSProcessInfo.processInfo.environment.objectForKey('sound')?.js || 'Submarine' 8 | const data_folder = $.NSProcessInfo.processInfo.environment.objectForKey('data_folder')?.js || $.NSProcessInfo.processInfo.environment.objectForKey('alfred_workflow_data').js 9 | const action = $.NSProcessInfo.processInfo.environment.objectForKey('split2')?.js || '' 10 | let items =[] 11 | 12 | function readFile(path) { 13 | if (fm.fileExistsAtPath(path)) { 14 | return $.NSString.stringWithContentsOfFileEncodingError(path, encoding, null).js 15 | } else { 16 | const sourcePath = `${PWD}/json/presets.json` 17 | fm.createDirectoryAtPathWithIntermediateDirectoriesAttributesError(data_folder, true, $(), null) 18 | fm.copyItemAtPathToPathError(sourcePath, path, null) 19 | return $.NSString.stringWithContentsOfFileEncodingError(path, encoding, null).js 20 | } 21 | } 22 | 23 | content = JSON.parse(readFile(`${data_folder}/presets.json`)) 24 | 25 | try { 26 | if (action == 'new') { 27 | const uuid = $.NSUUID.UUID.UUIDString.js 28 | const _new_preset = $.NSProcessInfo.processInfo.environment.objectForKey('_new_preset')?.js || '' 29 | const args = $.NSProcessInfo.processInfo.arguments.objectAtIndex(4).js.split('/') 30 | const title = args[0]?.trim() !== '' ? args[0]?.trim() : 'No title'; 31 | const subtitle = args[1]?.trim() !== '' ? args[1]?.trim() : 'No description'; 32 | items.push( 33 | { 34 | title: `${title}`, 35 | subtitle: `${subtitle}`, 36 | arg: `${_new_preset}`, 37 | id: `${uuid}`, 38 | icon: { path: 'icons/presets.webp' }, 39 | }, 40 | ) 41 | content.items.forEach(item => { items.push(item) }) 42 | app.doShellScript('./notificator --title "✅ Success !" --message "Preset ' + title + ' created" --sound "'+ sound + '"') 43 | } else if (action == 'delete') { 44 | const key = $.NSProcessInfo.processInfo.environment.objectForKey('split3')?.js || '' 45 | content.items.forEach(item => { 46 | if (item.id != key) { 47 | items.push(item) 48 | } else { 49 | app.doShellScript('./notificator --title "✅ Success !" --message "Preset ' + item.title + ' deleted" --sound "'+ sound + '"') 50 | } 51 | }) 52 | } else if (action == 'modify') { 53 | const type = $.NSProcessInfo.processInfo.environment.objectForKey('modif3')?.js || '' 54 | const new_value = $.NSProcessInfo.processInfo.arguments.objectAtIndex(4).js 55 | const key = $.NSProcessInfo.processInfo.environment.objectForKey('modif6')?.js || '' 56 | if (type == 'tl&sb') { 57 | const args = new_value.split('/') 58 | const title = args[0]?.trim() !== '' ? args[0]?.trim() : 'No title'; 59 | const subtitle = args[1]?.trim() !== '' ? args[1]?.trim() : 'No description'; 60 | content.items.forEach(item => { 61 | if (item.id == key) { 62 | item.title = title 63 | item.subtitle = subtitle 64 | app.doShellScript('./notificator --title "✅ Success !" --message "Preset ' + title + ' modified" --sound "'+ sound + '"') 65 | } 66 | items.push(item) 67 | }) 68 | } else if (type == 'arg') { 69 | content.items.forEach(item => { 70 | if (item.id == key) { 71 | item.arg = new_value 72 | app.doShellScript('./notificator --title "✅ Success !" --message "Preset ' + item.title + ' modified" --sound "'+ sound + '"') 73 | } 74 | items.push(item) 75 | }) 76 | } 77 | 78 | } 79 | 80 | $.NSString.alloc.initWithUTF8String(JSON.stringify({'items': items}, null, 4)) 81 | .writeToFileAtomicallyEncodingError(`${data_folder}/presets.json`, true, encoding, null) 82 | } catch (e) { 83 | app.doShellScript('./notificator --title "🚨 Error !" --message "' + e + '" --sound "'+ sound + '"') 84 | } --------------------------------------------------------------------------------