- TypeScript 89.6%
- CSS 7.9%
- JavaScript 1.3%
- HTML 1%
- Shell 0.2%
|
Jacqueline
ccf768a093
Spotify view: compare playlists against the library, build a 'missing' playlist
New sidebar view that talks to the Spotify Web API from the main process (renderer CSP stays closed). Search public playlists, list a user's public playlists (user:<name> or profile URL — Spotify search doesn't index small personal playlists), or paste a playlist link. Tracks are matched against the loaded session with the scan pipeline's own normalization: exact artist+title first, then Dice fuzzy (>= 0.82) over tags and filenames, duration-gated. Each track shows have/missing, with All/Have/Missing filters and CSV export of the missing ones. Reads use the client-credentials flow with the user's own app credentials (persisted in settings; secret never reaches the renderer). "New Spotify playlist from missing" needs a user token: one-time Authorization Code + PKCE browser login with a short-lived callback server on 127.0.0.1:8888, refresh token persisted separately in userData/spotify-auth.json so persistSettings can't clobber it. Creates a private playlist in 100-URI chunks. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> |
||
|---|---|---|
| build | Default Track Table to newest-added first; recolor icon to purple | |
| sample-data | Complete | |
| scripts | Default Track Table to newest-added first; recolor icon to purple | |
| src | Spotify view: compare playlists against the library, build a 'missing' playlist | |
| .gitignore | Stop tracking .claude/settings.local.json (local config); ignore build scratch files | |
| _validate_web.mjs | README | |
| ARCHITECTURE.md | Spotify view: compare playlists against the library, build a 'missing' playlist | |
| electron-builder.yml | Complete | |
| electron.vite.config.1781421717924.mjs | README | |
| electron.vite.config.1781421727264.mjs | README | |
| electron.vite.config.ts | Complete | |
| package-lock.json | Phase 2: Transition Prep Mode - two-deck waveforms with in/out markers | |
| package.json | Phase 2: Transition Prep Mode - two-deck waveforms with in/out markers | |
| README.md | Add Trash button on duplicate copies (move to system Trash, recoverable) | |
| TRANSITION_PREP_PLAN.md | Phase 1: persistent in/out transition markers + remove em dashes | |
| tsconfig.json | Complete | |
| tsconfig.node.json | Complete | |
| tsconfig.web.json | Complete | |
Boom
A local-first desktop app that sits between Rekordbox and your music folder. It detects duplicates, inspects tracks, and compares what's in Rekordbox against what's on disk - built for a DJ workflow, not a generic file browser.
Boom never writes to your Rekordbox library or your file tags - it only reads the XML export and your folder. The one file action it offers is moving a duplicate to the system Trash (recoverable), and only when you click Trash on a specific file. Nothing else is moved, renamed, retagged, or deleted.
What it does
- Load your Rekordbox XML export (the canonical source for playlists, BPM, and key).
- Scan a local music folder (
.mp3 .flac .wav .aiff .aif .m4a). - Match folder files to Rekordbox entries with layered strategies.
- Detect duplicates in layers (path → metadata → filename → fuzzy → optional acoustic fingerprint).
- Browse everything in a fast, sortable, filterable table.
- Review playlists from the XML (with
miscpinned to the top). - Compare "in folder but not in Rekordbox", "in Rekordbox but missing on disk", and "missing BPM/key".
- Export CSV / JSON reports (all tracks, duplicate groups, mismatches, a delete-candidates list, selected rows), and save/load scan sessions.
- Curate locally with staging playlists and custom tags that are never written to Rekordbox or your files.
- Mix harmonically - for any track, see compatible tracks by Camelot key + BPM.
- Preview audio - play any track on disk in a built-in player with seeking.
- Prep transitions in a two-deck mode: beatmatch and phrase-sync two tracks on your Rekordbox beatgrids, with in/out markers, master BPM, keylock, and a crossfader.
Audio preview
Click ▶ Play in the inspector (or double-click a row in the Track Table, or use ▶ on a
duplicate row) to preview a track in the bottom player bar - full native transport with seeking.
Files stream through a dedicated, range-enabled boom-audio:// protocol restricted to recognized
audio files, so nothing is copied and large files seek instantly. Playback is read-only.
Transition Prep (two-deck beatmatch)
A two-deck mode for auditioning transitions and finding the right bar to mix on. It is built
entirely on your Rekordbox beatgrid (the <TEMPO> anchors in the XML), so beats, bars, and phrase
guides line up with the actual music. Like the rest of Boom it is read-only: markers and deck state
are saved locally, never written to Rekordbox or your audio.
Open it from the Transition Prep view in the sidebar, or load a track straight onto a deck with the A / B buttons in the Track Table, or the Deck A / Deck B buttons in the inspector.
Each deck shows:
- A zoomed-in detail waveform (opens at ~3 bars) with the beatgrid drawn on top: every beat, stronger lines on each bar, and a prominent marker every 8 bars (toggle 8 / 16 / off). Bar.beat numbers appear as you zoom in, and a full-song overview strip sits below for navigation.
- BPM and Key from the Rekordbox grid, plus a fixed red center line. Drag the waveform to jog a beat onto the line; the start gets blank lead-in space so even bar 1.1 can sit on it.
- Persistent IN / OUT markers (where the track comes in and mixes out), saved per track and kept across reloads.
Mixing controls:
- Beat Sync (on by default): start a deck while the other is playing and it snaps to the nearest bar and stays locked, with a continuous correction loop holding the two in phase. The blue Sync button does it in one click and starts the deck for you.
- Master BPM: pin both decks to a common tempo (set 128 and a 126 and a 130 track both play at 128). Quick-set from either deck's native BPM, or turn it off.
- Keylock per deck preserves pitch when the tempo is stretched.
- A crossfader blends between A and B, and a live offset readout ("on beat" / "off +0.30 beat") shows the lock.
Both decks can play at once. Beat sync is a feedback loop over the browser's audio clock, so it
holds within a few milliseconds rather than being sample-perfect, which is plenty for curating and
prepping sets. The last XML and folder auto-load and scan on launch, and the two decks reload their
tracks and markers where you left them (saved in settings.json and annotations.json under the
app's user-data folder).
Local curation (staging playlists + custom tags)
Boom keeps a local annotation layer that never touches Rekordbox or your audio files:
- Staging playlists - create local playlists in the Playlists view ("Staging (local)"). Select tracks in the Track Table and use the Add ... to staging dropdown, or toggle membership per track in the inspector. Click a staging playlist to filter the table to it.
- Custom tags - add free-form tags to any track in the inspector. Tags show in the Track Table "Tags" column, are included in search, and appear in CSV exports.
These persist across rescans in ~/Library/Application Support/Boom/annotations.json (keyed by a
stable per-file id), so they survive re-scanning your folder. Nothing here is ever imported into
Rekordbox.
Harmonic matching ("Mix with")
Select any track and the inspector lists harmonically compatible tracks - same key, ±1 on the Camelot wheel, the relative major/minor, or a +2 energy boost - whose BPM is within 6% (also accepting double/half-time). Results are sorted by key relation then BPM closeness; click one to inspect it. Toggle Camelot in the toolbar to show Camelot codes everywhere.
Build a set from matches: in the "Mix with" section, pick a target playlist (or create one inline), then use + on any match to add it, or + Add all to add the seed track plus every compatible match to that staging playlist at once. This is the fast way to curate a key/BPM-matched playlist inside Boom - no Rekordbox involved.
BPM & Key sourcing
Rekordbox XML is treated as canonical for analyzed BPM and key. File tags are used only as a
fallback when the XML has no value (or when a file isn't in Rekordbox at all). The inspector
shows which source won (RB vs TAG) for every track. This matches reality: in a typical
library most files carry no BPM/key in their tags, so the XML is the reliable source.
Quick start
Requires Node 18+ (tested on Node 26) and macOS / Windows / Linux.
npm install
npm run dev
Then in the app:
- Click Choose XML... and select your Rekordbox XML export.
- Click Choose Folder... and select your
miscfolder. (On this machine it defaults to/Users/jacqueline/Documents/music/misc.) - Click Scan.
You can also try it immediately with the bundled sample data:
- XML:
sample-data/sample-rekordbox.xml - Folder:
sample-data/misc
The sample set intentionally contains duplicates (same track as FLAC + MP3, a (1) copy, a
- copy file) and one Rekordbox entry whose file is missing on disk, so every view has something
to show.
Exporting a Rekordbox XML
In Rekordbox: File → Export Collection in xml format (or Preferences → Advanced → Database → rekordbox xml, then File → Export). Boom reads that file; it never writes to it.
Scripts
| Command | Description |
|---|---|
npm run dev |
Run the app in development with hot reload. |
npm run build |
Production build into out/. |
npm run build:mac |
Build a macOS app + DMG into dist/ (Apple Silicon). |
npm run make:icon |
Regenerate build/icon.icns + icon.png from the Boom mark. |
npm start |
Preview the production build. |
npm run typecheck |
Type-check main + renderer projects. |
Building a Mac app
npm run build:mac
Produces dist/Boom-<version>-arm64.dmg and dist/mac-arm64/Boom.app. The build is unsigned
(no Apple Developer certificate), so the first time you open it macOS Gatekeeper will block it -
right-click the app → Open → Open, or run xattr -dr com.apple.quarantine /Applications/Boom.app
after dragging it from the DMG. Subsequent launches are normal.
Main screens
- Library Overview - counts for files, Rekordbox tracks, matched, duplicate groups, folder-only, Rekordbox-only, missing files, and missing BPM/key. Cards are clickable and jump to a filtered view.
- Track Table - every track with Artist, Title, Filename, Format, Duration, BPM, Key, In-Rekordbox, Playlists, Duplicate, Confidence, Reason, Path. Sortable on any column, text search, filter chips, multi-select (⌘/⇧-click), sticky header, row virtualization for large libraries.
- Duplicates - groups with side-by-side comparison, the recommended file to keep (★), and per-group "mark reviewed". Header shows how many delete candidates exist and the reclaimable space, with "Export report" and "Export delete candidates" buttons.
- Playlists - the Rekordbox playlist tree with track counts; click to filter the table;
miscpinned at the top. - Mismatch - three tabs: in-folder-not-Rekordbox, in-Rekordbox-file-missing, and missing-BPM/key.
- Transition Prep - two decks with beatgrid waveforms, beat/phrase sync, master BPM, keylock, crossfader, and persistent in/out markers (see above).
Selecting a track opens the inspector on the right: file info, tag metadata, Rekordbox metadata, playlist membership, issues, and the duplicate comparison.
Keyboard / UX
- Sort: click a column header (click again to flip direction).
- Multi-select rows: ⌘-click to toggle, ⇧-click for a range. With a selection, Export selected (N) writes just those rows to CSV.
- Camelot toggle in the toolbar switches key display to the Camelot wheel.
- Fuzzy toggle enables/disables the slower fuzzy duplicate stage.
- Fingerprint toggle enables acoustic-fingerprint duplicate matching (see below).
- ? button (top-right of the toolbar) opens a help panel listing every feature and where to find it. Press Esc or click outside to close.
Acoustic fingerprinting (optional)
Boom can confirm duplicates by how they sound, not just by names/tags - useful for catching the
same track under different filenames, or different rips of the same recording. This is off by
default and requires Chromaprint's fpcalc on your PATH:
brew install chromaprint # macOS
sudo apt install libchromaprint-tools # Debian/Ubuntu
Tick Fingerprint in the toolbar, then scan. Boom fingerprints the first ~120 s of each folder
file (concurrency-limited, so it's slower) and adds a high-confidence "Acoustic fingerprint match"
stage to duplicate detection. If fpcalc isn't installed, Boom simply skips this stage and tells
you - nothing else is affected.
Fingerprints are cached in fingerprints.json under the app's user-data folder and reused on
later scans; a file is only re-fingerprinted when its size or modified-time changes. So the first
fingerprint scan is the slow one, and re-scans are fast. The progress banner shows how many were
new vs. reused.
Because macOS GUI apps don't inherit your shell PATH, Boom looks for fpcalc in the usual
Homebrew/MacPorts locations (/opt/homebrew/bin, /usr/local/bin, /opt/local/bin, /usr/bin)
in addition to PATH. If yours lives elsewhere, set the BOOM_FPCALC environment variable to its
full path. Toggling Fingerprint off/on re-checks, so no relaunch is needed after installing it.
Safety
- Never writes to Rekordbox or your file tags. The only file action is Trash on a duplicate copy, which uses the OS Trash/Recycle Bin (recoverable) and is triggered per file by you.
- Electron security:
contextIsolation: true,nodeIntegration: false. All file access, dialogs, and the scan pipeline run in the main process and are reached only through a typed preload bridge (window.boom). A strict Content-Security-Policy is set on the renderer.
Tech stack
Electron + React + TypeScript, built with electron-vite.
fast-xml-parser- Rekordbox XML (collection, playlists, and<TEMPO>beatgrids)music-metadata- audio tag/format reading@tanstack/react-virtual- table virtualizationwavesurfer.js- deck waveforms, overview minimap, and in/out region markerszustand- renderer state
See ARCHITECTURE.md for how parsing, matching, duplicate detection, and the
keep-recommendation work, plus where to add acoustic fingerprinting later.