Interoperability: Omni Automation and Alfred
DISCLAIMER: Mention of third-party websites and products is for informational purposes only and constitutes neither an endorsement nor a recommendation. OMNI-AUTOMATION.COM assumes no responsibility with regard to the selection, performance or use of information or products found at third-party websites. OMNI-AUTOMATION.COM provides this only as a convenience to our users. OMNI-AUTOMATION.COM has not tested the information found on these sites and makes no representations regarding its accuracy or reliability. There are risks inherent in the use of any information or products found on the Internet, and OMNI-AUTOMATION.COM assumes no responsibility in this regard. Please understand that a third-party site is independent from OMNI-AUTOMATION.COM and that OMNI-AUTOMATION.COM has no control over the content on that website. Please contact the vendor for additional information.
This section concerns the fourth automation scenario listed on the main page:
- Alfred is used to launch an Omni Automation script that requires user input to perform a procedure in OmniFocus whose linked results are then displayed in the Alfred interface.
The following documentation details the construction of the fourth Alfred action in the OmniFocus Collection Alfred Workflow. This action is used to generate and display in the Alfred interface a linked list of OmniFocus projects that smart match the user-provided search terms.
Scenario 4: Display the Results of a Smart Search
The following self-invoking script function performs the following procedures:
- Using the user provided search string, the script implements the Database class method projectsMatching(…) to identify related projects. (see below: line 18)
- The matched projects are iterated and a JSON record is created for each, containing the project title, status, and unique identifier. The resulting JSON is then convert into a string, encoded, and appended to a URL that calls the “Display Results” action in the Alfred workflow. (see below: lines 31—60)
Smart Search OmniFocus Projects
(async (arg) => {
try {
function createUtterance(textToSpeak){
AlexID = (
(app.platformName === "macOS") ?
"com.apple.speech.synthesis.voice.Alex" :
"com.apple.speech.voice.Alex"
)
voiceObj = Speech.Voice.withIdentifier(AlexID)
voiceRate = 0.4
utterance = new Speech.Utterance(textToSpeak)
utterance.voice = voiceObj
utterance.rate = voiceRate
return utterance
}
var synthesizer = new Speech.Synthesizer()
matchedProjects = projectsMatching(arg)
if(matchedProjects.length === 0){
messageStr = `No projects were found matching: ${arg}`
throw {
name: "Empty Search",
message: messageStr
}
}
matchCount = matchedProjects.length
itemsArray = new Array()
for (i = 0; i < matchedProjects.length; i++){
aProject = matchedProjects[i]
switch(aProject.status) {
case Project.Status.Active:
var projectStatus = "Active"
break;
case Project.Status.Done:
var projectStatus = "Done"
break;
case Project.Status.Dropped:
var projectStatus = "Dropped"
default:
var projectStatus = "OnHold"
}
itemObj = new Object()
itemObj.title = aProject.name
itemObj.subtitle = `Status: ${projectStatus}`
itemObj.arg = aProject.id.primaryKey
itemsArray.push(itemObj)
}
jsonObj = new Object()
jsonObj.items = itemsArray
jsonStr = JSON.stringify(jsonObj)
encodedJSON = encodeURIComponent(jsonStr)
alfredWorkflowID = "com.omni-automation.of.alfred-collection"
alfredTriggerID = "displayResults"
urlStr = `alfred://runtrigger/
${alfredWorkflowID}/ ${alfredTriggerID}/ ?argument=${encodedJSON}` URL.fromString(urlStr).open()
projectOrProjects = (matchCount === 1)? "project":"projects"
response = `${matchCount} ${projectOrProjects} matched.`
utterance = createUtterance(response)
synthesizer.speakUtterance(utterance)
}
catch(err){
utterance = createUtterance(err.message)
synthesizer.speakUtterance(utterance)
//new Alert(err.name, err.message).show()
}
})(argument);
Using the Omni Automation Script URL Constructor encode the script and append the following argument parameter to the encoded results:
&arg=%22{query}%22
The {query} variable is used by Alfred to represent the default content passed between steps. During the action execution it will automatically replaced with the user-provided content or results.
Encoded Script URL with Argument
omnifocus://localhost/omnijs-run?script=%28async%20%28arg%29%20%3D%3E%20%7B%0A%09try%20%7B%0A%09%09function%20createUtterance%28textToSpeak%29%7B%0A%09%09%09AlexID%20%3D%20%28%0A%09%09%09%09%28app%2EplatformName%20%3D%3D%3D%20%22macOS%22%29%20%3F%20%0A%09%09%09%09%22com%2Eapple%2Espeech%2Esynthesis%2Evoice%2EAlex%22%20%3A%20%0A%09%09%09%09%22com%2Eapple%2Espeech%2Evoice%2EAlex%22%0A%09%09%09%29%0A%09%09%09voiceObj%20%3D%20Speech%2EVoice%2EwithIdentifier%28AlexID%29%0A%09%09%09voiceRate%20%3D%200%2E4%0A%09%09%09utterance%20%3D%20new%20Speech%2EUtterance%28textToSpeak%29%0A%09%09%09utterance%2Evoice%20%3D%20voiceObj%0A%09%09%09utterance%2Erate%20%3D%20voiceRate%0A%09%09%09return%20utterance%0A%09%09%7D%0A%09%09var%20synthesizer%20%3D%20new%20Speech%2ESynthesizer%28%29%0A%0A%09%09matchedProjects%20%3D%20projectsMatching%28arg%29%0A%0A%09%09if%28matchedProjects%2Elength%20%3D%3D%3D%200%29%7B%0A%09%09%09messageStr%20%3D%20%60No%20projects%20were%20found%20matching%3A%20%24%7Barg%7D%60%0A%09%09%09throw%20%7B%0A%09%09%09%09name%3A%20%22Empty%20Search%22%2C%0A%09%09%09%09message%3A%20messageStr%0A%09%09%09%7D%0A%09%09%7D%0A%09%09%0A%09%09matchCount%20%3D%20matchedProjects%2Elength%0A%09%09%0A%09%09itemsArray%20%3D%20new%20Array%28%29%0A%09%09for%20%28i%20%3D%200%3B%20i%20%3C%20matchedProjects%2Elength%3B%20i%2B%2B%29%7B%20%0A%09%09%09aProject%20%3D%20matchedProjects%5Bi%5D%0A%0A%09%09%09switch%28aProject%2Estatus%29%20%7B%0A%09%09%09%09case%20Project%2EStatus%2EActive%3A%0A%09%09%09%09%09var%20projectStatus%20%3D%20%22Active%22%0A%09%09%09%09%09break%3B%20%0A%09%09%09%09case%20Project%2EStatus%2EDone%3A%0A%09%09%09%09%09var%20projectStatus%20%3D%20%22Done%22%0A%09%09%09%09%09break%3B%0A%09%09%09%09case%20Project%2EStatus%2EDropped%3A%0A%09%09%09%09%09var%20projectStatus%20%3D%20%22Dropped%22%0A%09%09%09%09default%3A%0A%09%09%09%09%09var%20projectStatus%20%3D%20%22OnHold%22%0A%09%09%09%7D%0A%0A%09%09%09itemObj%20%3D%20new%20Object%28%29%0A%09%09%09itemObj%2Etitle%20%3D%20aProject%2Ename%0A%09%09%09itemObj%2Esubtitle%20%3D%20%60Status%3A%20%24%7BprojectStatus%7D%60%0A%09%09%09itemObj%2Earg%20%3D%20aProject%2Eid%2EprimaryKey%0A%09%09%09itemsArray%2Epush%28itemObj%29%0A%09%09%7D%0A%09%09jsonObj%20%3D%20new%20Object%28%29%0A%09%09jsonObj%2Eitems%20%3D%20itemsArray%0A%09%09jsonStr%20%3D%20JSON%2Estringify%28jsonObj%2C%20null%2C%202%29%0A%09%09%0A%09%09encodedJSON%20%3D%20encodeURIComponent%28jsonStr%29%0A%09%09alfredWorkflowID%20%3D%20%22com%2Eomni%2Dautomation%2Eof%2Ealfred%2Dcollection%22%0A%09%09alfredTriggerVar%20%3D%20%22displayResults%22%0A%09%09urlStr%20%3D%20%60alfred%3A%2F%2Fruntrigger%2F%24%7BalfredWorkflowID%7D%2F%24%7BalfredTriggerVar%7D%2F%3Fargument%3D%24%7BencodedJSON%7D%60%0A%09%09URL%2EfromString%28urlStr%29%2Eopen%28%29%0A%09%0A%09%09projectOrProjects%20%3D%20%28matchCount%20%3D%3D%3D%201%29%3F%20%22project%22%3A%22projects%22%0A%09%09response%20%3D%20%60%24%7BmatchCount%7D%20%24%7BprojectOrProjects%7D%20matched%2E%60%0A%09%09utterance%20%3D%20createUtterance%28response%29%0A%09%09synthesizer%2EspeakUtterance%28utterance%29%0A%09%7D%0A%09catch%28err%29%7B%0A%09%09utterance%20%3D%20createUtterance%28err%2Emessage%29%0A%09%09synthesizer%2EspeakUtterance%28utterance%29%0A%09%09%2F%2Fnew%20Alert%28err%2Ename%2C%20err%2Emessage%29%2Eshow%28%29%0A%09%7D%0A%7D%29%28argument%29%3B&arg=%22{query}%22
Constructing the Alfred Action
The Alfred action for this example will generate and display in the Alfred interface a linked list of OmniFocus projects that smart match the user-provided search terms. It will be comprised of two steps:
Double-click the “Keyword Trigger” step to summon its preferences window:
Double-click the “Open URL” step to summon its preferences window:
Constructing the “Display Results” Alfred Action
Once a script URL has executed and has performed its processing, it will need to have Alfred display any matching items. To do so, the script will call to an action in the Alfred workflow that is designed to be triggered via an external URL that contains an encoded JSON object containing the items to display in the Alfred interface. See this page for an example of the JSON data.
As shown in lines 62, 65, 68, and 69 of the main script, the response URL is constructed like the following with the highlighted placeholders replaced with the relevant information:
alfred://runtrigger/ALFREDWORKFLOWID/ALFREDTRIGGERID/?argument=ENCODEDJSON
Here is an illustration of the Alfred action for displaying results of an OmniFocus query:
Double-click the External Trigger step to summon its preferences window:
alfred://runtrigger/ALFREDWORKFLOWID/ALFREDTRIGGERID/?argument=ENCODEDJSON
Double-click the “Variable Constructor” step to summon its preferences window:
Double-click the “Script Filter” step to summon its preferences window:
Double-click the “Open URL” step to summon its preferences window:
Running the Alfred Command
To use the “Smart Match Projects Search” action, summon Alfred and enter the keyword you entered during the workflow setup. The default is: sp Press the Return key and a list of matched projects will be displayed in OmniFocus:
A list of matching projects will be presented. Navigate the list and press the return key to choose the project to have displayed in OmniFocus for you.
NOTE: as with all Omni Automation scripts, the initial execution of an external script must be approved by the user fully scrolling the script security dialog (see below) and manually selecting the “Run Script” button. Select the checkbox to enable the script to be executed again without requiring further approval.
Next Example
In the NEXT EXAMPLE, Alfred is used to launch scripts written in Apple’s built-in JavaScript for Automation (JXA) that will display lists of projects and tags.