In the past few years, I’ve been highly influenced by a few people in tech. Bart Busschots and his Programming By Stealth series of course, but also Ray Robertson from his AppleScript Bootcamp at Command-D and Sal Soghoian. Listening and learning from these people doesn’t mean that I can replicate what they do. The gift they give in their teaching is that we can learn to automate things that are repetitive to us.
Years ago I asked my good friend Dorothy if she’d help me automate the mechanics of producing my podcasts. She did a lot of work on it and much of it is automated now, but there was one piece that eluded automation. When you receive a podcast episode, you’ll see things like who produced it, the website URL, the episode will have a title, the genre will be podcast, and there will be album artwork so you can identify the show at a glance. All of this information is stored in what’s called the ID3 tag.
The ID3 tags are specified at id3.org but there’s no one single way to add the ID3 tags to the audio or video files we create as podcasters. For many years, I used iTunes to add my ID3 tags and part of Dorothy’s efforts went to automating that process. But after a while, I realized it was a lot of overhead to pull an uncompressed audio file into iTunes, have it compress the file, and then type in all of the ID3 tags once a week per show I produce.
I discovered the desktop version of Auphonic Leveler which not only compresses my files but also adjusts them to the loudness standards which is awesome, but it doesn’t add these ID3 tags I’ve been talking about. I found a lot of people use a lightweight app called ID3 Editor from pa-software.com/… for $15 on Mac or Windows. It does what it says on the tin and it does it easily and quickly.
You first go through the interface to enter all of the tag data, but then you can save that tag data into a file including adding the album artwork. The next time you want to add ID3 tags to a recording, you simply go to File → Load Tag Data and choose the your saved tag data file in the Finder. Since every episode has a new title, you might want to add that fresh each time, but in my case it was a simple TextExpander snippet to add the title.
So what is the problem to be solved? After 559 episodes of Chit Chat Across the Pond, I was really really tired of dragging my mp3 files onto the ID3 Editor icon in my Finder menu bar and then going aaaaalllll the way up to the menu bar and pulling down to Load Tag Data and then selecting the Tag Data file from the Finder like an animal and then using my TextExpander snippet and saving. I know, that whole process takes what, 15 seconds if I round up?
You might be wondering why I’m only talking about Chit Chat Across the Pond and not the NosillaCast. After I bought the desktop version of Auphonic Leveler, I got the request to add chapter markers to the NosillaCast and the only way I could do it was using the web-based version of Auphonic Leveler. The web-based version does a lot more than the desktop version: not only does it compress and level the audio, it also automatically adds the ID3 tags and uploads the resultant file to my server. The only problem is that Auphonic charges by the number of hours processed, and since there are no chapters in Chit Chat, it seemed more cost effective to use the desktop app and do the ID3 tag editing locally.
I know those 15 seconds of adding the tag data into ID3 Editor is only 2.39 hours of my life lost in all the time I’ve been doing Chit Chat Across the Pond, but still, it bugged me.
I begged the developer to at least add a keystroke to the menu to select Load Tag Data File but they haven’t updated it since Sierra that I can tell. I worked a long time on trying to get Keyboard Maestro to do it for me. I had small victories but it was fragile and failed way too often.
And this week, I had had enough. I thought, “Why don’t I just write my own script to add my ID3 tags?” Remember those names I mentioned at the beginning? They inspired me to think crazy thoughts like this, to realize that it’s not that hard, I should be able to figure this out. Bart even more than the others has taught me that if I just keep digging and experimenting and researching, I can eventually figure this out.
Spoiler alert, I figured it out.
My goal was to write an Automator Service where I could right-click on an MP3 file, choose Services, and have it add all of the ID3 tags in one quick go of it. I knew that Automator itself wouldn’t have the tools, but it would allow me to add scripts inside it using the simple Run Shell Script block and then write a BASH script inside it.
Bart taught us about BASH shell scripts in the very first episode of Taming the Terminal. I learned that if you can get a command to work in the Terminal, you can then put that command in a BASH shell script and run it from Automator. So if I could just find some command-line commands and get them to work one at a time, I could pile them together to make my own personalized ID3 editor.
id3v2 Command-Line Editor
I started trolling the Internet for ideas, and I found a command-line editor called id3v2 written by Myers Carpenter: github.com/myers/id3v2. Myers wrote this when the ID3 spec moved from v1 to v2, hence the name. He wrote it in May of 2000, and he hasn’t done any improvements in 10 years. The last “cleanup” update was 4 years ago but it sounded like it was designed to do exactly what I was looking for.
Unfortunately id3v2 was hosted on the now dumpster-fire service SourceForge. One look at it and I remembered Bart explaining that they actually inject things into the code you’re downloading. I wanted that program but I had to find another way to get it.
I decided to check on Homebrew. This is a repository available at the command line in the Terminal. Simply typing
brew install id3v2 would have done the trick, but I’ve become a fan of the GUI interface for Homebrew, playfully entitled Cakebrew from cakebrew.com.
With Cakebrew you can search and view search results in a nice interface, but it’s not that much easier than the command line. It’s power for me is that it has an update section where it shows you the outdated installations you have from Homebrew and a simple button to update all. I would never have thought to go back and update the apps I have installed using Homebrew without seeing that in Cakebrew.
Now I have my tool to edit my ID3 tags. The documentation on id3v2 is pretty weird. If you make the right mistakes, it will reveal the commands. Normally with command-line stuff, you can type man (for manual) plus the name of the tool and it will spit out the manual. That sort of worked with id3v2 but there was a whole ‘nother set of keys that you needed in order to unlock the magic.
The id3.org folks who define this stuff have determined a set of flags you can set in your file, and these flags are what turn into the ID3 tags. I eventually found the magic decoder ring that explained which flag turned into which tag.
Let’s say I want to enter the title tag for the episode. That would seem to be useful. The title flag is –TIT2. The command is pretty simple:
id3v2 --TIT2 MyTitle audio.mp3
I started by issuing commands like this into the Terminal and then opening the resulting file with my old pal ID3 Editor to see if it crammed the right information into the right place.
Automator & Bash
Once I got a command to do my bidding, it was a simple matter to plop the command into my Bash script over in Automator. But of course my shiny new command that worked perfectly well in the Terminal did nothing at all when I tried to use it in Automator.
The first reason things didn’t work was a classic problem. Commands like this id3v2 I’ve installed from Homebrew live in a directory, and you have to tell the Bash script explicitly where that directory is. It’s not too hard to do though. In the command line you can find out where your program is by typing
which and the name of the program. So
which id3v2 tells me it’s in /usr/bin.
I googled the syntax to tell my Bash script how to add that directory and my first speed bump was elegantly leapt over.
The next and, I thought, really fun part was figuring out how to break out the file name to use as the title. As you know, all of my podcast episodes are in the form CCATP_YYYY_MM_DD. The file name has that with the extension .mp3 and I wanted the title to be the same but without the extension and without the giant file path to get to the file.
Again, after some googling as Bart taught me, a new variable in my Bash script was born stripped of everything but the title. Now I could use that new variable name in that flag TIT2 instead of hard coding it.
I got all of the flags working one by one and was quite proud of myself. I wrote a tweet that said,
I’ve spent the last 3.5 hours writing a script that will save me 15 seconds a week.
My favorite response was from Bart:
I’m gonna call it. On 15 August @podfeet officially earned her coder wings 🙂 🎓🏅
That made me SO happy. As Bart would say, I was chuffed.
At this point, everything in my little script was working except I hadn’t yet figured out how to add the album artwork. There was a flag for it accessible with id3v2 but it simply didn’t do anything when I tried to point to it. After quite a bit more of the googles, I discovered what I should have thought of on my own.
Adding the image isn’t an attachment to the mp3 file, it has to actually be embedded inside the audio file itself. Just setting a flag wasn’t going to do the job.
One site suggested using the LAME encoder which is normally used to convert audio into other formats. I gave that a whirl and technically it did work. The command is quite simple:
lame --ti logo.png audio.mp3
The downside is that it took it 43 seconds to do what I do in 15 seconds with ID3 Editor today. The bigger downside is that LAME actually re-encodes the file, so you’d get a double compressed mp3 from me. Definitely not what I wanted to do.
On stackoverflow I found the suggestion to use the ffmpeg library to embed the album artwork. You may never have heard of ffmpeg, but I guarantee you use it all the time. I have yet to find a video encoding/decoding application that doesn’t use ffmpeg. VLC, VidConvert, Handbrake, even WMP all use ffmpeg to encode video.
You might wonder what a video encoder application has to do with putting album artwork into an audio file. Turns out ffmpeg can work on audio files too, it’s pretty much content-agnostic. I want to tell you a little side story to explain why I know anything about ffmpeg in the first place.
Raytheon Podcast Network
When podcasting was first getting off the ground, I thought it might be an effective communication and instruction tool within the company where I worked. I launched a project I called the Raytheon Podcast Network. The calculator nerds amongst you will appreciate that I purposely chose that because the acronym is RPN.
I was a manager of around 170 computer scientists and engineers at the time, so I tapped a few of them to help me. We got audio off the ground fairly quickly but video proved to be harder to do for a lot of reasons (mostly blob sizes in databases for those who care).
Around the time we got into video, I was reassigned from being a manager to becoming an IT Fellow, which is a purely technical job with no one working directly for me at all. Now I only had influence over the guy working on the RPN, but not positional authority. That becomes important to this story.
The higher ups made a decision that every video should have a disclaimer slide up front showing the company branding and a warning not to share these files outside of the company. So picture this: People across a 60,000 person company will be submitting videos that all might be of different aspect ratios and of different formats and we have to figure out how to cram an image file into the front of each video that matches these parameters exactly, all without re-encoding the file.
I asked one of the guys to work on this, and I got my first rude awakening of what not having positional power feels like. He said, “Why don’t YOU do it.”
The correct answer should have been, “Because I’m a mechanical engineer with no programming background, and this is all on Linux at the command line!” But instead, I decided to figure it out myself.
It took me longer than it’s taking for me to tell the story of how I saved 15 seconds on adding ID3 tags to crack but I finally figured it out. And of course, I did it with ffmpeg.
ffmpeg Can’t Write to the Same File
It was a pretty easy task to write the code for ffmpeg to embed the artwork into my file with the aid of the googles. But there was one little problem: adding ID3 tags can be done with a file while it’s open and save back into itself. But ffmpeg is doing much more serious brain surgery when combining two files, so you have to save out of ffmpeg into a new file name. I called that file name out.mp3.
ffmpeg -i audio.mp3 -i logo.png -map 0:0 -map 1:0 -c copy -id3v2_version 3 -metadata:s:v title="Album cover" -metadata:s:v comment="Cover (front)" out.mp3
But I don’t want two files, I only want one file and it should be named the original name, which for this explanation we’ll call audio.mp3. No worries, in linux you can simply enter:
‘mv out.mp3 audio.mp3`
This moves the first file into the name of the second file, overwriting it. I tested this part from the command line and of course it worked perfectly.
When Things Don’t Work Inside Automator
We’re now about 3 days into my work writing a 10-line script and this is when things got way harder. While my command to move the out.mp3 file into the original name worked perfectly in the Terminal, it did nothing at all inside my script inside Automator.
I figured it had something to do with that PATH nonsense, but the
mv command should be available everywhere, right? I thought maybe it was a permissions problem, like maybe Automator doesn’t have my permissions, but that wasn’t it. My script was creating the out.mp3 file just fine and it showed in Terminal as being owned by me.
I chatted briefly with Dorothy about it right before she went on a trip, and she asked me to send her the script so she could look at it, but I didn’t give it to her. I knew full well that she would be able to fix it for me, but I desperately wanted to figure this out on my own.
I fiddled with it on and off for a few days (completely neglecting writing much of anything else for the show). Then I had lunch with a friend of mine from work who recently retired himself. His name is Chris and he’s one of the smarter guys I got to work with over the years, and it turns out he listens to the NosillaCast! I noodled it with him at lunch and then when I got home I pinged him on Messages to ask if he’d like to take a look at the script himself in a screen share.
We poked and prodded my script for about 45 minutes and still couldn’t see the problem. We even took the script and made a text file out of it and ran it from the command line outside of Automator. Dorothy had suggested this idea too but I didn’t remember how to do that without some adult supervision. From the command line, that little move command inside the script still would not move the file.
Sadly we hung up the call. Then I used my favorite Dashboard app (remember Dashboard?) TimeScroller to see if it was daytime for Allister Jenks in New Zealand, and since it was 4pm on Saturday for me, I could see that it was 11am on Sunday for him. I pinged him and he jumped online with me. After trying both Messages and Discord to connect without success, we pulled out the old standby Skype and got to work.
I’d like to say that he instantly saw the problem but it even took Allister a while to spot it.
In the script, my ffmpeg command creates the out.mp3 file, so I assumed that since it created it, the script would know where it put it. I was wrong about that. Allister suggested I try adding the full path to out.mp3 in the command to overwrite the file, and Bob’s my uncle, it worked!
I wrote to Chris about it and of course he kicked himself for not noticing it, but then he wrote, “my props to Allister for resolving the issue!!!” And that made me really happy, because of course Chris “knows” Allister because they’re both NosillaCastaways. It doesn’t matter that Chris lives in Los Angeles and Allister lives in New Zealand, our community knows no bounds.
There’s one last ID3 tag I haven’t cracked the code on and it’s the URL that shows up in ID3 Editor. In the spec for ID3, it simply shows to set the flag WXXX, but if you dig deeply enough you’ll find that the XXX means “three more letters I haven’t revealed to you yet.” I eventually found a list of 7 options. I tried every single one of them and none of them filled in the field showing in ID3 editor. Oddly enough, that one flag is easily perturbed by commands coming after it in the script, like the ffmpeg command, so at Allister’s suggestion I moved all of the flag commands to the end of the script and now it works perfectly.
The key thing in developing an application or even a tiny script is that as soon as you get it done you think of something else you’d like to do with it. It works as a Service just as I designed it, but right clicking to select a Service from a long list is actually kind of tedious to me. I may make it into a standalone application and put it in my Finder window menubar so I can just drag my files right onto it like I used to do with ID3 Editor.
When I was on the MacCast with Adam Christianson, I told him about my script and he said if I get it to work as an app, he’d love to have it too. That means I need to create a version that has some standard variables, like location of the logo and location of the output file that aren’t hard-coded just for me. I know Tom Merritt and Sarah Lane use ID3 Editor, so I bet they’d like this too. If I get all three of them to use it, that’s a lot more 15 secondses that I will have saved with my 7 hours of time, right?
I had a blast working on this and abandoned many of my chores and a lot of writing time and even Tesla suffered as I skipped our afternoon walks a couple of times. But I had such a great time. I learned what I can do and I’m very proud of my little self as a result. If you’d like to see my 33 line masterpiece (Including comments and unnecessary lines), you can download it here.