Skip to content

Latest commit

Β 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

HeyHeyBot 🎡

HeyHeyBot is a simple Discord bot with soundboard functionality that enhances your voice chat experience. Whenever a user joins a voice chat, the bot plays a customizable greeting audio for that user, announcing their arrival to others in the channel.

Features 🌟

  • Personalized Greetings: Assign a unique audio file for each user. When they join the voice chat, their greeting is played.
  • Soundboard Functionality: By sending !playsound to a chat on Discord server, you can request buttons with the names of available sounds. Clicking a button will play the corresponding sound in the voice chat.
  • Automatic Audio Playback: The bot joins the voice channel to play audio, ensuring a seamless experience for users.
  • Webserver for Audio Uploads: Application includes a webserver that allows users to upload their audio files with ease if enabled.
  • User-Specific Greetings: Through the web interface, you can:
    • Upload custom greeting sounds for specific Discord users
    • Set existing soundboard sounds as user greetings
    • View and manage greeting history with automatic versioning
  • HTTPS Support: Secure your web interface with SSL/TLS encryption for added security.

Setup & Configuration πŸ› οΈ

Prerequisites

Get your Discord bot token from Discord Developer Portal. Token can be requested by creating a new application and clicking Reset Token button on a Bot page (link to this page looks like this: https://discord.com/developers/applications/{APPLICATION_ID}/bot).

Easiest way to run the bot is using Docker.
Change docker-compose.yml file to match your settings (example below):

services:
  heyheybot:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: HeyHeyBot
    environment:
      - DISCORD_TOKEN=PLACE_YOUR_DISCORD_TOKEN_HERE
      - DISCORD_CONTINUE_PRESENCE=True
      - DISCORD_MUTING_ANNOUNCE=False
      # - WEBPAGE_USERNAME=YOUR_WEBPAGE_USERNAME
      # - WEBPAGE_PASSWORD=YOUR_WEBPAGE_PASSWORD
      # - WEBPAGE_HOST=localhost
      # - WEBPAGE_PORT=5100
      # - SSL_CERT=/path/to/cert.pem
      # - SSL_KEY=/path/to/key.pem
    volumes:
      - ./data:/app/data
      - ./logs:/app/logs
      # For SSL certificates:
      # - ./certs:/app/certs
    # ports:
    #   - 5100:5100
    restart: unless-stopped

You can set environment variables in .env file in the root directory of the project. Or you can set them directly in docker-compose.yml file.
Possible environment variables:

  • DISCORD_TOKEN - Discord bot token (required)
  • DISCORD_CONTINUE_PRESENCE - Whether bot will leave voice channel after playing audio (default: False)
  • DISCORD_MUTING_ANNOUNCE - Whether to announce muting/unmuting (default: True)
  • DISCORD_ARRIVAL_ANNOUNCE - Whether to announce user arrivals (default: True)
  • DISCORD_LEAVE_ANNOUNCE - Whether to announce user departures (default: True, DISCORD_LEAVING_ANNOUNCE is accepted as an alias)
  • DISCORD_ANNOUNCE_COOLDOWN - Seconds before the same user can trigger the same announcement again, 0 disables it (default: 5)
  • DISCORD_VOLUME - Playback volume, 1.0 is the file's own level (default: 1.0). Keeping it at 1.0 is noticeably cheaper on CPU, see Performance
  • DISCORD_LOGLEVEL - Logging level (default: WARNING)
  • WEBPAGE_USERNAME - Username for a webpage where you can upload files (required for the webserver to start)
  • WEBPAGE_PASSWORD - Password for this webpage (required for the webserver to start)
  • WEBPAGE_HOST - Host for this webpage (default localhost, set to something like 0.0.0.0 if you want to access webpage from outside)
  • WEBPAGE_PORT - Port for webserver to use (default 5100, also uncomment ports section in docker-compose.yml)
  • SSL_CERT - Path to SSL certificate file (optional, for HTTPS support)
  • SSL_KEY - Path to SSL private key file (optional, for HTTPS support)
  • SECRET_KEY - Fixed key for signing web sessions (optional; without it everyone is logged out on restart)
  • MAX_UPLOAD_MB - Maximum upload size in megabytes (default: 16)
  • TRUSTED_PROXIES - Number of reverse proxies in front of the panel (default: 0, set to 1 behind Traefik/nginx, see Behind a reverse proxy)
  • SESSION_COOKIE_SECURE - Force the Secure flag on the session cookie (default: on when SSL or TRUSTED_PROXIES is set)
  • UPLOAD_FOLDER / GREETINGS_FOLDER - Override where soundboard and greeting files live (optional)
  • PROXY_URL - Proxy for the Discord API and gateway, e.g. http://host:3128 or socks5://host:1080 (optional, see Using a proxy)
  • PROXY_USERNAME / PROXY_PASSWORD - Credentials for that proxy (optional)

Then run the following command in the root directory of the project:

docker compose up -d

Configuration

  • Soundboard: Store greeting audios in the ./data/audio directory. Only .wav files are supported.
  • Announcements: Store announcement audios in the ./data/greetings, ./data/leavings and ./data/mutings directories. Default files should be hello.wav, bye.wav and muted.wav respectively. Custom greeting files are automatically versioned and stored as {discord_name}.wav for current greetings and {discord_name}.{version}.wav for previous versions. Only .wav files are supported.
  • Naming greetings: a greeting is matched by Discord user id first (123456789012345678.wav), then by user name (cooldiscordname.wav). The user id never changes when someone renames themselves, so it is the more reliable option - right-click a user in Discord with Developer Mode on and pick Copy User ID. Non-ASCII names (Cyrillic, CJK) are supported.

Example directory structure:

data
β”œβ”€β”€ audio
β”‚   β”œβ”€β”€ fuze.wav
β”‚   β”œβ”€β”€ amogus.wav
β”‚   β”œβ”€β”€ pew.wav
β”‚   └── ...
β”œβ”€β”€ greetings
β”‚   β”œβ”€β”€ hello.wav
β”‚   β”œβ”€β”€ cooldiscordname.wav
β”‚   β”œβ”€β”€ cooldiscordname.1.wav
β”‚   β”œβ”€β”€ cooldiscordname.2.wav
β”‚   └── ...
β”œβ”€β”€ leavings
β”‚   β”œβ”€β”€ bye.wav
β”‚   β”œβ”€β”€ cooldiscordname.wav
β”‚   └── ...
└── mutings
    β”œβ”€β”€ muted.wav
    β”œβ”€β”€ cooldiscordname.wav
    └── ...

HTTPS Configuration

To enable HTTPS:

  1. Prepare your SSL certificate and private key files (e.g., using Let's Encrypt)
  2. Add the certificate files to your Docker volume by adding this to docker-compose.yml:
    volumes:
      - ./certs:/app/certs
  3. Set the SSL environment variables in docker-compose.yml:
    environment:
      - SSL_CERT=/app/certs/cert.pem
      - SSL_KEY=/app/certs/key.pem
  4. Restart the container for changes to take effect

Adding a bot to your server

  1. Go to Discord Developer Portal and select your application.
  2. Go to OAuth2 tab and select URL Generator.
  3. Select bot scope and set bot permissions. At least Read Messages/View Channels, Send Messages in Threads, Connect, Speak, Use Voice Activity and Priority Speaker permissions are required.
  4. Copy the generated link and paste it in your browser. Select the server you want to add the bot to and click Authorize.
  5. Bot should now be visible in the server's member list.

Logs

Logs are stored in the ./logs directory and rotated by size (1 MB). History of 5 logs is kept.

Webserver

You can use web interface to manage audio files and user greetings. The interface provides:

  1. Soundboard Management:

    • Upload new sounds to the soundboard
    • Play and delete existing sounds
    • Set any soundboard sound as a user's greeting
  2. User Greetings Management:

    • Upload custom greeting sounds for specific Discord users
    • View all users' greeting sounds with version history
    • Play and delete greeting sounds
    • Automatic versioning of greeting sounds (old versions are preserved)

When file is uploaded it automatically converts to .wav. Use !playsound in Discord chat to request for a new updated soundboard buttons.

WEBPAGE_USERNAME and WEBPAGE_PASSWORD is required for a webserver to start. When it starts you can access it via browser:

  • HTTP: http://{WEBPAGE_HOST}:{WEBPAGE_PORT}/
  • HTTPS (if configured): https://{WEBPAGE_HOST}:{WEBPAGE_PORT}/

Default location is http://localhost:5100/ or https://localhost:5100/ if HTTPS is enabled.

Uploaded files will be automatically converted to WAV and volume will be normalized to -16.

Usage πŸš€

  1. Join a voice chat and experience personalized greetings!
  2. Trigger the soundboard by typing !playsound and click on the displayed buttons to play the sounds from ./data/audio directory. Soundboard will be send to chat as a message and will remain there. If you update the ./data/audio directory, you need to request new soundboard by typing !playsound again.
  3. Upload new audio to soundboard via webpage if you have set it up.
  4. Set custom greeting sounds for specific users through the web interface:
    • Upload a new sound directly as a greeting
    • Set an existing soundboard sound as a greeting
    • View and manage greeting history for each user

The bot handles multiple servers independently - each server gets its own voice connection and its own playback queue. The audio files themselves are shared between servers.

Behind a reverse proxy

To serve the panel on your own domain with automatic HTTPS, put it behind a reverse proxy instead of using SSL_CERT/SSL_KEY. Two settings matter:

  • WEBPAGE_HOST=0.0.0.0 - with the default localhost the panel only listens inside the container and the proxy cannot reach it.
  • TRUSTED_PROXIES=1 - makes the panel read X-Forwarded-For / X-Forwarded-Proto. Without it every request appears to come from the proxy itself, so one failed-login lockout would lock out every user at once, and generated URLs would say http.

Drop the ports: mapping once the proxy is in front, otherwise the panel stays reachable over plain HTTP on that port, bypassing TLS.

Example with Traefik (assumes Traefik already runs with a webnet network and a myresolver certificate resolver):

services:
  heyheybot:
    image: heyheybot:latest
    container_name: HeyHeyBot
    environment:
      - DISCORD_TOKEN=${DISCORD_TOKEN}
      - WEBPAGE_USERNAME=${WEBPAGE_USERNAME}
      - WEBPAGE_PASSWORD=${WEBPAGE_PASSWORD}
      # Must listen on all interfaces for Traefik to reach it
      - WEBPAGE_HOST=0.0.0.0
      - WEBPAGE_PORT=5100
      # Traefik terminates TLS and is the only hop in front of us
      - TRUSTED_PROXIES=1
      # Keeps logins alive across restarts
      - SECRET_KEY=${SECRET_KEY}
    volumes:
      - ./data:/app/data
      - ./logs:/app/logs
    # No ports: - Traefik reaches the container over the shared network
    labels:
      - "traefik.enable=true"
      - "traefik.docker.network=webnet"
      - "traefik.http.routers.heyheybot.rule=Host(`hey.example.com`)"
      - "traefik.http.routers.heyheybot.entrypoints=websecure"
      - "traefik.http.routers.heyheybot.tls.certresolver=myresolver"
      - "traefik.http.services.heyheybot.loadbalancer.server.port=5100"
    networks:
      - webnet
    restart: unless-stopped

networks:
  webnet:
    external: true

The panel is now internet-facing, so use a long WEBPAGE_PASSWORD. The built-in lockout (5 failed attempts, 5 minute block) applies per client IP once TRUSTED_PROXIES is set.

Using a proxy

If the Discord API is not reachable directly, set PROXY_URL to an HTTP or SOCKS proxy:

environment:
  # HTTP proxy
  - PROXY_URL=http://proxy.example.com:3128
  # or a SOCKS5 proxy
  # - PROXY_URL=socks5://proxy.example.com:1080
  # Credentials can be given separately instead of inline in the URL
  # - PROXY_USERNAME=user
  # - PROXY_PASSWORD=secret

Supported schemes are http, https, socks4, socks4a, socks5 and socks5h. SOCKS support comes from aiohttp-socks, which is already in requirements.txt.

Important: the proxy covers the REST API and the gateway websocket only. Voice traffic stays direct, so the bot still needs outbound UDP access to play audio.

To be precise about why: SOCKS5 can proxy UDP - the protocol has a UDP ASSOCIATE command (RFC 1928). It does not help here for two independent reasons:

  1. discord.py opens the voice socket itself, as a plain socket.socket(AF_INET, SOCK_DGRAM) in discord/voice_state.py. It never asks the HTTP connector, so no proxy setting can reach it.
  2. The libraries in use are TCP-only anyway: aiohttp_socks.ProxyConnector subclasses aiohttp.TCPConnector, and python-socks defines UDP_ASSOCIATE = 0x03 as a constant without any connector ever sending it.

HTTP proxies cannot do it at all - CONNECT is TCP-only (UDP would need CONNECT-UDP/MASQUE over HTTP/3).

If UDP is blocked on your network, route the whole container through a VPN (WireGuard/OpenVPN) or a transparent tun2socks-style layer instead of setting PROXY_URL.

Performance

  • Audio is streamed straight from disk by FFmpeg; nothing is preloaded into memory.
  • At DISCORD_VOLUME=1.0 FFmpeg encodes Opus itself, so Python never touches the audio stream. Any other volume forces per-packet re-encoding in Python, which costs noticeably more CPU. Prefer normalizing the files themselves (the web panel already does this on upload) over changing the volume.
  • Playback is serialized per server and waits for the real end of the sound, so announcements queue up instead of cutting each other off.
  • DISCORD_ANNOUNCE_COOLDOWN prevents a user who rejoins in a loop from making the bot spam a channel.
  • Announcements are skipped entirely when nobody is in the target channel to hear them.
  • The web panel caches directory listings and serves audio with revalidation headers.

Running the tests

python3 -m unittest discover -s tests -v

The web panel tests need flask and ffmpeg installed; they are skipped when ffmpeg is missing.

Additional Information πŸ“š

Converting audio files to WAV

You can use FFmpeg to convert audio files to WAV format.
Simpliest command:

ffmpeg -i "sound.mp3" "sound.wav"

Changing volume to 70% of original:

ffmpeg -i "sound.mp3" -af "volume=0.7" "sound.wav"

Trimming audio from 0 to 4 seconds:

ffmpeg -i "sound.mp3" -ss 0 -to 4 "sound.wav"

If we also want it to fading out at the end (fade out starts at 3 seconds and lasts 1 second):

ffmpeg -i "sound.mp3" -ss 0 -to 4 -af "afade=t=out:st=3:d=1" "sound.wav"

Learn more about FFmpeg here.

Normalizing volume of audio files

It is possible that some of your audio files will be louder than others. You can use volume_normalization.py script to normalize volume of all audio files in a given directory. It uses ffmpeg to do it, so you need to have it installed. Just run the script, it will ask you for the directory with audio files and then it will normalize them.
It works only with .wav files.

About

Discord bot with soundboard functionality that can announce when user is joining/leaving voice chat

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages