Tag: Tidal

  • Seizing the Means of Listening

    Soundtrack to this post.

    For years, Tidal had a very good idea of what I listened to. Every play, every skip, logged on a server I’d never see, feeding an algorithm I didn’t ask for, ready to hand me a glossy year-in-review graphic every December whether I wanted one or not.

    A few weeks ago I cancelled it. What I actually wanted was already sitting on my own server, in a library I’d spent months getting properly tagged, playing through a media server that already reaches every device in the house. Tidal wasn’t giving me anything my own kit couldn’t, once the kit actually worked properly. So I switched it off and set about rebuilding, on my own terms, whatever streaming had been giving me.

    Mine’s on my own server now. Every play, every skip, every 3am replay of the same Erasure track fifteen times in a row, logged by me, stored by me, shown back to me on my own website. Nobody else’s business.

    This is the story of how that happened, and it took a lot longer than I expected.

    The library had to actually be correct first

    None of this works if the files don’t know what they are. I’ve got a couple of thousand tracks on a Hetzner storage box, ripped from CDs going back years, and a lot of them had tags that were, generously, vibes-based. Artist names spelled three different ways. Compilation albums where every track thought it was the album artist. No MusicBrainz IDs at all, which meant no service anywhere could reliably say “this is that song” rather than “this is a song with a similar name.”

    Fixing that meant beets, a command-line tagger that’s less well known than it deserves to be. Point it at a folder, it fingerprints the audio and matches it against MusicBrainz’s catalogue, then writes the correct IDs straight into the file tags. No renaming, no moving things around, no gambling with a library that has no backup (a fact I am extremely careful about).

    It did not go smoothly on the first attempt. The MusicBrainz plugin isn’t even enabled by default any more, so my first real import returned nothing for every album and I spent an embarrassingly long time wondering why. Then, once it was working, I found that turning on audio fingerprinting (as opposed to matching on the existing text tags) actually made matches worse, dropping a known-good album from a perfect 100% match down to 93%. Counterintuitive, but the numbers didn’t lie, so fingerprinting only comes out now for genuinely hopeless cases.

    For freshly ripped CDs there’s a second layer to this: Picard, which handles the initial tagging before the files ever reach beets. Load a whole album onto one confirmed release before saving, every time, or Picard will happily scatter your tracks across three different pressings of the same record without telling you. And for the properly obscure stuff, like a 55-track singles box set that exists in several barely-distinguishable editions, the only reliable way to pick the right one turned out to be reading the barcode off the physical case and matching it against the MusicBrainz API directly. Title search alone just isn’t trustworthy once the tags are already a mess.

    (For the record: I’m still two tracks short on that box set. If anyone has a spare copy of the Pet Shop Boys’ “Smash”, get in touch.)

    Giving myself a proper name

    Small detour: my ListenBrainz account had been sitting under an old username, a leftover from some long-forgotten forum registration habit. One email to the MusicBrainz team and it became douglasireland, keeping every listen already logged. Nice to have your own name on your own listening history.

    Building the page

    With the library actually tagged, and my media server serving it to the house, and a scrobbling plugin sending every play to ListenBrainz, I had real data flowing for the first time. So I built /listening-log: what’s spinning right now, a running ledger of recent plays grouped into runs when I’ve clearly put a whole album on, and a chart of what’s had the most airtime lately. Styled to match the rest of the site rather than looking like a bolted-on widget, because a bolted-on widget is exactly what it would have been otherwise.

    Cover art turned out to matter more than I expected to how alive the page felt. Real sleeve art, pulled by MusicBrainz ID, made the ledger feel like a shelf of records rather than a spreadsheet. One entry kept showing a plain white box instead, which took a bit of hunting to run down: I’d built the image URL without ever checking whether the artwork existed, so a 404 quietly painted nothing. Now it tries the media server first, falls back to the Cover Art Archive, and only gives up to a plain sleeve icon if genuinely nobody has art for that release.

    There were smaller bugs too, the kind you only find by actually living with a thing. A run of exactly one track was silently hiding its own artist name, a leftover edge case in the “don’t repeat the artist for every track in an album run” logic. Box-set compilations were briefly crowning “Various Artists” as my most-played act, because the code trusted the album-level tag over the actual per-track one. And my phone’s scrobbler fires two or three near-identical “finished playing” events for a single track a second apart, which is a fun way to accidentally double your own listen count if you’re not watching for it.

    The bit where I stopped trusting someone else’s server

    Here’s the part that actually earns this post its title. ListenBrainz is a good project, run by a small non-profit, and I like what it stands for. But it went down. More than once, in the space of one day, and the second time it wasn’t just missing data, it was actively making my own front page slow, because every visitor was quietly waiting on a request to a server I don’t control and can’t fix.

    So I asked myself the obvious question: every track I listen to gets played through my own media server first. Why is my website asking a third party what I’ve been listening to, when the honest answer is sitting right there on my own infrastructure?

    It took an afternoon to switch the whole thing over. The “now spinning” widgets, the ledger, the charts, all of it now reads straight from the media server’s own session and activity data, over a private network connection that never touches the public internet. ListenBrainz still gets scrobbled to in the background, because I like having a public record too, and because it means this isn’t a single point of failure either way. But my own site no longer depends on it staying up. If ListenBrainz is down, mine just doesn’t notice.

    That, more than the tagging or the widgets or any of the rest of it, is the actual point of self-hosting. Not that it’s free, or that it’s more private, though it is both of those things. It’s that nothing about my own website’s uptime is someone else’s problem to have on a bad day.

    There was a knock-on bug from the migration worth admitting to, because it’s a good one: the switch briefly made the “now spinning” widget flash “nothing’s playing” for up to forty-five seconds every single time a track actually changed, because it trusted an empty reading the instant it saw one, with no allowance for the ordinary gap between one song ending and the next one registering. It now holds the last confirmed track for a minute, quietly flagged as unconfirmed, before it’ll admit the room’s gone quiet. Small fix, but it’s the difference between a page that feels alive and one that flickers like a loose wire every three minutes.

    Wrapped, but it’s mine

    The last piece was a proper year-in-review page, the kind Tidal used to send me every December, glossy and pre-packaged. Mine’s at /recap, rebuilt on a rolling 365 days rather than a calendar year, so it’s always current rather than sitting stale for eleven months.

    As of today it’s showing 1,209 listens, across 347 different artists and 845 different tracks, with just over 77 hours of confirmed listening time. A ten-day streak earlier this month. My single busiest day so far ran to 116 plays. Garbage are comfortably my most-played artist right now, on both the 30-day and 365-day view, which is either a sign of good taste or a sign I need to broaden my horizons. Possibly both.

    None of those numbers are borrowed from anyone. They’re not an estimate, not a “stats aren’t ready yet” placeholder, not something calculated by a batch job on someone else’s schedule. They’re read straight off my own server, whenever the page loads, because the data was mine the whole time.

    Douglas Ireland, Self-Hosted
    Listening record · no. 001174

    Listens logged
    1,209
    Unique artists
    347
    Unique tracks
    845
    Hours played, confirmed
    77.4
    Longest streak
    10 days
    Busiest day
    116 plays

    Top artist
    Garbage
    ×50

    Subtotal
    everything
    Third-party fee
    £0
    TotalMine, kept

    *** served from my own server ***
    *** no subscription required ***

    LB · DOUGLASIRELAND

    Go have a look

    The listening log updates live. The recap page is the honest, unglamorous version of Wrapped. Between them they represent a genuinely stupid number of hours spent on something that, at the end of the day, just tells me what I already knew: I listen to a lot of Erasure.

    Worth every hour, though. It’s my data. Might as well be my website too.

  • The Gregorian Pop Cover I Didn’t Know I Needed

    Soundtrack to this post.

    I was looking through Tidal for some relaxing music to play whilst doing the housework this morning when I stumbled across a Gregorian chants meditation playlist. It immediately made me nostalgic for that brief, strange period in the 90s when the Chant album by the Benedictine Monks of Santo Domingo de Silos unexpectedly shot up the pop charts.

    Album cover art for 'Chant' by The Benedictine Monks of Santo Domingo de Silos, showing several robed, hooded figures standing among stone blocks against a blue sky with clouds.
    The iconic 1994 album cover. (Image via Wikipedia).

    Do you remember that? Suddenly, ancient monophonic plainsong was everywhere, from chill-out rooms to car stereos. Then, just as abruptly, it vanished into the ether, leaving us all wondering if it had been a collective fever dream.

    Thinking I would revisit that vibe, I decided to give the playlist a go. The first few tracks were exactly what you would expect. It sounded like a scene from The Name of the Rose, somber and atmospheric.

    But then, a Gregorian Chant cover of John Lennon’s Imagine came on and stopped me in my tracks.

    I absolutely loved the rhythm of the sound. There was something fascinating about the juxtaposition of the deeply religious musical style against the famously humanist, secular anthem of the lyrics. It shouldn’t work, yet it somehow does.

    As I let the playlist run, it just kept giving. Later on, there were covers of Lady in Red, Angels by Robbie Williams, and plenty more. I didn’t know I needed this in my life, but I think Gregorian chant covers of pop songs might just be my new obsession.