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 &gt; 30*60 seconds: return true (pseudo code).



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 '" &amp; POSIX path of theFile &amp; "' | awk '/estimated duration:/{print int($3/60)}') -gt 30 ]] &amp;&amp; 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




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 '" &amp; POSIX path of theFile &amp; "' | awk 'FNR == 3 {print int($1/60)}') -gt 30 ]] &amp;&amp; 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