Shell Scripts with Progress Indicator and aerender

Like many people here, I believe I am on the right path but I am missing a few minor things to get my script to work. Also, I am pretty new to ASOC and recently purchased Shane Stanleys ASOC Explored book. Excellent resource but I am still struggling with one part.

In brief, I am build a script where the user input data into text fields that will write data to a Text Edit document. The text edit will be read by Adobe After Effects to change lower thirds and other text within the AE project. I have had no issues with that. After the Text Edit document is written, I have a shell script that sends the document to aerender via in the command line. No problem there either. Since other people will be using this, I want there to be a progress bar to show that something is happening so they dont quit the application or start monkeying on the keyboard. I can’t figure out how to feed the render progress to a progress indicator. The aerender has a stdout which it defaults to errors and progress with a verbose argument as seen here:

The progress bars binding are set in IB with is maxVal to the maxVal variable set in outlets and its value set to getProgress. usesThreadedAnimation is also set under User Defined Runtime Attributes.

All of my code is inside a single handler where a button is clicked (this may be my problem). I imagine I am doing something way off but I could but I could be close. Here is my code (sorry for the length but Im hoping more info will be better):

script AppDelegate
	property parent : class "NSObject"
    -- IBOutlets
    property clientName : ""
    property spotName : ""
    property isciCode : ""
    property director : ""
    property producer : ""
    property spotFrameRate : missing value
    property spotLength : missing value
    property resolution : missing value
    property leader : missing value
    property barsTone : true
    property renderText : missing value
    property progressBar : missing value
    property getProgress : missing value
    property myWindow : missing value
    property maxVal : 100
    on applicationWillFinishLaunching_(aNotification)
		-- Insert code here to initialize your application before any files are opened
	end applicationWillFinishLaunching_
	on applicationShouldTerminate_(sender)
		-- Insert code here to do any housekeeping before your application quits 
		return current application's NSTerminateNow
	end applicationShouldTerminate_
    -- IBActions (button clicks)
    on spotFrameRateUsed_(sender) -- connected to combobox in IB
		log sender's stringValue()
    end spotFrameRateUsed_
    on spotLengthUsed_(sender) -- connected to combobox in IB
        log sender's stringValue()
    end spotLengthUsed_
    on leaderUsed_(sender) -- connected to combobox in IB
        log sender's stringValue()
    end leaderUsed_
    on resolutionUsed_(sender) -- connected to combobox in IB
        log sender's stringValue()
    end resolutionUsed_
    on barsToneUsed_(sender)
        log sender's integerValue()
    end barsToneUsed_
    on create_(sender)
        tell my myWindow to displayIfNeeded()
        set clientName to clientName's stringValue() as text
        set spotName to spotName's stringValue() as text
        set isciCode to isciCode's stringValue() as text
        set director to director's stringValue() as text
        set producer to producer's stringValue() as text
        set slateText to "Users:home:Desktop:aeText.txt"
        tell application "TextEdit"
            make new document
            save document as slateText
            set clientName to do shell script "echo var clientName = [\\\"" & quoted form of clientName & "\\\"]\\;"
            set spotName to do shell script "echo var spotName = [\\\"" & quoted form of spotName & "\\\"]\\;"
            set isciCode to do shell script "echo var isciCode = [\\\"" & quoted form of isciCode & "\\\"]\\;"
            set director to do shell script "echo var director = [\\\"" & quoted form of director & "\\\"]\\;"
            set producer to do shell script "echo var producer = [\\\"" & quoted form of producer & "\\\"]\\;"
            set sourceText to clientName & return & spotName & return & isciCode & return & director & return & producer
            set slateText to open for access file "Users:home:Desktop:aeText.txt" with write permission
            write sourceText to slateText
            close access slateText
            quit application "TextEdit"
            end tell
        --This shell sends to aerender
        set renderText to POSIX path of "/Users/home/"
        do shell script  renderText
        getProgress's setString_("")
        set currentTask to NSTask's alloc's init()
        set outputpipe to NSPipe's pipe()
        currentTask's setStandardOutput_(outputpipe)
        currentTask's setStandardError_(outputpipe)
        currentTask's setLaunchPath_("/Users/home/")
        currentTask's setArguments_({"-v"})
        NSNotificationCenter's defaultCenter()'s addObserver_selector_name_object_(me, "readPipe:", "NSFileHandleReadCompletionNotification", currentTask's standardOutput()'s fileHandleForReading())
        NSNotificationCenter's defaultCenter()'s addObserver_selector_name_object_(me, "endPipe:", "NSTaskDidTerminateNotification", currentTask)
        currentTask's standardOutput()'s fileHandleForReading()'s readInBackgroundAndNotify()
        currentTask's |launch|()
        progressBar's incrementBy_(1)
        progressBar's displayIfNeeded()
    end create_
    on readPipe_(aNotification)
        set dataString to aNotification's userInfo's objectForKey_("NSFileHandleNotificationDataItem")
        set newstring to ((NSString's alloc()'s initWithData_encoding_(dataString, current application's NSUTF8StringEncoding)))
        getProgress's setString_((getProgress's |string|() as integer) & newstring as integer)
        aNotification's object()'s readInBackgroundAndNotify()
    end readPipe_
    on endPipe_(aNotification)
        NSNotificationCenter's defaultCenter()'s removeObserver_(me)
    end endPipe_
end script

And for reference the shell script I am calling is in my home directory and has been made executable through the terminal. This is what the shell script contains:

/Applications/Adobe\ After\ Effects\ CS5/aerender -project /Users/home/Desktop/lowerThirds.aep

Thanks for any direction or help you can lend.


I am not sure how your render works, but I think you may need run the actual aerender
commands as an NStask and not a script that then runs command line stuff ( hope it makes sense ).


‘/Applications/Adobe After Effects CS6/aerender’ -v ERRORS_AND_PROGRESS -close DO_NOT_SAVE_CHANGES -project ‘/Work/After Effects/3D CS6 TEST.aep’ - This should be run as a task and make sure you include " -v ERRORS_AND_PROGRESS" and not just “-v”

You will get the something like the following from your read pipe ( then you have to start ripping the important lines to work out the progress)

if you use Min and MaX values, convert all timecode to fames and then the current value is set to the frame number ( the line above in bold

Good luck

do shell script renderText

That’s launching it unnecessarily.

You guys are a huge help so far but Ive run into another issue.

Ive scrapped the shell script file and am instead doing this:

        tell current application's NSTask to set theTask to launchedTaskWithLaunchPath_arguments_("/Applications/Adobe After Effects CS5/aerender", {"-v ERRORS_AND_PROGRESS"}, , {"-close DO_NOT_SAVE_CHANGES"}, {"-project /Users/home/Desktop/lowerThirdTest.aep"})

In the console, aerender is called but I immediately get a syntax error saying “ILLEGAL ARGUMENT: -v ERRORS_AND_PROGRESS” from aerender followed by the aerender manual. Ive cross referenced it a dozen times but dont see where I am going wrong.

Originally I was referencing Shane’s book on Pages 209 and 210, “Section 2: Reference” but i was struggling there as well without my desired results. So I honed it back to simpler code to correct my errors and slowly build. Clearly, I am inputting my arguments incorrectly but I dont see how.

Try this instead:

tell current application's NSTask to set theTask to launchedTaskWithLaunchPath_arguments_("/Applications/Adobe After Effects CS5/aerender", {"-v ERRORS_AND_PROGRESS", "-close DO_NOT_SAVE_CHANGES", "-project /Users/home/Desktop/lowerThirdTest.aep"})

The { } contains all of the arguments

Even more, put everything separated by space in the shell line into a single list item

tell current application's NSTask to set theTask to launchedTaskWithLaunchPath_arguments_("/Applications/Adobe After Effects CS5/aerender", {"-v", "ERRORS_AND_PROGRESS", "-close", "DO_NOT_SAVE_CHANGES", "-project", "/Users/home/Desktop/lowerThirdTest.aep"})

If I could hear you guys speak, I think they would be angelic voices.

This has been a huge learning curve but Im inching closer to what I need. Especially for a designer with limited programming background.

Here is the functioning code for the app. The final part I am struggling with is getting the progress bar to work and I dont know if its in my code or how I am dealing with aerender.

I am using NSTask like this:

        set thepipe to NSPipe's pipe()
        set theFileHandle to thePipe's fileHandleForReading()
        set theTask to (NSTask's alloc)'s init()
        theTask's setLaunchPath_("/Applications/Adobe After Effects CS5/aerender")
        theTask's setStandardOutput_(thepipe)
        theTask's setArguments_({"-v", "ERRORS_AND_PROGRESS", "-close", "DO_NOT_SAVE_CHANGES", "-project", "/Users/home/Desktop/lowerThirdTest.aep"})
        theTask's |launch|()
        set Nf to NSNotificationCenter's defaultCenter()
        Nf's removeObserver_(me)
        Nf's addObserver_selector_name_object_(me, "readPipe:", "NSFileHandleReadCompletionNotification", theFileHandle)
        Nf's addObserver_selector_name_object_(me, "endPipe:", "NSTaskDidTerminateNotification", theTask)
        theFileHandle's readInBackgroundAndNotify()

This works like a charm thanks to you guys.

I have the read pipe handler set after the button sender like this:

    on readPipe_(aNotification)
        log "Started Render..."
        set dataString to aNotification's userInfo's objectForKey_("NSFileHandleNotificationDataItem")
        set newString to (((current application's class "NSString")'s alloc)'s initWithData_encoding_(dataString, current application's NSUTF8StringEncoding))
        set getProgress to newString as string   
    end readPipe_
    on endPipe_(aNotification)
        log "Finished Render"
    end endPipe_

So I get my “Started Render…” and “Finished Render.” in my console. I don’t get any update in between but I’m guessing its because its sent to the background? Its not important but I was curious for the sake of knowing.

And finally, I I have my Progress Bar’s value binding to my “getProgress” variable. I have the code set in the applicationWillFinishLaunching handler like so:

tell progressBar to setUsesThreadedAnimation_(true)
        tell progressBar to incrementBy_(1)
        tell progressBar to displayIfNeeded()

Unfortunately, the bar starts at about one increment and then does nothing.

Is this my code or how I’m interacting with aerender? Thanks Pez for the info as well. I have my project set to frames rather than timecode. I also found this snippet from the Adobe documentation provided online about a the “-log” argument. Not sure if this is just discussing the text file it outputs with renders or if its something deeper.

As written by Adobe:

“log_file_path is a file path or URI specifying the location of the log file. If this argument is not used, aerender uses standard output (stdout).”

i couldnt have gotten this far with out everyones assistance. Thanks for any help you can provide!

there’s a pair of parentheses missing after userInfo

set dataString to aNotification's userInfo()'s objectForKey_("NSFileHandleNotificationDataItem")

You shouldn’t be binding it to a string.

Ah, thank you Shane. In retrospect I see how silly it is to bind it to a string.

I’m learning a ton as I go.

I added the “-log” argument to the task arguments so aerender would output a txt file and see exactly what was going on like Pezwell showed. The beginning is all render settings and various details but then it starts to output the progress as frames are rendered as shown.

Does anybody know how I can extract just the frame rendering progress (and get it to an integer value) so that I can bind it to a determinate progress bar?

it looks like basically an exercise in parsing text.

The brackets “( )” would be the constant you need to isolate