I wondering if it’s possible to run an Automator workflow (.workflow file, not .app) from a script. I saw this below a while ago but I can’t get it to work.
tell application “Automator Launcher” to open “Macintosh HD:Users:userName:Desktop:foo.workflow”
If not I’ll just run a workflow saved an as application, but I would prefer to be able to run .workflow files if possible.
You can use the built-in automator command line utility to fire of Otto’s workflows from within AppleScript using the do shell script command:
set workflowpath to "Macintosh HD:Users:martin:Desktop:Example.workflow"
set qtdworkflowpath to quoted form of (Posix path of workflowpath)
set command to "/usr/bin/automator " & qtdworkflowpath
set output to do shell script command
Type man automator into an open Terminal window to learn more. Or visit Apple’s own website.
Sorry forgot, one last question. How would I send the selected file (e.g. on the Desktop, in a Finder window etc.) to that workflow? (So that the Automator workflow would act on the selected file).
In the past I’ve done it with a workflow saved as an application like this:
tell application "Finder" to open the selection using "Macintosh HD:Users:Jono:Documents:File A.app"
An example: Let’s say your workflow starts with the «Get Folder Contents» action. Then you could pass the initial folder path with code like follows:
set qtdstartpath to quoted form of (Posix path of (path to desktop))
set workflowpath to "Macintosh HD:Users:martin:Desktop:Example.workflow"
set qtdworkflowpath to quoted form of (Posix path of workflowpath)
set command to "/usr/bin/automator -i " & qtdstartpath & " " & qtdworkflowpath
set output to do shell script command
Thanks a lot for this, I really apreciate it (both of you).
I’ll mainly start the workflows with ‘Get Selected Finder Items’ to select 1 or more files. Would the script be different for this, or same as get a folder’s contents?
But I do also have some uses where I’d like to grab a folder’s contents, so the script above will also come in very handy.
I was going to post similar also, :rolleyes: but found it more bother and slower than just adding, the workflow action.
mainly because if you have more than one item selected, you have to play with a list, and add spaces …
tell application "Finder" to set Sel to (selection) as alias list
repeat with i from 1 to number of items in Sel
set item i of Sel to (quoted form of (POSIX path of item i of Sel)) & space
end repeat
set workflowpath to "Macintosh HD:Users:martin:Desktop:Example.workflow"
set qtdworkflowpath to quoted form of (POSIX path of workflowpath)
set command to "/usr/bin/automator -i " & (items of Sel as string) & qtdworkflowpath
set output to do shell script command
If you want to choose files/folders or both, and or folder content.
You can add Ask for finder items. And Get folder contents.
I’m having a little trouble with this. I’ve set up a workflow that converts image files to a PDF. I’ve tested it as both a Service and a Workflow. When it’s a service I just have to select the images in the Finder, right click and choose the workflow to convert them all into a single PDF. It works perfectly.
I want to put this into an AppleScript so I tried the following by adapting the last code from mark hunte above:
set InputFolder to alias "Macintosh HD:Users:david.morgan:Desktop:Temp:Test JPEGs:"
tell application "Finder" to set FileList to every file in folder InputFolder as alias list
repeat with i from 1 to count FileList
set item i of FileList to (quoted form of (POSIX path of item i of FileList)) & space
end repeat
--
set workflowpath to "Macintosh HD:Users:david.morgan:Desktop:Make_PDFs.workflow"
set qtdworkflowpath to quoted form of (POSIX path of workflowpath)
set command to "/usr/bin/automator -i " & (items of FileList as string) & qtdworkflowpath
set output to do shell script command
but it only ever makes the first image into a single page PDF, seemingly ignoring the other images in the folder. I looked up the manual for automator in Terminal and it says to use the newline character (\n) as the delimiter for multiple strings. I tried this too but with even less success.
Any suggestions?
Model: iMac
Browser: Chrome
Operating System: Mac OS X (10.10)
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
use framework "AppKit" -- for NSImage
use framework "Quartz" -- required for PDF stuff
set inFiles to (choose file of type {"public.image", "com.adobe.pdf"} with prompt "Choose your files:" with multiple selections allowed)
set destPosixPath to POSIX path of (choose file name default name "Combined.pdf" with prompt "Save new PDF to:")
my combineFiles:inFiles savingToPDF:destPosixPath
on combineFiles:inFiles savingToPDF:destPosixPath
-- make URL of the first file
set inNSURL to current application's |NSURL|'s fileURLWithPath:(POSIX path of item 1 of inFiles)
-- make PDF document from the URL
if (inNSURL's pathExtension()'s isEqualToString:"pdf") as boolean then
set theDoc to current application's PDFDocument's alloc()'s initWithURL:inNSURL
else
set theDoc to my pdfDocFromImageURL:inNSURL
end if
-- loop through the rest
set oldDocCount to theDoc's pageCount()
set inFiles to rest of inFiles
repeat with aFile in inFiles
-- make URL of the next PDF
set inNSURL to (current application's |NSURL|'s fileURLWithPath:(POSIX path of aFile))
-- make PDF document from the URL
if (inNSURL's pathExtension()'s isEqualToString:"pdf") as boolean then
set newDoc to (current application's PDFDocument's alloc()'s initWithURL:inNSURL)
else
set newDoc to (my pdfDocFromImageURL:inNSURL)
end if
-- loop through, moving pages
set newDocCount to newDoc's pageCount()
repeat with i from 1 to newDocCount
-- get page of PDF
set thePDFPage to (newDoc's pageAtIndex:(i - 1)) -- zero-based indexes
-- insert the page into main PDF
(theDoc's insertPage:thePDFPage atIndex:oldDocCount)
set oldDocCount to oldDocCount + 1
end repeat
end repeat
set outNSURL to current application's |NSURL|'s fileURLWithPath:destPosixPath
-- save the main PDF
(theDoc's writeToURL:outNSURL)
end combineFiles:savingToPDF:
on pdfDocFromImageURL:inNSURL
set theImage to current application's NSImage's alloc()'s initWithContentsOfURL:inNSURL
set theSize to theImage's |size|()
set theRect to {{0, 0}, theSize}
set theImageView to current application's NSImageView's alloc()'s initWithFrame:theRect
theImageView's setImage:theImage
set theData to theImageView's dataWithPDFInsideRect:theRect
return current application's PDFDocument's alloc()'s initWithData:theData
end pdfDocFromImageURL:
Rescued me again Shane. Let me guess, that’s something you prepared earlier?
I knew there must be a way to do this using Obj C but would never have worked it out. There sure is a lot going on in that code. Works blazingly fast though, thanks very much!
Perhaps academic now, but the trick with the automator shell script appears to be to use the quoted form of the entire linefeed-delimited input rather than quoting the paths individually:
set InputFolder to ((path to desktop as text) & "Temp:Test JPEGs:")
tell application "Finder" to set FileList to every file in folder InputFolder as alias list
repeat with i from 1 to count FileList
set item i of FileList to POSIX path of item i of FileList -- Not quoted forms here.
end repeat
-- Coerce the list to a single, linefeed-delimited text.
set astid to AppleScript's text item delimiters
set AppleScript's text item delimiters to linefeed
set input to FileList as text
set AppleScript's text item delimiters to astid
-- Get the quoted form of the result.
set qtinput to quoted form of input
--
set workflowpath to (path to desktop as text) & "Make_PDFs.workflow"
set qtdworkflowpath to quoted form of (POSIX path of workflowpath)
set command to "/usr/bin/automator -i " & qtinput & space & qtdworkflowpath
set output to do shell script command
use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"
use framework "Automator"
use scripting additions
set InputFolder to ((path to desktop as text) & "Temp:Test JPEGs:")
tell application "Finder" to set FileList to every file in folder InputFolder as alias list
repeat with i from 1 to count FileList
set item i of FileList to POSIX path of item i of FileList
end repeat
--
set workflowPath to POSIX path of ((path to desktop as text) & "Make_PDFs.workflow")
set workflowURL to current application's |NSURL|'s fileURLWithPath:workflowPath
set {theResult, theError} to current application's AMWorkflow's runWorkflowAtURL:workflowURL withInput:FileList |error|:(reference)
if theError is not missing value then error (theError's localizedDescription() as text)
This script’s problematic on my El Capitan machine for some reason. The PDF is invariably correctly created, but the runWorkflowAtURL: method usually doesn’t return. Script Debugger goes into an eternal beachball state; Script Editor reports after a quarter of a minute or so that the operation couldn’t be completed. Occasionally, though, the method does complete, usually (but not always) when I feed FileList in directly as a list of aliases instead of POSIX paths or NSURLs.
By my reading of the method’s documentation, the result will be nil either if an error occurs or if there’s no output from the workflow. If I’ve got that right, the last line of the script (assuming it gets that far!) should be:
if theError ≠missing value then error (theError's localizedDescription() as text)
Do you have Show this action. turned off and Replace Existing Files on?
Yes, you’re right: “The error argument must be examined to determine which scenario occurred.” Which flies in the face of Apple’s advice on how to deal with NSErrors.
Yep. And it actually does what it’s supposed to. It just doesn’t hand back to the script afterwards.
Prompted by the fact that the effect’s slightly different depending on whether I run the script in Script Debugger (beachball) or Script Editor (eventual “operation couldn’t be completed” message), I’ve just tried saving the script as an application with an extra line to say that it’s done and running it under its own steam. It works perfectly well in this form and announces “Finished” almost immediately. There must be something about running it in an editor which my system doesn’t like.
I’ve tried fewer JPEGs, smaller JPEGs, different JPEGs, and JPEGs all with the same orientation. I’ve also tried making all the script variables ” and even the script itself ” non-persistent. The results are always the same:
Script as application ” no problem. Script in Script Debugger ” workflow works, SD beachballs. Script in Script Editor ” workflow works, SE displays error message after several seconds: error “The operation couldn’t be completed. (com.apple.Automator error 0.)” number -2700 from «script» to item. In this case, if the error reporting line at the end of the script is left out, SE’s result pane eventually shows {missing value, «class ocid» id «data optr0000000000F1D1338D7F0000»}, so SE does get a reply from the workflow, even if it’s just the error.
I’ve also added a Run AppleScript action to the end of the workflow to announce when the New PDF from Images action has finished and how many items it’s passed on. The announcement always happens, however the script’s run. SD’s timer stops at the end of the announcement, but its status bar still shows “Running” and eventually the beachball appears.
PS. In ASObjC Explorer 4, the behaviour’s the same as in Script Editor. However, with the “Run in foreground” box checked, everything works perfectly! Could be a thread problem.