Advertisement
rubiks-sphere

Split Audio File at Defined Intervals - AppleScript

Mar 12th, 2017
993
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. -- Assigning the script to open when a "Start over" button is selected:
  2. -- From: http://apple.stackexchange.com/q/269936/184907
  3. set pathToThisScriptFile to (path to me)
  4.  
  5.  
  6.  
  7. -- Ensuring that FFmpeg is installed:
  8. try
  9.     set ffmpegCheck to "/usr/local/bin/ffmpeg -version"
  10.     do shell script ffmpegCheck
  11. on error
  12.    
  13.    
  14.     tell application "SystemUIServer"
  15.         with timeout of 999999 seconds
  16.             activate
  17.             display alert "This script cannot split any audio file." message "
  18. This script uses a third-party command line program called FFmpeg to split the source audio file.
  19.  
  20. FFmpeg is not currently installed on your computer. You must first install FFmpeg before you can utilize this script.
  21.  
  22.  
  23. If FFmpeg is currently installed and you are reading this message, then you need to open the script and modify the code, so that the code is aware of the location of FFmpeg on your system.
  24.  
  25. This script references the default location of:
  26. /usr/local/bin/ffmpeg
  27.  
  28. " buttons {"OK", "Open this script in Script Editor", "Go to official FFmpeg website"} default button "Go to official FFmpeg website" cancel button "OK"
  29.         end timeout
  30.     end tell
  31.    
  32.     if button returned of the result is "Go to official FFmpeg website" then
  33.         open location "https://ffmpeg.org/"
  34.     else if button returned of the result is "Open this script in Script Editor" then
  35.         if application "Script Editor" is running then
  36.             -- Check if this script file is already open.
  37.             try
  38.                 set theDocuments to every document
  39.                 set theNameOfThisScript to name of (info for (path to me))
  40.                 repeat with aDocument in theDocuments
  41.                     if ((path of aDocument) as string) contains theNameOfThisScript then
  42.                         -- This file is already open in Script Editor.
  43.                         activate aDocument
  44.                     else
  45.                         -- Script Editor is running but the file is not open in Script Editor.
  46.                         tell application "Script Editor"
  47.                             activate
  48.                             open (path to me)
  49.                         end tell
  50.                     end if
  51.                 end repeat
  52.             on error
  53.                 -- Script Editor is running but zero documents are open in Script Editor.
  54.                 tell application "Script Editor"
  55.                     activate
  56.                     open (path to me)
  57.                 end tell
  58.             end try
  59.         else
  60.             -- Script Editor is not running.
  61.             tell application "Script Editor"
  62.                 activate
  63.                 open (path to me)
  64.             end tell
  65.         end if
  66.     end if
  67. end try
  68.  
  69.  
  70.  
  71. repeat
  72.     activate
  73.     display dialog "Please enter the length of the desired interval:" default answer "(in seconds)" with title "Split Audio File at Defined Intervals" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
  74.     set desiredIntervalLength to text returned of result
  75.    
  76.     try
  77.         -- Check if variable is a number:
  78.         -- From: http://stackoverflow.com/a/20319349
  79.         set test to desiredIntervalLength as number
  80.         if desiredIntervalLength contains " " then
  81.             error
  82.         end if
  83.         exit repeat
  84.     on error
  85.         (*
  86.             You will find a "SystemUIServer" tell-block surrounding every instance of
  87.                 "display alert"
  88.                 "display dialog" (that does not receive a input)
  89.                 "choose from list"
  90.             in this code.
  91.  
  92.             Its function is to bring the dialog to the front of the screen and pin the dialog on top of all other windows.
  93.  
  94.             From:
  95.             http://apple.stackexchange.com/q/270749/184907
  96.         *)
  97.         tell application "SystemUIServer"
  98.             with timeout of 999999 seconds
  99.                 activate
  100.                 display alert "The interval that you entered is invalid." message "You must enter a number with no units or letters for the desired interval.
  101.  
  102. The interval that you've entered, " & desiredIntervalLength & ", is not a number." as critical
  103.             end timeout
  104.         end tell
  105.     end try
  106. end repeat
  107.  
  108.  
  109. activate
  110. set ButtonAndInput1 to (display dialog "Please enter the base filename for the resulting files:" default answer "Audio Segment" with title "Split Audio File at Defined Intervals" buttons {"Start over", "Quit", "Continue"} default button "Continue" cancel button "Quit")
  111. set desiredName to ButtonAndInput1's text returned
  112. set buttonChoice1 to ButtonAndInput1's button returned
  113. if buttonChoice1 is "Start over" then
  114.     run script pathToThisScriptFile
  115.     error number -128 (* cancels script *)
  116. end if
  117.  
  118. -- If the user submits a desired name and that name does not already end in a space, I want to add a space to the end (to separate the name and the number).
  119. if desiredName is not "" then
  120.     set lengthOfDesiredName to (length of desiredName)
  121.     if (character (lengthOfDesiredName) of desiredName is not " ") then
  122.         set desiredName to (desiredName & " ")
  123.     end if
  124. end if
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
  133.  
  134.  
  135.  
  136. repeat
  137.     activate
  138.     set ButtonAndInput2 to (display dialog "
  139. Please paste the file path of the audio file to split (including its file extension):
  140.  
  141.  
  142. (Tip: While holding down the Option ⌥ key, right-click on the file in Finder and select \"Copy [file] as Pathname.\")
  143.  
  144. (Alternatively, you can drag the file's icon itself to the below text field.)
  145.  
  146.  
  147. The resulting files will be output to a new folder within this audio file's parent folder.
  148. " default answer "" with title "Split Audio File at Defined Intervals" buttons {"Start over", "Quit", "Continue"} default button "Continue" cancel button "Quit")
  149.     set desiredSourceFile to (ButtonAndInput2's text returned) as text
  150.     set buttonChoice2 to ButtonAndInput2's button returned
  151.    
  152.     if buttonChoice2 is "Start over" then
  153.         run script pathToThisScriptFile
  154.         error number -128 (* cancels script *)
  155.     end if
  156.    
  157.    
  158.     -- Ensure that desiredSourceFile contains text:
  159.     if desiredSourceFile is "" then
  160.         tell application "SystemUIServer"
  161.             with timeout of 999999 seconds
  162.                 activate
  163.                 display alert "A path has not been provided by the user." message "You must enter the path of the source file to continue." as critical
  164.             end timeout
  165.         end tell
  166.     else
  167.        
  168.         if desiredSourceFile does not contain "." then
  169.             tell application "SystemUIServer"
  170.                 with timeout of 999999 seconds
  171.                     activate
  172.                     display alert "The path you entered is invalid." message "The path that you entered does not possess any file extension:
  173.                
  174. " & desiredSourceFile & "
  175.  
  176. Please provide the full file path of the audio file, including the extension." as critical
  177.                 end timeout
  178.             end tell
  179.         else
  180.             -- Check if desiredSourceFile contains the file's extension.
  181.             set lengthOfDesiredSourceFile to (length of desiredSourceFile)
  182.             if (character (lengthOfDesiredSourceFile - 3) of desiredSourceFile is ".") or (character (lengthOfDesiredSourceFile - 4) of desiredSourceFile is ".") then
  183.                 -- The third-to-last character or the fourth-to-last character is a period, so an extension exists.
  184.                
  185.                 -- Get audio file type of source file (by splitting text based on the dot (".") character):
  186.                 -- From: http://macscripter.net/viewtopic.php?id=24473
  187.                 set tempStorage to AppleScript's text item delimiters
  188.                 set AppleScript's text item delimiters to "."
  189.                 set the desiredSourceFileInAList to desiredSourceFile's text items
  190.                 set AppleScript's text item delimiters to tempStorage
  191.                 set theLastItemInTheList to (count of the items in desiredSourceFileInAList)
  192.                 set fileExtension to (item theLastItemInTheList of desiredSourceFileInAList) as text
  193.                 set fileExtensionWithDot to "." & fileExtension
  194.                
  195.                
  196.                 (*
  197. Ensuring that the file extension of the provided file is supported by FFmpeg:
  198.  
  199. I got the huge list of extensions by typing:
  200. ffmpeg -formats
  201. in Terminal.
  202. From:
  203. http://askubuntu.com/questions/286624/what-input-types-of-files-can-ffmpeg-convert-and-to-what-output-files/286655#286655
  204.  
  205. NOTE: This list contains non-audio file types, i.e., as video files.
  206.  
  207. I do not feel the urge to create a list that only contains audio file types.
  208.  
  209. But just note that this script has been designed to split exclusively AUDIO files. If you do use a non-audio file as the source file... the splitting functon might still not work...or it might give the user an error later on while getting the data for the summary dialog. So, if it matters to you, you should write some code to catch a non-audio file extension (that is supported by FFmpeg).
  210.  
  211. I just tested my script with a .mov file, out of curiosity, and the script worked perfectly, with no error whatsoever.
  212.  
  213. Of course, YMMV and use video files at your own risk.
  214. *)
  215.                
  216.                 set listOfAllFileExtensionsThatFFmpegSupports to {"3dostr", "3g2", "3gp", "4xm", "a64", "aa", "aac", "ac3", "acm", "act", "adf", "adp", "ads", "adts", "adx", "aea", "afc", "aiff", "aix", "alaw", "alias_pix", "amr", "anm", "apc", "ape", "apng", "aqtitle", "asf", "asf_o", "asf_stream", "ass", "ast", "au", "avfoundation", "avi", "avm2", "avr", "avs", "bethsoftvid", "bfi", "bfstm", "bin", "bink", "bit", "bmp_pipe", "bmv", "boa", "brender_pix", "brstm", "c93", "caf", "cavsvideo", "cdg", "cdxl", "cine", "concat", "crc", "dash", "data", "daud", "dcstr", "dds_pipe", "dfa", "dirac", "dnxhd", "dpx_pipe", "dsf", "dsicin", "dss", "dts", "dtshd", "dv", "dvbsub", "dvbtxt", "dvd", "dxa", "ea", "ea_cdata", "eac3", "epaf", "exr_pipe", "f32be", "f32le", "f4v", "f64be", "f64le", "ffm", "ffmetadata", "fifo", "film_cpk", "filmstrip", "flac", "flic", "flv", "framecrc", "framehash", "framemd5", "frm", "fsb", "g722", "g723_1", "g729", "genh", "gif", "gsm", "gxf", "h261", "h263", "h264", "hash", "hds", "hevc", "hls", "applehttp", "hnm", "ico", "idcin", "idf", "iff", "ilbc", "image2", "image2pipe", "ingenient", "ipmovie", "ipod", "ircam", "ismv", "iss", "iv8", "ivf", "ivr", "j2k_pipe", "jacosub", "jpeg_pipe", "jpegls_pipe", "jv", "latm", "lavfi", "live_flv", "lmlm4", "loas", "lrc", "lvf", "lxf", "m4v", "matroska", "webm", "md5", "mgsts", "microdvd", "mjpeg", "mkvtimestamp_v2", "mlp", "mlv", "mm", "mmf", "mov", "mp4", "m4a", "mj2", "mp2", "mp3", "mpc", "mpc8", "mpeg", "mpeg1video", "mpeg2video", "mpegts", "mpegtsraw", "mpegvideo", "mpjpeg", "mpl2", "mpsub", "msf", "msnwctcp", "mtaf", "mtv", "mulaw", "musx", "mv", "mvi", "mxf", "mxf_d10", "mxf_opatom", "mxg", "nc", "nistsphere", "nsv", "null", "nut", "nuv", "oga", "ogg", "ogv", "oma", "opus", "paf", "pam_pipe", "pbm_pipe", "pcx_pipe", "pgm_pipe", "pgmyuv_pipe", "pictor_pipe", "pjs", "pmp", "png_pipe", "ppm_pipe", "psp", "psxstr", "pva", "pvf", "qcp", "qdraw_pipe", "r3d", "rawvideo", "realtext", "redspark", "rl2", "rm", "roq", "rpl", "rsd", "rso", "rtp", "rtp_mpegts", "rtsp", "s16be", "s16le", "s24be", "s24le", "s32be", "s32le", "s8", "sami", "sap", "sbg", "sdp", "sdr2", "segment", "sgi_pipe", "shn", "siff", "singlejpeg", "sln", "smjpeg", "smk", "smoothstreaming", "smush", "sol", "sox", "spdif", "spx", "srt", "stl", "stream_segment", "stream_segments", "subviewer", "subviewer1", "sunrast_pipe", "sup", "svag", "svcd", "swf", "tak", "tedcaptions", "tee", "thp", "tiertexseq", "tiff_pipe", "tmv", "truehd", "tta", "tty", "txd", "u16be", "u16le", "u24be", "u24le", "u32be", "u32le", "u8", "uncodedframecrc", "v210", "v210x", "vag", "vc1", "vc1test", "vcd", "vivo", "vmd", "vob", "vobsub", "voc", "vpk", "vplayer", "vqf", "w64", "wav", "wc3movie", "webm_chunk", "webm_dash_manifest", "webp", "webp_pipe", "webvtt", "wsaud", "wsd", "wsvqa", "wtv", "wv", "wve", "xa", "xbin", "xmv", "xvag", "xwma", "yop", "yuv4mpegpipe"}
  217.                
  218.                 if listOfAllFileExtensionsThatFFmpegSupports does not contain fileExtension then
  219.                     tell application "SystemUIServer"
  220.                         with timeout of 999999 seconds
  221.                             activate
  222.                             display alert "The extension of the file that you provided is invalid." message "
  223. This script uses a third-party command line program called FFmpeg to split the source audio file.
  224.  
  225. FFmpeg cannot transcode multimedia files that possess the file extension that you submitted (" & fileExtension & ").
  226.  
  227. " buttons {"Start over", "Quit", "View supported file extensions"} default button "View supported file extensions" cancel button "Quit"
  228.                         end timeout
  229.                     end tell
  230.                     if button returned of the result is "Start over" then
  231.                         return run script pathToThisScriptFile
  232.                         error number -128 (* cancels script *)
  233.                     else if button returned of the result is "View supported file extensions" then
  234.                         tell application "SystemUIServer"
  235.                             with timeout of 999999 seconds
  236.                                 activate
  237.                                 set listButton to (choose from list listOfAllFileExtensionsThatFFmpegSupports with title "FFmpeg Supported File Extensions" with prompt "
  238. Here is a list of all file extensions that FFmpeg can accept, in alphabetical order.
  239.  
  240. Please note that this list includes various multimedia types(including video files), not only audio file extensions.
  241.  
  242.  
  243. The extension of the file that you provided, " & fileExtension & ", does not exist in the list.
  244.  
  245. For more info, please visit:
  246. https://ffmpeg.org/general.html#File-Formats
  247.  
  248. " cancel button name "Quit" OK button name "Start over" with empty selection allowed and multiple selections allowed)
  249.                             end timeout
  250.                         end tell
  251.                        
  252.                         if listButton is false then
  253.                             error number -128 (* user cancelled *)
  254.                         else
  255.                             return run script pathToThisScriptFile
  256.                             error number -128 (* cancels script *)
  257.                         end if
  258.                     end if
  259.                 end if
  260.                
  261.                
  262.                
  263.                
  264.                 -- Make sure that the desiredSourceFile actually exists:
  265.                 -- From: http://stackoverflow.com/a/3469708
  266.                 tell application "System Events"
  267.                     if exists file desiredSourceFile then
  268.                         exit repeat
  269.                     end if
  270.                 end tell
  271.                 tell application "SystemUIServer"
  272.                     with timeout of 999999 seconds
  273.                         activate
  274.                         display alert "The path you entered is invalid." message "The path that you entered does not exist:
  275.                
  276. " & desiredSourceFile & "
  277.  
  278. Please provide a valid source file." as critical
  279.                     end timeout
  280.                 end tell
  281.             else
  282.                 tell application "SystemUIServer"
  283.                     with timeout of 999999 seconds
  284.                         activate
  285.                         display alert "The path you entered is invalid." message "The file that you entered does not possess an extension:
  286.                
  287. " & desiredSourceFile & "
  288.  
  289. Please provide the full file path of the audio file, including the extension." as critical
  290.                     end timeout
  291.                 end tell
  292.             end if
  293.         end if
  294.     end if
  295. end repeat
  296.  
  297. -- Get duration of the source audio file in seconds:
  298. -- From: https://discussions.apple.com/message/22447897#message22447897
  299. set desiredSourceFileFormatted to (quoted form of (POSIX path of desiredSourceFile))
  300. set lengthOfSourceFileInSeconds to (word -2 of (do shell script "/usr/bin/afinfo " & desiredSourceFileFormatted & "|grep duration")) as text
  301. -- Round the length DOWN (to the nearest whole number integer):
  302. if lengthOfSourceFileInSeconds contains "." then
  303.     set tempStorage to AppleScript's text item delimiters
  304.     set AppleScript's text item delimiters to "."
  305.     set the lengthOfSourceFileInSecondsInAList to lengthOfSourceFileInSeconds's text items
  306.     set AppleScript's text item delimiters to tempStorage
  307.     set lengthOfSourceFileInSeconds to (item 1 of lengthOfSourceFileInSecondsInAList) as text
  308. end if
  309.  
  310.  
  311.  
  312. -- Ensuring that the audio file length is greater than the interval length:
  313. if (desiredIntervalLength as number is greater than or equal to lengthOfSourceFileInSeconds as number) then
  314.     tell application "SystemUIServer"
  315.         with timeout of 999999 seconds
  316.             activate
  317.             display alert "This script cannot continue." message "The interval that you desire (" & desiredIntervalLength & " seconds) is greater than or equal to the duration of the source audio file (" & (lengthOfSourceFileInSeconds as integer) & " seconds).
  318.  
  319. Therefore, it is not possible to split this audio file using the specified interval.
  320.  
  321. What would you like to do?
  322. " as critical buttons {"Quit", "Start over"} default button "Start over" cancel button "Quit"
  323.         end timeout
  324.     end tell
  325.     if button returned of the result is "Start over" then
  326.         run script pathToThisScriptFile
  327.         error number -128 (* cancels script *)
  328.     end if
  329. else
  330.     -- The desiredIntervalLength is good.
  331.     set howManyTimesCan_desiredIntervalLength_FitIn_lengthOfSourceFileInSeconds to (lengthOfSourceFileInSeconds div desiredIntervalLength)
  332.     set totalNumberOfFilesToBeCreated to (1 + howManyTimesCan_desiredIntervalLength_FitIn_lengthOfSourceFileInSeconds)
  333. end if
  334.  
  335.  
  336.  
  337. -- Getting the desired output file bit rate from the user:
  338. set bitRateOfSource to (word -4 of (do shell script "/usr/bin/afinfo " & desiredSourceFileFormatted & "|grep rate")) as text
  339. set bitRateOfSourceInKbps to (text 1 thru -4 of (bitRateOfSource as text))
  340.  
  341. set commonBitRates to {"Same as source", "32 kbps", "96 kbps", "128 kbps", "160 kbps", "192 kbps", "256 kbps", "320 kbps", "Custom number"}
  342.  
  343. tell application "SystemUIServer"
  344.     with timeout of 999999 seconds
  345.         activate
  346.         set theBitRate to choose from list commonBitRates with title "Bit Rate of Resulting Files" with prompt "
  347. Select a CBR (constant bit rate) for the resulting files.
  348.  
  349. (This script does not support VBR encoding.)
  350.  
  351. The source file has a bit rate of approximately " & bitRateOfSourceInKbps & " kbps.
  352.  
  353.  
  354. Note: The higher the bit rate, the larger the resulting file size.
  355.  
  356. Also note: If you select a bit rate other than \"Same as source,\" the processing time will dramatically increase. This is, e.g., the difference between a total runtime of 20 seconds and a total runtime of 2 minutes.
  357. " default items "Same as source" cancel button name {"       Quit       "} OK button name {"       Continue       "} without empty selection allowed
  358.     end timeout
  359. end tell
  360.  
  361. if theBitRate is false then
  362.     error number -128 (* user cancelled *)
  363. else
  364.     set theBitRate to theBitRate's item 1 (* extract choice from list *)
  365. end if
  366.  
  367.  
  368.  
  369.  
  370. if (theBitRate is "Same as source") then
  371.     -- Keep same setting as source audio file:
  372.     -- From:http://askubuntu.com/a/328180
  373.     set theBitRateFormatted to "-acodec copy"
  374. else if (theBitRate is "320 kbps") then
  375.     -- Format custom bit rate for ffmpeg:
  376.     -- From:
  377.     -- https://superuser.com/a/370637/598118
  378.     -- https://superuser.com/a/521684/598118
  379.     set theBitRateFormatted to "-b:a 320k"
  380. else if (theBitRate is "256 kbps") then
  381.     set theBitRateFormatted to "-b:a 256k"
  382. else if (theBitRate is "192 kbps") then
  383.     set theBitRateFormatted to "-b:a 192k"
  384. else if (theBitRate is "160 kbps") then
  385.     set theBitRateFormatted to "-b:a 160k"
  386. else if (theBitRate is "128 kbps") then
  387.     set theBitRateFormatted to "-b:a 128k"
  388. else if (theBitRate is "96 kbps") then
  389.     set theBitRateFormatted to "-b:a 96k"
  390. else if (theBitRate is "32 kbps") then
  391.     set theBitRateFormatted to "-b:a 32k"
  392. else if (theBitRate is "Custom number") then
  393.     repeat
  394.         activate
  395.         display dialog "Please enter the desired bit rate in kilobits per second (kbps):" default answer "128" with title "Custom Bit Rate of Resulting Files" buttons {"Quit", "Continue"} default button "Continue" cancel button "Quit"
  396.         set customBitRate to text returned of result
  397.        
  398.         try
  399.             -- Check if variable is a number:
  400.             -- From: http://stackoverflow.com/a/20319349
  401.             set checkCustomBitRate to customBitRate as number
  402.            
  403.             if customBitRate contains " " then
  404.                 error
  405.             else if ((length of customBitRate) is greater than 4) then
  406.                 tell application "SystemUIServer"
  407.                     with timeout of 999999 seconds
  408.                         activate
  409.                         display alert "The bit rate that you entered (" & customBitRate & ") is invalid." message "You must enter a desired bit rate in kilobits per second (kbps).
  410.                    
  411. A bit rate of " & customBitRate & " kbps is impossibly large.
  412.  
  413. Try again." as critical
  414.                     end timeout
  415.                 end tell
  416.             else if ((length of customBitRate) is less than 5) then
  417.                 exit repeat
  418.             end if
  419.         on error
  420.             tell application "SystemUIServer"
  421.                 with timeout of 999999 seconds
  422.                     activate
  423.                     display alert "The bit rate that you entered (" & customBitRate & ") is invalid." message "You must enter a number for the desired bit rate.
  424.                    
  425. Do not include punctuation or units in your entry." as critical
  426.                 end timeout
  427.             end tell
  428.         end try
  429.     end repeat
  430.     set theBitRateFormatted to ("-b:a " & customBitRate & "k")
  431. end if
  432.  
  433.  
  434.  
  435.  
  436.  
  437.  
  438.  
  439. -- Get parent folder of source file (since this is where the resulting files will be saved):
  440. -- From post #3 in this thread: http://macscripter.net/viewtopic.php?id=33828
  441. set parentDirectory to (do shell script "dirname " & quoted form of POSIX path of (desiredSourceFile))
  442.  
  443. -- Get the current date (in my preferred format):
  444. -- From: http://henrysmac.org/blog/2014/1/4/formatting-short-dates-in-applescript.html
  445. set TodayDate to current date
  446. set y to text -4 thru -1 of ("0000" & (year of TodayDate))
  447. set m to text -2 thru -1 of ("00" & ((month of TodayDate) as integer))
  448. set d to text -2 thru -1 of ("00" & (day of TodayDate))
  449. set FormattedTodayDate to y & "_" & m & "_" & d & " - "
  450.  
  451.  
  452.  
  453.  
  454. -- Putting all of the variables together:
  455. set folderToSaveResultingFiles to parentDirectory & "/" & FormattedTodayDate & "Script Output - Audio Segments By Interval/"
  456. set startingTimestamp to 0
  457. set endingTimestamp to desiredIntervalLength as number
  458. set counter to 1
  459. set theFullFilepath to folderToSaveResultingFiles & desiredName & counter & fileExtensionWithDot
  460. set theFullFilepathFormatted to quoted form of POSIX path of theFullFilepath
  461.  
  462. set theStringEnding to (startingTimestamp & " -t " & endingTimestamp & " " & theBitRateFormatted & " " & theFullFilepathFormatted) as text
  463. set theStringBeginning to "/usr/local/bin/ffmpeg -i " & desiredSourceFileFormatted & " -ss "
  464. (*
  465.     NOTE: One cannot simply use "ffmpeg -i" in the above string without including the leading filepath.
  466.         This is because of the fact that: "Scripts that run via Automator use the default search path which usually does not include /usr/local/bin."
  467.     See:
  468.         http://apple.stackexchange.com/questions/97502/my-automator-workflow-fails-because-it-fails-to-find-the-git-command-within-the/167783#167783
  469.         http://stackoverflow.com/a/3774262
  470.         http://apple.stackexchange.com/a/130841/184907
  471. *)
  472. set theFullString to (theStringBeginning & theStringEnding)
  473. (*
  474. theFullString should be in this format:
  475. ffmpeg -i source_audio_file.m4a -ss 0 -t 120 -acodec copy segment_1.m4a
  476. ffmpeg -i source_audio_file.m4a -ss 0 -t 120 -b:a 96k segment_1.m4a
  477. *)
  478.  
  479.  
  480.  
  481.  
  482.  
  483. -- Ensuring that the new folder for the resulting files to output to does not already exist:
  484. -- Original author: user3439894
  485.  
  486. set theFolderAlreadyExistsAndUserWantsToStartOver to false
  487. set theFolderAlreadyExistsAndUserWantsToOpenIt to false
  488.  
  489. set folderToCheck to POSIX file folderToSaveResultingFiles as string
  490. tell application "Finder" to set b to exists folder folderToCheck
  491. tell current application
  492.     try
  493.         if b then
  494.             tell application "SystemUIServer"
  495.                 with timeout of 999999 seconds
  496.                     activate
  497.                     display dialog "                                       The output directory:
  498.  
  499. \"" & POSIX path of folderToCheck & "\"
  500.                                            already exists!" & return & return & "Do you want to overwrite the directory?" buttons {"No. Start over.", "No. Open the folder that already exists.", "Yes"} default button 1 with title "Folder Already Exists" with icon caution
  501.                 end timeout
  502.             end tell
  503.             if the button returned of result is "No. Start over." then
  504.                 set theFolderAlreadyExistsAndUserWantsToStartOver to true
  505.                 -- I can't use  a return within a try block so, I am using the above boolean variable instead.
  506.                 -- This variable will be referenced after the try block is completed to restart the script.            
  507.             else if the button returned of result is "No. Open the folder that already exists." then
  508.                 --  # The file already exists, chose not to overwrite it, just open the document.
  509.                 set theFolderAlreadyExistsAndUserWantsToOpenIt to true
  510.                 -- Open folder in Finder:
  511.                 tell application "Finder"
  512.                     open (folderToSaveResultingFiles as POSIX file)
  513.                     -- Bring Finder window to foreground:      
  514.                     activate
  515.                     -- Enlarging the Finder window to my preferred size:
  516.                     -- From: http://apple.stackexchange.com/a/268667/184907
  517.                     set bounds of front window to {161, 49, 1260, 740}
  518.                 end tell
  519.             else if the button returned of result is "Yes" then
  520.                 tell application "Finder"
  521.                     -- Delete the folder, so that I can now recreate this folder.
  522.                     delete the folder folderToCheck
  523.                 end tell
  524.             end if
  525.         end if
  526.     on error eStr number eNum
  527.         activate
  528.         tell application "SystemUIServer"
  529.             with timeout of 999999 seconds
  530.                 activate
  531.                 display dialog eStr & " number " & eNum buttons {"OK"} default button 1 with icon caution
  532.             end timeout
  533.         end tell
  534.         error number -128
  535.     end try
  536. end tell
  537.  
  538. if (theFolderAlreadyExistsAndUserWantsToStartOver is true) then
  539.     run script pathToThisScriptFile
  540.     error number -128 (* user cancelled *)
  541. else if (theFolderAlreadyExistsAndUserWantsToOpenIt is true) then
  542.     error number -128 (* user cancelled *)
  543. end if
  544.  
  545.  
  546.  
  547.  
  548.  
  549.  
  550. -- Creating the new folder for the resulting files to output to:
  551. -- From: http://stackoverflow.com/a/4493619
  552. tell application "Finder"
  553.     make new folder at POSIX file parentDirectory with properties {name:FormattedTodayDate & "Script Output - Audio Segments By Interval"}
  554. end tell
  555.  
  556. set giveUpTime to 30
  557. tell application "SystemUIServer"
  558.     with timeout of 999999 seconds
  559.         activate
  560.         display alert "Dividing of 1 audio file into " & totalNumberOfFilesToBeCreated & " parts will now begin..." message "
  561. Depending on the duration of the resulting audio files, the number of new audio files to be created, and whether the desired bit rate differs from the bit rate of the source file, this process may take several minutes.
  562.  
  563. Please wait as the task is completed.
  564.  
  565. Do not shut down the computer until the splitting is complete.
  566.  
  567.  
  568. (automatically proceeding in " & giveUpTime & " seconds)" buttons {"Abort", "Start over", "Split audio file"} default button "Split audio file" cancel button "Abort" giving up after giveUpTime
  569.     end timeout
  570. end tell
  571. if button returned of the result is "Start over" then
  572.     run script pathToThisScriptFile
  573.     error number -128 (* cancels script *)
  574. end if
  575.  
  576. -- Keeping track of the elapsed time so that the script can notify the user that the script is still running:
  577. -- From: https://discussions.apple.com/message/6883418#message6883418
  578. set BeforeTime_m to minutes of (current date)
  579. set BeforeTime_s to seconds of (current date)
  580. set periodicIntervalToShowUserDialog to 60
  581.  
  582. set stopMark to 0
  583.  
  584. repeat until ((stopMark as integer) is greater than or equal to lengthOfSourceFileInSeconds as integer)
  585.     -- This line is where all of the action happens:
  586.     do shell script theFullString
  587.    
  588.     set startingTimestamp to ((startingTimestamp as integer) + desiredIntervalLength as integer) as integer
  589.     set endingTimestamp to (endingTimestamp + desiredIntervalLength)
  590.    
  591.     set counter to ((counter as integer) + 1) as integer
  592.    
  593.     set theFullFilepath to folderToSaveResultingFiles & desiredName & counter & fileExtensionWithDot
  594.     set theFullFilepathFormatted to quoted form of POSIX path of theFullFilepath
  595.     set theStringEnding to (startingTimestamp & " -t " & desiredIntervalLength & " " & theBitRateFormatted & " " & theFullFilepathFormatted) as text
  596.     set theFullString to (theStringBeginning & theStringEnding)
  597.    
  598.     set stopMark to (endingTimestamp)
  599.    
  600.    
  601.    
  602.     set AfterTimeCheck_m to minutes of (current date)
  603.     set AfterTimeCheck_s to seconds of (current date)
  604.     set checkRuntimeInSeconds to ((AfterTimeCheck_m * 60) + AfterTimeCheck_s) - ((BeforeTime_m * 60) + BeforeTime_s)
  605.    
  606.     if (checkRuntimeInSeconds as integer is greater than or equal to periodicIntervalToShowUserDialog as integer) then
  607.        
  608.         set periodicIntervalToShowUserDialog to (periodicIntervalToShowUserDialog + 120)
  609.        
  610.        
  611.         set midstCounter to (counter - 1)
  612.         set howManyMoreFiles to (totalNumberOfFilesToBeCreated - midstCounter)
  613.        
  614.         if (howManyMoreFiles is 1) then
  615.             set howManyMoreFilesDisplayString to "1 more file still has"
  616.         else if (howManyMoreFiles is greater than 1) then
  617.             set howManyMoreFilesDisplayString to (howManyMoreFiles & " more files still have")
  618.         end if
  619.        
  620.         tell application "SystemUIServer"
  621.             with timeout of 999999 seconds
  622.                 activate
  623.                 display alert "Splitting of the audio file is still occurring..." message "
  624. This script has just completed the creation of audio segment number " & midstCounter & ".
  625.  
  626. " & howManyMoreFilesDisplayString & " to be created.
  627.  
  628. This process may take several minutes to conclude.
  629.  
  630. Do you want to continue?
  631.  
  632.  
  633. (automatically proceeding in " & giveUpTime & " seconds)" buttons {"Stop now", "Start over", "Proceed"} default button "Proceed" cancel button "Stop now" giving up after giveUpTime
  634.             end timeout
  635.         end tell
  636.         if button returned of the result is "Start over" then
  637.             return run script pathToThisScriptFile
  638.             error number -128 (* cancels script *)
  639.         end if
  640.     end if
  641.    
  642. end repeat
  643.  
  644.  
  645. -- The final resulting file must have a shorter runtime than the specified interval. Calculate the custom length of this special, last file:
  646. set startingTimestamp to (stopMark - desiredIntervalLength)
  647. set customIntervalLength to (lengthOfSourceFileInSeconds - startingTimestamp)
  648. set theFullFilepath to folderToSaveResultingFiles & desiredName & counter & fileExtensionWithDot
  649. set theFullFilepathFormatted to quoted form of POSIX path of theFullFilepath
  650. set theStringEnding to (startingTimestamp & " -t " & customIntervalLength & " " & theBitRateFormatted & " " & theFullFilepathFormatted) as text
  651. set theFullString to (theStringBeginning & theStringEnding)
  652. do shell script theFullString
  653.  
  654.  
  655.  
  656.  
  657.  
  658. -- Convert seconds to minutes for display to user:
  659. set durationOfFinalResultingSegment to customIntervalLength as integer
  660. set desiredIntervalLength to desiredIntervalLength as integer
  661. set lengthOfSourceFileInSeconds to lengthOfSourceFileInSeconds as integer
  662.  
  663. if desiredIntervalLength is less than 60 then
  664.     if desiredIntervalLength is less than 2 then
  665.         set displayIntervalString to (desiredIntervalLength & " second")
  666.     else
  667.         set displayIntervalString to (desiredIntervalLength & " seconds")
  668.     end if
  669. else
  670.     set displayIntervalString to convertSecondsToHoursAndMinutes(desiredIntervalLength)
  671. end if
  672. if durationOfFinalResultingSegment is less than 60 then
  673.     if durationOfFinalResultingSegment is less than 2 then
  674.         set displayFinalFileLengthString to (durationOfFinalResultingSegment & " second")
  675.     else
  676.         set displayFinalFileLengthString to (durationOfFinalResultingSegment & " seconds")
  677.     end if
  678. else
  679.     set displayFinalFileLengthString to convertSecondsToHoursAndMinutes(durationOfFinalResultingSegment)
  680. end if
  681. if lengthOfSourceFileInSeconds is less than 60 then
  682.     if lengthOfSourceFileInSeconds is less than 2 then
  683.         set displaySourceFileDurationString to (lengthOfSourceFileInSeconds & " second")
  684.     else
  685.         set displaySourceFileDurationString to (lengthOfSourceFileInSeconds & " seconds")
  686.     end if
  687. else
  688.     set displaySourceFileDurationString to convertSecondsToHoursAndMinutes(lengthOfSourceFileInSeconds)
  689.     -- The comma placement is a bit confusing when the source file info is displayed, so change the comma to an ampersand:
  690.     if displaySourceFileDurationString contains ", " then
  691.         set displaySourceFileDurationString to replace_chars(displaySourceFileDurationString, ", ", " & ")
  692.     end if
  693. end if
  694.  
  695.  
  696. -- Get bit rates to display to user:
  697. set aRegularResultingFile to (folderToSaveResultingFiles & desiredName & (counter - 1) & fileExtensionWithDot)
  698. set aRegularResultingFileFormatted to (quoted form of (POSIX path of aRegularResultingFile))
  699. set bitRateOfResultingFile to (word -4 of (do shell script "/usr/bin/afinfo " & aRegularResultingFileFormatted & "|grep rate")) as text
  700. set bitRateOfResultingFineInKbps to (text 1 thru -4 of (bitRateOfResultingFile as text))
  701.  
  702. -- Get sample rates to display to user:
  703. set sampleRateOfResultingFile to (word 5 of (do shell script "/usr/bin/afinfo " & aRegularResultingFileFormatted & "|grep format")) as text
  704. set sampleRateUnitOfResultingFile to (word 6 of (do shell script "/usr/bin/afinfo " & aRegularResultingFileFormatted & "|grep format")) as text
  705. set sampleRateOfResultingFile to (sampleRateOfResultingFile & " " & sampleRateUnitOfResultingFile)
  706.  
  707. set sampleRateOfSourceFile to (word 5 of (do shell script "/usr/bin/afinfo " & desiredSourceFileFormatted & "|grep format")) as text
  708. set sampleRateUnitOfSourceFile to (word 6 of (do shell script "/usr/bin/afinfo " & desiredSourceFileFormatted & "|grep format")) as text
  709. set sampleRateOfSourceFile to (sampleRateOfSourceFile & " " & sampleRateUnitOfSourceFile)
  710.  
  711. -- Get file sizes to display to the user:
  712. set theFolderSize to size of (info for folderToSaveResultingFiles)
  713. set theFolderSize to convertByteSize(theFolderSize, 1000, 2)
  714.  
  715. set theSourceFileSize to size of (info for desiredSourceFile)
  716. set theSourceFileSize to convertByteSize(theSourceFileSize, 1000, 2)
  717.  
  718. set aRegularFileFileSize to size of (info for aRegularResultingFile)
  719. set aRegularFileFileSize to convertByteSize(aRegularFileFileSize, 1000, 1)
  720.  
  721. set theMostRecentlyCreatedFileSize to size of (info for theFullFilepath)
  722. set theMostRecentlyCreatedFileSize to convertByteSize(theMostRecentlyCreatedFileSize, 1000, 2)
  723.  
  724. -- Completing elapsed time calculation:
  725. set AfterTime_m to minutes of (current date)
  726. set AfterTime_s to seconds of (current date)
  727. set runtimeInSeconds to ((AfterTime_m * 60) + AfterTime_s) - ((BeforeTime_m * 60) + BeforeTime_s)
  728.  
  729. -- Convert runtime in seconds to minutes for display to user:
  730. set runtimeInSeconds to runtimeInSeconds as integer
  731. if runtimeInSeconds is less than 60 then
  732.     if runtimeInSeconds is less than 2 then
  733.         set displayRuntimeString to (runtimeInSeconds & " second")
  734.     else
  735.         set displayRuntimeString to (runtimeInSeconds & " seconds")
  736.     end if
  737. else
  738.     set displayRuntimeString to convertSecondsToHoursAndMinutes(runtimeInSeconds)
  739. end if
  740.  
  741. tell application "SystemUIServer"
  742.     with timeout of 999999 seconds
  743.         activate
  744.         display alert "Splitting of the audio file is complete." message "
  745. Summary:
  746.  
  747. • " & counter & " " & fileExtension & " audio files have been created.
  748.  
  749. • This script required " & displayRuntimeString & " to create the files.
  750.  
  751. • The segments are located in:
  752. " & folderToSaveResultingFiles & "
  753.  
  754. • The size of the output folder is " & theFolderSize & ".
  755.  
  756. • Each file has a file size of approximately " & aRegularFileFileSize & ", except for the last file, which has a file size of exactly " & theMostRecentlyCreatedFileSize & ".
  757.  
  758. • Each file has a duration of " & displayIntervalString & ", except for the last file, which has a duration of " & displayFinalFileLengthString & ".
  759.  
  760. • Each file has a bit rate of approximately " & bitRateOfResultingFineInKbps & " kbps.
  761.  
  762. • Each file has a sample rate of " & sampleRateOfResultingFile & ".
  763.  
  764. • The source audio file has a duration of " & displaySourceFileDurationString & ", a bit rate of " & bitRateOfSource & " bit/s, a sample rate of " & sampleRateOfSourceFile & ", and a file size of " & theSourceFileSize & ".
  765.  
  766. Do you want to open the output folder?
  767. " buttons {"No", "Yes"} default button "Yes"
  768.     end timeout
  769. end tell
  770.  
  771. if button returned of the result is "Yes" then
  772.     tell application "Finder"
  773.         open (folderToSaveResultingFiles as POSIX file)
  774.         -- Bring Finder window to foreground:      
  775.         activate
  776.         -- Enlarging the Finder window to my preferred size:
  777.         -- From: http://apple.stackexchange.com/a/268667/184907
  778.         set bounds of front window to {161, 49, 1260, 740}
  779.     end tell
  780.    
  781. else if button returned of the result is "No" then
  782.     error number -128 (* cancels script *)
  783. end if
  784.  
  785.  
  786.  
  787. on replace_chars(this_text, search_string, replacement_string)
  788.     set AppleScript's text item delimiters to the search_string
  789.     set the item_list to every text item of this_text
  790.     set AppleScript's text item delimiters to the replacement_string
  791.     set this_text to the item_list as string
  792.     set AppleScript's text item delimiters to ""
  793.     return this_text
  794. end replace_chars
  795.  
  796.  
  797.  
  798. on convertSecondsToHoursAndMinutes(timeInSeconds)
  799.    
  800.     -- Convert seconds to minutes and hours:
  801.     -- From: http://wiki.indigodomo.com/doku.php?id=applescript_snippit
  802.    
  803.     set theHours to (timeInSeconds div hours)
  804.     set theRemainderSeconds to (timeInSeconds mod hours)
  805.     set theMinutes to (theRemainderSeconds div minutes)
  806.     set theRemainderSeconds to (theRemainderSeconds mod minutes)
  807.    
  808.     set theTimeString to theHours & ":" & theMinutes & ":" & theRemainderSeconds as text
  809.    
  810.    
  811.     if (character 1 of theTimeString is "0") or (character 1 of theTimeString is ":") then
  812.         set theFirstCharIsAColonOrZero to true
  813.     else
  814.         set theFirstCharIsAColonOrZero to false
  815.     end if
  816.    
  817.    
  818.     repeat until (theFirstCharIsAColonOrZero is false)
  819.         -- Removing the first character of the string:
  820.         set theTimeString to ((characters 2 thru -1 of theTimeString) as string)
  821.        
  822.         if (character 1 of theTimeString is "0") or (character 1 of theTimeString is ":") then
  823.             set theFirstCharIsAColonOrZero to true
  824.         else
  825.             set theFirstCharIsAColonOrZero to false
  826.         end if
  827.     end repeat
  828.    
  829.     set tempStorage to AppleScript's text item delimiters
  830.     set AppleScript's text item delimiters to ":"
  831.     set colonCount to (count theTimeString's text items) - 1
  832.     set AppleScript's text item delimiters to tempStorage
  833.    
  834.    
  835.     if (colonCount is 1) then
  836.         -- Splitting text based on a specific character
  837.         -- From: http://macscripter.net/viewtopic.php?id=24473
  838.         set tempStorage to AppleScript's text item delimiters
  839.         set AppleScript's text item delimiters to ":"
  840.         set theTimeStringInAList to theTimeString's text items
  841.         set AppleScript's text item delimiters to tempStorage
  842.        
  843.         set minutesFig to item 1 of theTimeStringInAList
  844.         set secondsFig to item 2 of theTimeStringInAList
  845.        
  846.         set theWordExactlyShouldPrecedeTheMinuteFig to false
  847.        
  848.         if (minutesFig as number is less than 2) then
  849.             set minutesUnitInCorrectPluralState to "minute"
  850.         else
  851.             set minutesUnitInCorrectPluralState to "minutes"
  852.         end if
  853.         set minutesWithUnit to minutesFig & " " & minutesUnitInCorrectPluralState
  854.        
  855.        
  856.         if (secondsFig as number is less than 2) then
  857.             if (secondsFig as number is 0) then
  858.                 set secondsFig to ""
  859.                 set secondsUnitInCorrectPluralState to ""
  860.                 set theWordExactlyShouldPrecedeTheMinuteFig to true
  861.             else
  862.                 set secondsUnitInCorrectPluralState to " second"
  863.                 set secondsFig to ", " & secondsFig
  864.             end if
  865.         else
  866.             set secondsUnitInCorrectPluralState to " seconds"
  867.             set secondsFig to ", " & secondsFig
  868.         end if
  869.        
  870.         set secondsWithUnit to secondsFig & secondsUnitInCorrectPluralState
  871.        
  872.         set timeStringToDisplay to minutesWithUnit & secondsWithUnit
  873.        
  874.         if theWordExactlyShouldPrecedeTheMinuteFig is true then
  875.             set timeStringToDisplay to "exactly " & timeStringToDisplay
  876.         end if
  877.        
  878.     else if (colonCount is 2) then
  879.         -- Splitting text based on a specific character
  880.         -- From: http://macscripter.net/viewtopic.php?id=24473
  881.         set tempStorage to AppleScript's text item delimiters
  882.         set AppleScript's text item delimiters to ":"
  883.         set theTimeStringInAList to theTimeString's text items
  884.         set AppleScript's text item delimiters to tempStorage
  885.        
  886.         set hoursFig to item 1 of theTimeStringInAList
  887.         set minutesFig to item 2 of theTimeStringInAList
  888.         set secondsFig to item 3 of theTimeStringInAList
  889.        
  890.         set theWordExactlyShouldPrecedeTheMinuteFig to false
  891.         set theWordExactlyShouldPrecedeTheHourFig to false
  892.        
  893.         if (hoursFig as number is less than 2) then
  894.             set hoursUnitInCorrectPluralState to "hour"
  895.         else
  896.             set hoursUnitInCorrectPluralState to "hours"
  897.         end if
  898.         set hoursWithUnit to hoursFig & " " & hoursUnitInCorrectPluralState
  899.        
  900.        
  901.         if (minutesFig as number is less than 2) then
  902.             if (minutesFig as number is 0) then
  903.                 set minutesFig to ""
  904.                 set minutesUnitInCorrectPluralState to ""
  905.                 set theWordExactlyShouldPrecedeTheHourFig to true
  906.             else
  907.                 set minutesUnitInCorrectPluralState to " minute"
  908.                 set minutesFig to ", " & minutesFig
  909.             end if
  910.         else
  911.             set minutesUnitInCorrectPluralState to " minutes"
  912.             set minutesFig to ", " & minutesFig
  913.         end if
  914.         set minutesWithUnit to minutesFig & minutesUnitInCorrectPluralState
  915.        
  916.        
  917.         if (secondsFig as number is less than 2) then
  918.             if (secondsFig as number is 0) then
  919.                 set secondsFig to ""
  920.                 set secondsUnitInCorrectPluralState to ""
  921.                 set theWordExactlyShouldPrecedeTheHourFig to true
  922.             else
  923.                 set secondsUnitInCorrectPluralState to " second"
  924.                 set secondsFig to ", and " & secondsFig
  925.             end if
  926.         else
  927.             set secondsUnitInCorrectPluralState to " seconds"
  928.             set secondsFig to ", and " & secondsFig
  929.         end if
  930.         set secondsWithUnit to secondsFig & secondsUnitInCorrectPluralState
  931.        
  932.        
  933.        
  934.         set timeStringToDisplay to hoursWithUnit & minutesWithUnit & secondsWithUnit
  935.        
  936.         if theWordExactlyShouldPrecedeTheHourFig is true then
  937.             set timeStringToDisplay to "exactly " & timeStringToDisplay
  938.         end if
  939.     end if
  940.    
  941.     return timeStringToDisplay
  942.    
  943. end convertSecondsToHoursAndMinutes
  944.  
  945.  
  946.  
  947.  
  948. on convertByteSize(byteSize, KBSize, decPlaces)
  949.     -- Convert byte size to MG size.
  950.     -- From: Post #1 in this thread: http://macscripter.net/viewtopic.php?id=37035
  951.     if (KBSize is missing value) then set KBSize to 1000 + 24 * (((system attribute "sysv") < 4192) as integer)
  952.    
  953.     if (byteSize is 1) then
  954.         set conversion to "1 byte" as Unicode text
  955.     else if (byteSize < KBSize) then
  956.         set conversion to (byteSize as Unicode text) & " bytes"
  957.     else
  958.         set conversion to "Oooh lots!" -- Default in case yottabytes isn't enough!
  959.         set suffixes to {" K", " MB", " GB", " TB", " PB", " EB", " ZB", " YB"}
  960.         set dpShift to ((10 ^ 0.5) ^ 2) * (10 ^ (decPlaces - 1)) -- (10 ^ decPlaces) convolutedly to try to shake out any floating-point errors.
  961.         repeat with p from 1 to (count suffixes)
  962.             if (byteSize < (KBSize ^ (p + 1))) then
  963.                 tell ((byteSize / (KBSize ^ p)) * dpShift) to set conversion to (((it div 0.5 - it div 1) / dpShift) as Unicode text) & item p of suffixes
  964.                 exit repeat
  965.             end if
  966.         end repeat
  967.     end if
  968.    
  969.     return conversion
  970. end convertByteSize
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement