Overview
I wanted a music bot I could use with friends. I built an async Python bot with per-server queues and a separate web dashboard; SQLite tracks queue state, history, and favorites across restarts. It combines voice playback and server controls with soundboard clips and lyrics lookup, and restores active sessions after a restart.
What it is
Members can ask the bot to find a track by name or link, then control playback in a voice channel with skip, pause, volume, loop, and seek. It also supports bass boost, audio normalization, and instrumental playback.
Search, history, and playlist browsing use interactive Discord controls. A separate web dashboard provides remote playback and queue controls, favorites, and system monitoring.
Why I built it
Discord bots are a natural fit for practicing asynchronous Python—everything is event-driven through WebSocket gateway connections, and voice channels add real-time streaming on top of that. I wanted hands-on experience with async/await patterns, concurrency, and long-running services beyond typical request-response web apps.
I also wanted a project I could actually use with friends. Building something people depend on for shared listening sessions raised the stakes beyond throwaway side projects and forced me to handle edge cases—disconnects, silent failures, and state recovery—that tutorials never cover.
Architecture
The bot is built on discord.py with command prefixes and is structured into cogs for modularity. The Music cog manages per-guild VoiceState objects, each owning their own queue, audio player loop, and Discord voice connection. A HistoryService layer abstracts persistence through SQLite, tracking plays, searches, favorites, and queue state so everything survives restarts.
A separate aiohttp-based web server runs alongside the bot, serving a REST API with 25+ endpoints and a static frontend. Audio resolution uses yt-dlp for YouTube and SoundCloud with FFmpeg transcoding. The now-playing canvas is rendered server-side using Pillow, and the whole stack is containerized with Docker and deployed through docker-compose with persistent volumes.
What I worked through
Voice connections in Discord are unreliable in ways the documentation does not fully capture. The bot detects silent disconnects, reconnects gracefully without duplicating state, and restores active sessions after restart by persisting voice channel IDs and current song position to the database.
Audio streaming required careful resource management—each track goes through yt-dlp resolution and FFmpeg transcoding, and the player must clean up subprocesses, temporary files, and audio buffers between every song. Edge cases like empty queues, unavailable videos, permission changes mid-playback, rate limits, and the player loop restarting itself after failures were all production bugs that had to be handled without crashing the entire bot.
Lessons learned
This project taught me that real-time systems are unforgiving in ways tutorials never show. Discord's voice API has failure modes the documentation barely mentions—silent disconnects, stale connections that look active, and rate limits that punish naive retry loops. Building something people actually used forced me to handle every one of those edge cases instead of hoping they would not happen.
The deeper lesson was about long-running service design. Unlike a request-response app that starts and stops cleanly, a bot runs indefinitely and accumulates state. Being forced to think about session persistence, graceful restarts, and resource cleanup was the single biggest architectural lesson of the project.
Highlights
- Built an event-driven Discord bot handling real-time voice connections, audio streaming, and WebSocket gateway event processing using async Python
- Designed a modular architecture with per-guild voice state management, persistent queue persistence, and automatic session restoration across service restarts
- Integrated track resolution from YouTube and SoundCloud through yt-dlp with FFmpeg-based audio transcoding and gapless playback
- Built a web dashboard with 25+ REST API endpoints and a static frontend for remote play control, queue management, favorites, and system monitoring
- Implemented interactive Discord UI components including a paginated search view, history browser, and a server-side rendered now-playing canvas using Pillow
- Containerized the entire bot with Docker and deployed as a long-lived service alongside 15+ existing homelab services