Applescript to bulk transcode video files using Handbrake

Real life has taken over my life recently so my blog is feeling a little neglected.

However, thought I’d share something I’ve been working on for the last week.

After buying a bigger hard drive, I’ve finally got all my M2TS files from my Sony HDR-SR7 video camera consolidated together in one spot.  But so far, I’ve been using iMovie to capture and organise all my other home video footage from Video8 and miniDV tapes.

I know I can get the AVCHD (M2TS and MTS) files into iMovie by converting them with Voltaic first into a QuickTime MOV file (encoded using the Apple Intermediate Codec), or by opening up the MTS files as a camera archive.

However, one thing that the family have been bugging me for so far is to get them into a format that’s easy for the rest of the family to view.  iMovie is not exactly a media player.  Nor is using Finder with Voltaic easy for the family.

My plan was to transcode all the raw footage into something that can be viewed either on the PS3 or iPad.

Luckily Handbrake is able to transcode M2TS files into any other format.  But I had a few hundred files to process, and even though Handbrake has a queue for processing, it doesn’t have the ability to submit a bulk set of files to transcode at once.

So I ventured into AppleScript land!   I’m a professional programmer and familiar with DOS batch files, VBScript and javascript – but all really on a Windows platform.   What is this AppleScript thing?

After some mucking around, I’ve written an AppleScript which can be run, or be saved as a droplet and files or folders drag and dropped to it, which will convert the files to MP4 using Handbrake.

To help everyone else, here it is!

To use, just:

  1. Copy and paste the code below
  2. Open up Applications -> Utilities -> AppleScript Editor
  3. Paste into a new document
  4. Then either
    1. Click Run to run the script immediately    OR
    2. Save somewhere (e.g. the Desktop) with type of Application, then drag and drop the folders you want to transcode onto the icon

Sorry about the formatting – once you paste into AppleScript Editor it should look all nice again :)

(*
** TRANSCODE TO APPLE UNIVERSAL
** This droplet will convert any file/folder dropped onto it or selected to the Apple Universal format using Handbrake.
** It currently will reuse the same filename for all files except MTS files, with which it will rename using the file’s creation timestamp.
**
** by Jason Chong
** http://jasechong.wordpress.com
** jchong@iinet.net.au
**
** Revision Description
** 1.0 Initial version
**
*)

property type_list : {} — e.g.: {“PICT”, “JPEG”, “TIFF”, “GIFf”}
property extension_list : {“m2ts”, “mts”, “mov”, “avi”, “mpg”, “mkv”, “dv”} — e.g.: {“txt”, “text”, “jpg”, “jpeg”}, NOT: {“.txt”, “.text”, “.jpg”, “.jpeg”}
property typeIDs_list : {} — e.g.: {“public.jpeg”, “public.tiff”, “public.png”}

(*
** ON RUN HANDLER
** This function is called if the script is run by executing the script directly.
*)
on run
set these_items to choose folder with prompt “Select a folder to convert:” with multiple selections allowed
set dest_folder to choose folder with prompt “Select a destination folder:”
repeat with one_item in these_items
process_item(one_item, dest_folder)
end repeat
end run

(*
** ON OPEN HANDLER
** This function is called if the script is run by dropping files/folders onto the item
*)
on open these_items
set dest_folder to choose folder with prompt “Select a destination folder:”
repeat with one_item in these_items
process_item(one_item, dest_folder)
end repeat
end open

(*
** ON PROCESS_ITEM
** This function does the high level processing of the items chosen
*)
on process_item(the_item, dest_folder)
set the item_info to info for the_item
if folder of the item_info is true then
– If a folder then call this function recursively for each item within
set these_items to list folder the_item without invisibles
repeat with i from 1 to the count of these_items
set this_item to alias ((the_item as Unicode text) & (item i of these_items))
process_item(this_item, dest_folder)
end repeat
else
– If not a folder then check the extension, file type, etc
try
set this_extension to the name extension of item_info
on error
set this_extension to “”
end try
try
set this_filetype to the file type of item_info
on error
set this_filetype to “”
end try
try
set this_typeID to the type identifier of item_info
on error
set this_typeID to “”
end try
– Only process if meets all criteria
if (package folder of the item_info is false) and (alias of the item_info is false) and ((this_filetype is in the type_list) or (this_extension is in the extension_list) or (this_typeID is in typeIDs_list)) then
convert_video(the_item, dest_folder)
end if
end if
end process_item

(*
** ON CONVERT_VIDEO
** This procedure does the actual conversion of video files using Handbrake
*)
on convert_video(this_item, dest_folder)
log “Processing file: ” & this_item as string
with timeout of (720 * 60) seconds
tell application “Finder”
try
if (label index of this_item is 0) then

– Set to gray label to indicate processing
set label index of this_item to 7

– Set original file name
set origFilepath to this_item as string
set origFilepathPOSIX to quoted form of POSIX path of origFilepath

if name extension of this_item is “MTS” then
– If MTS then make destination filename equal to YYYYMMDDHHMMSS.MP4
set origFileCreationDate to creation date of this_item
set newFilepathPOSIX to POSIX path of dest_folder
set newFilepathPOSIX to (newFilepathPOSIX & (getDateAsString of me from (origFileCreationDate))) & “.mp4″
set newFilepathPOSIX to quoted form of newFilepathPOSIX

else
– For all other files, keep destination filename the same (assume it’s already in YYYYMMDDHHMMSS format)
set nameWithExtension to name of this_item
set nameWithoutExtension to getBaseName of me from (nameWithExtension)
set newFilepathPOSIX to POSIX path of dest_folder
set newFilepathPOSIX to newFilepathPOSIX & nameWithoutExtension & “.mp4″
set newFilepathPOSIX to quoted form of newFilepathPOSIX

end if

– Start the conversion
– Refer to https://trac.handbrake.fr/wiki/CLIGuide and https://trac.handbrake.fr/wiki/BuiltInPresets
– for HandBrakeCLI presets
set shellCommand to “nice /Applications/HandBrakeCLI -i ” & origFilepathPOSIX & ” -o ” & newFilepathPOSIX & ” –preset=\”Universal\””

– display dialog shellCommand — uncomment for troubleshooting
log “Executing command: ” & shellCommand
tell current application
do shell script shellCommand — comment out for debugging
end tell

– Set the label to green in case file deletion fails
set label index of this_item to 6
log “Successfully converted item: ” & this_item as string

– Remove the old file
– set shellCommand to “rm -f ” & origFilepath
– do shell script shellCommand

else
log “Skipping already processed item: ” & this_item as string
end if

on error errmsg
– Set the label to red to indicate failure
set label index of this_item to 2
log “Failed to convert item: ” & this_item as string

end try
end tell
end timeout
end convert_video

to getDateAsString from t
set creationDateString to year of t as string
set creationDateString to creationDateString & text -2 thru -1 of (“0″ & getMonthNum(t) as string)
set creationDateString to creationDateString & text -2 thru -1 of (“0″ & day of t as string)
set creationDateString to creationDateString & text -2 thru -1 of (“0″ & hours of t as string)
set creationDateString to creationDateString & text -2 thru -1 of (“0″ & minutes of t as string)
set creationDateString to creationDateString & text -2 thru -1 of (“0″ & seconds of t as string)
return creationDateString
end getDateAsString

on getMonthNum(theDate)
– French Vanilla, by Emmanuel Lévy
– set theDate to the current date –or any other date
http://hints.macworld.com/article.php?story=20060703160750583
copy theDate to b
set the month of b to January
set monthNum to (1 + (theDate – b + 1314864) div 2629728)
return monthNum
end getMonthNum

to getBaseName from t
– by Kai Edwards
http://macscripter.net/viewtopic.php?id=24725
set d to AppleScript’s text item delimiters
set AppleScript’s text item delimiters to “.” — separated at periods
if (count t’s text items) > 1 then set t to t’s text 1 thru text item -2
set t to t’s text items — splits t into a list again at the periods
tell t to set t to beginning & ({“”} & rest) — puts it back together to
set AppleScript’s text item delimiters to d — always set them back again!
return t
end getBaseName