Search for music, download it, tag it properly, and file it into a library — either a folder on your own machine or an AzuraCast station's request playlist.
It runs two ways from the same code: a portable Windows program you double-click, and a server deployment behind a reverse proxy.
- Search YouTube, Deezer, optionally every musicdl platform, and Soulseek peers from one box, or paste a URL to a track, album, playlist, or artist. How many results each source returns is a setting, and every search can ask for a different number
- Retries you can tune. Bulk imports get refused in batches by YouTube — 403 and "video unavailable" on tracks that download fine later. Extra attempts per track, a gap between tracks, a cooldown after repeated refusals, a final pass over what failed, and a retry button on every finished download
- Open any artist or YouTube channel to take everything, or tick only the releases, albums, and videos you actually want
- Upload a TXT, XLSX, or PDF list of music and it indexes the whole thing, then works through it
- Upload a playlist you already have — M3U, M3U8, PLS, XSPF, WPL, ASX, CUE, or foobar2000 FPL — and it fetches the tracks the playlist names, without needing the original files
- Finished files are readable by every account on the machine, with no permission fixing afterwards
- Clear the download history whenever you like; the music files are left alone
- With a Deezer subscriber ARL configured, downloads come from Deezer first — FLAC, or 320 kbps MP3 when the account does not offer FLAC (which quality you prefer is a setting) — and YouTube is only the fallback
- Prefers Deezer's copy of a track's metadata when one matches cleanly, so artist, title, album, year, and ISRC come out right instead of guessed from a video title
- Optional Soulseek source for tracks the other sources do not carry: search peers, pick the best result, and optionally share your library back — the AzuraCast media folder when one is configured, else the download folder — so the network stays alive
- Fetches synced lyrics from LRCLIB for Deezer downloads and tags them alongside the cover art
- Artist-only lines take that artist's entire catalogue by default, or a cap you choose
- Preserves audio quality — the source stream is remuxed, never re-encoded, and the tests verify the audio packets come out bit-identical
- Writes proper tags and cover art for MP3, MP4/M4A, FLAC, Ogg, and WAV/AIFF
- Optionally uploads each finished file to AzuraCast and adds it to a request playlist
- YouTube livestreams play live instead of downloading: "Add & request" on a live URL relays it straight into the station's live input so it goes on air (and a Stop button hands the air back to AutoDJ)
- Yields to outside live events. A scheduled show, remote DJ, or other live source already on air takes priority: RequestCast shows it on the home page and never stomps it with a requested stream, its own title, or an "ended" signal
- Installs and updates its own tools. yt-dlp, ffmpeg, and Deno are fetched in the background on first run, and yt-dlp, Deno, and musicdl are kept up to date after that
- Python 3.11 or newer, if running from source
- yt-dlp, ffmpeg, and
Deno — RequestCast downloads yt-dlp and Deno itself on every platform,
and ffmpeg too on Windows, into a
toolsfolder beside the program. Install ffmpeg with your package manager elsewhere
Deno is not optional for YouTube. YouTube answers with JavaScript challenges that yt-dlp cannot solve on its own, so it hands them to an external JavaScript runtime and enables Deno by default. Without one, YouTube downloads lose the better formats and fail with 403 errors that retrying will not clear.
Download the release, unzip it anywhere, and run RequestCast.exe. The setup page opens in
your own default browser — RequestCast never downloads, installs, or copies a browser of
its own. Everything it writes — settings, the job database, downloaded music — stays inside
that folder, so the whole thing can live on a USB stick.
On first run it asks for:
- A download folder. The only required answer.
- AzuraCast details — optional. Leave the box unticked and RequestCast is a plain music downloader that saves tagged files to your download folder.
- A password — opens RequestCast.
- An admin password — protects Preferences.
Use Preferences to change these later.
Diagnostics are off. When they are on, RequestCast writes a request log and collects a
support ZIP of Windows networking evidence beside the program — tens of megabytes — so it
only does that when someone has asked you for one. Turn it on in Preferences, or start
with RequestCast.exe --diagnostics. --diagnose collects one bundle and exits.
pip install -r requirements.txt pyinstaller
python scripts/build_windows.py
The result is dist/RequestCast/.
pip install -r requirements.txt
python run.py
On a server, configure it with environment variables instead of the setup page — any variable that is set overrides the settings file, so the setup page never has to be exposed.
REQUESTCAST_DOWNLOAD_DIR=/var/lib/requestcast/downloads
REQUESTCAST_STATE_DIR=/var/lib/requestcast/state
REQUESTCAST_AZURACAST_API_BASE=http://127.0.0.1:12000/api
REQUESTCAST_AZURACAST_API_KEY=...
REQUESTCAST_STATION_ID=1
REQUESTCAST_REQUEST_PLAYLIST_ID=10
REQUESTCAST_AZURACAST_LIVE_ENABLED=1 # optional; play YouTube livestreams live on request
REQUESTCAST_AZURACAST_LIVE_URL=icecast://automation:PASSWORD@127.0.0.1:8005/live
REQUESTCAST_AZURACAST_LIVE_METADATA_URL=... # optional; Liquidsoap metadata API
REQUESTCAST_AZURACAST_LIVE_METADATA_KEY=... # optional; Liquidsoap API key
REQUESTCAST_SECRET_KEY=...
REQUESTCAST_PASSWORD_SALT=... # 32 bytes, hex
REQUESTCAST_PASSWORD_HASH=... # scrypt, hex
REQUESTCAST_ADMIN_PASSWORD_SALT=...
REQUESTCAST_ADMIN_PASSWORD_HASH=...
REQUESTCAST_DEEZER_ARL=... # optional Deezer subscriber ARL
REQUESTCAST_DEEZER_QUALITY=flac # flac (lossless, falls back to 320 kbps) or mp3_320
REQUESTCAST_YOUTUBE_AUDIO_FORMAT=original # original, opus, mp3, or flac
REQUESTCAST_MUSICDL_ENABLED=1 # optional; musicdl fallback between Deezer and YouTube
REQUESTCAST_MUSICDL_SOURCES=MiguMusicClient,NeteaseMusicClient,QQMusicClient,KuwoMusicClient,QianqianMusicClient
REQUESTCAST_SOULSEEK_ENABLED=1 # optional; peer-to-peer source (needs aioslsk)
REQUESTCAST_SOULSEEK_USERNAME=...
REQUESTCAST_SOULSEEK_PASSWORD=...
REQUESTCAST_SOULSEEK_MAX_RESULTS=500 # 10 to 2000
REQUESTCAST_SOULSEEK_SHARE_DOWNLOADS=1
REQUESTCAST_DIAGNOSTICS=1 # optional; collects a support bundle, off by default
REQUESTCAST_SEARCH_LIMIT=50 # results per source and per result type, 5 to 200
REQUESTCAST_SEARCH_MUSICDL=1 # optional; include musicdl platforms in name searches
REQUESTCAST_DOWNLOAD_RETRIES=2 # extra attempts per track, 0 to 10
REQUESTCAST_DOWNLOAD_RETRY_DELAY=20 # seconds before the first retry; doubles after that
REQUESTCAST_DOWNLOAD_GAP=2 # seconds between tracks in a queue, 0 to 120
REQUESTCAST_RATE_LIMIT_COOLDOWN=180 # pause after repeated refusals, 0 to 3600
REQUESTCAST_JOB_RETRY_LIMIT=1 # times to requeue a whole failed download
REQUESTCAST_DENO=/usr/local/bin/deno # optional; found on PATH or installed automatically
REQUESTCAST_AUTO_UPDATE_TOOLS=1 # keep yt-dlp, Deno, and musicdl current
REQUESTCAST_AUTO_UPDATE_HOURS=24 # hours between update checks, 1 to 720
Setting REQUESTCAST_AZURACAST_API_KEY turns the AzuraCast integration on. Serve it with
gunicorn or waitress behind nginx, and give it a generous request timeout and body size —
indexing happens inside the upload request, and uploads are accepted up to 64 MB.
systemd unit and nginx examples are in docs/deployment.md.
With a Deezer subscriber ARL configured (the settings page, or REQUESTCAST_DEEZER_ARL),
audio comes from the Deezer account first: FLAC when the account is offered it, or 320 kbps
MP3 directly, depending on REQUESTCAST_DEEZER_QUALITY (flac by default; mp3_320
skips FLAC). Tracks the account cannot supply fall back to musicdl — which searches the
configured platforms (NetEase, QQ, Kugou, Kuwo, and Migu by default;
REQUESTCAST_MUSICDL_SOURCES changes the list, and REQUESTCAST_MUSICDL_ENABLED=0 turns
the fallback off) — and finally to YouTube, fetched with yt-dlp. REQUESTCAST_YOUTUBE_AUDIO_FORMAT
controls what YouTube audio is delivered as: original keeps the source codec untouched (the
default and the quality-preserving choice), while opus, mp3, and flac convert it with one
ffmpeg pass. Without an ARL, YouTube is the last source and Deezer is used for metadata
only, through its public API.
With REQUESTCAST_SOULSEEK_ENABLED=1 and a username and password, a separate Soulseek
search appears and can download files straight from peers. Soulseek results have no catalog
fallback, so a peer that goes offline fails that one track rather than silently substituting
another source. By default the station's AzuraCast media folder is shared back to peers
(the download folder is shared when AzuraCast is off); set REQUESTCAST_SOULSEEK_SHARE_DOWNLOADS=0
to download without sharing anything.
musicdl also widens URL input: pasting a track or playlist URL from any platform it supports (NetEase, QQ Music, Kugou, Kuwo, Migu, Qianqian, Spotify, SoundCloud, TIDAL, Qobuz, Apple Music, JOOX, JioSaavn, Jamendo, and more) downloads it through musicdl directly.
The ARL is runtime configuration. It lives in the settings file or the environment, and must never be committed to the repository.
You are responsible for having the right to download and broadcast whatever you point it at.
Run the self-contained test suite from the repository root:
python tests/run_all.pyThis includes the Deezer quality, decryption, source-preference, YouTube-fallback, setup,
configuration, import, playlist-format, artist-browsing, job-history, download-permission,
default-browser, diagnostics, request, upload, audio-preservation, URL-input, search-limit,
download-retry, and tool-update checks. The
remaining scripts under tests/ are manual integration checks: they require either the private
playlist fixtures named in the script or a live RequestCast/AzuraCast deployment.
The interface is plain HTML with real headings, labelled form controls, and no scripted widgets. It is built to be usable with a screen reader.
MIT — see LICENSE.
yt-dlp, ffmpeg, and Deno are separate programs under their own licences; RequestCast runs them, and does not include them.