├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md └── PULL_REQUEST_TEMPLATE.md ├── contributing.md ├── go.mod ├── license ├── main.go ├── modd.conf ├── readme.md ├── search.go ├── update.go └── workflow ├── alfred-awesome-lists ├── icon.png ├── icons └── update-available.png └── info.plist /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 🐞 3 | about: Something isn't working as expected? 4 | labels: bug 5 | --- 6 | 7 | ### Bug 🐞 8 | 9 | 10 | 11 | 12 | ### Steps to Reproduce: 13 | 14 | 1. 15 | 2. 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature ✨ 3 | about: Suggest new idea for the project 4 | labels: enhancement 5 | --- 6 | 7 | ### Feature ✨ 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 🤔 3 | about: Usage question or discussion 4 | labels: question 5 | --- 6 | 7 | ### Question 🤔 8 | 9 | 10 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Summary 2 | 3 | 4 | 5 | 6 | ### Changes 7 | 8 | - 9 | 10 | 11 | ### Notes 12 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /contributing.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Thank you for taking the time to contribute! ♥️ You can: 4 | 5 | - Submit [bug reports or feature requests](../../issues/new/choose). Contribute to discussions. Fix [open issues](../../issues). 6 | - Improve docs, the code and more! Any idea is welcome. 7 | 8 | ## Run project 9 | 10 | The workflow is written in [Go](https://golang.org/) and uses [AwGo](https://github.com/deanishe/awgo) library for all Alfred related things. 11 | 12 | It uses [modd](https://github.com/cortesi/modd) and [Alfred command](https://godoc.org/github.com/jason0x43/go-alfred/alfred) to ease its development. 13 | 14 | 1. Clone repo 15 | 2. Run `alfred link` (makes symbolic link of [`workflow`](workflow) directory) 16 | 3. Run `modd` (starts a process that automatically builds the workflow with `alfred build` on any changes you make to `.go` files, this builds and places a binary inside [`workflow`](workflow) directory.) 17 | 4. Make changes to code or modify Alfred objects to do what you want! Open debugger in Alfred or run the workflow with `workflow:log` passed in as argument to see the logs Alfred produces. 18 | 19 | ![](https://i.imgur.com/FFYOecx.png) 20 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/nikitavoloboev/alfred-awesome-lists 2 | 3 | go 1.14 4 | 5 | require ( 6 | github.com/deanishe/awgo v0.24.0 7 | github.com/nikitavoloboev/markdown-parser v0.0.0-20200514190103-adb11a66522a 8 | ) 9 | 10 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Nikita (nikiv.dev) 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 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | // Command awesome is Alfred 3 workflow for quickly navigating GitHub Awesome lists. 2 | package main 3 | 4 | import ( 5 | "log" 6 | "time" 7 | 8 | aw "github.com/deanishe/awgo" 9 | "github.com/deanishe/awgo/update" 10 | ) 11 | 12 | var ( 13 | // Icons 14 | iconUpdate = &aw.Icon{Value: "icons/update-available.png"} 15 | 16 | query string 17 | 18 | repo = "nikitavoloboev/alfred-awesome-lists" 19 | 20 | // Workflow stuff 21 | wf *aw.Workflow 22 | ) 23 | 24 | func init() { 25 | wf = aw.New(update.GitHub(repo), aw.HelpURL(repo+"/issues")) 26 | } 27 | 28 | func run() { 29 | reload := func() (interface{}, error) { 30 | listIndex, err := searchAwesomeLists() 31 | 32 | if err != nil { 33 | log.Fatal(err) 34 | } 35 | 36 | var lists []List 37 | for _, list := range listIndex { 38 | lists = append(lists, list) 39 | } 40 | 41 | return lists, err 42 | } 43 | 44 | // Cache Awesome lists for 6 hours 45 | maxCache := 6 * time.Hour 46 | var lists []List 47 | err := wf.Cache.LoadOrStoreJSON("awesomeLists", maxCache, reload, &lists) 48 | 49 | if err != nil { 50 | wf.Fatal(err.Error()) 51 | } 52 | 53 | for _, list := range lists { 54 | wf.NewItem(list.Name).UID(list.UID).Valid(true).Arg(list.URL) 55 | } 56 | 57 | args := wf.Args() 58 | var searchQuery string 59 | if len(args) > 0 { 60 | searchQuery = args[0] 61 | } 62 | 63 | if searchQuery == "" { 64 | wf.WarnEmpty("No matching items", "Try a different query?") 65 | } else { 66 | wf.Filter(searchQuery) 67 | wf.WarnEmpty("No matching items", "Try a different query?") 68 | } 69 | 70 | wf.SendFeedback() 71 | } 72 | 73 | func main() { 74 | wf.Run(run) 75 | } 76 | -------------------------------------------------------------------------------- /modd.conf: -------------------------------------------------------------------------------- 1 | **/*.go { 2 | prep: alfred build 3 | } 4 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Alfred Awesome Lists 2 | 3 | > [Alfred](https://www.alfredapp.com/) workflow to search [awesome lists](https://github.com/sindresorhus/awesome) 4 | 5 | img 6 | 7 | ## Install 8 | 9 | Download workflow from [GitHub releases](../../releases/latest). 10 | 11 | See [here](https://github.com/deanishe/awgo/wiki/Catalina) for instructions on fixing permissions in macOS refusing to run Go binary. 12 | 13 | ## Contribute 14 | 15 | Always open to useful ideas or fixes in form of issues or PRs. 16 | 17 | Can [open new issue](../../issues/new/choose) (search [existing issues](../../issues) first) or [start discussion](../../discussions). 18 | 19 | It's okay to submit draft PR as you can get help along the way to make it merge ready. 20 | 21 | Join [Discord](https://discord.com/invite/TVafwaD23d) for more indepth discussions on this repo and [others](https://github.com/nikitavoloboev#src). 22 | 23 | ### 🖤 24 | 25 | [Support on GitHub](https://github.com/sponsors/nikitavoloboev) or look into [other projects](https://nikiv.dev/projects). 26 | 27 | [![Discord](https://img.shields.io/badge/Discord-100000?style=flat&logo=discord&logoColor=white&labelColor=black&color=black)](https://discord.com/invite/TVafwaD23d) [![X](https://img.shields.io/badge/nikitavoloboev-100000?logo=X&color=black)](https://twitter.com/nikitavoloboev) [![nikiv.dev](https://img.shields.io/badge/nikiv.dev-black)](https://nikiv.dev) 28 | -------------------------------------------------------------------------------- /search.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | 6 | parser "github.com/nikitavoloboev/markdown-parser" 7 | ) 8 | 9 | // List holds an awesome list. 10 | type List struct { 11 | UID string 12 | Name string 13 | URL string 14 | } 15 | 16 | func searchAwesomeLists() (map[string]List, error) { 17 | showUpdateStatus() 18 | 19 | log.Printf("query=%s", query) 20 | 21 | // Get the list from GitHub 22 | urls, err := parser.ParseMarkdownURL("https://raw.githubusercontent.com/sindresorhus/awesome/main/readme.md") 23 | if err != nil { 24 | log.Println("Error parsing links") 25 | } 26 | 27 | links := make(map[string]List) 28 | 29 | for name, url := range urls { 30 | links[url] = List{ 31 | UID: name, 32 | Name: name, 33 | URL: url, 34 | } 35 | } 36 | 37 | return links, nil 38 | } 39 | -------------------------------------------------------------------------------- /update.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "log" 5 | "os" 6 | "os/exec" 7 | 8 | aw "github.com/deanishe/awgo" 9 | ) 10 | 11 | // doUpdate checks for a newer version of the workflow. 12 | func doUpdate() error { 13 | log.Println("Checking for update...") 14 | return wf.CheckForUpdate() 15 | } 16 | 17 | // checkForUpdate runs "./alsf update" in the background if an update check is due. 18 | func checkForUpdate() error { 19 | if !wf.UpdateCheckDue() || wf.IsRunning("update") { 20 | return nil 21 | } 22 | cmd := exec.Command(os.Args[0], "update") 23 | return wf.RunInBackground("update", cmd) 24 | } 25 | 26 | // showUpdateStatus adds an "update available!" message to Script Filters if an update is available 27 | // and query is empty. 28 | func showUpdateStatus() { 29 | if query != "" { 30 | return 31 | } 32 | 33 | if wf.UpdateAvailable() { 34 | wf.Configure(aw.SuppressUIDs(true)) 35 | log.Println("Update available!") 36 | wf.NewItem("An update is available!"). 37 | Subtitle("⇥ or ↩ to install update"). 38 | Valid(false). 39 | Autocomplete("workflow:update"). 40 | Icon(&aw.Icon{Value: "icons/update-available.png"}) 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /workflow/alfred-awesome-lists: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikitavoloboev/alfred-awesome-lists/7647cab3f1920bc2025d4c8ab5a7717237c8680b/workflow/alfred-awesome-lists -------------------------------------------------------------------------------- /workflow/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikitavoloboev/alfred-awesome-lists/7647cab3f1920bc2025d4c8ab5a7717237c8680b/workflow/icon.png -------------------------------------------------------------------------------- /workflow/icons/update-available.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nikitavoloboev/alfred-awesome-lists/7647cab3f1920bc2025d4c8ab5a7717237c8680b/workflow/icons/update-available.png -------------------------------------------------------------------------------- /workflow/info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | bundleid 6 | nikivi.awesome.lists 7 | category 8 | Mine 9 | connections 10 | 11 | 09B97908-9A52-4275-855F-41A8C354E5B8 12 | 13 | 14 | destinationuid 15 | 185DBDA9-7F2E-40C9-A8C6-C84B737806CF 16 | modifiers 17 | 0 18 | modifiersubtext 19 | 20 | vitoclose 21 | 22 | 23 | 24 | destinationuid 25 | 7BED6B3C-632D-4E17-B07C-6411AC259F94 26 | modifiers 27 | 1048576 28 | modifiersubtext 29 | Edit list 30 | vitoclose 31 | 32 | 33 | 34 | destinationuid 35 | 37F1E515-5CF8-4276-8A8A-305D169D7BC9 36 | modifiers 37 | 524288 38 | modifiersubtext 39 | View contribution guidelines 40 | vitoclose 41 | 42 | 43 | 44 | 37F1E515-5CF8-4276-8A8A-305D169D7BC9 45 | 46 | 47 | destinationuid 48 | C4DD0986-C311-4550-9E12-F754F61F30BA 49 | modifiers 50 | 0 51 | modifiersubtext 52 | 53 | vitoclose 54 | 55 | 56 | 57 | 7BED6B3C-632D-4E17-B07C-6411AC259F94 58 | 59 | 60 | destinationuid 61 | C14883EE-9E77-4120-B375-97E42BD808B6 62 | modifiers 63 | 0 64 | modifiersubtext 65 | 66 | vitoclose 67 | 68 | 69 | 70 | B22AABA1-E682-48A2-A417-B8D983A8867F 71 | 72 | 73 | destinationuid 74 | EE1712A5-3B88-4D36-ADDE-E366B0DD8FC4 75 | modifiers 76 | 0 77 | modifiersubtext 78 | 79 | vitoclose 80 | 81 | 82 | 83 | C14883EE-9E77-4120-B375-97E42BD808B6 84 | 85 | 86 | destinationuid 87 | C37D87EC-752A-4D60-A7C8-20E488267314 88 | modifiers 89 | 0 90 | modifiersubtext 91 | 92 | vitoclose 93 | 94 | 95 | 96 | C4DD0986-C311-4550-9E12-F754F61F30BA 97 | 98 | 99 | destinationuid 100 | 633B3C4A-0415-4EA4-A080-FF110E6CA2D9 101 | modifiers 102 | 0 103 | modifiersubtext 104 | 105 | vitoclose 106 | 107 | 108 | 109 | EE1712A5-3B88-4D36-ADDE-E366B0DD8FC4 110 | 111 | 112 | destinationuid 113 | 09B97908-9A52-4275-855F-41A8C354E5B8 114 | modifiers 115 | 0 116 | modifiersubtext 117 | 118 | vitoclose 119 | 120 | 121 | 122 | 123 | createdby 124 | Nikita Voloboev 125 | description 126 | Search awesome lists 127 | disabled 128 | 129 | name 130 | Awesome lists 131 | objects 132 | 133 | 134 | config 135 | 136 | browser 137 | 138 | spaces 139 | 140 | url 141 | {query} 142 | utf8 143 | 144 | 145 | type 146 | alfred.workflow.action.openurl 147 | uid 148 | 185DBDA9-7F2E-40C9-A8C6-C84B737806CF 149 | version 150 | 1 151 | 152 | 153 | config 154 | 155 | browser 156 | 157 | spaces 158 | 159 | url 160 | {var:link} 161 | utf8 162 | 163 | 164 | type 165 | alfred.workflow.action.openurl 166 | uid 167 | C37D87EC-752A-4D60-A7C8-20E488267314 168 | version 169 | 1 170 | 171 | 172 | config 173 | 174 | triggerid 175 | search lists 176 | 177 | type 178 | alfred.workflow.trigger.external 179 | uid 180 | B22AABA1-E682-48A2-A417-B8D983A8867F 181 | version 182 | 1 183 | 184 | 185 | config 186 | 187 | concurrently 188 | 189 | escaping 190 | 102 191 | script 192 | query=$1 193 | 194 | echo -n "${query//}" 195 | scriptargtype 196 | 1 197 | scriptfile 198 | 199 | type 200 | 0 201 | 202 | type 203 | alfred.workflow.action.script 204 | uid 205 | 7BED6B3C-632D-4E17-B07C-6411AC259F94 206 | version 207 | 2 208 | 209 | 210 | config 211 | 212 | alfredfiltersresults 213 | 214 | alfredfiltersresultsmatchmode 215 | 0 216 | argumenttreatemptyqueryasnil 217 | 218 | argumenttrimmode 219 | 0 220 | argumenttype 221 | 1 222 | escaping 223 | 102 224 | keyword 225 | awe 226 | queuedelaycustom 227 | 3 228 | queuedelayimmediatelyinitially 229 | 230 | queuedelaymode 231 | 0 232 | queuemode 233 | 1 234 | runningsubtext 235 | Loading... 236 | script 237 | ./alfred-awesome-lists "$1" 238 | scriptargtype 239 | 1 240 | scriptfile 241 | 242 | subtext 243 | 244 | title 245 | Search Awesome Lists 246 | type 247 | 0 248 | withspace 249 | 250 | 251 | type 252 | alfred.workflow.input.scriptfilter 253 | uid 254 | 09B97908-9A52-4275-855F-41A8C354E5B8 255 | version 256 | 3 257 | 258 | 259 | config 260 | 261 | json 262 | { 263 | "alfredworkflow" : { 264 | "arg" : "{query}", 265 | "config" : { 266 | "title" : "", 267 | "runningsubtext" : "", 268 | "subtext" : "" 269 | }, 270 | "variables" : { 271 | } 272 | } 273 | } 274 | 275 | type 276 | alfred.workflow.utility.json 277 | uid 278 | EE1712A5-3B88-4D36-ADDE-E366B0DD8FC4 279 | version 280 | 1 281 | 282 | 283 | config 284 | 285 | argument 286 | {query} 287 | passthroughargument 288 | 289 | variables 290 | 291 | link 292 | {query}/edit/master/README.md 293 | 294 | 295 | type 296 | alfred.workflow.utility.argument 297 | uid 298 | C14883EE-9E77-4120-B375-97E42BD808B6 299 | version 300 | 1 301 | 302 | 303 | config 304 | 305 | concurrently 306 | 307 | escaping 308 | 102 309 | script 310 | query=$1 311 | 312 | echo -n "${query//}" 313 | scriptargtype 314 | 1 315 | scriptfile 316 | 317 | type 318 | 0 319 | 320 | type 321 | alfred.workflow.action.script 322 | uid 323 | 37F1E515-5CF8-4276-8A8A-305D169D7BC9 324 | version 325 | 2 326 | 327 | 328 | config 329 | 330 | browser 331 | 332 | spaces 333 | 334 | url 335 | {var:link} 336 | utf8 337 | 338 | 339 | type 340 | alfred.workflow.action.openurl 341 | uid 342 | 633B3C4A-0415-4EA4-A080-FF110E6CA2D9 343 | version 344 | 1 345 | 346 | 347 | config 348 | 349 | argument 350 | {query} 351 | passthroughargument 352 | 353 | variables 354 | 355 | link 356 | {query}/blob/master/CONTRIBUTING.md 357 | 358 | 359 | type 360 | alfred.workflow.utility.argument 361 | uid 362 | C4DD0986-C311-4550-9E12-F754F61F30BA 363 | version 364 | 1 365 | 366 | 367 | readme 368 | Details on how to use this workflow are found in the GitHub repo attached to the workflow. 369 | 370 | Double click this workflow in sidebar -> Open website. 371 | 372 | Post any issues and feature requests you have there. 💜 373 | uidata 374 | 375 | 09B97908-9A52-4275-855F-41A8C354E5B8 376 | 377 | note 378 | Seach Awesome Lists 379 | xpos 380 | 245 381 | ypos 382 | 160 383 | 384 | 185DBDA9-7F2E-40C9-A8C6-C84B737806CF 385 | 386 | xpos 387 | 465 388 | ypos 389 | 30 390 | 391 | 37F1E515-5CF8-4276-8A8A-305D169D7BC9 392 | 393 | xpos 394 | 465 395 | ypos 396 | 300 397 | 398 | 633B3C4A-0415-4EA4-A080-FF110E6CA2D9 399 | 400 | note 401 | View contribution guidelines 402 | xpos 403 | 725 404 | ypos 405 | 300 406 | 407 | 7BED6B3C-632D-4E17-B07C-6411AC259F94 408 | 409 | xpos 410 | 465 411 | ypos 412 | 160 413 | 414 | B22AABA1-E682-48A2-A417-B8D983A8867F 415 | 416 | xpos 417 | 10 418 | ypos 419 | 160 420 | 421 | C14883EE-9E77-4120-B375-97E42BD808B6 422 | 423 | xpos 424 | 635 425 | ypos 426 | 190 427 | 428 | C37D87EC-752A-4D60-A7C8-20E488267314 429 | 430 | note 431 | Edit Awesome list 432 | xpos 433 | 725 434 | ypos 435 | 160 436 | 437 | C4DD0986-C311-4550-9E12-F754F61F30BA 438 | 439 | xpos 440 | 635 441 | ypos 442 | 330 443 | 444 | EE1712A5-3B88-4D36-ADDE-E366B0DD8FC4 445 | 446 | xpos 447 | 160 448 | ypos 449 | 190 450 | 451 | 452 | version 453 | 1.2 454 | webaddress 455 | https://github.com/nikitavoloboev/alfred-awesome-lists 456 | 457 | 458 | --------------------------------------------------------------------------------