Categories
Programming Tools

Playlister

In the past couple months, I’ve had an ongoing series on converting iTunes playlists to text files, with a brief digression into scripting with Swift. While I doubt that I’m entirely done with the topic, I have reached a point where I’m ready enough to do another write-up.
This morning, I made playlister available to the public. It is not a consumer-facing application like my others; it is very much a tool for people who are comfortable with the command line.
In between the previous iteration of this tool and the current, I actually had a version of playlister built and shareable (Chase has that version installed on his Mac, actually) but, before releasing it to the public, I looked at the code and thought “I can do better.”1
So I buckled down and spent some time indulging in my love for API design, and tried some tricks I’ve been wanting to try.
The rewritten version ships with a library, LibPlaylister, that provides the basic ideas — protocols that allow for interacting with the library, playlists, and tracks; conversion to Markdown — as well as some neat new tricks. There’s some hooks for customization, such as the RatingFormatter protocol, and included FiveStarRatingFormatter, and the new LinkStore protocol, which provides a layer of abstraction on the SQLite-based caching of links.2
It was also an excuse to add to my Swift toolbox. I worked with SwiftCLI for a while, and then converted to ArgumentParser when that was released. I’ve done file interactions, and a lightweight database. I’ve learned a lot about Swift Package Manager.3 I learned a bit about XCTest, and figured out how to get it working in GitHub Actions. (And, more interestingly, figured out how to conditionally include frameworks in an SPM package. I wanted the tests running on Linux, but Linux… doesn’t have the iTunesLibrary framework, shockingly.)
I had fun building this, and will probably continue to tweak it. (I mean, it could be fun to get it automatically pulling links from the iTunes Search API, and just asking ‘is this the right link?’ instead of requiring manual entry.4)
For now, though, it’s ready enough to share, and made for a fun write-up and a good way to de-stress by tinkering.


  1. Interesting aside from giving that to Chase: Did you know that macOS has a ‘quarantine’ flag it puts on executables sent via AirDrop? That was some fun googling to figure out. The solution: xattr -d com.apple.quarantine ./playlister 
  2. That caching is definitely the biggest productivity gain of this, as compared to the previous version — now, when I go to write up my monthly playlist, the whole first part of the playlist doesn’t require any interaction at all. 
  3. Coming from working with nom’s package.json format at work, SPM Package.swift files are nice. Like, you can have comments in them! And, more, you can have actual code, so you can do neat stuff like this
  4. Although, at that point, I’d probably wind up writing it up as a SwiftUI app so I can show images. Which… might have been part of the inspiration for making LibPlaylister a separate library. 
Categories
Programming Technology Tools

Automated Playlist Backup With Swift

I mentioned in my post about scripting with Swift that I’d been working on something that inspired this. Well, here’s what it was: a rewrite of my automated playlist backup AppleScript in Swift. That version ran every hour… ish. Partly that scheduling issue is because launchd doesn’t actually guarantee scheduling, just ‘roughly every n seconds’, and partly it’s because the AppleScript was slow.1
Then I found the iTunesLibrary API docs, such as it is, and thought “well, that’d be a much nicer way to do it.”
And then I remembered that Swift can be used as a scripting language, cracked my knuckles, and got to work. (I also had some lovely reference: I wrote up my very basic intro post, but this post goes further in depth on some of the concepts I touched on.)

https://gist.github.com/grey280/0126ac93df1d52d91e78f52d97805246

Not the best API I’ve ever written, but not bad for something I threw together in a few hours. And I had fun doing it, more so than I did with the AppleScript one.
Oh, and it’s much faster than the AppleScript equivalent: this runs through my ~100 playlists in under a minute. So now I have it run every 15 minutes.2
(The configuration for launchd is about the same, you just replace the /usr/bin/osascript with the path to the Swift file, and make the second argument the full path to the directory where you want your backups going. See the original post for the details.)
I’m a bit tempted to turn this into a macOS app, just so I can play around with SwiftUI on macOS, and make it a bit easier to use. Of course, by ‘a bit tempted’ I mean ‘I already started tinkering,’ but I doubt I’ll have anything to show for a while — near as I can tell, SwiftUI has no equivalent to NSOutlineView as of yet, which makes properly showing the list a challenge. Still, it’s been fun to play with.


  1. I was going to cite this lovely resource, but since that website was built by someone who doesn’t understand the concept of a URL, I can’t link to the relevant section. Click ‘Configuration,’ then the ‘Content’ thing that’s inexplicably sideways on the left side of the screen, and ‘StartInterval’ under ‘When to Start’. 
  2. I’m also looking at the FSEvents API to see how hard it would be to set it up to run whenever Music (née iTunes) updates a playlist, but that… probably won’t happen anytime soon. 
Categories
Technology Tools

Automatic Playlist Backup

You may have seen my monthly playlist posts on here; I put those together with a Shortcut that grabs the playlist, runs through all the songs, and makes a spirited attempt to fill in all the links off the iTunes Store Search API without hitting their mysterious rate limits.1
It’s not the be-all end-all, though — I’ve been wanting more and more lately to start making more and smaller playlists, things to match different moods. Y’know, the way normal people do playlists.
But, of course, I’m me, and I want to have the history of my music tastes, because, hey, sometimes you feel like reminiscing.
So, what to do? Well, I’ve done some work with the iTunes Library XML file, and while it’s sorta true that just wrapping that in, like, Git or something for version control could work, there are three problems with that:
1. iTunes is a weird, weird piece of software, and I don’t want to mess with its files too much.
2. The result is not at all human-readable.
3. It isn’t an excuse to learn something new.

So, what else can I do? Well, I’ve done a very light bit of tinkering with AppleScript,2 so I know it can interact with iTunes pretty well; there’s gotta be a way to do it there, right?
There is! I’ll share the script in a moment, but the functionality I wanted was “clear out the folder I give you, replicate my playlist hierarchy as directories, and spit out each playlist as a markdown file listing the title, artist, and album for each track, then commit the changes to a git repository.”
It took a while to get working — I’ve learned that AppleScript’s repeat with in loop is hilariously slow, unless you change it to repeat with in (get). I’ve also found out that the way it works with paths is super annoying, and that while it can write to a file, it can’t conceptualize creating a directory. There’s some great workarounds for that.
Now, here’s the script: I’ve left a couple {replace me} type things where you should fill in variables – namely, the path to your home directory (or wherever else you want it), and your own username, to fix some permission issues that can crop up.3

https://gist.github.com/grey280/9b95fdc8c16ec544a214f159bd008bbc

But wait, there’s a caveat: it’ll fail if the folder you gave it isn’t a git repository. Considering that I wanted this as a ‘set it and forget it’ sort of thing, I figured it wouldn’t be worth the effort to write a bunch of conditional code to do the setup. Do it yourself: git init && touch temp.txt && add temp.txt && git commit -m "Initial commit" takes care of all you need.4
Oh, and if you want it to be pushing the changes somewhere, because you’re paranoid and want everything in someone’s cloud, at least, add the remote and set it as the default upstream: git remote add origin {remote URL} && git push --set-upstream origin master

Set It and Forget It

So that’s pretty neat, but it isn’t really “set it and forget it,” now, is it? You’ve gotta open up Script Editor, pull up the script, and run it every time you want it to back up your playlists. Possibly workable for some people, but I don’t have a home server for nothing. Let’s make this truly automated.
From my prior experience with AppleScript, I know that you can set it off through a shell script by way of /usr/bin/osascript, so my first thought was to add a cron job. After a bit of research, though, I found out that Apple would prefer we use launchd instead, so I set about figuring out how to do that.
Now, if this wasn’t all an excuse to learn how to do something, I’d probably have just bought one of the GUI clients for launchd; Lingon looks pretty nice, and seems to work well.5
The process for writing your own launchd process is actually pretty simple: create a .plist file containing some XML, add it to the launchd queue with launchctl, and you’re off to the races!6
(Hint: if you want an easier way to see if your script runs than waiting and checking git log, you can add a line to the start of the AppleScript: display notification "Running playlist export".)
So, creating the XML: you want it to live in ~/Library/LaunchAgents/, and the convention is the usual reverse-TLD. (You can also use local.{your username}.{your script name}, but I’m so used to using net.twoeighty. in bundle identifiers that I just went with that.)
The important parts are the ProgramArguments array and the StartInterval integer. For ProgramArguments, give it the path to osascript,7 and as your second argument, the full path to the .scpt of the AppleScript.
Then, set the StartInterval to the number of seconds between runs; I’m using 3600, because hourly change tracking seems frequent enough for my purposes.
The result:

https://gist.github.com/grey280/f643a159a426ae25eb57139afd4f3cd5

(You can skip the StandardErrorPath and StandardOutPath – they help a little with debugging, more so if you’re running a full shell script and not a wrapper on an AppleScript.)
Finally, add it to the queue:

launctl load ~/Library/LaunchAgents/net.twoeighty.backupPlaylists.plist

And there you go – every hour, your iTunes playlists will get backed up to your Git repo, and you’ll have a nice history of your music tastes over time.


  1. iTunes Search is a really fun API to use, because via Shortcuts you only get a single input to it, and it is really bad at finding anything. Seriously — try to find anything off the top charts. As far as iTunes Search is aware, Billie Eilish doesn’t exist. 
  2. In lieu of Shortcuts having a way to set the volume on a HomePod, I’ve achieved a similar result with “run SSH script: osascript -e tell iTunes ...”. 
  3. Related: don’t put this anywhere with weird macOS access control things. Y’know, places like “Documents”, “Desktop”, anywhere in iCloud Drive or Dropbox, or even “Downloads”, which apparently is a much worse work directory than I thought it was. I eventually configured it to run out of and into my Public directory, because I figured that’d be easier than trying to mess around with the permissions somewhere else. 
  4. Without a file there, the git rm -rf . && git clean -fxd bit at the beginning is unhappy. 
  5. I used the ‘free trial’ version as a viewer for my works in progress; I figured if I’d done something really wrong, it’d complain about it being an invalid file or something. 
  6. He said, glossing over the couple hours of “fight me, macOS, why isn’t this working” 
  7. Probably /usr/bin/osascript, but you can use which osascript in Terminal to check. 
Categories
App Portfolio Technology

Open-sourcing Variations

Now that the whole concert is over, and I’ve finished going through approximately all of the WWDC sessions, I’ve decided that Variations won’t be receiving any further development — it wasn’t going to be enough of a priority for me to do it any justice, and I’d hate to half-ass it.1 The app will remain on the App Store, for now, though if it breaks in future iOS versions, I’ll probably pull it entirely. Instead, I’m releasing the source code, as-is; if you’d like to look through it, it’s right here.
I had fun building it, and I like to think that it does some interesting things with the implementations under the hood, so hopefully somebody can find some use from it.


  1. This is, hopefully, a hint about some of my other projects that are a higher priority; announcements of those will, of course, show up on this here blog. 
Categories
Education

“Cara Mia Addio”

This was a short paper I wrote about the titular song for a class on music technology, which I said at one point I might post. Here it is!
I’ve made two changes: the transitioning of my citations from a “available in my notes but not visible otherwise” to “accessible by all,” and the addition of this note.

I chose to partially ignore the “no YouTube videos” part of this assignment, because I felt that the video was an important part of the song. They were created together, after all, as part of an even larger multimedia project: Portal 2, one of the top-selling games made by one of the world’s most famous video game companies. The compositional arc of the game as a whole is fascinating: Valve’s in-house composer, Mike Morasky, wrote almost the entire soundtrack for the game1 while working closely with their programming teams. Though the soundtrack was eventually rendered down to a still form for the release of Songs to Test By, within the game they’re procedurally-generated MIDI, with pre-set starting points that are then algorithmically developed to match the gameplay in a way that’s almost guaranteed to be unique to the player. (Morasky once stated that one of the pieces only repeats itself every 76,911.3 years, roughly.)
“Cara Mia Addio” was not a procedurally generated song, though the exact method by which it was made did rely on MIDI audio. In the studio, Morasky gave McClain2 the music he’d written for the turrets to sing and a melodic line for her, and asked her to improvise the words. The resulting melody, based on what she referred to as “my terrible Italian” became the Turret Opera. Morasky edited that recording to ensure that it didn’t sound too human – the ‘singer’ within the game being a robotic gun-turret – and then fed the backing sounds into the game engine itself.
That’s what I found most interesting about this – though the scene was rendered as a video file, not running live on the game engine,3 it was built within the same game engine that ran Portal 2, Source. Valve’s in-house animating tool, now released to the public as Source Filmmaker,4 provides deep control of every aspect of the game engine. Morasky (and, presumably, some of Valve’s animators) used sounds that had already been implemented in the game engine to provide all the voices save the melodic line. If I had to guess, I’d say that the system running animation queues was based on MIDI, as that’d be the easiest way to sync the visuals with the triggered sounds.
And a final note on those triggered sounds: all of the ‘turret voice’ effects were based on McClain’s voice, meaning that she sang the full chorus and solo of the song. Quite an impressive range.


  1. A single song, “Want You Gone” was composed by Jonathan Coulton as a call-back to the piece he wrote for the first Portal, “Still Alive”.
    “Exile Vilify” was written and recorded by The National, though based on early materials given to the band by Valve, in order to match the scene in which the song would be played. 
  2. The game has very few voice actors involved – the main character, in a manner characteristic of Valve games, never speaks. Off the top of my head, there are only two other characters with repeat appearances, GLADoS and Wheatley. (A few other minor characters have lines, but nothing more than a couple of words at a time.)
    McClain, by contrast, voices GLADoS, a character who moves from ‘narrator’ to ‘ally’ to ‘antagonist’ and back fluidly, as well as providing the sounds that would be edited into the audio for all of the turrets throughout. 
  3. Citation 
  4. Citation 
Categories
Technology

This Month's Playlist

I use iTunes a lot.1 Like, a lot. I don’t think I’ve ever had it closed on this computer.

Why? you may ask. Well, I like music. Hopefully you’ve figured that out by now, since I listed a music textbook in the ‘what I’m reading’ thing earlier, and I’m sure I’ve mentioned how many music classes I’m taking somewhere.2 It’s what I use to play music on my laptop, and it’s what I3 use to keep my music library organized.

It’s a respectably-sized music library, at that: 2,100+ songs at the moment, and it’ll probably keep going up.4 So, what’s up with the title of this post?

Well, I make a new playlist every month. For a while, I just had one playlist,5 but I got tired of that after a while. 300 songs in one playlist seemed like a bit much, especially when I’d be listening to it on my phone, spot a song that I didn’t want on there… and then forget before I could do anything about it when I got back to my laptop. This way, it’s always fresh; a song I don’t like will be on my playlist for a month at the most,6 and whenever I get some new music I like, the smaller size of the list means that I’ll be able to hear it much more frequently.7

The other really cool benefit of this system, to me at least, is the fact that I can look back and see what I was listening to at any time. I’m a big fan of the whole ‘quantified self’ thing – my phone tracks my steps and distance walked, and I use an app to keep track of what I eat just because I like looking at the charts – and this is, to Grey-the-vague-audiophile a very cool thing.

Anyhow, readers, since I know there’s at least one of you out there – what’s your system for music? Pandora list? Thousands of playlists for every possible mood? Something I haven’t thought of because I only listed three ideas? I’d like to know, so hit up that comment box.


  1. It’s a much less terrible program if you’re using Mac OS X instead of Windows; I’m convinced that Apple was so intense about having it look like it was on OS X that they actually wrote the entire OS X windowserver system into the program and then run iTunes within that. 
  2. If I haven’t, I’m taking 6 music classes at the moment. That in addition to working for the music department at school. 
  3. As someone with not-actually-OCD-stop-calling-it-that, or “I prefer things to be organized, but I don’t compulsively clean them.” 
  4. The nice thing about the remixes that I’m partial to at the moment is that, thanks to copyright law, they’re generally free to download. 
  5. Titled “Main Music List” because I am super creative you guys 
  6. Just because I’ve changed tactics doesn’t mean I’m any less forgetful. 
  7. Handily increasing the efficiency of the whole “repeating a song until I can no longer listen to it because I hate it so much” thing. Y’know, like Owl City’s Fireflies