Dig Discogs by ear.
Digga is a local-first app for digging through Discogs records by ear. Choose the styles and years you care about, load the releases, then listen to a few seconds of each record and decide with one key. It keeps track of what you have heard, what you want, and what is still waiting.
Use it to build a DJ wantlist, work through a label's back catalogue, or find a tune you remember from an old radio set but never knew the name of. The defaults focus on late-1990s and early-2000s drum & bass; the styles, years, and formats are yours to change.
Digga is the app. Your twelves are what it finds.
Triage puts the release details, tracklist, and YouTube player on one screen. Tracks start partway through, at a position you choose, and the next track and the next release are preloaded while you listen. Mark a record as a want, skip it, flag a grail, or leave it for later. Undo walks back through your session.
| Key | Action |
|---|---|
Space |
Play or pause |
J / K |
Next or previous track |
← / → |
Seek backward or forward |
A |
Want |
R |
Skip |
C |
Grail: a top want or the tune you have been hunting |
L |
Snooze for another listening session |
N |
Move on without a verdict; keep the record in the queue |
X |
Hide the record's label from the queue |
E |
Note on the record, saved with its verdict |
Z |
Undo |
? |
Show the keys for the current page |
You can also mark individual tracks, jump to a percentage of a video, and open the release on
Discogs. Records play the videos of all their pressings. When nothing plays, S searches
YouTube; copy a video's link, press ⌘V in Digga, and it is attached to the release and plays. See the full keymap.
Twelves brings together your wants, grails, maybes, snoozed records, and imported Discogs wantlist and collection. Filter and sort the shelves, add notes, change a verdict, or return to snoozed records for another listen. The Tracks shelf lists every track you marked grail or keep, with a note of its own.
With your Discogs account configured, A and C add a record to your Discogs
wantlist, with the tracks you marked and your note as the want's note. A grail stays a grail in
Digga. Undo reverses the addition. If you use a Discogs Maybe list, select it in Settings to
enable M. Digga records maybes locally; adding them to the Discogs list is manual.
Settings controls the styles, years, formats, and countries in your queue, plus whether to skip
releases without videos. Format details such as Unofficial Release or Compilation can leave
records out, and so can hidden labels; X in Triage hides the label on screen, and Z brings it
back. Sweep label by label in catalogue order,
browse by country or year, or use a daily shuffle. Set where playback starts and how far
the seek keys jump.
Imports of your collection and wantlist can keep records you already know out of the queue. The session counter shows how many you have judged, how many remain, and an estimated time to finish once you have a listening pace.
Digga runs on your computer, in a window of its own on macOS or in a browser. The catalogue and saved listening decisions live in a local SQLite database. Playback uses YouTube, and account imports, fresh release data, and wantlist updates use Discogs, so those features need an internet connection.
Verdicts, notes, track marks, and listens are saved from the first one. Z undoes the last
verdict, and takes a want back off your Discogs wantlist; Twelves lets you judge a record again.
A Discogs token is needed for wantlist updates, but your catalogue and verdicts remain local.
Use Node.js 24.11+ on the 24.x line and npm. Vite+ is installed with the project, so the commands
below do not need a global vp installation.
git clone https://github.com/razorjack/digga.git
cd digga
npm install
npm run build
npm run serveKeep the server running and open http://localhost:3456. Use
localhost: some YouTube videos refuse to play when the page is opened at 127.0.0.1. On later
runs, npm run serve is enough. Rebuild after updating the frontend.
On macOS, Digga can also run in a window of its own, on the same library:
npm run electron:devThis builds the frontend, starts the server on a free port and opens the window; quitting the
app stops the server. One Digga uses a library at a time, so stop npm run serve first. A
terminal inside another Electron app may set ELECTRON_RUN_AS_NODE=1, which stops Electron from
opening a window; unset it there.
To build the app for Macs with Apple silicon:
npm run electron:packageIt builds the frontend and writes release/Digga-0.0.0-arm64.dmg, with the app itself in
release/mac-arm64/Digga.app. The app is ad-hoc signed and not notarized, and it opens the same
library as npm run serve.
Draft, to be confirmed on the first release. These steps follow macOS 15 and later; the dialogs have not been seen with a downloaded copy of this build yet.
Digga is not notarized by Apple, so macOS refuses to open a downloaded copy until you allow it:
- Open the dmg and drag Digga to Applications.
- Open Digga. macOS says it could not verify that Digga is free of malware; choose Done.
- Open System Settings > Privacy & Security. Under Security, beside the message that Digga was blocked, choose Open Anyway, then confirm with Open Anyway and your password.
Instead of steps 2 and 3, you can remove the download mark in Terminal:
xattr -dr com.apple.quarantine /Applications/Digga.appWhen the app first reads or saves your Discogs token, macOS asks whether Digga may use the "Digga Safe Storage" item in your Keychain; choose Always Allow. Every new build of the app asks again. If you choose Deny, Digga cannot read the saved token, and Settings asks for it again.
A new library opens the setup, which takes about 20 minutes, most of it waiting:
- Fetch the catalogue. Digga downloads the newest monthly releases dump,
discogs_YYYYMMDD_releases.xml.gzfrom Discogs data dumps, about 10.5 GB, and checks it against the checksum Discogs publishes. The first screen says how big it is and how much space the disk has before anything downloads. - Bring your Discogs (optional). Paste a personal access token from Discogs Settings → Developers; Digga takes your username from it. It then imports your collection and wantlist, so records you own or want stay out of the queue. Without a token, your username reads a public collection and wantlist.
- Pick your sound. Every Discogs style, with its size, and the years to dig, over a histogram of their releases. Styles your Discogs records mostly carry are picked already, and the estimate says how many releases the picks come to.
- Fill the crate. The load reads the dump while it downloads, and keeps the releases in your styles and years. It takes 15 to 20 minutes, but records arrive from the first seconds: "Start digging" lights up once 500 wait, and the header shows the load while you dig.
Start digging digs for real, so your verdicts are kept from the first one.
Digga keeps its library in a folder of your user account: ~/Library/Application Support/Digga
on macOS, %APPDATA%\Digga on Windows and ~/.config/Digga on Linux. It holds the database, its
daily backups, your settings in digga.config.json and the Discogs token you save in Settings.
Dumps go in the cache folder, which backups skip: ~/Library/Caches/Digga/dumps,
%LOCALAPPDATA%\Digga\Cache\dumps or ~/.cache/Digga/dumps. npm run serve prints both.
To keep the library elsewhere, set DIGGA_DATA_DIR, and DIGGA_DUMPS_DIR or
DIGGA_CONFIG_FILE if needed, in the environment or in a .env in the folder you run Digga from
(.env.example lists them). A library placed with DIGGA_DATA_DIR keeps its
dumps inside it unless DIGGA_DUMPS_DIR says otherwise. DIGGA_DUMPS_DIR also puts the dumps on
another disk when the one with the cache folder is short of space. In the desktop app, the setup
offers another folder then; Digga keeps that choice in dumps-folder.json in the library, and
DIGGA_DUMPS_DIR overrides it.
Digga reads the catalogue from the dump, not through your account. It uses the token only for things you do, one request at a time:
- your account: when you connect, and each time you open Settings, which shows whose token is saved and offers your lists for the Maybe list, about two requests a visit;
- your collection and wantlist: one request per 100 records, when you import them;
- the Maybe list: when you import it, or press
Iin Twelves; - a want: one request 1.5 s after
AorC, and one more whenZtakes it back, and in Twelves when you re-judge a want onto or off the wantlist; - a price: one request when you press
P, for the record on screen; - a seller's shop: one request per 100 listings, when you read it.
Digga leaves 1.1 s between requests, which keeps it under Discogs' limit of 60 a minute. It
pauses when Discogs says the limit is nearly used, and waits as long as Discogs asks when it says
too many. Nothing runs in the background. Digga never changes your collection or lists, and never
reads orders or messages. A Discogs token cannot be limited to some actions, so Digga saves it
only on this computer, in secrets.env in the library folder (or reads DISCOGS_TOKEN from the
environment), and sends it only to api.discogs.com. The window encrypts it there with the system's
keychain when there is one; otherwise, and in the browser version, it is saved as text, and
Settings says so. The command
line cannot read a token the window encrypted, so its imports then need DISCOGS_TOKEN. You can
revoke the token on discogs.com at any time.
Settings changes everything the setup chose, and digga.config.json holds it:
universe.stylesselects the styles to load, by Discogs' exact names, such asDrum n Bass.universe.loadYearslimits the years loaded into the library. The setup loads three years more on each side of the years you dig;nullloads all years for the selected styles.universe.coveragealso loads releases in other styles from the labels and artists of the records you want or own, when those labels and artists mostly release the selected styles.filtersnarrows what you listen to from the loaded catalogue. These filters change in Settings without loading the dump again.discogs.usernameis the account to use for collection and wantlist imports.
Changing the queue filters is immediate; loading more styles or years takes another dump load.
Discogs publishes a new dump at the start of each month. "Update from the newest dump" in
Settings, under Library, loads it: it adds the records Discogs has added since, and F in Triage
digs just those. Settings also lists the dumps in the folder, says which one the library came
from, and deletes the ones you no longer want, about 10 GB each.
The dump has no prices or have/want counts. When a record might be worth buying, press P in
Triage and Digga asks Discogs for them. The same request brings the release's current videos, so a
track whose video was added to Discogs after the dump becomes playable.
Every setup step also runs from the command line:
npm run digga -- dump update # download the newest dump unless it is there, then load it
npm run digga -- dump download # the newest dump into the dumps folder, checked against its checksum
npm run digga -- dump load ~/Library/Caches/Digga/dumps/discogs_YYYYMMDD_releases.xml.gz
npm run digga -- import collection
npm run digga -- import wantlistTo rehearse the setup without downloading from Discogs, serve a dump you have with
node tools/dev/fake-services.ts <dump.xml.gz>, which also fakes the Discogs API (token
e2e-token-dj) and YouTube's oEmbed. Start Digga with the three addresses it prints
(DIGGA_DUMPS_URL, DIGGA_DISCOGS_API_URL, DIGGA_YOUTUBE_OEMBED_URL) and a throwaway
DIGGA_DATA_DIR and DIGGA_DUMPS_DIR.
| Command | Purpose |
|---|---|
npm run digga -- stats |
Show catalogue size, verdicts, remaining records, and ETA |
npm run digga -- import list |
Import the Maybe list selected in Settings |
npm run digga -- backup |
Write both backups now (see below) |
npm run digga -- restore <file> |
Restore a backup (see below) |
npm run digga -- serve --port 3457 |
Use a different port |
npm run digga -- help |
Show every CLI command and option |
Discogs only learns about your wants and grails, through your wantlist. Every skip, maybe,
snooze, note, track mark and tune you heard exists only in Digga's database on your computer, so
Digga backs them up every day. Both kinds of backup go to the backups folder in the library
folder:
| System | Backups folder |
|---|---|
| macOS | ~/Library/Application Support/Digga/backups |
| Windows | %APPDATA%\Digga\backups |
| Linux | ~/.config/Digga/backups, or $XDG_CONFIG_HOME/Digga/backups when set |
With DIGGA_DATA_DIR set, it is backups in that folder. Settings shows the path on its
Backups tab.
decisions-YYYY-MM-DD.json.gz: your decisions. Every verdict, your notes and track marks, the tunes you heard and every listen, the YouTube links you attached, the videos a record marked "no audio" had, the history of every decision, your recent digging sessions and your settings. Your imported wantlist, collection and Maybe list are in it too. Release details are not: the Discogs ids find them again. Digga keeps the last 30. A day on which nothing changed adds no file, so they cover your last 30 days of digging, and a library with nothing decided in it yet writes none. A library with 40,000 decisions, 120,000 logged changes to them and 300,000 listens writes about 17 MB.digga-YYYY-MM-DD.sqlite: the whole database. Digga keeps the last two. It restores everything with one command, but is 100 MB or more.
The server writes both when it starts, and again each day while it runs. npm run digga -- backup
writes both at once.
gunzip -c decisions-2026-09-30.json.gz shows what a decisions backup holds: a header line, then
one record per line, each naming its kind in record. Here, Stakka & Skynet's Clockwork is a
want, and Crime Audio by Item A La Playa is a grail, marked on its track (lines shortened):
{"app":"digga","kind":"decisions","version":3,"backedUpAt":"2026-09-30T21:04:12.518Z","dataHash":"9c41…","config":{…}}
{"record":"verdict","key":"m:34620","status":"accepted","source":"triage","releaseId":8667,"decidedAt":"2026-09-30T20:41:07.332Z","updatedAt":"2026-09-30T20:41:07.332Z"}
{"record":"verdict","key":"r:620767","status":"candidate","source":"triage","releaseId":620767,"decidedAt":"2026-09-30T20:52:39.905Z","updatedAt":"2026-09-30T20:52:39.905Z"}
{"record":"trackMark","releaseId":620767,"position":"A","mark":"candidate","notes":null,"decidedAt":"2026-09-30T20:52:31.118Z","heardKey":"item a la playa - crime audio",…}
{"record":"heardTune","heardKey":"stakka and skynet - clockwork","firstReleaseId":8667,"secondsListened":14.2,…}
{"record":"listen","eventId":"3f0c…","releaseId":8667,"position":"A","videoId":"…","seconds":14.2,…}keyis the record:m:and a Discogs master id, like discogs.com/master/34620, orr:and a release id for a release without a master, like discogs.com/release/620767.statusis the verdict:accepted(want),candidate(grail),rejected(skip),maybe,snoozedorno_audio, orseenfrom the browser history import of earlier versions. A record you skipped looks the same with"status":"rejected". What your Discogs collection, wantlist and Maybe list hold is inmemberships, apart from your decisions.sourceistriagefor a decision you made in Digga, orseed:historyfor a page the history import of earlier versions found.releaseIdis the pressing you heard. Times are in UTC.
To restore, stop the server first. With a database copy, run
npm run digga -- restore digga-YYYY-MM-DD.sqlite, with a path or the name of a file in the
backups folder, and that is all. It keeps the database it replaces in the backups folder as
before-restore-YYYY-MM-DD-HHMMSS.sqlite, and upgrades a copy from an older Digga. The
before-migration-<version>.sqlite copy that Digga writes before a schema upgrade restores the
same way. Without a database copy:
- Load the catalogue again:
npm run digga -- dump update, or Update from the newest dump in Settings. - Run
npm run digga -- restore decisions-YYYY-MM-DD.json.gz, with a path or the name of a file in the backups folder. It copies the database first, then merges the file in: each verdict and track mark keeps whichever side changed it last, so one you changed or deleted after the backup was written stays as it is. To go back to an earlier state, restore a database copy instead. - Import your collection and wantlist again, so what changed on Discogs since the backup applies.
Both backups live on the same disk as the library. To survive a lost disk, copy the decisions files somewhere else, such as a cloud drive. Settings also exports your verdicts and track marks as JSON or CSV, with artist, title and label, for reading outside Digga.
Run the API server and frontend dev server in separate terminals:
npm run servenpm run devOpen http://localhost:5173. The dev server proxies API requests to the
backend on port 3456. Both use your library; to develop against another one, set DIGGA_DATA_DIR
in .env.
npm run verifyThis runs formatting, lint, type checks, tests, the portability checks, and Svelte checks. The frontend uses Svelte 5; the server uses Hono and SQLite. Node runs the server's TypeScript sources directly.
Digga runs as a local server and browser app, and in an Electron window, from the repository
(npm run electron:dev, electron/) or packaged as an ad-hoc signed macOS app
(npm run electron:package).
- Architecture and data model
- Discogs and YouTube integration notes
- Design brief and decisions
- Roadmap and Electron plan
- Contributor guide
MIT; see LICENSE.




