5

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.

  • 2
    I don't have Hazel, so I can't test with it and why a comment vs. an answer, however here's an AppleScript do shell script command that will set theResult to true or false if you can figure out how to pass it theFileName: set theResult to (do shell script "[[ $(afinfo -r '" & theFileName & "' | awk '/estimated duration:/{print int($3/60)}') -gt 30 ]] && echo 'true' || echo 'false'") as boolean. You can then add this line after it, return theResult and it will be equivalent to return true or return false accordingly. – user3439894 Jul 8 '17 at 20:57
  • 1
    @user3439894 I understand why you didn't post this as an answer, but I still think you should because doing so prevents the OP from deleting the question (for whatever reason). And, in this case, your answer is likely to lead to a solution that helps others. :) – Monomeeth Jul 9 '17 at 3:59
  • @Monomeeth, I went ahead and downloaded Hazel and after a slight modification, validated the code in my comment. By the way, I do not believe that adding an answer can stop the author of the OP from deleting his/her question. – user3439894 Jul 9 '17 at 11:44
  • 1
    @Winterflags, I've update the answer to add info on how to make it faster, read the section at the end of the answer after: "If you want the content of do shell script command to run faster, then use the following:" – user3439894 Jul 9 '17 at 15:04
6

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
  • 4
    +1 Nice work! I'm sure others will find this useful to know. :) – Monomeeth Jul 9 '17 at 11:56
  • 1
    @Monomeeth, so as to live up to your gracious comment, I updated the answer to include a little bit of an understanding of what the do shell script command is doing. BTW +1 for you on the Community Moderator Election! :) – user3439894 Jul 9 '17 at 13:00
  • 2
    Thanks for the solution, and especially for adding context and explanation which I think will be most beneficial for a wider audience! – Winterflags Jul 9 '17 at 14:29

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .