TuneFinder: Taste-Driven Music Discovery for DJs
Thousands of new releases processed every week. Scored against a taste profile built from years of actual mix history, by an engine that retunes its own weights from the verdicts I give it. The shortlist lands in a self-hosted web app, and every reason on every pick is composed from catalog facts. No LLM anywhere in the run.
The Problem
Crate digging is central to DJing. It is also, in 2026, a grind. Thousands of new releases land every week across Beatport, Juno Download, Bandcamp, Traxsource, and a dozen other platforms. The process is monotonous: open a genre page, scroll, click a track, listen for 20 seconds, decide if it fits, move on. A productive session might yield five to ten tracks worth buying.
Covering D&B, Breakbeat, UK Bass, UK Garage, House, and Electronica means tracking a wide scene. No single platform surfaces everything. And all of them optimise for what is commercially popular, not what fits a specific taste.
The Insight
Years of mixes on SoundCloud already contain a detailed record of taste. Every track chosen to play, in any context, is a data point: artist, genre, BPM, energy level, all of it encoded in the tracklists.
Describing preferences to an AI in abstract terms is the obvious approach. It is also the wrong one. Point the system at what has already been played and let it infer the profile from real behaviour. The mix history is the taste profile.
System Architecture
TuneFinder has two halves: a taste layer that reads mix history and builds an artist profile, and a discovery layer that pulls new releases from the stores. These meet in a ranking pipeline, which feeds a deterministic report renderer, served through a self-hosted web app whose verdicts loop back into the scoring.
- Known-track filterFuzzy match removes already-owned tracks, including variant suffixes
- Deduplication & cross-source mergeTracks appearing on multiple sources are merged; all metadata retained
- Ranker8 weighted signals - artist affinity, label match, chart position, cross-source validation, genre, recency, source discovery - retuned weekly from feedback
- Reason composerDeterministic - reasons built from catalog facts: play counts, prior titles, chart position, label and artist data
- Report rendererDeterministic - weekly and mix-prep reports, structured JSON artifact per run for the web app
- Runtimelaunchd schedule + web-triggered runs, serialised by a data lock
Building the Taste Profile
TuneFinder needs two things: which artists to look for, and which tracks to exclude. Both come from a .NET Web API built at changsta.com, deployed to Azure App Service.
The API maintains a structured catalogue of every published SoundCloud mix by merging two sources: a historical catalogue in Azure Blob Storage, and SoundCloud's RSS feed for recent mixes. New mixes discovered via RSS are automatically written back to the blob, so the catalogue grows without manual intervention. Results are cached in-memory to avoid hitting both sources on every request.
One endpoint returns a deduplicated track list across all mixes. Each entry carries a recurrenceCount (how many different mixes include that track), which becomes the primary signal.
From that, TuneFinder builds an artist profile for every artist in the history. Collaborative credits are split individually. Play count is weighted by recurrence: an artist whose tracks appear across four mixes contributes more weight than one played once. That naturally separates genuine preferences from passing experiments.
The result is a dictionary of 1,000+ artist profiles, each with a weighted play count and associated genres. Alongside it, a known-track exclusion set fingerprints every track already played, so the system never recommends something already owned.
Finding New Music
Four source fetchers run in parallel every week. The goal is breadth: no single platform covers the full scene, so casting a wide net and cross-referencing produces a much stronger signal than relying on any one store's algorithm.
- Beatport - genre top-100 charts (D&B, Electronica, UKG, Breaks, five house sub-genres). Chart position, BPM, key, and label data now come from the v4 catalog API, which replaced the earlier
__NEXT_DATA__extraction and made the fetcher boring in the best way. - Bandcamp - queried by genre tag to surface independent releases that often appear here before hitting the main stores.
- Volumo - an underground-focused store covering the end of the market the big platforms miss. No preview embeds, so its picks render list-only.
- SoundCloud - the official API, fishing the free-download and bootleg lane. These route to their own report section, so a bootleg never competes with a store release for a slot.
A track on Beatport's chart and Bandcamp is a stronger signal than one platform alone. Cross-source agreement ends up being the pipeline's most reliable quality filter. Traxsource, Resident Advisor, and Mixupload fetchers exist behind config flags, currently disabled; Juno Download and the Subsurface newsletter archive served earlier eras of the pipeline.
The Ranking Pipeline
After fetching, ~4,000 raw candidates pass through several stages. First, deduplication: tracks appearing on multiple sources are merged into a single candidate, retaining all source metadata. Then the known-track filter removes anything matching the play history. A history filter also excludes tracks already recommended in previous reports.
Each surviving candidate is scored against weighted signals:
| Signal | Weight | Trigger |
|---|---|---|
| Known artist | 3.0 × play count | Artist in mix history |
| Recurring artist | +2.0 | Artist with 3+ plays in history |
| Label match | +2.5 | Label associated with known artists |
| Chart position | up to +1.5 | Position 1–100, decays linearly |
| Cross-source | +1.0 | Track appeared on 2+ sources |
| Genre match | +0.5 per tag | Genre in known set |
| Fresh release | +0.5 | Released within the last 30 days |
The chart position bonus matters. A track at #1 on the Juno chart gets the full 1.5 bonus, decaying to zero at position 100. This surfaces music the broader scene considers significant, not just what is algorithmically new.
Tracks that score well but miss the weekly cut are held in a persistent candidate pool and re-evaluated in future runs. A track appearing across multiple weeks without being recommended gradually accumulates credibility.
Top candidates split into four sections: Top Picks, Label Watch, Artist Watch, and Wildcards, with per-artist and per-genre caps to keep variety.
The weights started as intuition and manual experimentation. Now they retune themselves: every verdict marked in the web app feeds a weekly learning pass that adjusts signal weights, boosts liked artists, and decays what keeps getting skipped. An eighth signal, a source discovery bonus, rewards fetchers that keep finding tracks that get bought. The architecture accepts new signals without restructuring the pipeline, which is what made that evolution cheap.
The Report Went Deterministic
TuneFinder ran a two-stage LLM pipeline for most of its life: a cheap model writing a one-sentence reason per track, a frontier model writing the weekly report. It worked, and it cost about £10 a month.
Then the feedback loop landed and the reasons got better without a model. The engine already knows why it picked a track, because the score is the sum of named signals. "You play Calibre regularly and this is his first EP in two years" turns out to be a database query, not a paragraph of prose. The renderer now composes every reason from catalog facts (play counts, prior titles, chart position, label and artist data) and the report template does the rest. LLM calls per run: zero.
From AI Agent to Web App
TuneFinder started as a Python script run manually from the terminal. It worked, but it was fragile - SSH to the server, activate the venv, remember the flags, babysit the output. Silent failures were hard to track down.
The first fix was OpenClaw, a self-hosted AI agent platform on the Mac Mini. It ran TuneFinder as a shell skill on a weekly schedule, posted failures to a #logs channel, and could be triggered conversationally: @mention the agent on Discord, ask for a mix-prep report, get it back in the channel. No terminal, no flags.
That era ended in 2026 when the agent platform was stood down. What replaced it is plainer and better. The schedule is a launchd agent (Sunday 09:00, London time). On-demand runs moved out of Discord chat and into the app itself, with a data lock serialising web-triggered and scheduled runs so they cannot interleave. The conversational layer turned out to be scaffolding too: once the app existed, "ask the agent to run mix prep" became a button.
Why a Mac Mini Under a Desk
The Mac Mini M1 draws about 7 watts at idle. It runs 24/7 and costs almost nothing beyond electricity. Running locally avoids paying for a cloud VM and keeps the whole thing simple. That is a deliberate architectural choice, not a limitation.
The worst realistic failure is a missed weekly report, which does not justify the operational overhead of cloud infrastructure or container orchestration. The complexity budget is better spent improving the pipeline logic than building resilience the system does not really need.
The Web App
The report used to arrive in Discord and get worked through by hand. Now it lands in a React app served by the same FastAPI backend that runs the pipeline - one origin, reached through an outbound-only Cloudflare Tunnel, behind a fail-closed bearer secret. Weekly triage happens track by track: audition through store embeds, then mark a verdict. Bought, liked, skip, own. Each mark is a scoring input, not a bookmark.
Every pick carries its reason. The score is the sum of the signal weights a track earned, and the app shows the signals and a full pipeline trace per track. An insights page shows per-signal lift, genre and label affinity, the candidate pool, and what the engine changed after each week's learning pass. Mix-prep runs launch from the app too, constrained by genre, tempo range with half and double-time flex, and Camelot key picked from a key wheel. Runs triggered here show live progress.
Results
TuneFinder surfaces 15–20 relevant tracks per week from ~4,000 candidates, and growing as new sources are added. The known-artist signal is the strongest predictor by some margin. If an artist who gets regular play has a new release, it surfaces immediately. Cross-source agreement is the most reliable quality filter: a track independently validated by Juno's chart buyers and Bandcamp's independent listeners is almost always worth a listen.
Mix-prep runs launch from the web app on demand, narrowed by genre, tempo, and key, useful when building a set and wanting to narrow the focus. And since the feedback loop closed, the engine measures its own hit rate instead of me guessing at weights.
The label watch section has introduced several labels now followed directly. The system inferred label relevance from play history without any explicit label list being provided. That was a surprise.
There is nothing to remember. The report is waiting in the app every Sunday morning, and Discord gets a copy.
A Reusable Pattern
The most interesting outcome is not TuneFinder itself. It is that the architecture turned out to be a reusable template.
The same Mac Mini runs a second automation called Signal Monitor that tracks ~30 companies in the Exhibitions & Events industry for hiring, product, M&A, and expansion signals: the same watch, score, report pattern with scheduled execution and error routing. Both systems have since grown web front ends of their own.
What's Next
- Seeded discovery everywhere - positive verdicts already seed targeted searches on Beatport and SoundCloud, so a liked artist gets actively hunted rather than passively awaited. Extending seeded queries to the remaining sources is the obvious next step.
- Broader source coverage - the Traxsource, Resident Advisor, and Mixupload fetchers are built and sitting behind config flags; label-direct Bandcamp pages and artist reposts are signals still missed. Each new source adds noise, but also strengthens the cross-source validation that is already the ranker's most reliable quality filter.
- Longer-horizon learning - the weekly pass tunes weights from recent verdicts. A season's worth of marks could say more: which genres fade, which labels earn a standing boost, whether the engine's hit rate is actually climbing.
Tech Stack
Building something similar?
TuneFinder started as a personal tool, but the pattern it uses is domain-agnostic: aggregate from multiple sources, score and filter, deliver a readable report to where you already are.
If you are working on something similar (industry monitoring, research aggregation, personal tooling with a real ranking problem), feel free to get in touch.