I am using a Folder Action to post-process mpeg files. I am using a piece of software called Tivotool to pull the mpeg files from my DVR.
TivoTool pulls file, and begins to write the mpeg file in folder “pre-process”
My folder action responds by running a ffmpeg command to process these mpeg files into another format, and places the final movie files in the folder “Post-Process”.
The problem is that TIvotool begins writing the mpeg file immediatly in my “pre-process” folder, so my Folder Action IMMEDIATLY begins to run, before the mpeg file is finished being written.
Since I am a complete noob to applescript, I have a delay set of 8 minutes. So, once TivoTool begins to write the mpeg file, the Folder Action waits 8 minutes before running my ffmpeg command. This allows TivoTool time to completely write the file - about 5-7 minutes for a 1 hour mpeg.
This works, but does not seem very efficient when I have several mpeg files in my TivoTool que. (Maybe I am using delay in the wrong place?) I was hoping one of you experts could show me a better way of doing this. Is there some applescript command that could tell when the mpeg file from TivoTool is finished being written, before it begins to act on that file? Or some other method?
on adding folder items to this_folder after receiving added_items
-- Loop through the file references.
repeat with this_item in added_items
set this_name to name of (info for this_item)
-- Get the POSIX path of the file being referenced.
set this_File to quoted form of POSIX path of this_item
delay 800
do shell script "~/Movies/vx8300/Temp/ffmpeg -i " & this_File & " -acodec aac -ac 2 -ar 22050 -ab 128 -f 3gp -vcodec h263 -s 176x144 -r 15 ~/Movies/vx8300/Post-Process/" & quoted form of this_name & ".3gp"
end repeat
end adding folder items to
Thank so much,
Ryan
Model: Mac Mini PPC
AppleScript: 1.10.7
Browser: Firefox 2.0b2
Operating System: Mac OS X (10.4)
You can use something similar to this code instead of the “delay” (pretty self-explaining):
set this_item_oldsize to 0
repeat
delay 3
set this_item_newsize to get eof of this_item --> get file size
if this_item_newsize is this_item_oldsize then exit repeat
set this_item_oldsize to this_item_newsize
end repeat
In regards to my original post, I tried the code jj supplied, but nothing happens when I copy a file into the folder. Here is what I have:
on adding folder items to this_folder after receiving added_items
-- Loop through the file references.
repeat with this_item in added_items
set this_name to name of (info for this_item)
-- Get the POSIX path of the file being referenced.
set this_File to quoted form of POSIX path of this_item
set this_item_oldsize to 0
repeat
delay 3
set this_item_newsize to get eof of this_item --> get file size
if this_item_newsize is this_item_oldsize then exit repeat
set this_item_oldsize to this_item_newsize
end repeat
do shell script "~/Movies/vx8300/Temp/ffmpeg -i " & this_File & " -acodec aac -ac 2 -ar 22050 -ab 128 -f 3gp -vcodec h263 -s 176x144 -r 15 ~/Movies/vx8300/Post-Process/" & quoted form of this_name & ".3gp"
end repeat
end adding folder items to
Thanks again,
Ryan
Model: Mac Mini PPC
AppleScript: 1.10.7
Browser: Firefox 2.0b2
Operating System: Mac OS X (10.4)
I followed Adams suggested change, and managed to get the script working, with only one slight problem.
When I queue multiple items to be copied to the folder, the script will wait for the first file to be written completely, before processing the actions, but the problem is for the files afterwards, it will begin processing them immediately. It doesn’t seem to be ‘listening’ to the size part in the middle of the script.
Here is my code
on adding folder items to this_folder after receiving added_items
-- Loop through the file references.
repeat with this_item in added_items
do shell script "chmod -R 777 ~/Movies/vx8300/1of3/*.*"
set this_name to name of (info for this_item)
-- Get the POSIX path of the file being referenced.
set this_File to quoted form of POSIX path of this_item
set this_item_oldsize to 0
repeat
delay 3
set this_item_newsize to get eof of contents of this_item --> get file size
if this_item_newsize is this_item_oldsize then exit repeat
set this_item_oldsize to this_item_newsize
end repeat
delay 3
do shell script "~/Movies/vx8300/ffmpeg -i " & this_File & " -acodec aac -ac 2 -ar 22050 -ab 128 -f 3gp -vcodec -b 96 h263 -s 176x144 -r 15 ~/Movies/vx8300/3of3/" & quoted form of this_name & ".3gp"
end repeat
end adding folder items to
If I could get it to do the same file size check on all files that are being copied, and not just the first one, I will be all set.
I’ve never known what was going on with folder actions, so I allways stick with a monitorization app for this kind of task, a stay-open applet checking a given folder periodically. Something as:
global dirToMonitorize, idleAmount, dirToMonitorizePP, detectedItems, queueItems, queueSizes
(*
This is a sample skeleton for a monitorization app. It will check the given folder (dirToMonitorize)
for new files. When they arrive -they finished growing in size-, it will execute the handler
"processItem" with such files as argument.
You can customize the vars dirToMonitorize and idleAmount, and add your own actions to the
"processItem" handler.
You can as well add error trapping, logging, etc. Specially if you will be deleting files, adding
new ones with old ones' names or replacing files, while this app is running. In such case, I would
simply check file sizes for every file, every time, and fire "processItem" when newSize = oldSize.
This way, you would rely only in the list-of-files and list-of-sizes of the last run, and check it
against the new list-of-files and list-of-sizes.
*)
set dirToMonitorize to alias "path:to:dir:"
set idleAmount to 2
to processItem(filespec) --> filespec = file "blah:foo:bar.mpg"
tell application (path to frontmost application as text) to ¬
display dialog (name of (info for filespec)) & return & return & ¬
"Finished: " & (time string of (current date)) with icon 1 giving up after 5
end processItem
set dirToMonitorizePP to POSIX path of dirToMonitorize
set detectedItems to list folder dirToMonitorize without invisibles
set queueItems to {}
set queueSizes to {}
on idle
set itemLst to list folder dirToMonitorize without invisibles
if itemLst is not detectedItems then addNewItems(itemLst)
if queueItems is not {} then monitorize()
return idleAmount
end idle
to monitorize()
set itemsInProcess to {}
repeat with i from 1 to count queueItems
set itemToMonitorizeNewSize to get eof of ¬
(POSIX file (dirToMonitorizePP & queueItems's item i))
if itemToMonitorizeNewSize is queueSizes's item i then --> item stopped growing
processItem(POSIX file (dirToMonitorizePP & queueItems's item i))
set itemsInProcess's end to i
else
set queueSizes's item i to itemToMonitorizeNewSize
end if
end repeat
--> remove items sent to process from queue
set queueItems to strip(itemsInProcess, queueItems)
set queueSizes to strip(itemsInProcess, queueSizes)
end monitorize
to addNewItems(itemLst)
repeat with i from 1 to count itemLst
if itemLst's item i is not in detectedItems then
set detectedItems's end to itemLst's item i
set queueItems's end to itemLst's item i
set queueSizes's end to 0
end if
end repeat
end addNewItems
to strip(itlst, lst)
script o
property a : lst
property nl : {}
property b : itlst
end script
set o's b to o's b as list
repeat with i from 1 to count lst
if i is in o's b then
else
set o's nl's end to o's a's item i
end if
end repeat
o's nl
end strip
I agree with jj, '79. When I have troubles of this sort with a Folder Action, I always abandon that approach and go for a stay-open app with an ‘on idle’ handler that simply checks what’s going on externally to the folder itself. Folks worry that stay-open AppleScripts will tie up their CPU but for tasks like this that is not so - when you are through with the task, you quit the stay-open in the dock.
How do I use this script? I tried saving it as an application/run only - but it doesn’t seem to do anything once I run it and try dropping files in the folder. I’m just doing a simple chmod to test the operation of the script.
global dirToMonitorize, idleAmount, dirToMonitorizePP, detectedItems, queueItems, queueSizes
(*
This is a sample skeleton for a monitorization app. It will check the given folder (dirToMonitorize)
for new files. When they arrive -they finished growing in size-, it will execute the handler
"processItem" with such files as argument.
You can customize the vars dirToMonitorize and idleAmount, and add your own actions to the
"processItem" handler.
You can as well add error trapping, logging, etc. Specially if you will be deleting files, adding
new ones with old ones' names or replacing files, while this app is running. In such case, I would
simply check file sizes for every file, every time, and fire "processItem" when newSize = oldSize.
This way, you would rely only in the list-of-files and list-of-sizes of the last run, and check it
against the new list-of-files and list-of-sizes.
*)
set dirToMonitorize to alias "Firewire:Users:mac:Movies:vx8300:1of3:"
set idleAmount to 2
to processItem(filespec) --> filespec = file "blah:foo:bar.mpg"
do shell script "chmod -R 777 ~/Movies/vx8300/1of3/*.*"
tell application (path to frontmost application as text) to ¬
display dialog (name of (info for filespec)) & return & return & ¬
"Finished: " & (time string of (current date)) with icon 1 giving up after 5
end processItem
set dirToMonitorizePP to POSIX path of dirToMonitorize
set detectedItems to list folder dirToMonitorize without invisibles
set queueItems to {}
set queueSizes to {}
on idle
set itemLst to list folder dirToMonitorize without invisibles
if itemLst is not detectedItems then addNewItems(itemLst)
if queueItems is not {} then monitorize()
return idleAmount
end idle
to monitorize()
set itemsInProcess to {}
repeat with i from 1 to count queueItems
set itemToMonitorizeNewSize to get eof of ¬
(POSIX file (dirToMonitorizePP & queueItems's item i))
if itemToMonitorizeNewSize is queueSizes's item i then --> item stopped growing
processItem(POSIX file (dirToMonitorizePP & queueItems's item i))
set itemsInProcess's end to i
else
set queueSizes's item i to itemToMonitorizeNewSize
end if
end repeat
--> remove items sent to process from queue
set queueItems to strip(itemsInProcess, queueItems)
set queueSizes to strip(itemsInProcess, queueSizes)
end monitorize
to addNewItems(itemLst)
repeat with i from 1 to count itemLst
if itemLst's item i is not in detectedItems then
set detectedItems's end to itemLst's item i
set queueItems's end to itemLst's item i
set queueSizes's end to 0
end if
end repeat
end addNewItems
to strip(itlst, lst)
script o
property a : lst
property nl : {}
property b : itlst
end script
set o's b to o's b as list
repeat with i from 1 to count lst
if i is in o's b then
else
set o's nl's end to o's a's item i
end if
end repeat
o's nl
end strip
I greatly appreciate all the help in getting me this far.
Your script need not be ‘run only’, but it must be ‘stay-open’. The ‘on run’ portion of the script (in your case, implicit - it’s everything that isn’t a handler at the top level of the script) will run only once when you start the script. After that, only what’s in the ‘on idle’ portion and handlers it calls will run every ‘idleAmount’ seconds. That means your ‘on idle’ handler has to keep things current. At the end of your handler for example, you ought to save a new value of ‘detectedItems’ so anything you have processed will not be processed again. If that’s not clear, ask some more.