//rp.wtf

My music listening algorithm

Sun Oct 11 2026

Smart Playlists

It's been more than a year since Navidrome became my primary driver of daily music listening. Since then, I've gotten way more familiar with the software, and unless they somehow screw it up, I don't think I'll switch to anything else in the near future.

I'm sort of on this journey towards having my "Spotify at home". Obviously, I have my regular playlists, mostly genre-based, but the real game changer came with my discovery of smart playlists. They allow you to, basically, write a database query in a declarative manner and store that in JSON format in a nsp file. In my brain, I just call them "dynamic playlists", because there's nothing really smart about the playlists themselves, but I have no doubt that the implementation is pretty smart.

That's about it; you can kinda stop reading now. That was the main thing I wanted to share.

The System

Anyway, the examples in the linked Navidome docs paint a good picture of what kinda stuff you can do with the smart dynamic playlists. I tried some random ideas until I decided that I want to make sure I've listened to every single track in my library, so this playlist became my daily go-to:

{
  "name": "100 unplayed",
  "comment": "Tracks with a play count of 0",
  "all": [
    {"is": {"playCount": 0}}
  ],
  "limit": 100
}

It was really fun listening to my music like this because I felt like I was reaching into the cobwebbed parts of my library and hearing tracks that I forgot I had.

Eventually all tracks got listened to, and this playlist came up empty. I felt some sort of achievement, like I had completed something and there was no more to do. Like getting Prestige in Call of Duty, back in the day.

There was more to do, though. Why not keep going with this? Just raise the floor from 0 to 1. I updated the playlist file with the following contents:

{
  "name": "prestige 1",
  "comment": "Tracks with a play of less than 2",
  "all": [
    {"lt": {"playCount": 2}}
  ],
  "sort": "lastPlayed",
  "order": "asc"
}

I dropped the limit as my library was modest enough to not cause performance issues when querying. I changed the play count test from equality to a less-than so that new music I add would also land in this playlist so it could be "caught up". Now that I had a play count for the entries, I could sort them so that the ones I hadn't heard the longest would come up first (I eventually realized that an unpredicable order was more important for me, so now I just shuffle it). And I titled it "Prestige 1", because that sounds cool.

Now I had an ever-shrinking playlist which felt like a goal I could work towards while making sure I listen to the deep cuts. I could always go and listen to my popular stuff whenever I wanted, but this felt like I was building a more intimate relationship with my music collection overall, and I'd end up finding more tracks to add to my "main" playlists.

Eventually I also discovered that you can filter on static playlists, so if I wanted to listen to Prestige 1 but was only in the mood for, let's say, metal, I could quickly "fork" Prestige 1 to only include tracks from a metal playlist:

{
  "name": "prestige 1 metal",
  "comment": "Tracks with a play of less than 2",
  "all": [
    {"lt": {"playCount": 2}},
    { "inPlaylist": { "id": "1yWtxhL986a4YuF0JzmWUp" } }
  ],
  "sort": "lastPlayed",
  "order": "asc"
}

This also kind of exposed the weakness of the standard shuffle. Many tracks in my most popular static playlist had a bump in the playcount only because of my system and not through getting played naturally, so that validated my approach even more.

Clients

For this system to work, you obviously need to use a client which "scrobbles" the music you play, which is LastFM-ese for letting the server know that you've listened to a track. In practice, it utilizes the /rest/scrobble endpoint in the Subsonic API to increase the playCount property of a track by 1.

Some clients, for the iPhone in particular, didn't do that, so here's a list of the software I personally use with Navidrome daily:

Conclusion

I've wanted to make a follow-up to the Navidrome article for a while now. There's more I want to share, but everything in due time.

If you've got a Navidrome box as well, I recommend you try this system or smart dynamic playlists in general to make your music listening sessions a bit more interesting and varied.