← cd ~

How I kinda Fixed Qobuz's Awful Music Recommendations with AI

Hey folks,

I’ve been using Qobuz since a long time now. For those who don’t know, Qobuz is a French music streaming provider. Unlike Deezer (also French), Spotify, Apple Music and many others, it’s less known but I’ve been subscribed to their service yearly since 2017. So yeah, quite loyal.

Why Qobuz?

What I love:

  • Hi-Res audio quality (that’s the main reason I stayed)
  • Works well on Android, iOS, and desktop (Windows/Mac)

About That Hi-Res Audio

This is really the killer feature. Qobuz streams in FLAC up to 24-bit/192kHz - that’s studio master quality. To put this in perspective:

QualityFormatBitrate
MP3 (Spotify, etc.)Lossy320 kbps
CD QualityFLAC 16-bit/44.1kHz~1,411 kbps
Hi-ResFLAC 24-bit/96kHz~4,608 kbps
Hi-Res MaxFLAC 24-bit/192kHz~9,216 kbps

That’s almost 30x more data than Spotify’s maximum quality. You actually hear the difference, especially on good headphones or a proper Hi-Fi setup. The dynamic range, the detail, the separation between instruments - it’s just not the same in lossy formats.

Qobuz offers over 100 million tracks in lossless quality, and they support multiple download formats too: FLAC, ALAC, WAV, AIFF, and even MP3 if you need smaller files. All DRM-free, which I really appreciate.

What drives me crazy:

  • Music suggestion algorithm is absolutely awful
  • No native Linux desktop app (it’s an Electron app, could have been ported easily imho)
  • No fading between tracks (as far as I know)

That’s a lot of cons right? But you know how it goes, each year it renews and you just accept it because what you really care about is listening to music.

The Breaking Point

This year I was about to cancel my subscription and switch to Deezer. They probably have everything I miss at Qobuz. But then I thought… why not fix it myself? The nerd way. With AI (yeah, the hype).

The Idea

What if I could:

  • Fetch data from my Qobuz account
  • Leverage Last.fm for music discovery
  • Use Claude AI for smart curation
  • And push tailored playlists directly into my Qobuz account on a weekly basis?

That way I’d get personalized playlists without relying on their crappy algorithm.

Spoiler: it works marvelously. I’m super happy I was able to achieve that in basically an evening.

How It Works

All of this is orchestrated through my self-hosted n8n instance. Here’s the technical breakdown.

Architecture Overview

Qobuz API Sync Discover Score Curate Qobuz Playlist
↑ Last.fm API feeds Discover ↑ Weighted Scorer feeds Score ↑ Claude AI feeds Curate

Step 1: Library Sync

First, I fetch all my favorites from Qobuz and cache them locally in SQLite.

Qobuz Account Fetch Favorites SQLite Cache
Artists (14)
Albums (50+)
Tracks (200+)

Step 2: Discovery Pipeline

This is where Last.fm comes in. For each artist in my library, I fetch similar artists and their top tracks. This gives me a pool of candidates.

My Library
Misié Sadik Kery James L. Einaudi
Last.fm getSimilar
Similar Artists
Admiral T Youssoupha Yann Tiersen
Top Tracks
500+ Candidates

Step 3: Content Filtering

I have kids, so I built in a filter to separate regular content from kids content. Keywords like “relaxation”, “meditation”, “baby”, “enfants”, “comptine”, “lullaby” get filtered into a separate kids playlist.

All Candidates (500+)
Content Filter
↙ regular
Regular (420+)
Main Playlist
↘ kids keywords
Kids (80+)
Kids Playlist

Step 4: Scoring Algorithm

Not all tracks are equal. I built a weighted scoring system to rank candidates based on how likely I am to enjoy them.

FactorWeightSource
Artist Similarity0.30Last.fm match score
Genre Overlap0.25Jaccard index
Label Affinity0.20Same label bonus
Year Proximity0.15Release date closeness
Inverse Popularity0.10Hidden gems bonus

Example scoring:

FactorRawWeighted
Similarity0.850.255
Genre0.700.175
Label1.000.200
Year0.900.135
Popularity0.400.040
Total0.805

The “Inverse Popularity” factor is interesting - it helps surface hidden gems instead of just recommending mainstream tracks.

Step 5: AI Curation

Here’s where Claude AI comes in. I feed it the top 200 scored candidates along with my user profile (top genres, favorite labels, year preferences, favorite artists). Claude then picks 20 tracks with variety in mind and explains why each one was selected.

Input
Top 200 Scored Candidates User Profile (genres, labels, years)
Claude AI
Output
20 Curated Tracks Explanations Playlist Name + Summary

Rules for Claude:

  • Only select from provided candidates (no hallucination)
  • Ensure variety (different artists, labels, years)
  • Explain each selection in context of user taste

Step 6: Push to Qobuz

Finally, each curated track is searched on Qobuz, matched by track ID, and pushed to a new playlist.

Curated Track
Qobuz search/getResults
Match Found?
↙ yes
playlist/addTracks
play.qobuz.com/playlist/...
↘ no
Skip

I also built a separate pipeline that fetches trending tracks from Last.fm (both global and France charts), filters out what I already have, and creates a “Les Hits du Moment” playlist.

Last.fm Global Charts Last.fm France Charts
↓ ↓
Merge & Dedup (France first)
Filter out owned tracks
Push to Qobuz "Les Hits du Moment"

Weekly Automation with n8n

Everything runs automatically every Sunday morning at 9:00. I get a Telegram notification when the playlists are ready.

Schedule
Sun 09:00
Execute Commands
Découvertes Urbaines Les Hits du Moment
Telegram Notify

Error Handling

Since this runs automatically, I built proper error handling with specific error codes that trigger appropriate alerts:

Error CodeMeaningAction
QOBUZ_AUTH_FAILEDToken expiredAlert: Refresh token
ANTHROPIC_NO_CREDITSBilling neededAlert: Add API credits
NO_LIBRARY_DATACache emptyRun sync first
NO_CANDIDATES_FOUNDNot enough artistsIncrease artist count

Tech Stack

ComponentTechnology
RuntimeBun (TypeScript)
ArchitectureHexagonal (Ports & Adapters)
DatabaseSQLite (bun:sqlite)
ValidationZod schemas
AIClaude API (Anthropic)
HTTPCustom client with rate limiting
LoggingPino
Automationn8n compatible (JSON output)

CLI Commands

# Sync your Qobuz library to local cache
bun run start sync

# Preview discovered tracks (no AI, no push)
bun run start discover --artists 20

# Full pipeline: discover + AI curate + push
bun run start generate --artists 20 --tracks 25

# Trending hits playlist (France + Global)
bun run start hits --tracks 25

# JSON output for automation
bun run start generate --json
bun run start hits --json

The Results: Actual Surprises

So what kind of suggestions do I actually get? That’s the real test right?

Well, here’s the thing - the system doesn’t just recommend more of the same. It actually surprised me. One recommendation that genuinely astonished me was:

Experience - Angèle Dubeau Ludovico Einaudi: Portrait (Deluxe Edition)

Classical violin. And you know what? It’s beautiful. I would never have found this on my own, and Qobuz’s algorithm would certainly never have suggested it.

That’s exactly what I wanted: not an echo chamber of similar tracks, but genuine musical discoveries that still somehow connect to my tastes through the scoring algorithm and AI curation.

Wrapping Up

Instead of switching providers, I ended up building something that actually works better than any streaming service’s built-in recommendations. The combination of Last.fm’s data and Claude’s curation gives me genuinely personalized playlists every week.

Was it overkill? Probably. But sometimes the nerd solution is the right solution.

Thanks for reading!


Built with Bun, TypeScript, and Claude AI