Soundbored
Soundbored is an unlimited, self-hosted soundboard for Discord. It allows you to play sounds in a voice channel.
Install / Use
/learn @christomitov/SoundboredREADME
Soundbored
Soundbored is an unlimited, no-cost, self-hosted soundboard for Discord. It allows you to play sounds in a voice channel.
<img width="1468" alt="Screenshot 2025-01-18 at 1 26 07 PM" src="https://github.com/user-attachments/assets/4a504100-5ef9-47bc-b406-35b67837e116" />CLI Companion
Install the cross-platform CLI with npm i -g soundbored for quick automation. Source: christomitov/soundbored-cli.
Quickstart
- Copy the sample environment and set the minimum values:
cp .env.example .env # Required for local testing # DISCORD_TOKEN=... # DISCORD_CLIENT_ID=... # DISCORD_CLIENT_SECRET=... # PHX_HOST=localhost # SCHEME=http - Run the published container:
docker run -d -p 4000:4000 --env-file ./.env christom/soundbored - Visit http://localhost:4000, invite the bot, and trigger your first sound.
Create the bot in the Discord Developer Portal, enable Presence, Server Members, and Message Content intents, and grant Send Messages, Read History, View Channels, Connect, and Speak permissions when you invite it.
Discord App Setup
- In the Discord Developer Portal, open your application and go to Bot → enable Presence, Server Members, and Message Content intents.
- Still in the portal, go to OAuth2 → Redirects and add every URL that will serve Soundbored to the Redirects list. For example:
http://localhost:4000/auth/discord/callback(local development)https://your.domain.com/auth/discord/callback(production, replace with your domain) Discord requires the redirect in your app configuration to match exactly what the browser uses during login; otherwise, OAuth will fail.
- Copy the Client ID and Client Secret from the same page—add them to your
.envfile asDISCORD_CLIENT_IDandDISCORD_CLIENT_SECRET. - Use OAuth2 → URL Generator (scope
bot) to produce the invite link with the permissions listed above.
Local Development
mix setup # Fetch deps, prepare DB, build assets
mix phx.server # or iex -S mix phx.server
Useful commands:
mix test– run the test suite (coverage viamix coveralls).mix credo --strict– linting.
docker compose up also works for a containerized local run; it respects the same .env configuration.
Environment Variables
All available keys live in .env.example. Configure the ones that match your setup:
| Variable | Required | Purpose |
| --- | --- | --- |
| DISCORD_TOKEN | ✔ | Bot token used to play audio in voice channels. |
| EDA_DAVE | optional | Override for Discord E2EE voice negotiation in EDA. Default is enabled; set false only for troubleshooting. |
| DISCORD_CLIENT_ID / DISCORD_CLIENT_SECRET | ✔ | OAuth credentials for Discord login. |
| BASIC_AUTH_USERNAME / BASIC_AUTH_PASSWORD | optional | Protect the browser UI with HTTP basic auth. API routes stay behind API token auth. |
| SECRET_KEY_BASE | ✔ | Signing/encryption secret; generate via mix phx.gen.secret or openssl rand -base64 48. Takes precedence over SECRET_KEY_BASE_FILE.|
| SECRET_KEY_BASE_FILE | optional | Path to file containing signing/encryption secret (e.g. for docker secrets). Preferred for security. |
| PHX_HOST | ✔ | Hostname the app advertises (localhost for local runs). |
| SCHEME | ✔ | http locally, https in production. |
| AUTO_JOIN | optional | Set to true to let the bot auto-join voice channels. |
Deployment
The application is published to Docker Hub as christom/soundbored.
Simple Docker Host
docker pull christom/soundbored:latest
docker run -d -p 4000:4000 --env-file ./.env christom/soundbored
If you place the container behind your own reverse proxy, set PHX_HOST and SCHEME in .env to match the external URL and terminate TLS in your proxy. No additional compose files are required.
Usage
After inviting the bot to your server, join a voice channel and type !join to have the bot join the voice channel. Type !leave to have the bot leave. You can upload sounds to Soundbored and trigger them there and they will play in the voice channel.
The bot is also able to auto-join and auto-leave voice channels. This is controlled by the AUTO_JOIN environment variable. Leave it unset (or false) to disable, or set it to true to have the bot join voice channels with members and auto-leave when the last user leaves.
API
The API is used to trigger sounds from other applications. Create a personal API token in Settings after signing in, then send it as Authorization: Bearer <USER_API_TOKEN>.
Current API workflow supports:
- listing sounds
- uploading local files
- creating URL-backed sounds
- queueing playback for a specific sound
- stopping active playback
Endpoints
List sounds
curl https://soundboardurl.com/api/sounds \
-H "Authorization: Bearer <USER_API_TOKEN>"
Returns 200 OK with %{data: [...]}.
Upload a local file
curl -X POST https://soundboardurl.com/api/sounds \
-H "Authorization: Bearer <USER_API_TOKEN>" \
-F "source_type=local" \
-F "name=wow" \
-F "file=@/path/to/wow.mp3" \
-F "tags[]=meme" \
-F "volume=90"
Returns 201 Created with %{data: sound}.
Create a URL-backed sound
curl -X POST https://soundboardurl.com/api/sounds \
-H "Authorization: Bearer <USER_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"source_type":"url","name":"wow","url":"https://example.com/wow.mp3","tags":["meme","reaction"],"volume":90}'
Returns 201 Created with %{data: sound}.
Queue playback for a sound
curl -X POST https://soundboardurl.com/api/sounds/123/play \
-H "Authorization: Bearer <USER_API_TOKEN>"
Returns 202 Accepted with %{data: %{status: "accepted", ...}} because playback is queued asynchronously.
Stop active playback
curl -X POST https://soundboardurl.com/api/sounds/stop \
-H "Authorization: Bearer <USER_API_TOKEN>"
Returns 202 Accepted with %{data: %{status: "accepted", ...}} because the stop request is also asynchronous.
Errors use %{error: message} or %{errors: changeset_errors} depending on whether the failure is request-level or validation-level.
Changelog
v1.7.0 (2026-03-07)
✨ New Features
- Switched the Discord voice/runtime integration over to EDA, bringing DAVE support for current Discord voice encryption negotiation.
- Expanded the authenticated API so external tools can list sounds, upload local files, create URL-backed sounds, queue playback, and stop playback with personal user tokens.
- Public URL handling is now centralized so Discord invite/auth links and API examples stay aligned with the configured host and scheme.
⚙️ Improvements
- Audio playback startup is faster and more resilient, reducing common delay/glitch cases during sound playback.
- Voice runtime handling was split into smaller policy/command/presence modules, making Discord connection behavior easier to reason about and maintain.
- Upload and tag persistence flows were consolidated so the LiveView and API paths share the same domain logic.
- The app now boots in a degraded mode when optional voice runtime capabilities are unavailable instead of failing startup entirely.
🧪 Tests & Quality
- Added coverage for command handling, runtime capability detection, public URL behavior, API auth, upload flows, and collaborative sound management rules.
- Clarified the intended collaboration model: any signed-in user can edit shared sound details, but only the original uploader can delete a sound.
- Removed stale dependencies and cleanup scaffolding while continuing the broader code-health refactor.
v1.6.0 (2025-10-01)
✨ New Features
- New consolidated
Settingsview replaces the standalone API tokens screen and keeps token creation, revocation, and inline API examples in one place. - Stats dashboard adds a week picker, richer recent activity stream, and refreshed layout under the new name “Stats”.
- “Play Random” now respects whatever filters are active, pulling from the current search results or selected tags only.
⚙️ Improvements
- Shared tag components and modal tweaks streamline sound management and reduce layout shifts.
- Navigation highlights the active page and keeps Settings aligned with the rest of the app.
- Mobile refinements across the main board and settings eliminate horizontal scrolling and polish button spacing.
- Basic Auth now quietly skips enforcement when credentials are not configured instead of blocking the UI.
🧪 Tests & Quality
- Expanded LiveView coverage for the new Settings page, Stats interactions, and filtered random playback.
- Updated CI workflow and Dependabot configuration keep coverage and dependency checks automated.
📦 Dependencies
- Bumped Phoenix stack and related dependencies, plus cleaned up mix configuration and docs to match the new release.
v1.5.0 (2025-09-14)
✨ New Features
- User-scoped API tokens with DB storage (generate/revoke in Settings > API Tokens).
- API requests authenticated via
Authorization: Bearer <token>are attributed to the token’s user and increment stats accordingly. - In-app API help with copy-to-clipboard curl commands that auto-fill your site URL and token.
- Added Settings link in the navbar for quick access.
- Released a new CLI for easier local and CI integrations.
⚙️ Improvements
- Search bar: reduced debounce to
Related Skills
node-connect
337.4kDiagnose OpenClaw node connection and pairing failures for Android, iOS, and macOS companion apps
frontend-design
83.2kCreate distinctive, production-grade frontend interfaces with high design quality. Use this skill when the user asks to build web components, pages, or applications. Generates creative, polished code that avoids generic AI aesthetics.
openai-whisper-api
337.4kTranscribe audio via OpenAI Audio Transcriptions API (Whisper).
commit-push-pr
83.2kCommit, push, and open a PR
