SkillAgentSearch skills...

Soundbored

Soundbored is an unlimited, self-hosted soundboard for Discord. It allows you to play sounds in a voice channel.

Install / Use

/learn @christomitov/Soundbored
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Soundbored

Coverage Status Build Status

Soundbored is an unlimited, no-cost, self-hosted soundboard for Discord. It allows you to play sounds in a voice channel.

Hexdocs

<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

  1. 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
    
  2. Run the published container:
    docker run -d -p 4000:4000 --env-file ./.env christom/soundbored
    
  3. 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

  1. In the Discord Developer Portal, open your application and go to Bot → enable Presence, Server Members, and Message Content intents.
  2. 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.
  3. Copy the Client ID and Client Secret from the same page—add them to your .env file as DISCORD_CLIENT_ID and DISCORD_CLIENT_SECRET.
  4. 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 via mix 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 Settings view 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

View on GitHub
GitHub Stars242
CategoryDevelopment
Updated2d ago
Forks18

Languages

Elixir

Security Score

80/100

Audited on Mar 24, 2026

No findings