AppleScript to return condition depending on audio file length

I'd like to use Hazel (a rule-based file system automator) for macOS to automatically move mixtape audio files from one folder to another, if their duration is longer than 30 minutes.

Hazel doesn't provide a built-in method of checking for audio file length (that I know of), but it provides the ability to run rules if an AppleScript condition is passed, i.e. return true.

Judging from the screenshot below, I think it works if length of theFile > 30*60 seconds: return true (pseudo code).

enter image description here

I'm not however sure how to accomplish this via AppleScript. Any ideas how to do it, or where to start? A search online didn't provide many basic ideas, but it seems to be possible.


Note: Giving advice on AppleScripts is outside the scope of the Hazel support AFAIK, so I can't get any help from them.


Okay, I've downloaded Hazel and tested the following AppleScript code on a New Rule to validate it works. The following code when used in an embedded script will set theResult to true on theFile, an audio file that is longer than 30 minutes. Any file 30 minutes or less, or a non-audio file will set theResult to false:

set theResult to (do shell script "[[ $(afinfo -r '" & POSIX path of theFile & "' | awk '/estimated duration:/{print int($3/60)}') -gt 30 ]] && echo 'true' || echo 'false'") as boolean
return theResult
  • Note that from my first comment before posting this answer, I've changed theFileName to POSIX path of theFile, and as you can see in the image below, it validated the rule. It then also processed the rule, as I defined it, successfully.
  • To change the number of minutes, change the value on the right side of the operator, e.g.
    -gt 30 to the desired time, e.g. -gt 20. The operator can also be changed to any one of the following: -eq, -ne, -lt, -le, -gt or -ge

Hazel Preference Pane

Understanding, a little bit, the content of the do shell script command:

  • afinfo doesn't have much in the way of an manual page, so just type afinfo in Terminal and press enter for its options.
  • afinfo -r - {-r --real} get the estimated duration after obtaining the real packet count
  • Example output of afinfo -r:

     $ afinfo -r '09 Karn Evil 9.mp3'
     File:           09 Karn Evil 9.mp3
     File type ID:   MPG3
     Num Tracks:     1
    ----
     Data format:     2 ch,  44100 Hz, '.mp3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1152 frames/packet, 0 bytes/frame
                        no channel layout.
     audio bytes: 85117515
     audio packets: 81460
     estimated duration: 2127.935 sec
     bit rate: 320000 bits per second
     packet size upper bound: 1052
     maximum packet size: 1045
     audio data file offset: 275530
     optimized
    ----
     $
    
    • The above output gets piped (|) to awk.
  • awk '/estimated duration:/{print int($3/60)}'
    • awk finds the record (line) containing estimated duration: in the output of afinfo piped to it and prints the third field, $3, 2127.935 as an integer, having been divided by 60 to get the number of minutes, as the time value is in seconds. In the example output, awk returned: 35
  • $(...) The command substitution portion passed 35 to the test [[ $(...) -gt 30 ]], so it equated to [[ 35 -gt 30 ]] and as a result, using logical operators, echoed true. Had the value been equal to or less than 30, or a non-audio file, it would have echoed false.

If you want the content of do shell script command to run faster, then use the following:

set theResult to (do shell script "[[ $(afinfo -b '" & POSIX path of theFile & "' | awk 'FNR == 3 {print int($1/60)}') -gt 30 ]] && echo 'true' || echo 'false'") as boolean
return theResult
  • afinfo -b - {-b --brief} print a brief (one line) description of the audio file
    • This runs faster then using -r as it's not counting the packets, but getting the info from embedded data. Note that while the help says "(one line)", the output is actually three lines, but still faster then the long form, especially if not using -r.
  • Example output of afinfo -b:

    $ afinfo -b '09 Karn Evil 9.mp3'
    09 Karn Evil 9.mp3, MPG3, Num Tracks:     1
    ----
    2127.938 sec, format:   2 ch,  44100 Hz, '.mp3' (0x00000000) 0 bits/channel, 0 bytes/packet, 1152 frames/packet, 0 bytes/frame
    $
    
    • The above output gets piped (|) to awk.
  • awk 'FNR == 3 {print int($1/60)}'
    • awk prints the first field ($1) of the third record (line) of output piped from afinfo -b, 2127.935 as an integer, having been divided by 60 to get the number of minutes, as the time value is in seconds. In the example output, awk returned: 35