# MP3DJ — online DJ app (mp3dj.info)

Two decks, 3‑band EQ, filter, crossfader, pitch/SYNC, hot cues, loops, Auto‑DJ queue and mix recording, all in the browser.
Tracks can come from **local files, Google Drive, OneDrive, YouTube (default), Spotify and Tidal**.

## What each source can do

| Source | Playback path | EQ / filter / waveform / BPM / SYNC / loops | Notes |
|---|---|---|---|
| Local files / folders | Web Audio | ✔ | Drag & drop onto a deck or use the Local tab |
| Google Drive | Web Audio | ✔ | Needs a Google OAuth client ID |
| OneDrive | Web Audio | ✔ | Needs a Microsoft app registration |
| YouTube + **browser extension** | Web Audio | ✔ | Best option: MP3DJ YouTube Bridge, runs in the DJ's own browser (see below) |
| YouTube + local companion | Web Audio | ✔ | Alternative: yt‑dlp script on the DJ's own PC |
| YouTube + server extractor | Web Audio | ✔ | `api/yt.php`; usually bot‑blocked by YouTube on a hosting IP unless `cookies.txt` is supplied |
| YouTube + Invidious | Web Audio | ✔ | Optional; set an instance URL in Settings. Public instances are often dead |
| YouTube embedded player | IFrame API | volume + coarse pitch only | Automatic fallback; always works |
| Spotify | Web Playback SDK | volume only | Premium account required; only one deck at a time (Spotify limit); no pitch |
| Tidal | Tidal embed | none | Search via Tidal API; playback only through the embed's own controls |

Streaming services do not expose raw audio to web pages, which is why they can't go through the EQ/BPM engine.

## YouTube full‑mix: the browser extension (recommended)
`extension/` hosts **MP3DJ YouTube Bridge**, a Manifest V3 extension for Chrome/Edge/Brave/Firefox. It runs [YouTube.js](https://github.com/LuanRT/YouTube.js)
inside the extension with a QuickJS WebAssembly evaluator for YouTube's obfuscated player code (no `eval`, MV3‑compliant). The site talks to it through a
content‑script bridge (`window.postMessage`). Audio is fetched by the extension from the DJ's own IP, optionally with their YouTube login, and handed to the page as a Blob.
Install instructions and the zip: <https://mp3dj.info/extension/>. Chrome Web Store policy forbids YouTube downloaders, so it is sideloaded (developer mode / temporary add‑on).

Source and build: `../extension-src/` (outside the web root). `./build.sh` bundles `src/background.js` with esbuild into `public_html/extension/unpacked/` and re-zips.
When YouTube breaks extraction: `npm update youtubei.js && ./build.sh`, and bump `version` in `static/manifest.json`.
Priority in the app: extension → local companion → Invidious → server extractor → embedded player.

## YouTube full‑mix: the local companion (alternative)
The DJ runs a tiny script on their own machine. It uses **their** IP and (optionally) their browser's YouTube login, so the web server never talks to YouTube.

```bash
pip install -U yt-dlp
python3 mp3dj-companion.py                 # add: --cookies chrome   (or firefox/edge/brave) if YouTube asks to sign in
```
Download it from <https://mp3dj.info/companion/mp3dj-companion.py>. Then open the site; the YouTube tab shows "Local companion connected". Chrome may ask to allow access to the local network the first time.

## Server extractor (optional)
`api/yt.php` shells out to `~/.local/bin/yt-dlp` and caches audio in `../cache/` (outside the web root, pruned after 3 days).
YouTube currently answers this server's IP with *"Sign in to confirm you're not a bot"*. To make it work, export cookies from a logged‑in browser
(yt‑dlp wiki: "Exporting YouTube cookies") to `/home/cash/domains/mp3dj.info/cookies.txt`. Keep yt‑dlp current: `pip install --user -U yt-dlp`.
Note that downloading is against YouTube's Terms of Service; you take that on as site owner.

## Credentials (Settings ⚙ in the app, or defaults in `js/config.js`)
All flows are client‑side PKCE, so no secrets live on the server. Register each app with:
- **JavaScript origin / SPA redirect:** `https://mp3dj.info` and redirect URI `https://mp3dj.info/`

| Setting | Where to get it |
|---|---|
| YouTube Data API key | Google Cloud Console → APIs → YouTube Data API v3 → API key (only needed for search in embed mode) |
| Google OAuth Client ID | Google Cloud Console → Credentials → OAuth client (Web). Enable Drive API. Scope `drive.readonly` |
| Microsoft App (client) ID | Azure Portal → App registrations → New; platform **SPA**; permissions `Files.Read`, `Files.Read.All` |
| Spotify Client ID | developer.spotify.com → Create app; tick *Web Playback SDK*; redirect URI `https://mp3dj.info/` |
| Tidal Client ID | developer.tidal.com → Create app; redirect URI `https://mp3dj.info/`; scopes `user.read search.read` |

## Keyboard
`Q`/`W` play–cue deck A · `O`/`P` play–cue deck B · `←`/`→` crossfader · double‑click pitch or crossfader to reset · right‑click a hot cue to clear.

## Files
```
index.html  css/app.css  js/{config,util,audio-engine,deck,app}.js  js/backends/*.js
api/yt.php                 server-side yt-dlp extractor
companion/mp3dj-companion.py   local yt-dlp companion for DJs
```
