Jump to content

deanishe

Member
  • Posts

    8,759
  • Joined

  • Last visited

  • Days Won

    523

Reputation Activity

  1. Like
    deanishe reacted to zusatzstoff in Linguee.de German-English/English-German Dictionary Workflow   
    I released a new version of this workflow written in golang. You don't need NodeJS anymore as a precondition. 
  2. Like
    deanishe reacted to juliosecco in Handling workflow/environment variables   
    Hi,
    I would like to share a thing I just discovered about environment variables and php:
     
    today I have changed my php.ini.default in php.ini to test a workflow with a 'developer' php warning level, and I was not more able to read environment variables using $_ENV['name'].
    I have discovered that in the php.ini there was a directive variables_order, its comment is:
     
    " This directive determines which super global arrays are registered when PHP starts up ... There is a performance penalty paid for the registration of these arrays and because ENV is not as commonly used as the others, ENV is not recommended on productions servers. Yo can still get access to the environment variables through getenv() should you need to."
     
    it was set to "GPCS" where the letters mean GET, POST, COOKIE, ENV and SERVER, and in its default value the E for ENV was missing, for that the $_ENV was not working anymore.
     
    Setting it to  "GPCSE" made everything work again, but what I have learned is that using $_ENV and getenv() is not equivalent, being the latter better to be sure to correctly read the variable with every php.ini setting, so from now I will always use getenv().
     
    hope this helps,
     
        Giulio
  3. Like
    deanishe got a reaction from jopemachine in What is your workflow for developing these workflows?   
    Create a new directory for your project with a "src" subdirectory. Create a new, empty workflow in Alfred. Configure the workflow's name, bundle ID, icon etc. in Alfred's UI. Reveal the workflow in Finder. Move everything to the "src" subdirectory of your new project. Delete the workflow from Alfred. Symlink your workflow from the project directory: workflow-install -s src workflow-install script.
  4. Like
    deanishe got a reaction from nikivi in Writing workflows with go help   
    You have it all wrong.
     
    Go is a compiled language. You do not run your workflow with go run main.go.
     
    go run is a convenience when developing that compiles your program (in some temp directory) then runs it. It will crash and burn in Alfred because GOPATH isn't set.
     
    Instead, you compile your Go program with go build and run the resulting executable program from your workflow.
     
    GOPATH and GOROOT are just for development. GOPATH tells Go where to install libraries and binaries, and where to look for them when you import them.
     
    Before you can import any libraries, you have to go get them first, so they (and their dependencies) are available locally.
     
    Once your program is compiled, none of that matters. Go programs are always statically compiled, so it will run on any Mac regardless of whether they have Go installed.
     

    You need to go get ... any libraries you want to use.
     

    fmt.Println() doesn't work because it writes to STDOUT, whereas console.log() writes to STDERR. If you write anything but JSON/XML to STDOUT, your Script Filter won't work. You need fmt.Fprintln(os.Stderr, ...), though log.Println() is probably a better choice.
     
    The reason it's "complicated" is because you're trying to figure out two things at the same time. How Alfred/workflows work, and how to program. That is to say, you don't know what you need to do, nor how to do it. That's a hard place to be.
     
    My advice is to pick one language (Python or Ruby) and learn it. Read Dive into Python and How to Think Like a Computer Scientist (I'm sure there are Ruby equivalents). Go is a great language, but not a great first language. In particular, almost everything written about it (docs, tutorials, books etc.) assumes you're an experienced coder and know what things like mutexes and pointers are.

    Start by looking at other workflows to see how they do stuff, and try adapting them.
  5. Like
    deanishe got a reaction from vanderholm in Multilingual translation dictionary with Glosbe.com   
    Translate between hundreds of languages with Glosbe.com.
     

    By default, the workflow is set up to translate between German and English:
    .ende English query — show German translations of English query. .deen German query — show English translations of German query. ENTER — copy selected translation to the clipboard. CMD+ENTER — open translation in browser. glosbehelp — open the included help file in your browser. glosbelang [query] — view and search supported languages. To use other language pairs, you will have to edit the workflow, either changing the included English <-> German Script Filters or adding your own using them as a template.  
    For more information and to download the workflow, see the Packal page or grab it from GitHub.
  6. Like
    deanishe got a reaction from jopemachine in What is your workflow for developing these workflows?   
    I symlink my own workflows. Your code belongs in version control, not in an .alfredpreferences bundle in your Dropbox.
    So that this works cleanly, for Python, I keep the actual workflow in a src subdirectory of the repo. That way, I can symlink the subdirectory to Alfred without the .git directory ending up in Dropbox, which isn't great. Also, building the workflow is as simple as zipping up the contents of the src directory. Keeps it nice and simple. When the repo root is the same as the workflow root, you have to be careful to exclude files during building. I've seen a few workflows that contained copies of themselves that contained copies of themselves that contained copies of themselves… because the author kept the built workflow alongside the source in his repo.
    With Go, because it needs compiling anyway, I write a build script that puts the completed workflow in a build subdirectory, which can then be symlinked to Alfred or (its contents) zipped into a workflow.
    I also keep all the code in external files and use Alfred's Script boxes like a shell to call the scripts. Alfred is a terrible programmer's editor, and you lose a lot of the benefits of git etc. if all your code is embedded in info.plist.
    This has the overhead of an extra bash process, but that's about 0.01s when it isn't loading your dotfiles.
    With regard to libraries like Alfred-Workflow, I don't think they're as necessary in Alfred 3 thanks to the ease of generating JSON compared to XML (at least in scripting languages). There's a lot more to AW than just generating XML/JSON, but with Alfred 2 you basically needed a library for the XML generation alone.
    Finally, I generally write my workflows as command-line programs. If you have environment variables mapped to command-line flags, you can do some really neat stuff with workflow variables.
  7. Like
    deanishe got a reaction from dfay in How do I add Safari history to default search results?   
    Yup! I've been digging into this for a Safari workflow I'm working on.

    It stores a whole bunch (many thousands) of .webhistory files in ~/Library/Caches/Metadata/Safari/History
     
    Drag one of those to a File Filter to search your Safari history. I wouldn't recommend adding your history to your default scope, as the entries might overwhelm your other results.
     
    The UTI is com.apple.safari.history
     
    Safari also exports its bookmarks (to ~/Library/Caches/Metadata/Safari/Bookmarks with the extension .webbookmark and UTI com.apple.safari.bookmark).
     
     
    OmniFocus also exports its metadata to files under ~/Library/Caches/Metadata. I hope this is something a lot of apps start doing. It's very handy.
  8. Like
    deanishe reacted to madvas in iTerm Sessions   
    Alfred workflow to quickly select of one currently opened iTerm sessions

     

    Just type “sessions” and it will show currently opened iTerm sessions. Optionally, you can type text to filter by session name.

    You can download on Github: https://github.com/madvas/alfred-iterm-sessions

     



  9. Like
    deanishe reacted to vitor in OneUpdater — Update workflows with a single node   
    OneUpdater is an updater you can plug with minimal configuration into workflows, to keep them up-to-date in users’ machines.

    Easiest way to use it is to copy one of its OneUpdater nodes (the pink ones, with the note) to another workflow.

    If the workflow actions anything (you press ↵ at some point during usage), copy the top node (Run Script). Connect it to the most used action and double click to edit it. Fill the top variables with the correct values and you’re done.



    If the workflow doesn’t action anything (Script Filters with no connections), copy the bottom node (Script Filter) instead and make its Keyword the same as the most used in the workflow. Edit the top variables the same way.

    The top lines must be set, and the rest of the code should be left untouched.
    remote_info_plist is the URL to the workflow’s up-to-date info.plist on a server. workflow_url and download_type work in tandem. download_type must be one of direct, page, or github_release. When direct, workflow_url must be a direct link to a Workflow file. When page, workflow_url must be a link to a download page. When github_release, workflow_url must be of the form username/repo. frequency_check is the number of day between update checks. Set it to when testing, so it fires on every use.
    Example:
    readonly remote_info_plist='https://raw.githubusercontent.com/vitorgalvao/alfred-workflows/master/ShortFilms/source/info.plist'  readonly workflow_url='https://raw.githubusercontent.com/vitorgalvao/alfred-workflows/master/ShortFilms/ShortFilms.alfredworkflow' readonly download_type='direct' readonly frequency_check='4'
    For it to work you need only update the workflow version in the configuration sheet (which should be done anyway). When any update happens, the user will be informed via a notification. It will be delivered by one of (in order and stopping at the first it finds) notificator, terminal-notifier, or plain AppleScript-called notification.

    With both direct and github_release, new Workflow versions will be downloaded directly and opened (github_release grabs the first file from the latest release of the repository). page will open a page on the default web browser.
     
    Download | Source
  10. Like
    deanishe got a reaction from vanderholm in Relative Dates   
    Generate relative dates based on a simple input format and your own date formatting parameters (there are some default placeholders you can delete).

    Supports multiple locales/languages.



    Downloading

    Get the workflow from GitHub.

    Keywords
    date — Generate a formatted date using the [input format][] ↩ — Copy date to clipboard ⌘+↩ — Copy date to clipboard and paste into frontmost app datehelp — Open the help file dateformats — View saved date formats ⌘+↩ — Delete date format dateadd — Add a new date format ↩ — Save the date format datereset — Reset the saved date formats to the defaults Input format

    (+/-)<NUM>(w|d|y) where w = week(s), d = day(s) and y = year(s)

    You needn't specify a sign: + is understood as the default, so +1d and 1d mean the same thing.

    Months are not supported, as it leads to ambiguity: what if today is the 31st, but the target month only has 30 days? Similarly, a year is naively defined as 365 days.

    Examples
    0 = now = today — today's date 1d — 1 day from now 7d = 1w — 1 week from now -21d = -3w — 3 weeks ago Supported formats

    The Workflow includes a few defaults for the locales en_US, en_GB and de_DE.

    You can specify your own custom date formats using the formatting options listed at the below links, and you can also specify a language with the format lang=de or lang=de_DE if you want to use dates formatted for a language different to your system's.

    For a list of the formatting options, please see the GitHub page or the Packal page.

    Examples
    %d/%m/%Y — e.g. 21/01/2014 %A %B %d %Y — e.g. Wednesday March 12 2014 %A %d. %B %Y lang=de — e.g. Mittwoch 12. März 2014 Bug reports, feedback

    Report any issues or feature requests either on GitHub or in this thread.

    Licensing, thanks etc.

    This Workflow is released under the MIT Licence.

    It uses the docopt library.
  11. Like
    deanishe got a reaction from giovanni in Using tags or comments in search scope?   
    I think you'd have to add a Run Script in your workflow that finds the tagged folder and set that as a variable to use in a dynamic file search.
     
    For example, this shell command will print the path of the first folder it finds tagged "unwatched": 
    mdfind 'kMDItemContentType == "public.folder" && kMDItemUserTags =="unwatched"' | head -n 1 Put that in a Run Script followed by an Args and Vars or JSON Utility to configure the dynamic search.
  12. Like
    deanishe got a reaction from HOrdover in Your must-have workflows?   
    I was calling you a distributed version control system.
  13. Like
    deanishe got a reaction from xilopaint in Issue with non-standard library [Python]   
    That's a question for the Ghostscript forum, tbh.
  14. Like
    deanishe got a reaction from Empyreal in Multiple results in script filter [Python]   
    http://www.deanishe.net/alfred-workflow/user-manual/update.html
  15. Like
    deanishe reacted to dettogatto in Ruby Interpreter   
    I followed your suggestions and updated my AWF to use REXML library (such a pain not to use Nokogiri to avoid dependancies!)
    Now you can use UTF-8 chars with no trouble (I hope)
    Thank you agin for your tips and feedback!
     

  16. Like
    deanishe got a reaction from xilopaint in Multiple results in script filter [Python]   
    If a web request fails (no Internet connection, server error, file not found etc. etc.), instead of exploding immediately, web.py stores the error on the Response object.
     
    raise_for_status() simply re-raises the stored error if there is one. This is normally the behaviour you want (if the request failed, you have no data). But you might be doing something else, like checking a bunch of URLs to ensure they're valid (i.e. not 404). In that case, you don't care whether the request succeeded or not, you just need the HTTP status code.
     
    The reason for implementing it this way is simply because that's what requests does, and web.py is basically a very lightweight clone of requests to cover the most common use cases without adding megabytes to the size of your workflow (requests is a big library). The idea is that you can replace web.py pretty easily with requests if you need a more full-featured HTTP library.
     
    Thanks for the beer money! I'll spend that tonight on drowning my sorrows now my idiot countryfolk have voted to leave the EU and screwed me royally
  17. Like
    deanishe got a reaction from Vero in Creating recursive date-output (%y%m%d)   
    FWIW, nothing about this request is recursive.
     
    That's not what "recursive" means.
     
    In order to understand recursion, you must first understand recursion.
  18. Like
    deanishe got a reaction from sxalexander in Alfred 3 Tip: Use stderr to output to the debug console   
    If you're going to use sys.stderr.write() in Python, don't forget to add the trailing newline: 
    sys.stderr.write('Message\n')  
    For simple scripts, I normally use this log() function: 
    # Needed to use print this way from __future__ import print_function   def log(s, *args):     if args:         s = s % args     print(s, file=sys.stderr)   # Usage  log('var1=%r, var2=%r', var1, var2)
  19. Thanks
    deanishe got a reaction from kristof in Handling workflow/environment variables   
    Note: This post is out of date as of Alfred 3.6 (which introduced AppleScript functions to set and remove variables).

    There is an updated version on my own site: Workflow/environment variables in Alfred.

    This post will not be updated due to the difficulty of editing complex posts using the forum software. Sorry.
     
     
    This is a brief look at how to get, set and save variables in code (i.e. in Script Filters, Run Script Actions, etc.).

    In Alfred 2, you had one single variable to work with: the {query} macro. Alfred 3 adds the ability to specify as many variables as you want. Alfred's own help provides a great description of working with variables in Alfred's own UI. I'm going to look more closely about getting and setting workflow/environment variables in your own code within a workflow.

    First of all, it bears mentioning that all variables are strings. Sure, you can set a variable to a number in JSON, but when it reaches your next script or one of Alfred's Filter Utilities, it will be a string. If you set a variable to an array (e.g. [1, 2, 3, "mach dat Mäh mal ei"]), Alfred will turn it into a single, tab-delimited string ("1\t2\t3\tmach dat Mäh mal ei").

    Setting variables

    There are several ways to set variables. The most obvious ones are in the Workflow Environment Variables table in the workflow configuration sheet and using the Arg and Vars Utility. The configuration sheet is largely without magic, but in an Args and Vars Utility, you can use variable expansion macros: {query} expands (as always) to the input (which may be a user-entered query or the output from a previous Action), and you can use {var:VARIABLE_NAME} macros for your own custom variables.  This is described in detail in the above-mentioned help pages.

    More interestingly, you can also set variables via the output of your scripts (i.e. dynamically) by emitting appropriate JSON. How you set variables depends on whether you are using a Script Filter or a Run Script action.

    You must use the appropriate mechanism, or it won't work.

    From Run Script actions

    Let's say your script outputs a URL, e.g. https://www.google.com. Normally you just do print('https://www.google.com') (or echo or puts) and that gets passed as the input to the next action. To also pass variables, you instead emit JSON in a very specific format:
    {"alfredworkflow": {     "arg": "https://www.google.com",     "variables": {"browser": "Google Chrome"}}} The root alfredworkflow object is required. If it's missing, Alfred won't parse the JSON, but will pass it as-is as input to the next action (which can also be very useful). Your output (i.e. the next Action's input/{query}) goes in arg, and any variables you wish to set go in the variables object.

    From Script Filters

    You can also set workflow variables via Script Filter feedback at three different levels: the root level, the item level and the modifier level. (Note: This only applies to JSON feedback; XML feedback is now deprecated and does not support the features described here.)

    In each case, variables are set via a variables object at the appropriate level (feedback root, item or mod).

    Root-level variables

    Root-level variables are always passed to downstream elements regardless of which item is actioned. They are also passed back to the same Script Filter if you've set rerun, so you can use root-level variables to implement a progress bar.

    browser is set to Safari for all items:
    {"variables": {"browser": "Safari"},  "items": [{"title": "Google",    "arg": "https://www.google.com"}]}
    Item-level variables

    Item-level variables are only passed downstream when the item they're set on is actioned, and they override root-level variables. Root-level variables are also passed downstream when you action an item.

    browser is set to Safari by default, but Google Chrome for Reddit:
    {"variables": {"browser": "Safari"},  "items": [    {"title": "Google",      "arg": "https://www.google.com"},    {"title": "Reddit",      "arg": "https://reddit.com",      "variables": {"browser": "Google Chrome"}}]}
    Modifier-level variables

    Modifier-level variables are only passed downstream when the corresponding item is actioned with the appropriate modifier key pressed. They replace item- and root-level variables (i.e. if a modifier sets any variables, Alfred ignores any root- and item-level variables).

    As above, browser is set to Safari by default and Google Chrome for Reddit. But you can also pass browser=Google Chrome for Google by holding ⌘ when actioning it:
    {"variables": {"browser": "Safari"},  "items": [    {"title": "Google",      "arg": "https://www.google.com",      "mods" {"cmd": {"variables": {"browser": "Google Chrome"}}}},    {"title": "Reddit",      "arg": "https://reddit.com",      "variables": {"browser": "Google Chrome"}}]}
    Using variables

    So you've set a few variables, and now you want to use them. Within Alfred elements like Arg and Vars or Filter Utilities, you use the above-mentioned {var:VARIABLE_NAME} macros. Very simple.

    Where it gets a little more complicated is in your own code. First and foremost, {var:VARIABLE_NAME} macro expansion does not work in Run Script Actions (or Run NSAppleScript).

    When Alfred runs your code, it does not use {var:...} macros, but rather takes any workflow variables and sets them as environment variables for your script. Using the above example again, Alfred would pass "https://www.google.com" to my script as input (either via ARGV or {query} depending on the settings) and it would set the environment variable browser to Safari or Google Chrome. How you retrieve environment variables depends on the language you're using.

    Accessing environment variables in different languages

    In bash/zsh, the variables are already in the global namespace. Just use $browser

    In Python, use the os.environ dictionary or os.getenv('VARIABLE_NAME'):
    import os browser = os.environ['browser'] # Or browser = os.getenv('browser')
    In AppleScript, use system attribute:
    set theBrowser to (system attribute "browser")
    In JavaScript (JXA), use $.getenv():
    ObjC.import('stdlib') var browser = $.getenv('browser')
    In PHP, use getenv():

    (Please see this comment by juliosecco on why you should use getenv() over $_ENV.)
    $browser = getenv('browser'); // Or $browser = $_ENV['browser'];
    In Ruby, use ENV:
    browser = ENV["browser"]
    Saving variables
     
    NOTE: This section is out of date as of Alfred 3.6. Please see the updated version linked at the top of the post.
     
    As amoose136 points out, any variables you set in a running workflow are not saved. They exist as long as the workflow is running and then disappear. Any Workflow Environment Variables will "reset" to their values in the workflow configuration sheet on the next run.

    Generally, this is what you want, but sometimes you want to save a variable's value. For example, you might have an API_KEY Workflow Environment Variable in the configuration sheet. The user can enter their API key for the service in the configuration sheet, but you'd also like to add the ability to set it from within your workflow, e.g. with a setapikey Keyword and corresponding Run Script action.

    WARNING: As of Alfred 3.4.1, Alfred takes several seconds to notice when info.plist has been updated by something other than itself. As a result, relying on altering info.plist programatically can be problematic, as Alfred won't notice the changes for several seconds (5–10 seconds is typical on my machine). If you update a workflow variable in info.plist and run your workflow again immediately, it is unlikely that Alfred will have picked up the change.

    The Workflow Environment Variables are contained in the variables section of info.plist. Consequently, to update them, you need to update info.plist.

    Regardless of which language you're using, you can call the PlistBuddy program to alter Workflow Environment Variables:
    # Set a variable /usr/libexec/PlistBuddy -c "Set :variables:API_KEY \"ABC-XYZ\"" info.plist # Delete a variable (i.e. remove it entirely from Workflow Environment Variables) /usr/libexec/PlistBuddy -c "Delete :variables:API_KEY" info.plist
    In Python, there's no need to use an external program, as it has the built-in plistlib library:
    from plistlib import readPlist, writePlist # Read info.plist into a standard Python dictionary info = readPlist('info.plist') # Set a variable info['variables']['API_KEY'] = 'ABC-XYZ' # Delete a variable del info['variables']['API_KEY'] # Save changes writePlist(info, 'info.plist')
    (Note: plistlib only works with XML property lists, which is fine for info.plist, but using PlistBuddy is generally more robust.)

    Don't forget: any changes you make to info.plist only take effect the next time the workflow is run. This likely doesn't matter in most cases, but if you need a variable to be updated immediately (i.e. also for the current workflow run), you must also set it "live" using one of the methods described in the Setting variables section above.

     
  20. Like
    deanishe got a reaction from Shadde in Searchio! Auto-suggestion from search engines in different languages   
    Searchio! workflow for Alfred
    Auto-suggest search results from multiple search engines and languages.
     
    There are a few existing workflows that provide auto-suggest results from one or the other search engine, but this includes not only multiple search engines, but also allows you to specify multiple languages/regions for your results.

    Supports the following search engines/websites:
    Google Google Images Google Maps YouTube Wikipedia Wiktionary Amazon eBay DuckDuckGo Bing Yahoo! Ask.com Yandex.ru Naver.com Wikia.com  
    Download and installation
    Download the latest version from the GitHub releases page or Packal.
    Usage
    There are several searches pre-configured. Only some have keywords (i.e. can be used as-is):
    g — Search Google in system (i.e. default) language m — Search Google Maps in system (i.e. default) language gi — Search Google Images in system (i.e. default) language w — Search Wikipedia in system (i.e. default) language wn — Search Wiktionary in system (i.e. default) language a — Search Amazon in system (i.e. default) language. If your system language is English, this will search Amazon.com. Use -l uk in the Script Filter to search Amazon.co.uk or -l ca to search Amazon.ca. yt — Search YouTube in system (i.e. default) language searchio [<query>] — Show settings and list of supported search engines. Currently, the only setting is a toggle to also show the <query> in the results list (default: No). searchiohelp — Open help file in your browser You can add a keyword to (and edit) one of the existing examples or add your own searches. For details on how to do that, see the GitHub page.
     
    Licensing, thanks
    The code in this workflow is released under the MIT Licence.
    The icons belong to the respective search engines.
    This workflow uses the Alfred-Workflow library and docopt (both MIT-licensed).
  21. Like
    deanishe reacted to Cedric in SmartFolders: Browse and search the contents of your Saved Searches   
    Hey,
     
    Just wanted to say that it works perfectly for me.
    Thanks so much for the workflow and its beautiful documentation.
     
    Best,
     
    OSX 10.11.5 El Capitan
    Macbook Air mid-2011
    Alfred 3
  22. Like
    deanishe got a reaction from jceelen in 'sub-menu's' and modifier keys   
    Here's an example how to create submenus in Alfred 3.
  23. Like
    deanishe got a reaction from artdev in Handling workflow/environment variables   
    Note: This post is out of date as of Alfred 3.6 (which introduced AppleScript functions to set and remove variables).

    There is an updated version on my own site: Workflow/environment variables in Alfred.

    This post will not be updated due to the difficulty of editing complex posts using the forum software. Sorry.
     
     
    This is a brief look at how to get, set and save variables in code (i.e. in Script Filters, Run Script Actions, etc.).

    In Alfred 2, you had one single variable to work with: the {query} macro. Alfred 3 adds the ability to specify as many variables as you want. Alfred's own help provides a great description of working with variables in Alfred's own UI. I'm going to look more closely about getting and setting workflow/environment variables in your own code within a workflow.

    First of all, it bears mentioning that all variables are strings. Sure, you can set a variable to a number in JSON, but when it reaches your next script or one of Alfred's Filter Utilities, it will be a string. If you set a variable to an array (e.g. [1, 2, 3, "mach dat Mäh mal ei"]), Alfred will turn it into a single, tab-delimited string ("1\t2\t3\tmach dat Mäh mal ei").

    Setting variables

    There are several ways to set variables. The most obvious ones are in the Workflow Environment Variables table in the workflow configuration sheet and using the Arg and Vars Utility. The configuration sheet is largely without magic, but in an Args and Vars Utility, you can use variable expansion macros: {query} expands (as always) to the input (which may be a user-entered query or the output from a previous Action), and you can use {var:VARIABLE_NAME} macros for your own custom variables.  This is described in detail in the above-mentioned help pages.

    More interestingly, you can also set variables via the output of your scripts (i.e. dynamically) by emitting appropriate JSON. How you set variables depends on whether you are using a Script Filter or a Run Script action.

    You must use the appropriate mechanism, or it won't work.

    From Run Script actions

    Let's say your script outputs a URL, e.g. https://www.google.com. Normally you just do print('https://www.google.com') (or echo or puts) and that gets passed as the input to the next action. To also pass variables, you instead emit JSON in a very specific format:
    {"alfredworkflow": {     "arg": "https://www.google.com",     "variables": {"browser": "Google Chrome"}}} The root alfredworkflow object is required. If it's missing, Alfred won't parse the JSON, but will pass it as-is as input to the next action (which can also be very useful). Your output (i.e. the next Action's input/{query}) goes in arg, and any variables you wish to set go in the variables object.

    From Script Filters

    You can also set workflow variables via Script Filter feedback at three different levels: the root level, the item level and the modifier level. (Note: This only applies to JSON feedback; XML feedback is now deprecated and does not support the features described here.)

    In each case, variables are set via a variables object at the appropriate level (feedback root, item or mod).

    Root-level variables

    Root-level variables are always passed to downstream elements regardless of which item is actioned. They are also passed back to the same Script Filter if you've set rerun, so you can use root-level variables to implement a progress bar.

    browser is set to Safari for all items:
    {"variables": {"browser": "Safari"},  "items": [{"title": "Google",    "arg": "https://www.google.com"}]}
    Item-level variables

    Item-level variables are only passed downstream when the item they're set on is actioned, and they override root-level variables. Root-level variables are also passed downstream when you action an item.

    browser is set to Safari by default, but Google Chrome for Reddit:
    {"variables": {"browser": "Safari"},  "items": [    {"title": "Google",      "arg": "https://www.google.com"},    {"title": "Reddit",      "arg": "https://reddit.com",      "variables": {"browser": "Google Chrome"}}]}
    Modifier-level variables

    Modifier-level variables are only passed downstream when the corresponding item is actioned with the appropriate modifier key pressed. They replace item- and root-level variables (i.e. if a modifier sets any variables, Alfred ignores any root- and item-level variables).

    As above, browser is set to Safari by default and Google Chrome for Reddit. But you can also pass browser=Google Chrome for Google by holding ⌘ when actioning it:
    {"variables": {"browser": "Safari"},  "items": [    {"title": "Google",      "arg": "https://www.google.com",      "mods" {"cmd": {"variables": {"browser": "Google Chrome"}}}},    {"title": "Reddit",      "arg": "https://reddit.com",      "variables": {"browser": "Google Chrome"}}]}
    Using variables

    So you've set a few variables, and now you want to use them. Within Alfred elements like Arg and Vars or Filter Utilities, you use the above-mentioned {var:VARIABLE_NAME} macros. Very simple.

    Where it gets a little more complicated is in your own code. First and foremost, {var:VARIABLE_NAME} macro expansion does not work in Run Script Actions (or Run NSAppleScript).

    When Alfred runs your code, it does not use {var:...} macros, but rather takes any workflow variables and sets them as environment variables for your script. Using the above example again, Alfred would pass "https://www.google.com" to my script as input (either via ARGV or {query} depending on the settings) and it would set the environment variable browser to Safari or Google Chrome. How you retrieve environment variables depends on the language you're using.

    Accessing environment variables in different languages

    In bash/zsh, the variables are already in the global namespace. Just use $browser

    In Python, use the os.environ dictionary or os.getenv('VARIABLE_NAME'):
    import os browser = os.environ['browser'] # Or browser = os.getenv('browser')
    In AppleScript, use system attribute:
    set theBrowser to (system attribute "browser")
    In JavaScript (JXA), use $.getenv():
    ObjC.import('stdlib') var browser = $.getenv('browser')
    In PHP, use getenv():

    (Please see this comment by juliosecco on why you should use getenv() over $_ENV.)
    $browser = getenv('browser'); // Or $browser = $_ENV['browser'];
    In Ruby, use ENV:
    browser = ENV["browser"]
    Saving variables
     
    NOTE: This section is out of date as of Alfred 3.6. Please see the updated version linked at the top of the post.
     
    As amoose136 points out, any variables you set in a running workflow are not saved. They exist as long as the workflow is running and then disappear. Any Workflow Environment Variables will "reset" to their values in the workflow configuration sheet on the next run.

    Generally, this is what you want, but sometimes you want to save a variable's value. For example, you might have an API_KEY Workflow Environment Variable in the configuration sheet. The user can enter their API key for the service in the configuration sheet, but you'd also like to add the ability to set it from within your workflow, e.g. with a setapikey Keyword and corresponding Run Script action.

    WARNING: As of Alfred 3.4.1, Alfred takes several seconds to notice when info.plist has been updated by something other than itself. As a result, relying on altering info.plist programatically can be problematic, as Alfred won't notice the changes for several seconds (5–10 seconds is typical on my machine). If you update a workflow variable in info.plist and run your workflow again immediately, it is unlikely that Alfred will have picked up the change.

    The Workflow Environment Variables are contained in the variables section of info.plist. Consequently, to update them, you need to update info.plist.

    Regardless of which language you're using, you can call the PlistBuddy program to alter Workflow Environment Variables:
    # Set a variable /usr/libexec/PlistBuddy -c "Set :variables:API_KEY \"ABC-XYZ\"" info.plist # Delete a variable (i.e. remove it entirely from Workflow Environment Variables) /usr/libexec/PlistBuddy -c "Delete :variables:API_KEY" info.plist
    In Python, there's no need to use an external program, as it has the built-in plistlib library:
    from plistlib import readPlist, writePlist # Read info.plist into a standard Python dictionary info = readPlist('info.plist') # Set a variable info['variables']['API_KEY'] = 'ABC-XYZ' # Delete a variable del info['variables']['API_KEY'] # Save changes writePlist(info, 'info.plist')
    (Note: plistlib only works with XML property lists, which is fine for info.plist, but using PlistBuddy is generally more robust.)

    Don't forget: any changes you make to info.plist only take effect the next time the workflow is run. This likely doesn't matter in most cases, but if you need a variable to be updated immediately (i.e. also for the current workflow run), you must also set it "live" using one of the methods described in the Setting variables section above.

     
  24. Like
    deanishe reacted to Vero in Question About Workflows & Deleting Searches   
    A little correction to deanishe's response; The custom searches (which have a cog in the "custom search" column) can be deleted. The default web searches can't be deleted but unchecking them is sufficient to remove them from your search results.
     
    The padlock deanishe was referring to simply highlights which web searches are available as https://
     
    You can create your own custom searches and check the boxes next to them. You could even use the same keyword as the web search you've disabled for easy memorable access to them.
     
    Cheers,
    Vero
  25. Like
    deanishe got a reaction from tvaughan in Workflow to get the latest BTC price in GBP   
    You could remove almost all the imports but the code looks otherwise spot-on.

    If you want to share the workflow, it might be a better idea to export it and put it on Packal rather than just post the script here. That way, if someone wants to use it, they can just download and install it instead of having to create their own workflow to put the script in, install Alfred-Workflow etc.
×
×
  • Create New...