A cross-platform desktop app for getting a DJ collection under control: one canonical copy of every track, playlists that preserve your curation, clean tags, and an intake lane for new music. Runs on macOS, Windows and Linux.
The consensus among working DJs is that the filesystem should be shallow and predictable, and the software should do the organising — crates and playlists reference a track, they don't copy it. Sortero applies that:
- One file per track, at
Tracks/<Genre>/Artist - Title.ext - Playlists as pointers. Every folder you have today — Spotify/Tidal vibe
imports, gig sets — becomes an
.m3u8in_Playlists/pointing at that one file. A track curated into five vibes is five playlist entries and one file. - Key, BPM and energy live in tags, where rekordbox and Mixxx can sort them.
- Nothing is deleted. Extra copies go to
_Quarantine/. Every operation is journalled and reversible from the History tab.
DJ Collection/
Tracks/<Genre>/Artist - Title.ext canonical home for every track
Sets/<Set Name>/ optional: gig folders kept as folders
Albums/<Album>/ full releases, left intact
Mixes/ recordings over 20 minutes
_Playlists/*.m3u8 every folder you had, as a playlist
_Quarantine/ duplicates and rejects, never deleted
To Be Processed/ tracks waiting to be analysed
Processed/ analysed and ready to file
To Be Processed and Processed are never reorganised.
Genre detail is a choice on the Organise tab. Broad gives a handful of wide
folders; fine keeps subgenres apart — Techno (Peak Time) separate from
Techno (Hypnotic), Deep House from Tech House. Either way the layout stays
one flat level. Labels Sortero picked always get their own folder; a raw tag
value that matched no rule needs at least 8 tracks to earn one, so oddities like
Mainstage don't litter the tree.
| Tab | What it does |
|---|---|
| Overview | Track count, size, and what share has key+BPM, genre and energy. Lists what needs attention. |
| Organise | Previews every move before anything happens. Untick folders, or exclude individual rows, to leave things where they are. Collapses duplicates, writes playlists, files tracks by genre. |
| Tags | Strips download-site spam from Genre/Comment, infers missing Artist/Title from filenames, normalises Genre, and promotes Mixed In Key energy into the sortable Grouping field. |
| Duplicates | Exact (identical audio) and Likely (same artist/title/version, same length). Different remixes are never grouped. Extras move to _Quarantine. |
| Import | Add files or folders. Analysed tracks go straight to Tracks/<Genre>; anything missing key/BPM lands in To Be Processed. Tracks already in the library are flagged, not copied. "Sort the 'Processed' folder" files everything you've already run through PN and MIK. |
| Needs Work | Everything Sortero can't fix by itself, filtered by what's missing (key/BPM, energy, genre, artist, low bitrate). Select tracks and stage them in To Be Processed for whichever analysis tool you use. Your own set recordings are excluded. |
| Genres | Assign genres in bulk. Use folder name fills the tag in from the genre folder a track already sits in. Filter to tracks with none, sort by artist or folder, select a group and set it — or look them up on Discogs, whose styles are the subgenre detail you want. Every write is undoable. |
| Playlists | Rebuild a Spotify or TIDAL playlist against your local files, rebuild the folder playlists, or repair broken links when tracks come back from analysis renamed or re-encoded. |
| History | Every operation, with one-click undo. |
Sortero works out genre, artist and title on its own, but not key, BPM or energy — those come from an analysis tool. The Needs Work tab closes that loop:
- Filter by Missing key or BPM and select what you want.
- Stage selected in 'To Be Processed'.
- Run that folder through your analysis tool, saving the results into
Processed. - Import → "Sort the 'Processed' folder" files them by genre automatically.
Sortero also shows a green bar whenever
Processedhas tracks waiting, and the setup wizard files them as its first real step, so the loop closes even if you walk away mid-way.
Staged tracks remember the genre they came from. Analysis tools routinely strip
the genre tag when they re-encode, and without that memory every returning track
would land in Unsorted — on a real batch, 251 of 262.
Sortero doesn't care which tool wrote the tags — only that key and BPM are there. Any of these work:
| Tool | Notes |
|---|---|
| rekordbox / Serato / Traktor | Already analyse on import. Free, and you probably have one. |
| Mixxx | Free and open source on every platform. Built-in key and BPM detection. |
| Mixed In Key | Paid. Widely considered the most accurate for key, and the source of the 1–10 energy rating. |
| KeyFinder | Open source, key detection only. |
If you use Platinum Notes, run it before analysing. It re-encodes the audio, so mastering afterwards leaves key and energy tags describing a file that no longer exists — silently, with no error. Platinum Notes is entirely optional; it improves audio quality and writes no tags Sortero needs. For the loudness part alone, MP3Gain or your DJ software's auto-gain is a free substitute.
Staging a track out of a set or vibe folder does not cost you that
curation. Before anything moves, Sortero writes the folder out as a playlist
and records which playlists each staged track belonged to. When the track is
filed back out of Processed, it rejoins exactly those playlists at its new
location. Matching is on artist and title, so it survives Platinum Notes
renaming the file and changing its format — an MP3 that comes back as FLAC
still lands back in its set.
Filing a track into Tracks/<Genre> also writes that genre into the file.
Without it the folder knew the genre and the tag didn't, so rekordbox, Mixxx and
Sortero's own Genres tab all still saw the track as untagged. An existing genre
tag is never overwritten.
Sortero derives genre from tags and folder names. When a file has neither —
an analysis tool stripped the tag, or a Bandcamp rip never had one — there is
nothing to infer from, and it lands in Unsorted. The Genres tab is the way
out: select a group and set it, or ask Discogs.
Discogs needs no API token. Its free tier is rate limited, so lookups are paced at 2.5s and cached on disk — re-running never asks twice. A free personal token from discogs.com/settings/developer raises the rate to about one per second; paste it into the Genres tab if you're doing a big batch.
A long run reports as it goes: results fill the Suggested column while it works,
the status line shows how many are done and roughly how long is left, and Stop
keeps everything already fetched. The cache is written throughout, so a stopped
or crashed run resumes where it left off rather than starting over. Queries are cleaned
first (Track (Original Mix)_PN → Track), which took the hit rate from 1-in-8
to 6-in-10 on a real batch. Only artist and title are sent.
Coverage is honest, not magic: well-known club tracks resolve, obscure Bandcamp material often doesn't. For that tail, set it by hand — that's what bulk assignment is for.
Paste a Spotify or TIDAL playlist link on the Playlists tab and Sortero
matches each track against files you already own, then writes an .m3u8.
Connect an account (Playlists → Accounts) to read playlists of any length. It
uses OAuth 2.0 with PKCE: you sign in on Spotify's or TIDAL's own website, so
Sortero never sees your password, and the tokens are stored in your OS
credential store. One-time setup is creating a free app at
developer.tidal.com or the
Spotify dashboard and adding
http://127.0.0.1:8899/callback as a redirect URI.
Without connecting, Spotify links fall back to a public preview capped at 50
tracks, and TIDAL links need a connection. Pasting a tracklist as
Artist - Title lines, or loading a CSV export, always works.
Mixed In Key writes Cm - Energy 6 into the comment field. The key half
usually also reaches TKEY, but the energy half is stranded somewhere no DJ
software can sort on. Sortero copies it to Grouping as 5A - Energy 6
(Camelot + energy), which rekordbox and Mixxx expose as a sortable column.
A setup wizard walks you through choosing your collection folder, reads it, and explains the analysis loop. It appears once; after that Sortero opens straight into your library. Reopen it any time from Help → Setup Wizard….
Help → Check for Updates… compares your version against the latest GitHub release. If there's a newer one it offers to download, install and relaunch in one step: Sortero fetches the build for your platform, hands the swap to a small helper, quits, and reopens on the new version.
The helper waits for Sortero to exit before touching anything, keeps the old copy aside until the new one is in place, and puts it back if the move fails — a failed update never leaves you without an application.
Two caveats. Running from source it won't self-update, and says so. And macOS
asks permission before one app modifies another in /Applications; if it's
refused, allow Sortero under System Settings → Privacy & Security → App
Management, or keep Sortero somewhere in your home folder.
It can also check automatically on launch (at most once a day) — toggle that in the same menu.
While the repository is private, the update check can't read the release list anonymously and will say so. Either make the repo public, or add a GitHub token with
reposcope tosettings.jsonin the app data folder (File → Open App Data Folder).
Build the app, then open Sortero.app and point it at your collection.
Sortero runs on macOS, Windows and Linux. Grab the build for your platform from the Releases page:
| Platform | Artifact |
|---|---|
| macOS (Intel + Apple Silicon) | Sortero-macOS-universal2.zip |
| Windows | Sortero-windows-x86_64.zip |
| Linux | Sortero-linux-x86_64.zip |
Builds are signed ad-hoc, not notarised — notarising requires a paid Apple Developer account — so macOS blocks the first launch.
- Drag
Sortero.appwherever you want it; Applications is fine. - Open it once. macOS refuses, and the icon may bounce in the Dock without a window appearing.
- System Settings → Privacy & Security, scroll to Security, click Open Anyway next to Sortero.
- Quit the bouncing icon if it's still there, then open Sortero again.
Step 4 matters: the blocked launch leaves a stuck process behind, and while it's running, opening the app again just brings that stuck copy to the front rather than starting a working one. Only needed once per download.
Windows — SmartScreen may warn about an unknown publisher; More info → Run anyway.
Linux — needs Tk (apt install python3-tk).
python3.12 -m venv .venv
./.venv/bin/pip install -U pip mutagen keyring pyinstaller
./.venv/bin/python build/build_app.pyRequires Python 3.12 with Tk — brew install python-tk@3.12 on macOS,
apt install python3-tk on Debian/Ubuntu; the Windows installer includes it.
A universal2 macOS build needs a universal2 Python (the python.org installer ships one; Homebrew's is single-architecture):
./.venv/bin/python build/build_app.py --universal2The script checks the interpreter first and tells you if it can't. Release
builds run in GitHub Actions, where setup-python provides a universal2
interpreter — see .github/workflows/release.yml.
./.venv/bin/python run.pyFor a first big reorganisation, turn on Testing → Start Testing Session.
Everything you do from then on is recorded into a single restore point, saved
continuously as a .bak file, and a banner keeps count of what has changed.
- Keep All Changes — make it permanent and delete the backup. Individual operations stay in History and can still be undone one at a time.
- Undo Everything in This Session — put the collection back as it was.
- Save Backup As… / Load Backup and Undo… — the
.bakis portable and self-contained, so it can undo the work from a different machine or after reinstalling.
The backup holds no audio, only the log: every move, and every tag change with its previous value. That's enough to reverse everything, because none of these operations ever delete a file.
Reverting restores the folder structure exactly and puts every tag value back. Files whose tags were edited won't be byte-identical afterwards — rewriting an ID3 tag rebuilds the tag container's padding and frame order. The audio streams are bit-identical; verified with a decode-and-compare.
- Dry-run previews on every destructive tab; nothing moves until you confirm.
- Journals live alongside your other app data:
~/Library/Application Support/Sorteroon macOS,%APPDATA%\\Sorteroon Windows,$XDG_DATA_HOME/sorteroon Linux. - Duplicate removal is quarantine-only — Sortero never calls
unlinkon your music. - Back up before the first big reorganisation anyway — or use Testing mode.
GPL-3.0-or-later — see LICENSE.
Sortero links mutagen, which is GPL-2.0-or-later, so distributed builds have to be GPL-compatible. keyring is MIT, and PyInstaller is GPLv2 with a linking exception that does not constrain the bundled app.