Jump to content

Script Filter Output - A Very Basic Question


Recommended Posts

I have a very basic question about how script filters work that I haven’t been able to find a direct answer to on this forum or on Alfred’s support page. To be fair, there’s a ton of fantastic information on both, but I simply haven’t found one dumbs its explanation down enough for me to follow it. I've been using Alfred for quite some time, but have never been able to understand much about script filters.

 

In short, I was wondering how to get items from an AppleScript list to show up as JSON formatted items in a script filter’s output (so that I can select one of them, and have it operate like the argument in a subsequent object)?

 

For simplicity, let’s say I have an AppleScript that generates the following list:

{"Red", "Green", "Blue”}

But, in practice, that list will be dynamically produced and longer. In other words, I can't get away with just manually listing each item in the script filter (like in Alfred's jsonformat workflow example: Getting Started/Script Filter). 

 

Based on this example, how do I get the script filter’s output to operate like the following?

 

  • Item 1
    • Title: Red
    • SubTitle: Same Words Red
    • Argument: Red
  • Item 2
    • Title: Green
    • SubTitle: Same Words Green
    • Argument: Green
  • Item 3
    • Title: Blue
    • SubTitle: Same Words Blue
    • Argument: Blue

 
To illustrate, here’s what the output might look like when created with a list filter:

 

69239772_ListFilterOutput.thumb.jpg.c3917344a4a99d2c559a2219e297d272.jpg

 

***

 

@deanishe, I tried following your helpful advice and added a json.scpt file from another workflow that also used this approach. However, I couldn’t quite figure it out. Is there any way that I could talk you - or anyone else - into walking me through this, using the following example? 🙏

 

Based on the example above, I’ve created a very basic workflow to help illustrate things (for myself and others): Download Workflow.

 

The workflow contains: (1) a script filter and (2) a list filter. The script filter has been stripped down to a single line of code that sets a variable to the afore mentioned list above (set theList to {"Red", "Green", "Blue"}) (AppleScript). In other words, I removed all of my failed attempts, and have only included this line in the AppleScript as a starting point (I understand there’s more to be done here). 

 

132010394_ScriptFilter.jpg.b19f78d3a3c015896749bd07f52ff2fe.jpg

 

As for the list filter, it was included to illustrate how I’d like the script filter to perform (i.e., its output). I understand that if the string/list was fixed, that I could always just use it (instead of a script filter). Again, this was added strictly for illustrative purposes.

 

432723106_ListFilter.jpg.c6c3933b46531bd30c65d793e9d6a28e.jpg

 

To keep things simple, both filters simply copy their output to the clipboard. So, if you select the “Green” item from Alfred’s output, it would copy the word “Green” to the clipboard. In practice, this would be connected to another object that would do something else with the variable. But this struck me as an easiest way to test things.

 

Can someone help walk me through how to set up the script filter so that it operates like the list filter (using an applescript list of variables)?

 

Thanks in advance for any help you can lend! I really appreciate it.

Edited by Jasondm007
typos
Link to post

The fact that you’re using AppleScript makes the task significantly harder. AppleScript is an awful language: it’s too different from other languages, lacks several features, and is badly documented. That in turn makes it that few people want to use it, meaning there’s less people to help you and less people making resources for you to learn from.


AppleScript falls flat on its goal of being a language for people who don’t know how to program. It’s sole redeeming quality is that it can talk to GUI apps in a programatic way built into the system. But I advise you to use it for that alone, and get out and use something else as soon as possible. If you want to learn to program, do not start with AppleScript. It’s weighing you down.

 

At the very least, as @deanishe mentioned in the thread you linked to, use JXA (JavaScript for Automation), which gives you the only good part of AppleScript in a better (yet still not good) language.

 

AppleScript doesn’t understand JSON, you have to build it by hand and that’s not a good situation to be in. You want to use a language that can build the JSON for you from a simple list you give it.


JavaScript (works with Alfred’s /usr/bin/osascript (JS)):

const my_list = ['Red', 'Green', 'Blue'] // Your example list

let script_filter_items = [] // We will build this array with the elements for the Script Filter

my_list.forEach(element => { // For each item in your list
  script_filter_items.push({ 'title': element, 'subtitle': element, 'arg': element }) // Add them to the empty array
});

JSON.stringify({ 'items': script_filter_items }) // Transform it into JSON Alfred understands

 

Ruby

require 'json' # We need the JSON gem, to be able to use JSON functions

my_list = ['Red', 'Green', 'Blue'] # Your example list

script_filter_items = [] # We will build this array with the elements for the Script Filter

my_list.each do |element| # For each item in your list
  script_filter_items.push(title: element, subtitle: element, arg: element) # Add them to the empty array
end

puts({ items: script_filter_items }.to_json) # Transform it into JSON Alfred understands

 

Link to post

Or to continue with AS, look at the examples here:

 

 

This is what I used to figure out how to do the recent folders and active folders scripts in 

 

 

 

 

 

And here's a solution for you:

 

set theList to {"Red", "Green", "Blue"}

# What next?

-- import JSON library
set workflowFolder to do shell script "pwd"
set json to load script POSIX file (workflowFolder & "/json.scpt")

-- Create and add items
set theItems to {}
repeat with i from 1 to count theList
	set end of theItems to json's createDictWith({{"title", (item i of theList) as text}, {"uid", i},{"arg", (item i of theList) as text}, {"subtitle", "Same Words " & (item i of theList) as text}})
	
end repeat


-- Create root items object and encode to JSON
set itemDict to json's createDict()
itemDict's setkv("items", theItems)
return json's encode(itemDict)

 

Edited by dfay
Link to post

@vitor Thanks a ton for the explanation and the two working examples. This was extremely helpful, and it got me thinking that I could probably figure out a way to use my existing AppleScript to generate the list and then feed it into your JavaScript or Ruby script filter examples? It's a pretty complicated AppleScript - for my scripting ability, anyways - that generates the list. To be sure, I don't disagree with any of your statements - or others' on this forum - about AppleScript's 💩 status. But it would take me ages to learn one of these better languages, and then reverse engineer the existing AppleScript. As you can tell, I hardly understand AppleScript 😉

 

@dfay Thanks for the sources above! One of the first failed variations that I mentioned above came from my hackneyed attempts at pulling out pieces of your windows workflow (the one that works for Preview and a few others apps). When @deanishe mentioned a json.scpt file, I knew that I had seen one in your workflow, so I used it in several iterations. But I could never get any of them to work. However, I completely forgot about your more streamlined workflows for only Preview and Finder. In the multi-app version, I think stringing all those variables together for the different apps got me a little turned around. In any case, I'll go back and take a look at those other versions. Thanks a ton!!

 

I can't thank you both enough!!

Link to post
6 hours ago, Jasondm007 said:

As you can tell, I hardly understand AppleScript 😉

 

That's normal, tbh. It's insane.

 

It'd probably be a better use of your time trying to re-implement your workflow in a sensible language (if that's possible) than muddling through with AppleScript. It's so crazy, I still don't really understand it after using it for years.

Link to post

@dfay@vitor & @deanishe - Thanks for taking the time out to help a coding neophyte, like myself. I really appreciate it. Honestly, I can't thank you guys enough.

 

Alfred's great, but it wouldn't be the first thing I'd install on a Mac, if it weren't for you guys and others on the forum. I've learned a ton from you guys!

 

For others who may be struggling with script filters and JSON outputs, I've uploaded a new version of the workflow to use as a learning example: Download Workflow. 

  • The workflow combines everyone's suggestions from above: AppleScript, JavaScript & Ruby.
  • All three are nearly identical, with the exception that the JavaScript and Ruby versions lack the prefix "Same Words" in the subtitle.
  • This should be enough to get you started, if you're also struggling to get your head around how script filters' outputs work.
Link to post
  • 2 weeks later...

@dfay@vitor & @deanishe - I've been tinkering around quite a bit with my old workflows have updated some of them with script filters. For the most part, everything seems to working great! I really like the flexibility they provide over other fixed lists, etc.

 

However, I have three small questions that I was hoping to bounce off you.

 

1 - The first question has to do with how to manually add items to the script filter's output. Building on the previous example - which contained a list with the colors Red, Green, and Blue - let's say that I want to manually add options for the colors Yellow and Orange (i.e., they're not in the original list). As shown below in the script filter's code bold, do you just add them after the repeat loop? This seems to work fine, but I wanted to make sure I wasn't going to break anything. 

 

2 - If I wanted to give the Yellow and Orange items their own icons, how would I specify that? Assume that the workflow's folder contains an image for each ("iconyellow.png" and "iconorange.png"). The approach below does not work (shown in bold). The output just displays the usual icon for the workflow ("icon.png"). Based on feedback from other posts (e.g., Post 1, Post 2), I've tried several permutations of this approach, but I haven't had any luck thus far.

 

You can download the script filter shown below with icons here: Download

 

Quote

 

set theList to {"Red", "Green", "Blue"}

 

-- import JSON library
set workflowFolder to do shell script "pwd"
set json to load script POSIX file (workflowFolder & "/json.scpt")

 

-- Create and add items
set theItems to {}
repeat with i from 1 to count theList
    set end of theItems to json's createDictWith({{"title", (item i of theList) as text}, {"uid", i},{"arg", (item i of theList) as text}, {"subtitle", "Same Words " & (item i of theList) as text}})

end repeat

 

-- Add two items that were not in the list for Yellow & Orange, and add their respective icons (which are both found in the workflow's folder)

-- Yellow
set end of theItems to json's createDictWith({{"title", "Yellow"}, {"uid", i},{"arg", "Yellow"}, {"subtitle", "Same Words Yellow"}, {"icon", {"path", "iconyellow.png"}}})

-- Orange
set end of theItems to json's createDictWith({{"title", "Orange"}, {"uid", i},{"arg", "Orange"}, {"subtitle", "Same Words Orange"}, {"icon", {"path", "iconorange.png"}}})

 

-- Create root items object and encode to JSON
set itemDict to json's createDict()
itemDict's setkv("items", theItems)
return json's encode(itemDict)

 

 

In case its helpful, here's what the script filter's output looks like in the debugger. As you can see, the icons' paths appear to have a different kind of bracket around them.

 

Quote

[16:07:38.897] - Sandbox - Testing Script Filter Output[Script Filter] {"items": [{"title": "Red", "uid": 1, "arg": "Red", "subtitle": "Same Words Red"}, {"title": "Green", "uid": 2, "arg": "Green", "subtitle": "Same Words Green"}, {"title": "Blue", "uid": 3, "arg": "Blue", "subtitle": "Same Words Blue"}, {"title": "Yellow", "uid": 3, "arg": "Yellow", "subtitle": "Same Words Yellow", "icon": ["path", "iconyellow.png"]}, {"title": "Orange", "uid": 3, "arg": "Orange", "subtitle": "Same Words Orange", "icon": ["path", "iconorange.png"]}]}

 

 

3 - Lastly, is there any way to stop Alfred from "learning" while using a script filter? In other words, is possible to make Alfred spit out the results in the way you have them sorted?

 

Thanks again for all of your help!

Link to post

@Jasondm007 Please do yourself a favour and stop using AppleScript, you’re banging your head for no reason. AppleScript is a bad language that Apple doesn’t develop anymore and may kill at any moment, just like they gutted their automation division. Their newest apps and new features of old apps don’t support it. Pick up any other scripting language. It will be easier over time, and more importantly your skills will transfer when you switch to another language. By insisting on AppleScript you’re throwing away valuable learning time.


I can’t answer 1 and 2 without checking the code, and it’s already late where I live. As for 3, simply remove uid.

Link to post
5 hours ago, Jasondm007 said:

The first question has to do with how to manually add items to the script filter's output.

 

I'm not exactly sure what you mean by "manually add", but generally you'd add them to the list before the loop that generates the JSON. As a rule, you should try to avoid writing the same code over and over again.

 

But yeah, mostly what Vítor said. AppleScript is a stupid language that's absolutely awful to work with, and you're going to find it difficult to get help when you inevitably run into problems (because it's a stupid language) because nobody uses it. It's basically useless for anything but scripting macOS apps, and it also sucks for that, even though that's literally what it was designed to do.

 

Learn Ruby or Python, or even PHP instead. Python is generally considered a great first language, and there is a huge amount of material aimed at beginners. They're also much more useful languages. With Ruby or Python, you can build just about anything from a webserver to a desktop app.

 

5 hours ago, Jasondm007 said:

In case its helpful, here's what the script filter's output looks like in the debugger. As you can see, the icons' paths appear to have a different kind of bracket around them.

 

Yup. The JSON is wrong. [ ... ] is an array, but it should be an object { ... }. I don't know why it's wrong because I've never been able to figure out the difference between the two in AppleScript. Because it's stupid.

Link to post

@vitor Thanks for letting me know about the uid component of that script! As always, you were correct that I merely needed to remove it to get Alfred to stop "learning" from past selections (and everything still works perfectly fine).

 

As for your feelings and @deanishe's about AppleScript, I certainly don't disagree. At some point, I'd like to take up python. Unfortunately, at the moment, I just don't have the time or skillset to take up a new language (beyond the limited tinkering that I currently do).

 

As always, thanks for your support everything! Happy Holidays!

 

Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...