Installing Linux Mint 21 on a Late 2013 iMac with Fusion Drive

I’ve had my old Late 2013 27″ iMac sitting in its box in our back room ever since I bought my Apple Silicon MacBook Pro at the end of 2021, I did some cleaning and tidying the other weekend and ended having enough space to be able to set the iMac up on the desk with a keyboard and mouse. While it’s not a retina-quality screen, it is a quite nice display, and there have been a few occasions when I’ve been doing something out in the back room and wanted to look something up but it was awkward doing it on my phone.

Once I set the iMac up I turned it on, it still works fine but the latest OS it can run is Mac OS X 10.15 Catalina which is ooold. The latest Firefox still works on it, but the rest of the OS would be a Swiss cheese of security holes so I figured I would do what I do to basically all my old Macs at some point or another and install Linux on it. 😛

I remember trying to install Linux on this machine a few years ago and having zero luck at even booting it, though I mostly just gave up and went and did something else at that point, there wasn’t much troubleshooting actually done! As with my previous adventures installing it on my old MacBook Air, I went with Linux Mint because I’ve found it to be the easiest to use and has wide hardware support.

During my research I found this repository on GitHub which claims to be a guide but doesn’t actually have any guides to follow, just a selection of software versions of various things. Even so, it was quite helpful because it seems that anything that uses kernel version newer than 5.x will have problems on the iMac’s specific hardware, and the latest Linux Mint 22 uses the 6.x line. Linux Mint 21 still uses the 5.x kernel, so I grabbed the latest as of writing 21.3 Cinnamon Edition from their main downloads page and imaged it onto a portable SSD using Raspberry Pi Imager (even though the iMac has an SD card slot, you can’t boot from an SD card sadly).

Step 1: Splitting the Fusion Drive

My model of iMac was one that has Apple’s “Fusion Drive”, which is marketing speak for a smaller SSD combined with a large hard disk that appears as one single drive to the OS, and where the OS puts the system and applications onto the SSD for fast access. The size of the SSD shrunk in later iMac revisions before they went all-SSD, but the one in the Late 2013 iMac is 128GB which is plenty for just installing Linux onto, and I was going to partition it so I could still have a Mac OS X installation.

The first thing is that the Fusion Drive needs to be split up so it appears as its two separate drives in order to partition them, so boot into Recovery Mode by holding down Cmd-R as soon as you press the power button, then go into the Utilities menu and open Terminal.

Run diskutil apfs list and you’ll see an entry that says something like APFS Container Reference: disk3 (Fusion). That disk number (disk3) is the identifier for the Fusion Drive, so run disktuil apfs deletecontainer disk3 to break the Fusion Drive apart, then you can close the Terminal window and open Disk Utility to format or otherwise partition the drives. I split the SSD into a 75GB partition for Linux Mint and the rest for Mac OS X, and partitioned the hard drive exactly in half, half of which will be used to mount my home folder under Linux Mint, and the other half for use by Mac OS X.

Step 2: Install Linux Mint

At this point it’s pretty straightforwards, reboot and hold down Option to select the “EFI Boot” disk that is the Linux Mint live image on the external SSD and follow the installer steps to format the partitions from Step 1 above, I set the 75GB portion of the SSD to be mounted at / and the half of the hard disk as /home.

Once it’s all installed, it’ll prompt you to reboot.

Step 3: Getting wifi working

Fortunately unlike some distributions (looking at you, Debian) Linux Mint actually includes the wifi drivers that the iMac needs, but because they’re proprietary it doesn’t install them by default. You install them by running the Driver Manager, but if you simply open Driver Manager from the application menu it complains that you’re offline and doesn’t give you any options. It points out that you can also use installation media, but for whatever reason even though the portable SSD was still plugged in, it wasn’t actually mounted so Driver Manager couldn’t see it.

Instead of mucking around with mount commands, you can just open a terminal window and type mintdrivers, which will open the Driver Manager but detect that the installation media is there and offer to mount it for you. Once that’s done you can enable both the NVIDIA drivers and the Broadcom wifi drivers and reboot when prompted, and you’ll be up and running!

Miscellanous odds and ends

Linux’s equivalent of macOS’s Night Shift

I had been using F.lux for many many years to tint my screen orange at night to make it easier on the eyes after dark, and switched to the macOS/iOS native “Night Shift” when that was added a number of years back. F.lux exists for Linux but it hasn’t been updated since 2013 and doesn’t work anymore. Linux Mint 22 has a new thing called Night Light that’s the exact same thing as Night Shift and gives you a nice UI to control everything from, but unfortunately it doesn’t come with Mint 21. There is an older application called Redshift but the automatic sunset/sunrise detection relies on another executable geoclue2 that isn’t being updated either and the Redshift applet installed with Mint doesn’t give you any configuration options. Fortunately you can configure Redshift manually, so create a file ~/.config/redshift.conf and drop the following contents into it:

[redshift]
temp-day=6500
temp-night=3700
gamma=0.8
fade=1
adjustment-method=randr
location-provider=manual

[manual]
lat=-33.8
lon=151.2

You may need to adjust the temp-* values to taste, lower is warmer, and the [manual] section at the bottom contains the latitude and longitude for your current location. fade=1 will mean the colour will change gradually when sunset happens, if it’s set to 0 it’s an immediately switch from day to night mode.

Once that’s created, find Redshift in the application menu and open it and if it’s night time, you’ll see the nice orange-tinted colour!

Changing keyboard shortcuts to match the Mac’s with Toshy

One of my biggest dislikes when using Linux (or Windows for that matter) is that the primary shortcut key is Control. Apart from the muscle memory of my entire life worth of using Macs, using Control as the primary key for shortcuts is ergonomically extremely awkward. Plus you end up with the really stupid situation of copy being Ctrl-C except for if you’re in a terminal session and it’s Ctrl-Shift-C because Ctrl-C interferes with the standard UNIX shortcut for terminating the currently-running process.

A little while back I discovered Toshy, which is a whole package that modifies all the standard Linux keyboard shortcuts to be remapped to use Command instead of Control as the primary shortcut, so it feels exactly like you’re on a Mac and aren’t constantly breaking muscle memory. It works extremely well to the point where as I type this on my Asahi Linux-equipped M1 MacBook Pro, I’m frequently forgetting that I’m even using Linux at all because all my shortcuts are just working completely seamlessly!

Migrating from iTunes to Navidrome

I posted of my woes with reliably syncing music onto my iPhone back in October last year, and after I had written that post I discovered an additional irritation in that a bunch of random albums just… didn’t have their album artwork showing when viewed on my iPhone. The art was there in iTunes, it was there embedded in the damn music file, but the iPhone just stubbornly refused to show it even after another full remove-all-the-music-and-resync (which took well over twelve hours — ?!? — because apparently iTunes won’t transcode and then sync more than one single file at once and it does them in serial). I even nuked the iTunes artwork cache and rebuilt it then resynced, to no avail. At this point I decided I wanted to seriously start looking at alternatives.

I had already been dabbling a little bit with Navidrome, although it seemed like it was a lot more focused on streaming rather than what I wanted to do (have all my music synced to my iPhone so I didn’t need to rely on a decent internet connection when listening to music during my commute). Navidrome uses the OpenSubsonic API and so any client that uses that protocol can talk to it, and it turns out that the API has a download endpoint and you can have it set up whereby that download will be transcoded to a smaller format first, which is great because an increasingly-large portion of my music library is lossless and so it won’t actually fit on my phone anymore. At this point I figured I’d go ahead and see about migrating for real.

Initial music import

Navidrome is quite simple, you point it at a directory of music and it’ll read all the metadata for album/artist/etc. and give you a nice shiny UI to listen to it with. It has no ability to make any changes to the music files and is strictly read-only, so I started out by simply pointing it to the existing music directory on my laptop and seeing what happened.

The first obvious thing to check was to compare the number of songs that iTunes reported and the number that Navidrome had picked up, and these did not actually match! I poked around and discovered two reasons for this. First and most obvious, there were a couple of albums that I somehow had sitting my music directory that hadn’t been added to iTunes, but of course Navidrome happily picked up. 🤦🏻‍♀️

Secondly, there were a number of random files that had a .m4p extension, which is the extension that iTunes used for the old DRM-protected music files that you used to buy from the iTunes Store before Apple did away with DRMing them. Navidrome saw this extension and was like “Nope, not even going to try to read this!”

I definitely did not have any DRM music left, I’d redownloaded all my DRMed stuff and replaced it with better quality non-DRM files pretty much as soon as Apple allowed that, but for some reason some (but not all!) of the files’ extensions had remained as .m4p. A quick rename to .m4a and Navidrome happily picked those files up, and at this point the song counts between iTunes and Navidrome matched.

Importing play counts and ratings from iTunes

Similar to iTunes, Navidrome keeps track of play counts across individual songs and supports ratings and favouriting items, but Navidrome also aggregates up to the album and artist level so you can see how many plays of a given album or overall artist you’ve had. My next order of business was figuring out how to get my play counts and ratings imported from iTunes into Navidrome, because I’ve been using iTunes for my music ever since I got my original iPod way back in 2001 and I didn’t want to lose all that history.

Given Navidrome is open source I figured someone had to have written something so I went digging, and found a Python script from three years ago that someone had written to take the XML export of an iTunes library, read it, and write that data into the SQLite file that Navidrome uses. It didn’t actually work because Navidrome’s database structure had changed between the version of Navidrome that the script had been written to run against and what was current, but it was a good excuse to do some Python hacking. Over the course of quite a few weeks’ worth of evenings I got it working and made a number of improvements, plus tidied up the code and added a lot of clarifying comments to explain what was going on, and have published the code over on Codeberg.

The main issue I ran into when I ran it against my full music library was XML encoding problems with file names, I described this in the README and how to work around them, but otherwise it was quite seamless once I’d worked out all the kinks in the script itself.

Sound Check and ReplayGain

iTunes has long had an option called “Sound Check” that you can enable that analyses the actual loudness of every song and then adds a tag into that song file to tell iTunes how much to adjust the playback volume by so your whole library plays back at the same relative loudness. This is extra good when you tend to listen to your whole library on shuffle like I do where albums from different eras were mastered at different volumes: Sound Check saves you from having your ears blasted out when a song that’s much louder than another comes on and you have to scramble to adjust the volume down (and then back up when a quiet song comes on, and so on).

There’s a thing called ReplayGain that does the same thing as Sound Check but better and more accurately, and I have long been using a piece of software called iVolume that analyses your music using ReplayGain then overwrites iTunes’ own Sound Check tag with the ReplayGain value. That tag is an iTunes-specific thing and not any sort of standard that any other player uses (because of course), so I needed to run my whole music library through something that would update the files with the actual ReplayGain tag that players will read.

It turns out there are quite a few options to choose from, I ended up using the rsgain command line utility installed via Homebrew and letting it loose it in easy mode against my entire music directory. And as I subsequently discovered later on, MusicBrainz Picard has a plugin system and one of those plugins is called “ReplayGain 2.0” which will use your rsgain installation and allows you to generate the ReplayGain tags as part of updating the rest of the metadata.

Mobile client apps

On desktop I can just use Navidrome’s UI, but I needed a mobile client for when I’m commuting or just otherwise out of the house and listening to music. The first batch I found were quite janky open-source-feeling ones, but then I discovered first Nautiline which actually feels like a properly native iOS app, and then subsequently Arpeggi. Both are highly recommended if you’re on iPhone or iPad.

Transcoding

Because my music library has quite a few lossless files in it, I can’t just actually fit my whole library onto my phone anymore without transcoding to a smaller lossy format.

(Before anything else, since it’s the machine that Navidrome is running on that’s responsible for the transcoding, you need to have ffmpeg installed, brew install ffmpeg will do the trick if you’re using Homebrew.)

Navidrome has a number of options for controlling transcoding, but it’s very confusing because the client app you’re using also can set options, and it’s been rather difficult to figure out the exact incantation of options configured everywhere to do what I want, namely always transcode to Opus at around 160Kbps and download in that same format.

For Navidrome itself, the only configuration setting I’ve tweaked has been to set the AutoTranscodeDownload option to true. The client side is more confusing though, because there are separate options for downloading, plus transcoding based on whether you’re on a mobile connection or wifi and a lot of the transcoding decision seems to come down to the client app’s request.

In Arpeggi, I’ve gotten it working how I want by going into the Playback settings and setting the “Cache Type” to “Download”, and the “Cellular” and “WiFi” options under “Transcoding” to both be Opus at 160Kbps, with the “Only transcode lossless files” option off.

For Nautiline, the magic configuration seems to be going into Settings > Transcoding, setting the Format to “Opus”, the “Connection Quality” for both Cellular and Wi-Fi to “Low”, then configuring both High Quality and Low Quality to 160Kbps and “Transcode Lossless” under “High Quality” to be “Always”. Then under Settings > Downloads & Cache, “Transcode Lossless” should be on.

Running Navidrome as a service

Up until this point I had been running Navidrome just on my local laptop by manually running the navidrome executable in a terminal window, but to actually move this into “production” as it were, Navidrome would need to be running a service at all times on our home server Mac mini, and all the music files would need to be transferred to it as well.

I copied across all of the music via rsync, plus the Navidrome SQLite database file containing my imported iTunes data, fired up Navidrome on the Mini and added it as a server in my iOS client app, but when I tried to play music… nothing happened. After a bunch of confusion, I figured out what was going on: VNCing into the Mac mini revealed that it was sitting at the “Do you want to allow navidrome access to removable disks?” prompt, because all of the music was on the external hard disk attached to the Mac mini, and until I clicked yes Navidrome couldn’t actually read the files. 🤦🏻‍♀️ I also discovered that this gets reset on every Navidrome upgrade, so each time Navidrome is upgraded it’ll require another trip into VNC to allow it to access the external drive.

With that out of the way, it was time to keep Navidrome itself up and running, and launched at boot. The Navidrome installation instructions for macOS helpfully include an example LaunchAgent plist file you can use, but when running it like this I found that the location that Homebrew installed ffmpeg into wasn’t actually in the $PATH that Navidrome uses so it wasn’t able to transcode anything. Navidrome has a specific FFmpegPath configuration option that can be set in the configuration file, so I just pointed that at the ffmpeg executable (/opt/homebrew/bin/ffmpeg in my case).

I also discovered that the trusty old launchctl load and launchctl unload commands to start and stop a LaunchAgent are actually considered “legacy” and there’s a new and significantly more confusing way of doing it. This blog post has a good overview, but the tl;dr is:

  • Use launchctl bootstrap gui/$(id -u) <PATH_TO_PLIST> to start a LaunchAgent
  • Use launchctl bootout gui/$(id -u) <PATH_TO_PLIST> to stop it

To save myself having to remember this ridiculous incantation, I wrote a quick shell script called navidromectl and call it with navidromectl start or navidromectl stop:

#!/usr/bin/env bash

if [[ $# -eq 0 ]] ; then
    echo "Usage: navidromectl [start|stop]"
    exit 1
fi

ACTION=$1

case $ACTION in
    "start")
        launchctl bootstrap gui/$(id -u) ~/Library/LaunchAgents/navidrome.plist
        ;;
    "stop")
        launchctl bootout gui/$(id -u) ~/Library/LaunchAgents/navidrome.plist
        ;;
esac

Automatically organising newly-imported music

iTunes has a pair of options, “Copy files to Media folder when adding to library” and “Keep Media folder organised” that when enabled mean that files added to iTunes will be copied to wherever your music is stored and automatically sorted into an $ARTIST/$ALBUM folder structure, with the files themselves named as $TRACK_NUMBER $TITLE. I wanted some way of replicating this once I was fully on Navidrome, but since Navidrome is read-only and does no organisation of anything on its own, I would need some other solution.

I went digging and discovered this frankly ridiculous Python package called Beets. It does basically everything and the kitchen sink, and has a whole system to write your own plugins as well in case it doesn’t do what you need it to. As well as doing the automatic organisation and file naming I was after, it can also fetch file metadata from MusicBrainz (the same as what I’m doing with MusicBrainz Picard), calculate ReplayGain values, and write it all to the files before it organises them.

I didn’t actually need the vast majority of what it does, but it does do the things I need it to well (i.e. point it at an “Import” directory and have it automatically move and rename things), and after a bunch of fiddling with configuration options, I’ve settled on this beets.yaml configuration file:

# The directory where the music library lives
directory: /Volumes/Multifarious/Music/virtualwolf
library: ~/Library/Application Support/beets/library.db

# This is required for the disc_and_track template below
# to work
plugins:
  - inline

item_fields:
  # Include the disc number at the beginning of the
  # filename ONLY if there is more than one disc
  disc_and_track: f"{disc:01d}-{track:02d}" if disctotal > 1 else f"{track:02d}"

# Set the desired file and folder organisation
paths:
  default: $albumartist/$album%aunique{}/$disc_and_track $title
  comp: Compilations/$album%aunique{}/$disc_and_track $title

import:
  log: ~/Library/Application Support/beets/beets.log
  quiet: true

  # This is important to allow the "Import anything
  # dropped into this directory" workflow 
  incremental: true

  # Don't write any tags to files
  autotag: false

  # Move the files from the import directory
  move: true
  
  # Don't write tag changes to files since I'm handling
  # that with MusicBrainz Picard earlier
  write: false

The last missing magic ingredient here was the ability to automatically have Beets run when I drop music into the Import directory (with the setup above, I’d need to SSH into the Mac mini, activate the Python virtualenv that the beet package is installed in, and then run the import command).

As it turns out, there is a built-in solution in macOS to automatically run a script or perform an action when something is added to a folder: Folder Actions. Firstly the action itself needs to be created, and then it gets attached to a folder.

To create the action, open the Automator application, go File menu > New, and choose “Folder Action”. In the right-hand pane at the top where it says “Folder Action receives files and folders added to” click on “Choose folder” and select the folder that’s going to be using to drop the music into to be auto-imported, then find the “Run Shell Script” action in the left-hand pane and double-click on it to add that action. Set the “Shell” dropdown to /bin/bash, set the “Pass input” dropdown to “as arguments”, and add the beet import command into there. Mine looks like this because I’m also using a virtualenv to install Beets into, and that directory argument to beet import on the second line is the same directory as the “Folder Action receives files and folders added to” dropdown:

. /Users/virtualwolf/Library/Application\ Support/beets/.venv/bin/activate
beet import "/Volumes/Multifarious/Music/Import/"

Save the workflow as “Import Music” or whatever, then in the Finder go to that directory you’ll be using for imports, right-click on it, and go to Services > Folder Actions Set-Up…”, then click “Run Service” at the prompt. It shows a list of actions, one of which will be the shiny new Import Music option. Select that, and job done! Once a directory full of music is dropped into that Import directory, Beets will trigger and automatically grab the files, read their metadata, and move them into the correct locations in your music directory.

One thing to note here is that Beets keeps a log of which directories it’s already imported, in the state.pickle file in its config directory. I was tripped up by this when I was trying to test that everything was working because I was repeatedly using the same directory to test the importing, and once it had been imported by Beets one time, that was it, it would be ignored from then on and I couldn’t figure out out what on earth was going on. So if you’re doing testing, make sure you use unique directory names before you drop them into the import directory that Beets is looking at!

UPDATE: One thing I realised with this is that it falls over if you’re copying files into the Import directory rather than just moving them from another location on the same drive. If you copy them, they don’t all arrive in the Import directory all at once and so as soon as the first file or two have successfully copied over, the folder action triggers, Beets dutifully runs and imports the files that are there, and then ignores the rest when they’re finished. So this is a bit of a two-step process now, I copy onto the drive that all my music lives on, and then move it into the Import directory in one hit so Beets can do its thing.

Smart playlists and one-click downloading

I suspect I’m probably an outlier amongst music-listeners, but I don’t tend to use regular playlists at all. In iTunes I have a handful of smart playlists set up, and by far my most heavily-used one is my “Random” playlist which is every song that I haven’t listened to in the last two years. If I’m not listening to a specific album, typically I’ll just chuck that playlist on shuffle.

Navidrome has the concept of smart playlists as well, though they’re currently in beta and are not currently exposed through the UI, but you can manually create files with the correct syntax, drop them somewhere in the music directory, and they’ll show up.

To recreate my Random playlist, I used this:

{
  "all": [
    { "notInTheLast": { "lastplayed": 730 } }
  ],
  "sort": "lastplayed",
  "comment": "All songs that have not been played in the last two years."
}

The other thing I wanted was an easy way to just download (and thus transcode) everything from Navidrome into my mobile client app. There isn’t any direct way to do that in either Nautiline or Arpeggi, but creating a smart playlist that lists every single song did the trick:

{
  "all": [{ "gt": { "playCount": -1 } }],
  "sort": "album",
  "comment": "Every single song, to one-click download for offline listening."
}

Opening that playlist then downloading the contents worked a treat, and as a bonus Arpeggi has an “Auto-download” option for playlists, so as soon as new music is imported into Navidrome, Arpeggi picks that up and downloads those new songs!

Making Navidrome accessible from outside the local network

The very last piece that I needed to set up was making it possible to access Navidrome outside of our local network. I didn’t want to expose it directly to the internet via port forwarding, but I also couldn’t set up Wireguard so my devices could VPN in because I wanted to be able to access Navidrome via my work machine so I can listen to music on my fancy speakers while working, and my workplace uses Cloudflare WARP which is Wireguard under the covers (and I suspect the security team would very much frown on me running a VPN to somewhere random).

A while back I had set up a Cloudflare Tunnel to my internal Grafana and InfluxDB instances, which meant I had a publicly-accessible domain that I could get to on my work laptop, but actually loading it required a login through Cloudflare (specifically a 2FA code via email). It was straightforward enough to set that up for Navidrome too, but the wrinkle was that the mobile client apps didn’t know anything about Cloudflare and so if that externally-available address was added to them they’d be redirected to Cloudflare instead of getting the expected OpenSubsonic API response back.

Fortunately this sort of problem had been anticipated on both the Cloudflare and Navidrome client end of things! Cloudflare lets you create a service token to be sent in a header with each request, and in both Nautiline and Arpeggi you can add a custom header to be sent on every request when you add a server address.

Getting the service token created on the Cloudflare side was a bit fiddly, their documentation is here and you need to follow the “Authenticate with a single header” to make a couple of manual curl calls against their API to update the application configuration to allow the single-header configuration.

That’s only a one-time setup though, and once that was done I was able to add the externally-accessible domain to the Navidrome client apps and configure it to include that authentication header, and now I’m able to be completely disconnected from our local network and still access Navidrome!

Custom backgrounds for the login screen

One fun thing that Navidrome allows is custom backgrounds on the login page. By default it uses various music-related images from this Unsplash collection, but you can specify a configuration option UILoginBackgroundUrl to choose your own image. There isn’t a built-in way to do the same “Select a random image from a selection of them” that Navidrome does by default, so I wrote a PHP script that I dropped onto my VPS alongside a group of images to choose from that loads the filenames of those images, then redirects to a random one:

<?php

    $files = glob('*.jpg');
    $file = array_rand($files);

    header('Location: ' . "https://virtualwolf.org/files/navidrome/$files[$file]")
?>

By setting the UILoginBackgroundUrl option to this script, I get a different random image of my own from the ones I uploaded!

Dealing with log files

Navidrome logs a fair bit of stuff as it’s working, and under Linux you’d typically use logrotate to automatically compress log files and eventually delete the oldest ones so you don’t end up with all of your disk space being eaten up by logs. BSD and thus macOS has its own log rotation tool called newsyslog but unfortunately the version that’s installed with macOS doesn’t support the R configuration flag to specify a path to a shell command to run instead of using a file that contains the process ID of the process to reload, and as a result Navidrome never gets reloaded and will just keep writing to the rotated file and not the new one.

Rather than screwing around installing logrotate, I decided to take the lazy way out and added a cronjob to just empty out the Navidrome log once a week, at midnight on Monday:

0 0 * * MON cat /dev/null > /Users/virtualwolf/Library/Application\ Support/navidrome/navidrome.log

Phew!

When I started this post I wasn’t expecting to write over three and a half thousand words on it, and yet here we are! I’m very excited to see how this all goes over the next while, and I’m already really enjoying that Navidrome (and as a result both Nautiline and Apeggi too) are a lot more focused on individual albums and displaying their wonderful artwork, it’s nice to just browse through and see what strikes my fancy.

Lacuna Coil at Liberty Hall, Moore Park

Along with Opeth, Lacuna Coil are another of my absolute favourite bands and I was extremely excited last year when I saw that they were touring here again, since they haven’t been out since 2016 when I last saw them. Prior to that I saw them (twice) in 2007, then 2008, and 2009, and I believe that’s been the entirety of their Australian presence.

They played at Liberty Hall which is at Moore Park, which used to be an absolutely shit location to get to but with the advent of the light rail it’s an absolute breeze now! It’s all of two stops from Central and the trams run super-frequently.

I’ve been to the Hordern Pavilion at Moore Park a couple of times for other shows but haven’t been to Liberty Hall before, and it was a fair bit smaller than I was expecting. It was a fine location though, and I was significantly closer to the stage than I was at Opeth. 😛

This was also one of the very few concerts I’ve been to that hasn’t been just me seeing the band by myself, I met up with @damonism who made the trip up from Canberra for it!

The opening band was Future Static who are from Melbourne, and they have two women, one on lead vocals and the other on bass plus backing vocals, and I’m always endlessly impressed by anyone who can sing and play bass at the same time! They were quite good, and unlike Opeth’s opening band Caligula’s Horse, they actually have their songs for sale on Bandcamp instead of their page being an empty placeholder. 😛

Lacuna Coil came on bang on 9pm and played for not quite an hour and a half. I was delighted that they played two of my absolute favourite songs of theirs (Kill The Light from their Dark Adrenaline album and Spellbound from Shallow Life), and man can Cristina Scabbia still belt it out. She hits these notes in some of their songs that are just so crystal clear and pure that the hairs on the back of your neck stand up! I also had completely missed that they had a new album release last year oops, so a few of the songs weren’t familiar to me.

As with at Opeth, and Heilung before that, I took a bunch of photos in RAW format on my phone and processed them this morning, very happy with how they’ve turned out. These are my favourite ones, the full set is on Flickr.

And just for giggles, compare these to my absolutely garbage photos of when I saw them in 2007. 😅 Obviously technology has come a long way since then but man, I didn’t even straighten them or ditch the utterly blurry photos.

Opeth at the Sydney Opera House

Opeth are one of my all-time favourite bands, I first saw them back in 2003 and have seen them… uh… probably six? times since then, though not since 2013 when we moved to our house and it became more of a pain getting home late at night. With the advent of the Metro now it’s significantly easier, at least as long as you’re going in the general area of somewhere that’s serviced by the Metro, and so I leapt on the tickets when they went on sale for Opeth’s show at the Sydney Opera House. It’s a slightly odd venue for a metal show because it’s all seating, though the seats do that flipping-up thing you get in movie theatres (I appreciated the seating because I’m an old 😛), but the sound and the lighting were excellent.

I arrived pretty much bang-on 8pm when the opening band was starting, and missed the first half of their set because I was waiting in the merch line to get a tour shirt, but the last couple of songs that I was in the concert hall for were really good. The band is called Caligula’s Horse though irritatingly they have a Bandcamp page with absolutely nothing on it. They’ve got a kind of epic prog metal thing going on, so definitely check them out if that’s up your alley.

Opeth came on right on schedule at about 9:10pm which was a nice change from things running late. I’ve seen a few bands that were just boring as hell on stage, where the vocalist doesn’t interact with the crowd (looking at you, Megadeth), but the frontman from Opeth is thankfully very much not in that vein, and I’d forgotten how hilarious he is, he’s got a very dry sense of humour. Some choice quotes follow:

Encouraging the crowd to sing along to To Rid The Disease (one of the songs off their Damnation album, the whole album doesn’t have any growling):

Feel free to sing along!

…the lyrics are a bit shit, it’s because we’re Swedish. Just correct the grammar and sing along!

On the fact that the track names on their latest album (with the exception of the last track) are named “§1”, “§2”, “§3”, etc:

We had the record labels come to us to ask how people are meant to find the tracks on Spotify given when they’re named like that.

I don’t care! We’re not naming our tracks based on how easy they are to find on fucking Spotify!

On the fact that the crowd was sitting:

I’m an awful concert-goer, I’ll always sit down. For us playing here, it’s better if you stand.

But if it was me, I’d sit.

Towards the end of the show when he was doing the giving a shoutout for each band member:

And we have a youngster on drums, Waltteri Väyrynen! He’s 30. 31? He was born the same year we put out our first record.

It hurts.

The setlist was interesting, there weren’t any songs off their most proggy mid-era albums. The Devil’s Orchard from their Heritage album is probably the closest, that album was definitely where they really started veering into prog, but I think it’s also probably the heaviest song from the album.

  1. §1 (The Last Will and Testament, 2024)
  2. Master’s Apprentices (Deliverance, 2002)
  3. The Leper Affinity (Blackwater Park, 2001)
  4. §7 (The Last Will and Testament, 2024)
  5. The Devil’s Orchard (Heritage, 2011)
  6. To Rid the Disease (Damnation, 2003)
  7. The Grand Conjuration (Ghost Reveries, 2005)
  8. §3 (The Last Will and Testament, 2024)
  9. Demon of the Fall (My Arms, Your Hearse, 1998)
  10. Ghost of Perdition (Ghost Reveries, 2005)
  11. Deliverance (Deliverance, 2002)

The last track there was the encore, and I’ve definitely seen them play that on multiple prior occasions as the encore final track, and man is it an excellent song to finish on!

As with Heilung in 2023, I was able to get some pretty decent photos (though a straight-up metal band is less of a theatrical spectacle compared to Heilung!) and with the improvements in my iPhone 16 Pro I didn’t even need to run them through any denoising. These are my favourite shots, the full set is on Flickr.

Farewell TypeScript, bye Sass

Around this time-ish in 2019, I wrote a post about having migrated my website from Javascript and Sails.js to TypeScript and Express.js. Now six years later, I’ve just spent a bit over two months doing another rewrite, but from TypeScript back to Javascript, and along the way I ditched the CSS preprocessor Sass that I’d been using since 2013 with the previous Perl-based incarnation of my website!

Why ditch TypeScript?

I’d been getting a little irritated with TypeScript for a while now, mostly around dependency upgrade time and problems with the TypeScript compiler tsc complaining about types not matching when the definitions hadn’t been updated to match the library. It also meant a bunch more dev dependencies in my package.json and just generally more places for things to go wrong. I can definitely see the value in TypeScript for larger codebases, but when it comes down to it, my website is just a little hobby project worked on by one person (even if it does have comprehensive test coverage and a deployment pipeline in Bitbucket Pipelines) and I decided it’d be nice to simplify things as much as possible, especially since a lot of the modern tech stack is decreed by huge tech companies that have far more complex requirements than I do.

The process

Most of the conversion process was just renaming files from .ts to .js, updating the import statements to include the .js in the filename, and removing all the type information. And having my existing test suite made it far easier to make sure I hadn’t accidentally ballsed anything up! It look a while to get through everything but it wasn’t particularly arduous, just time-consuming.

As part of the simplification process, I also tackled the page rendering process as well. Back in August of last year I moved from EJS templates to Mustache — which was an absolute delight, the templates are so much easier to read now — and I wanted to see what else I could do.

I’d been using the library Pikaday as the date picker for the Memories pages on my website and hadn’t upgraded it in ages, so I figured that would be a good first start. I found that the maintainer had marked the library as read-only and recommended that people use the native HTML date picker which I didn’t even know existed! A few changes later to handle dates being set via query parameter, and I could completely ditch Pikaday. I also discovered that the charting library I’m using on the Weather pages, D3, has its own built-in date/time parsing, and as a result I was able to entirely ditch Moment.js on the frontend. Now the only frontend Javascript is the aforementioned D3, along with Fancybox on the Media, Photos, and Memories pages to give a nice full-screen lightbox when clicking on images (and if Javascript is entirely disabled, it’ll just link to the original image file instead).

The only extra complexity I added with all of this was moving from Linkify (for simple conversion of URLs to add an <a> tag so they can clicked on) to the Marked library to do full Markdown rendering of my Media posts. All my posts are sent to my GoToSocial instance which supports Markdown, but it was getting increasingly ugly having the raw Markdown showing on my website.

Ditching Sass

As I mentioned in the intro paragraph, I’d been using Sass since 2013 when I first started mucking around with theming on my website because it made it quite simple to have a base file with most of the styling in it, and just include overrides for the different themes.

I knew CSS had gotten a fair few new features over the years, but I hadn’t realised just how many, and with the help of this guide I was able to migrate to CSS variables and remove the need for Sass at all. I also discovered the color-mix() function which I used to make automatic colour theme matching for blockquotes and the background of <pre> blocks!

Moving from VS Code to WebStorm

During this whole rewrite period I’ve also been making another parallel switch, from Microsoft’s VS Code IDE to JetBrains’ WebStorm as part of my ongoing project to migrate away from the huge US tech companies as much as possible (and Microsoft’s jamming of AI into everything it can get its hands on in particular, hence my migration from GitHub to Codeberg a few months ago).

The developers at work use JetBrains’ products a lot and we’ve got a site license for it, and I was quite delighted to discover that WebStorm is actually free for non-commercial use. I’ve had to import a keyboard mapping so it’d match VS Code so I didn’t get frustrated because none of my muscle memory worked for the keyboard shortcuts (I should probably just suck it up and put up a cheatsheet of the default keys and make myself learn it), but WebStorm has been really nice to use. It was far easier than VS Code to set up the run/debug configurations, and it’s got really neat stuff like database integration such that it can look at my opaque SQL query strings in the codebase (literally strings in the editor surrounded by backticks) and actually analyse them and let me know if I’ve made an error or if a table or column doesn’t exist!

Onwards!

I have a few items in my backlog that came out of all of this, mostly some other areas that could do with a tidy-up, but it’s been far nicer to work on the codebase now and should be less fiddly to keep things updated.

Excluding package-lock.json because it’s absurdly large, there was a fair bit of change:

$ git diff --stat 9.15.4 10.0.0 -- . ':(exclude)package-lock.json'
 [...]
 175 files changed, 3990 insertions(+), 4482 deletions(-)

(9.15.4 being the version of my website I was on prior to all of this, and 10.0.0 being the initial release with all of these changes included.)

Fixing iPhone music sync issues: “The file was not found” or “The file could not be converted”

(If you don’t care about the background and just want to see the fix, click here.)

I’m one of that dying breed of people who doesn’t use streaming services to listen to music and instead prefers to actually own it, with digital files that live on my computer and whose availability isn’t at the whim of some record label or artist who might suddenly decide to take it down. And when I’m commuting to work, I also don’t want to have to depend on the vagaries of my phone signal to listen to music were I to set up some sort of streaming-from-home thing. As a result, I manually plug my iPhone in to my laptop and sync my entire music library to it, so I have a full copy of everything that doesn’t require an internet connection at all.

Back when Apple first started using AAC as its audio format of choice for the iTunes Store, I ripped all my CDs at 160Kbps to save space and improve audio quality over the MP3s I’d previous been using, but it turns out on good headphones (or good speakers) 160Kbps is actually not all that good quality, particularly around the highs. Around 2018 or so I decided to re-rip all of my CDs again this time in Apple Lossless format so they would be a fully archival-quality copy and if anything came along that improved on AAC I could just encode a copy of the original lossless in that new format.

In 2017 I had started buying music primarily from Bandcamp, and a couple of years after that I realised that they offered downloads in Apple Lossless format too, so I redownloaded everything as lossless and the size of my iTunes library quickly ballooned, to the point where I needed to enable the “Convert higher bit rate songs” option for syncing the music to my iPhone or it wasn’t all going to fit, even on a 256GB iPhone.

With all of those points above, I’d been doing all sorts of screwing around with the underlying music files to ensure that I could keep all of the Music.app playcounts and date added metadata and such but with the underlying file being the new lossless version. I don’t know if there’s a better way of doing it, but my process for the Bandcamp-sourced files involved quitting Music entirely, completely deleting the original crummy format files (as in moving them to the Trash then emptying it) and dropping the new lossless version in its place, then opening Music.app and doing a Get Info on the first song in the album. It pops up with a “The file could not be found, do you want to locate it?” message, then I’d navigate to the new lossless version and select that as the file for that song. Rinse and repeat for each song in the album.

And just to add some more screwing around to the mix, recently I’ve been checking out the self-hosted music server software Navidrome and getting my tagging in order with MusicBrainz Picard, since the MusicBrainz database is primarily what Navidrome uses to identify songs, which in turn involved getting Music.app to refresh its metadata from the underlying files.

Yesterday I decided to make a clean start with the music syncing to my iPhone and turned it off entirely so all the music would be deleted, then turned it back on again and kicked off a brand new sync. I’ve been syncing music like this since the days of the original iPod when there was no other option to get music onto your iDevice, but with the rise of Apple Music it appears that Apple has been paying very little attention to making sure the sync process works flawlessly and my sync wasn’t problem-free, out of a library of 8586 songs I ended up with 21 songs that failed to sync with a “<SONG> could not be copied to the iPhone because the file could not be converted” error, and another 44 that failed with “<SONG> could not be copied to the iPhone because the file could not be found”.

Fixing the failures

The files were all there in Music.app and could all be played perfectly fine on my computer, so it was clearly something weird going on with the sync process. I went through and checked the “File could not be converted” songs first, and it turned out to be about half the songs off just three of the albums I had ripped from CD as Apple Lossless, and one single song I had ripped from another CD. Looking at the underlying song files in the Finder, I noticed a strange detail: all of the ones that failed ended in ” 1.m4a”, so the song “Tear Down The Walls” was 01 Tear Down The Walls 1.m4a instead of what I’d have expected which was 01 Tear Down The Walls.m4a (the 01 coming from it being the first track on the album). I have Music.app set to automatically manage and name the underlying files based on the ID3 tags, so I did a Get Info on the whole album and added an exclamation mark to the end of the album name, which then triggered iTunes to update the folder and filenames to match the ID3 tags and removed the ” 1″ at the end of the filenames. I then did another Get Info and removed the exclamation mark, repeated the process for the other problem albums and then resynced, and all of them synced successfully.

Even more strangely, this also fixed all of the entirely separate set of songs that had failed with “File could not be found” errors! I got a new set of songs with that same error, but this time it was one single album that I’d just re-bought as lossless from Bandcamp and had forgotten to do the “relocate files” dance I described above and once I fixed that it worked fine too. I have no idea why that didn’t show up in the initial sync though.

So I guess in summary this is less of a “This is a 100% foolproof fix” and more of a “Trying fiddling with the metadata and maybe it’ll kick things into gear” suggestion. 😅

Praise be to the digital collectors!

I posted back in 2019 about how I’d been going by “VirtualWolf” online for twenty years at that point, and that the earliest mention of that name was from a Myth II map I’d created called Realm of the VirtualWolf that I’d been unable to find the actual original map file for (and that there was one Marathon map I couldn’t find either).

Fast forward to a couple of weekends ago when I decided to poke around and see if there had been any more updates to Project Magma’s work on Myth II, and it turns out that they’ve released two huge projects that included a re-render of every single model and asset for both Myth I and Myth II (from the original 3D models no less), as well as an update to the Myth I campaign to bring it into line with the improvements from Myth II.

I also decided to see what the Aleph One folks had been up to (the open-source release of Marathon) and while poking around various Marathon sites, I discovered this absolutely incredible treasure trove on archive.org that had been uploaded two years ago and I somehow missed until now: a RIDICULOUSLY LARGE archive of almost three thousand third-party Marathon maps that had been created over the years!

This “for all time” Marathon archive is from a hard drive purchased at the estate sale of a man who died early May 2023. I was always a fan of the Bungie Software game series Marathon so I was delighted to connect the drive and find lots of cool apps and files, along with a folder named “The Marathon Maps”.

After examining the maps collection, it was clear that all these Marathon maps and files were curated since the release of the original Marathon 1 app, which was December 1994. Yes, in the meantime the old man who owned the hard drive collected almost every Marathon map ever made.

And the big difference in what he’s done is the fact that all folders, Read Mes, and maps are professionally named and organized: no cryptic, uninformative, or baffling titles, and no separated Read Mes. Plus, all Read Mes are cleanly formatted in the header, with date, author, and map name.

And even better, this same gentleman had also collected a trove of Myth maps as well, uploaded separately here, and my “Realm of the VirtualWolf” map was included! 🤯

Sadly the missing Marathon map continues to be missing (technically it’s two, but one of them I had converted for use with Marathon Evil so it’s essentially the same thing; I think I must have just updated the original file rather than duplicating it, and apparently the original missed the attention of Old Man Map Collector) but all the other ones I I’d already found myself and uploaded to archive.virtualwolf.org were included in the archive, which is pretty incredible.

I’m absolutely stoked that I was finally able to find the Myth II map and I’ve dutifully added it to archive.virtualwolf.org, though I still can’t figure out how I don’t have it in my home directory because fucking everything is still in my home directory (for example I have a school assignment from 1994 when I was in primary school 😛). Ah well!

Goodbye Linode, hello Binary Lane

Way back in 2011 when I started on different support role at work that involved more sysadmin-type duties, I signed up with the VPS provider Linode so I would have my own remote Linux box that I could muck around with and break and generally learn about Linux a bit more on. At that point, my actual website was hosted on Dreamhost but I slowly expanded what I was using my Linode box for, and in 2017 I eventually ditched Dreamhost and migrated everything to the Linode. Linode’s hosting has been absolutely rock solid, I think in the 14 years I’ve been with them there have been… maybe two outages? And from memory both of them were when I had my VPS in one of their older datacentres California prior to them starting up a datacentre in Sydney and me migrating to it.

Towards the end of 2023 I posted about how I’d used Ansible to keep the configuration of the system under version control, and set up a whole migration script to migrate from one Linode box to a new one. Since then I’ve also started up a second smaller (1GB RAM) Linode to experiment with the fediverse software GoToSocial as an lightweight alternative to Mastodon that I could host myself instead of being on someone else’s server. I dutifully reused my existing Ansible playbooks and extended them for this purpose, and Linode have a whole collection that allows you to manage the actual VPSes and their external firewall as well.

Unfortunately with the orange idiot in charge of the US and all his tariff nonsense, the Australian dollar has gone right downhill compared to the USD and so a 1GB Linode + 2GB Linode and automatic backups were costing around AU$37/month. With that and the whole vibe of “Hey maybe we shouldn’t depend so much on US tech companies” lately, I figured maybe some local Australian company might have a decent VPS offering. I saw some recommendations for Binary Lane, did some poking around and even the people on Whingepool liked them. The price was certainly good, around AU$4 for a 1GB VPS versus US$5 with Linode (which works out to be over AU$8 once you do the currency conversion and tack on GST).

Binary Lane don’t have anything as fancy as Linode’s Ansible offerings, though the actual process of creating the VPS in the first place really isn’t something that happens very often so it’s not a big deal. The larger downside I discovered was that while Linode have a very robust external firewall that you can use Ansible to configure programmatically (and you bet your bippy I did!), Binary Lane’s offering is far less capable. I decided I’d need to add a local firewall instead that runs on the actual VPS itself, and found ufw which Ansible conveniently has a module for. After a bunch of trial and error I got it all figured out, and started modifying my existing Ansible migration script to consolidate the two Linode boxes into the one single Binary Lane one.

One interesting stumbling block I ran into when I first tried to migrate my GoToSocial instance — which runs in a Docker container and uses PostgreSQL that’s running directly on the box as its database — was that it turned out GoToSocial couldn’t actually contact PostgreSQL because it was being blocked by ufw! I did a whole lot of reading and figuring things out, and eventually it ended up being as easy as allowing the IP range that Docker Compose uses by default to connect to 172.17.0.1:

ufw allow from 172.16.0.0/16 to 172.17.0.1

Once that was figured out, it was relatively smooth sailing, though with a reasonable amount of trial and error and testing various bits of the migration. I had previously updated my Ansible playbooks to put all the static parts of my DNS configuration (things like MX/DKIM/SPF records and CNAMEs and so forth, all the parts that don’t point at a specific IP address) under version control and use Cloudflare’s† DNS Ansible collection to update it, and I was able to extend this to have full control of DNS records that actually point to an individual server and update that all dynamically from my playbooks!

†Yes I know Cloudflare are also a US tech company. One thing at a time. 😛

I ran the final migration last Sunday, and while there were a few hiccups there were far fewer than when I had originally migrated back in 2023 and I should be much better prepared next time I migrate boxes again.

One weird post-migration issue that I ran into that really stumped me for a while was that trying to load the URL of the website I run my IRC client through was giving me an invalid certificate error where it was trying to load one of the Cloudflare-proxied domain SSL certificates instead, and when I clicked through the warning I ended up on the domain for my GoToSocial instance instead.

After a whole lot of scratching my head, I figured out that while I had IPv6 enabled for the new Binary Lane VPS it turns out that Nginx won’t use IPv6 unless you explicitly turn it on in the virtual host configuration with a listen directive like on line 3 here:

server {
    listen 443 ssl;
    listen [::]:443 ssl;
    server_name blog.virtualwolf.org;
    [...]

With that all figured out and everything running along nicely, my next projects are going to be to set up fail2ban for Nginx (looking at my logs, there were almost ten THOUSAND requests to /xmlrpc.php on this blog URL, just within the last day of having it running 😑), and migrating my aus.social Mastodon account over to my GoToSocial at toot.virtualwolf.org!

Now, let’s see if publishing this blog post via the WordPress ActivityPub plugin makes my new VPS crumble…

More songwriting: Highland Fugue

First up, the song! (I’m not going to do a recipe blog style thing where you have to read everything before getting to the bit you’re really after. 😛)

And now, the backstory!

At the end of last year/beginning of this year I put together a song called Sans Metronome, I definitely learnt a lot about mastering and getting the song to actually fit together properly, but listening to it back again after a month or so I realised it was too… upbeat for my usual taste in music (by far the biggest overall genre of music in my iTunes library is metal of some sort). I’m definitely not at the stage where I could play guitar or drums well enough to write a legit metal song, but I’ve always loved the sound of the minor key and wanted to do something a little closer to what I normally listen to.

I was mucking around with my MIDI keyboard with the extremely large selection of synth sounds in the Alchemy plugin in Logic Pro when I came across one called Cathedral Fugue:

Rather than being a single sound, it was arpeggiated so you’d press a single key on the keyboard and then starting from that root note it would play through a bar of 16th notes, and I absolutely loved the progression. I spent probably a couple of hours listening and playing it back on the keyboard trying to transcribe it into individual notes, and decided that I should build a song around it. I’m not good at all on the keyboard so I wasn’t going to attempt to actually play it for real, so I manually put the notes into the MIDI editor in Logic Pro and quickly realised I needed a few different variants to keep the song interesting.

After that I delved into Superior Drummer 3‘s library of MIDI grooves and fills just to put some placeholder drums in to play along to — not only does it have the actual drum sounds but it comes with a big selection of preset grooves that you can just drop into your DAW. I discovered while doing this that they’ve done a really clever thing and each “family” of presets has a number of different variants, each of increasing intensity, so you can mix and match and make your drums get more and more complex as the song goes on:

I had a lot of fun playing around with this and really getting a solid progression going as the song went through.

Next up was the bass guitar which I did a bunch of fiddling around with and then settled on a chugging rhythm mostly on A with a three note walk-up every second bar, then jumping to F then E, and a less chuggy rhythm for the chorus.

After that was recording the guitar, which I’m not hugely good at and it was just rhythm anyway since the “lead” role was already taken by the Cathedral Fugue preset. The song was in A minor and I went for a i-iv-V-i progression with a replacement of the V chord with a VI-V every second-ish repeat through.

Logic Pro’s “Flex and Follow” option was a god-send here, my timing is definitely getting better but it still wasn’t 100% for guitar or bass, and Flex and Follow analyses the beat of the audio you’ve recorded and just slightly massages it to fit against the actual project BPM so it all sits perfectly.

At this point I had a bit of a play around with a number of other synth sounds in Alchemy because the Cathedral Fugue sound wasn’t quite doing it for me. I kept the notes I had already written but flipped through the presets, and stumbled upon one called “Highlands Bagpipe Ensemble” which I immediately loved and really made the whole song click together. This inspired the final name of the song too, “Fugue” from the original Cathedral Fugue arpeggiation, and “Highland” because it sounds sort of bagpipes-ish.

Then finally I decided I should really actually record myself playing the drums instead of just having dropped a bunch of preset MIDI grooves in. I did really like the grooves themselves though, so I sat down and looked at the MIDI notes in Logic Pro and transcribed them and over the course of multiple sessions managed to actually play them back:

It wasn’t too bad at the beginning where the grooves and fills were simpler, but towards the end (like in the screenshots above) they were doing things completely out of the standard rock groove that I’m used to that at one point it took me a solid two hours just to get sixteen bars recorded because my hands and feet were just not cooperating. I recorded each section in chunks because there was absolutely no way in hell I was going to be able to just play along to the whole thing, and each section took generally between 10-15 looped takes until I got something that was correct. You can see in the full screenshot of Logic Pro here how the “Drums” track at the bottom is split up into each groove and fill section:

I had to go through and tweak a number of note positions because they were too far off the timing grid, but by and large I’m pretty happy with how little I did need to change! I didn’t need to do the full quantise option to squash everything into the nearest 16th note either. 😁

The very final step was mastering, and I used a compressor plugin for the first time (on the drums), gave everything a good solid listening through over and over again, changed the positioning of a few of the crash cymbals so the drums flowed better, then made sure it sounded good across headphones, through the guitar amp, as well as the HomePod and our big subwoofer system in the lounge room.

I think this is definitely the best song I’ve done so far, and I’m going to keep practicing some of those Superior Drummer 3 grooves and fills to keep in my repertoire in future because they sound great. And this was just one single family of grooves, there are tons more, but I think I have more than enough here to keep me busy for a goodly while. 😅

Buffy the Vampire Slayer

Buffy the Vampire Slayer

I’m caught up on all the Severance episodes that have aired so far so now I think it’s time to go way back and do another rewatch of Buffy the Vampire Slayer1!

I never actually saw it at the time it was airing on TV, but I remember being over at a friend’s house and there was a random episode on and I thought “Huh this looks cool.” I got the first season on DVD for Christmas in 2004, absolutely devoured it and then immediately bought as many of the rest of the seasons as I could get my hands on. 😛 It was the first “Unassuming woman absolutely wails on fucking everybody and kicks their arses” show I’d seen and really established my love for that trope (see Faith also from Buffy, Max from Dark Angel, River from Firefly, Echo from Dollhouse, and I’m sure a whole lot more I’m forgetting right now).

The absolute standout episode for me would have to be Season 5’s The Body, I don’t think a TV show has ever gotten me in the feels that much, I was legit crying. Season 4’s “Hush” where a group of monsters come and steal everyone’s voices has only seventeen minutes of dialog in the entire 44-minute episode was fantastic too, plus Season 2’s “Innocence” where Angel loses his soul. And Season 6’s “Normal Again” really fucked me up, the Wikipedia page describes the plot as “a demon whose hallucinogenic venom makes Buffy believe that her implausible and nightmarish life as vampire slayer has actually been her own elaborate hallucination as a mental patient, catatonic in a hospital for the past six years.” It was so well done, I felt just somehow subtly off for a good day or two after watching it.

I watched the first episode of Season 1 tonight, and man I’d forgotten how wonderfully 90s campy it was. And this is from my actual original ripped DVDs rather than the absolutely dismal 1080p “remaster” that Fox clearly did as cheaply as possible. Given I’m watching it on my 11″ iPad while I use the elliptical the standard definition resolution isn’t nearly as noticeable anyway.

For how much I love the show, I do definitely remember there being a number of clearly filler episodes, which I guess isn’t that surprising given how damn long seasons of TV shows were back in the day compared to now! I’m also going to slot in alternating episodes of Angel when I start Season 4 of Buffy, I really enjoyed that as well, it was good to see Cordelia becoming a much more capable character in her own right. And one of my absolutely favourite moments in “Holy shit this person can act” was Amy Acker’s transformation from the bookish and nerdy Fred into the absolute evil badass that was Illyria. Just everything changed, all the subtle mannerisms, her voice, even though it was clearly still Amy Acker you honestly couldn’t see them as the same person, very similar to Tatiana Maslany’s absolutely incredible performance as five entirely distinct and clearly separate characters in 2013’s Orphan Black (well, more than five but those were the primary ones).

[EDIT] Thanks to @[email protected] for pointing out this recommended viewing order that someone put together, once I get to the point that the Buffy and Angel episodes are intertwined! I don’t trust a random Blogspot blog to remain around so I’ve tidied the HTML up and uploaded a copy to my website.

  1. Yes I know Joss Whedon turned out to be a huge piece of shit, but Sarah Michelle Gellar made a point of saying “While I am proud to have my name associated with Buffy Summers, I don’t want to be forever associated with the name Joss Whedon… I stand with all survivors of abuse and am proud of them for speaking out.” So I’m content to enjoy the show and recognise that the creator is a fuckwit. ↩︎