How I broke & fixed my chronological music library

Posted 2026-01-14 #unfortunately, computers

My music library is a fountain of memories I'd otherwise have forgotten by now. I can tell you which Monstercat compilation I was listening to the first time I played hooky from college, driving 2 hours to visit my first partner. I can picture the hotel room I was sitting in while listening to Rossz Csillag Alatt SzΓΌletett that one time. And Mouth Silence was the unofficial soundtrack of my senior year college job.

But those are just a few sparse anchor points. What if I wanted to know what else I was listening to around these times?

Well, if you stick to one music player for life, you can sort your library by "Date Added". Sounds implausible, but this was actually my situation for a long time! I was vendor-locked into iTunes from my teenage years up until very recently. Even at the points when I reinstalled my OS (Windows back then), I made sure to copy my iTunes Media folder over, ensuring my chronological timeline stayed pristine. But nothing lasts forever, and my switch to Linux meant a lot of things were going to change all at once.

I know this sounds preposterous, but β€” bear with me β€” I actually have very little desire to run iTunes under Wine. Its allure was never more than convenience, and syncing songs from my PC to the stock Music app on my phone was no longer the easy path. So, my first order of business was to find alternative software. I had a Plex instance languishing on my NAS, and I must admit I enjoyed my short stint with Plexamp on my phone, but the mere idea of self-hosted software requiring a centralized log-in always felt gross to me. After giving both Jellyfin and Emby a trial run, I found that Jellyfin had a somewhat more vibrant ecosystem, with apps that worked and felt comfortable enough to use.

Luckily for me, Jellyfin has a "Date Added" sort mode that leans on the filesystem's modified timestamps during initial import. I've always been invested in preserving this kind of metadata, and I've usually succeeded at that goal!

The problem: even good software is bad

Unluckily for me, sometimes the technology you trust changes, with or without your knowledge. Specifically: syncthing, which I recently used to migrate my files from my Windows desktop to my Linux laptop, stopped preserving directory timestamps around the end of last decade. And in the chaos of upending my entire personal tech stack, I didn't realize my mistake until it was too late to re-transfer the original files.

Not all is lost, though! This gap in syncthing's functionality only affects directories, never files. For my purposes, I still had all the metadata I needed β€” it just needed to be propagated upward from the files to the directories.

The fix: Python and a little touch-up

To that end, I wrote a Python script to fix the directory timestamps. I'd share it here if it were less tailored to my music organization system, or if it had unit tests, but I'm not in the mood to write & maintain a new open-source software project today. I'll give you the general recipe, though:

  • Scan the root music library folder depth-first.
    • In Python, I recommend the standard os.scandir to do this one layer at a time, then wrapping that in your own recursive function.
    • Alternatively, you could use os.walk, but because you'll need to perform certain tasks at the end of a directory scan, I found the recommended approach to be easier to conceptualize.
  • For each directory, keep track of the latest file modified timestamp. Initialize it to 0 (representing the Unix epoch).
  • Recurse into nested directories and return the latest modified timestamp, so that the outer directories' new timestamps account for nested files.
    • Consider whether you want to take any file's timestamp, or just certain kinds of files. (Personally, I only took .mp3 / .flac / .ogg files' timestamps into account.)
  • Once your scan through a directory is complete, check if the latest modified timestamp you gathered is earlier than its current modified timestamp, but later than the default value of 0. If so, update it!
    • In Python, use the standard os.utime to update modified timestamps. The timestamps it accepts are a 2-tuple of the form (atime, mtime). You're probably only concerned with updating mtime, so for atime, take the DirEntry object (let's call it entry) from os.scandir β€” the one corresponding to the directory whose timestamp you're currently updating β€” and pass in entry.stat().st_atime for that first tuple member to preserve its existing value.

After tweaking & running my script a few times, the timestamps finally looked perfect. From there, I had one more step, which was to update my NAS's copy of my music library with the same dates. One option would be to blow it all away and rsync the updated files over from my laptop, but I instead opted to mount the NAS copy as an NFS share from my laptop, then tweaked my Python script to output a sequence of touch --reference="/home/ash/Music/dir/path" "/mnt/Music/dir/path" commands, which I could spot-check and then run en masse. This was lightning fast compared to a re-transfer, and probably even faster than re-running the Python script on the (HDD-based) NAS.

It's worth noting that this solution is only valid if you don't edit your music files after adding them to your library. Otherwise, you'll end up with modified dates that are actually the date they were modified, not also incidentally the date they were initially added! I've always treated metadata cleanup as a mandatory step of adding music to my library, and I've never made any sweeping changes to the existing library, so this wasn't a problem for me.

Some actual conclusions

Ultimately, this is a pretty inconsequential story to be telling on my blog. I borked my files and then I fixed them. No, you can't have the script. But I did it! Aren't you proud of me?

But... I think there's a lesson worth communicating in all of this. It's a lesson about learned helplessness, particularly when it comes to software getting worse & more opaque, and how learning a scripting language can combat that.

See, I was aware of this problem for the last few months, but rather than fixing it, I sat on my hands. I was frustrated with the involved software, and I really didn't feel like writing a throwaway script when I could be working on a dozen other more fulfilling things. It wasn't even clear to me if writing & running such a script would solve my problem! Different apps care about different timestamps, and certain kinds of filesystem timestamps are much harder to change than others.

All that to say: gathering the motivation to fix this kind of problem is hard enough even when you have 80% of the necessary technical knowledge. I can't imagine how much more helpless it would feel if I wasn't already deeply comfortable in Python.

Breaking away from big tech (arguably the reason why I ended up in this mess) isn't just a matter of principled decision-making. It's a journey that demands your time and patience, along with a knack for problem-solving. Those solutions don't always require code, but even then, it's usually a matter of proportion; to use my situation as an example, I have over 1,500 albums and obviously would not want to fix their timestamps by hand. I think this is a selling point that the "learn how to code" evangelists of the last decade underappreciated & largely overlooked. Having a scripting language under your belt is the digital equivalent of having a toolbox in your home and knowing how to do basic maintenance & repair.

At a time when corporate giants are building walled gardens, abstracting away the details of how things work, and instructing customers to destroy faulty products on camera rather than offering repair... don't be afraid to get your hands dirty.