mobygratis
v1.0.1An Ableton Live extension for browsing and importing tracks from MobyGratis directly into your Live Set.
mobygratis
An Ableton Live extension for browsing and importing tracks from MobyGratis directly into your Live Set.
Architecture
Extension Host
- Entry:
src/extension.ts, bundled todist/extension.js - Registers a context-menu action "MobyGratis: browse & import" on scopes:
AudioClip,AudioTrack,MidiTrack,ClipSlot,Scene - Opens a WebView modal dialog served from a local HTTP server (
http://127.0.0.1:PORT/) - All HTTP requests to MobyGratis APIs are proxied through the local server (ExtensionHost sandbox strips Web API globals like
fetch,URL,URLSearchParams)
Local HTTP Server
Created in startServer() on a random port. Endpoints:
| Method | Path | Purpose |
|---|---|---|
| GET | / | Serves the dialog HTML (replaces __API_BASE__ placeholder) |
| GET | /api/tracks | Lists audio tracks in the Live Set (filtered via native getObjectIsOfClass) |
| GET | /api/auth-status | Returns { signedIn, email } from stored Firebase idToken |
| POST | /api/verify-magic-link | Verifies Firebase email magic link, stores idToken |
| POST | /api/sign-out | Clears auth token |
| GET | /api/preview/<uuid> | Proxies to https://mobygratis.com/api/preview/<uuid> with Bearer token, returns pre-signed audio URL as plain text |
| POST | /api/search | Proxies to https://mobygratis.com/api/search |
Authentication
- Firebase email magic link auth via Identity Toolkit REST API (
accounts:sendOobCode+accounts:signInWithEmailLink) - Token stored as module-level
authToken(non-anonymous Firebase idToken) - Anonymous tokens rejected by MobyGratis server
Track Import Flow
- User clicks Import in the dialog
- Dialog sends
{ action: "import", slug, uuid, format }viacloseWithResult importTrack()callsPOST https://mobygratis.com/api/fetchwithid=<uuid>&format=WAV+ Bearer token- Parses response HTML for
<a href="...">to get pre-signed Cloudflare R2 download URL - Downloads audio file via
getFile()(supportsRIFF/WAV andFORM/AIFF) - Imports into Live project via
context.resources.importIntoProject() - Creates session clip: tries selected track's first empty clip slot; falls back to creating a new audio track
- All steps wrapped in
withinProgressDialogwith abort support
Track Preview
- Play button (▶) in track listing fetches
GET /api/preview/<uuid>→ proxies tohttps://mobygratis.com/api/preview/<uuid>with Bearer token → returns pre-signed Cloudflare R2 audio URL - URL is set on a hidden
<audio>element in the WebView for playback - Clicking the same button again stops playback; clicking another track switches playback
- Requires sign-in (same as import)
Key SDK Quirks
ExtensionHost Sandbox
Node.js globals stripped: fetch, URL, URLSearchParams, AbortController.
Use node:https for HTTP, manual URL parsing via parseUrl(), custom query-string building via qs().
Track Type Resolution
Live 12 beta resolves existing audio tracks as Track base class (not AudioTrack) — getObjectIsOfClass(handle, "AudioTrack") returns false for pre-existing tracks. Freshly-created tracks via song.createAudioTrack() DO resolve as AudioTrack.
Workaround: filter tracks by calling dataModel.getObjectIsOfClass() directly, and fall back to creating a new track if clip slot creation fails on the selected track.
File Format Detection
Some MobyGratis tracks return AIFF (starts with FORM) instead of WAV (RIFF). The download saves with .aiff extension and Live imports it correctly.
Firebase
- API key:
AIzaSyCTwaxUqAP88DzfAkhVaaYAdpmfl_hh5wc - Auth domain:
mobygratis-2945d.firebaseapp.com - Uses
identitytoolkit.googleapis.com/v1REST endpoints
Build & Run
npm run build # production bundle
npm run build:dev # dev bundle with sourcemaps
npm start # build + run in Extension Host
npm run package # build + create .ablx archive
Extension Host path: /Applications/Ableton Live 12 Beta.app/Contents/Helpers/ExtensionHost/ExtensionHostNodeModule.node
Dependency Versions
@ableton-extensions/sdk:^1.0.0-beta.0- Node.js:
>=24.14.1 - ESM project (TypeScript), CJS bundle via esbuild (
platform: node,format: cjs) - HTML inlined via esbuild
loader: { ".html": "text" }
Rate this extension
One rating per account; you can change it any time.
Comments
No comments yet.