A Python-based RTMP broadcaster for Raspberry Pi that streams video playlists to Twitch with dynamic overlays and "Now Playing" text.
✅ Web Interface Available: Access the control panel at http://localhost:8080 to manage streams, playlists, and overlays through a modern web UI.
/opt/rpi-broadcaster/
├── app/
│ ├── runner.py # Main playlist runner
│ └── run_ffmpeg.sh # FFmpeg streaming script
├── config/
│ └── overlays/ # Overlay presets (watermark, text)
│ └── default.json
├── media/
│ └── shows/ # Show directories with video files
│ └── my-show-01/
│ ├── manifest.json
│ └── video/
├── state/
│ ├── current.json # Current playback state
│ └── now_playing.txt # Dynamic text file for FFmpeg
└── systemd/
└── rpi-broadcaster.service
Busey-Box automatically generates example configurations for your hardware when you first run it!
# 1. Clone and start
git clone https://github.com/lancer1977/Busey-Box.git
cd Busey-Box
docker compose up -d
# 2. Container creates hardware-specific examples in ./config/examples/
# Read the guide:
cat ./config/examples/README.txt
# 3. Choose and copy your config
cp ./config/examples/YOUR-HARDWARE.json ./config/config.json
# 4. Add your Twitch stream key
nano ./config/config.json
# Replace YOUR_TWITCH_STREAM_KEY_HERE with your key from:
# https://dashboard.twitch.tv/settings/stream
# 5. Restart and start streaming!
docker compose restart
✨ That's it! The container automatically creates optimized configs for:
📖 See Auto-Generated Configs Guide for more details.
Automated setup (for non-Docker installations):
cd Busey-Box
./setup.sh
The setup script will:
After setup:
./verify-install.sh~/.buseybox/config.json with your Twitch stream key and media directorysudo systemctl start rpi-broadcaster rpi-broadcaster-webhttp://localhost:8080Note: The installer uses a Python virtual environment (
.venv) to avoid PEP 668 errors on Debian Bookworm/Raspberry Pi OS. See PEP668-FIX.md for details.
Yes — Busey-Box runs headless in Docker (FFmpeg + runner + web API, no desktop/GUI required).
cp config.json.example config.json
Edit config.json and set your Twitch stream key. For easiest container compatibility, set:
"video_codec": "libx264"
(You can still try h264_v4l2m2m on Raspberry Pi with extra device mapping; see below.)
docker compose -f docker-compose.local.yml up -d --build
Open the web UI at: http://localhost:8080
./config.json → /config/config.json (Twitch + app settings)./media/shows → /opt/rpi-broadcaster/media/shows (your playlists/videos)./state → /opt/rpi-broadcaster/state (runtime state + now_playing)./config/overlays → /opt/rpi-broadcaster/config/overlays (overlay presets)If you want Pi hardware encode in container (h264_v4l2m2m), you may need to expose /dev/video* devices and group permissions in docker-compose.yml (commented examples are included). If hardware encoding fails, switch back to libx264.
docker compose -f docker-compose.local.yml logs -f
docker compose -f docker-compose.local.yml restart
docker compose -f docker-compose.local.yml down
# Build local image
./scripts/docker-build-local.sh
# Build + run local stack
./scripts/docker-up-local.sh
# Stop local stack
./scripts/docker-down.sh
If port 8080 is already used on your host:
HOST_PORT=8081 ./scripts/docker-up-local.sh
Then open http://localhost:8081.
lancer1977/busey-box)# Build and push image (set TAG to a release version)
TAG=v0.1.0 ./scripts/docker-publish.sh
# Deploy from Docker Hub image
TAG=v0.1.0 ./scripts/docker-deploy-hub.sh
You can also deploy with compose directly:
TAG=v0.1.0 docker compose -f docker-compose.hub.yml up -d
If you prefer manual installation or need customization:
Install dependencies:
sudo apt update
sudo apt install ffmpeg python3-full python3-venv
Set up configuration:
mkdir -p ~/.buseybox
cp config.json.example ~/.buseybox/config.json
nano ~/.buseybox/config.json # Add your stream key and configure paths
chmod 600 ~/.buseybox/config.json
Create directory structure and virtual environment:
sudo mkdir -p /opt/rpi-broadcaster/{app,config/overlays,media/shows,state,logs}
sudo cp -r app/* /opt/rpi-broadcaster/app/
sudo cp -r config/* /opt/rpi-broadcaster/config/
sudo chown -R $USER:$USER /opt/rpi-broadcaster
# Create virtual environment
python3 -m venv /opt/rpi-broadcaster/.venv
/opt/rpi-broadcaster/.venv/bin/pip install --upgrade pip
/opt/rpi-broadcaster/.venv/bin/pip install -r /opt/rpi-broadcaster/app/requirements.txt
Install systemd services:
sudo cp systemd/*.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable rpi-broadcaster rpi-broadcaster-web
sudo systemctl start rpi-broadcaster rpi-broadcaster-web
Access the control panel at http://localhost:8080 (or http://your-pi-ip:8080 remotely).
Features:
Create a show directory:
mkdir -p /opt/rpi-broadcaster/media/shows/my-show/video
Add video files to the video/ subdirectory
Create a manifest.json:
{
"name": "my-show",
"loop": true,
"shuffle": false,
"overlayPreset": "default",
"playlist": [
{
"path": "video/intro.mp4",
"title": "Show Intro"
},
{
"path": "video/episode01.mp4",
"title": "Episode 1"
}
]
}
Via Web Interface (easiest):
http://localhost:8080Via REST API:
# Get status
curl http://localhost:8080/api/status
# Start streaming
curl -X POST http://localhost:8080/api/control/start
# Stop streaming
curl -X POST http://localhost:8080/api/control/stop
# Select a show
curl -X POST http://localhost:8080/api/control/select-show \
-H "Content-Type: application/json" \
-d '{"show_dir": "/opt/rpi-broadcaster/media/shows/my-show"}'
# Jump to video index
curl -X POST http://localhost:8080/api/control/jump \
-H "Content-Type: application/json" \
-d '{"index": 2}'
# Next/previous video
curl -X POST http://localhost:8080/api/control/next
curl -X POST http://localhost:8080/api/control/previous
Via JSON file (manual):
Edit /opt/rpi-broadcaster/state/current.json:
{
"running": true,
"show_dir": "/opt/rpi-broadcaster/media/shows/my-show",
"index": 0,
"overlay_preset": "default"
}
The runner script monitors this file and automatically applies changes.
Edit /opt/rpi-broadcaster/config/overlays/default.json:
{
"name": "default",
"description": "Watermark bottom-right + dynamic Now Playing text top-left",
"watermark": {
"enabled": true,
"path": "overlays/watermark.png",
"x": "W-w-20",
"y": "H-h-20",
"alpha": 0.9
},
"dynamic_text": {
"enabled": true,
"textfile": "/opt/rpi-broadcaster/state/now_playing.txt",
"x": 24,
"y": 24,
"font_size": 36,
"box": true,
"boxborderw": 12
},
"video": {
"scale_w": 1280,
"scale_h": 720,
"fps": 30
}
}
/opt/rpi-broadcaster/state/current.jsonrunning: true, it reads the show's manifest.json/opt/rpi-broadcaster/state/now_playing.txt with the titledrawtext=textfile=...:reload=1 to display live-updating "Now Playing" textThe "Now Playing" feature uses FFmpeg's drawtext filter with reload=1:
/opt/rpi-broadcaster/state/now_playing.txt every framerunner.py updates this file atomically when switching videosSee DYNAMIC-TEXT.md for technical details.
Set in /etc/systemd/system/rpi-broadcaster.service or export before running:
VIDEO_CODEC: Default h264_v4l2m2m (Pi 4 hardware encoder) or libx264 (software fallback)VBITRATE: Video bitrate (default: 3000k for 720p30)ABITRATE: Audio bitrate (default: 160k)FPS: Frame rate (default: 30)GOP: Keyframe interval (default: 120)FONTFILE: Path to TTF font for text overlay (optional but recommended)TWITCH_INGEST: Twitch ingest server (default: live.twitch.tv)Check service status:
sudo systemctl status rpi-broadcaster
sudo systemctl status rpi-broadcaster-web
journalctl -u rpi-broadcaster -f
journalctl -u rpi-broadcaster-web -f
Test web interface manually:
cd /opt/rpi-broadcaster/app
python3 web_server.py
# Access at http://localhost:8080
Test streaming manually:
# Configuration is loaded automatically from ~/.buseybox/config.json
# Test with a single video
cd /opt/rpi-broadcaster/app
./run_ffmpeg.sh /path/to/video.mp4 /opt/rpi-broadcaster/config/overlays/default.json
Common issues:
video_codec in config.json to libx264~/.buseybox/config.json contains correct key and is readablemedia.root_dir in config.json points to correct locationpython3-venv is installed and re-run setup.shAll settings are stored in ~/.buseybox/config.json (user-specific, no sudo required):
{
"twitch": {
"stream_key": "YOUR_TWITCH_STREAM_KEY_HERE",
"ingest_server": "live.twitch.tv"
},
"media": {
"root_dir": "/opt/rpi-broadcaster/media/shows"
},
"streaming": {
"video_codec": "libx264",
"video_bitrate": "3000k",
"audio_bitrate": "160k",
"fps": 30,
"gop": 120,
"resolution": {
"width": 1280,
"height": 720
}
},
"web": {
"port": 8080,
"host": "0.0.0.0"
}
}
🎯 Quick Start - Choose Your Hardware:
| Your System | Copy This Config |
|---|---|
| Raspberry Pi 4 | cp docs/examples/config-raspberry-pi-4.json ~/.buseybox/config.json |
| Raspberry Pi 5 | cp docs/examples/config-raspberry-pi-5.json ~/.buseybox/config.json |
| PC/Server (CPU) | cp docs/examples/config-pc-cpu.json ~/.buseybox/config.json |
| NVIDIA GPU | cp docs/examples/config-nvidia-rtx.json ~/.buseybox/config.json |
| AMD GPU | cp docs/examples/config-amd-vaapi.json ~/.buseybox/config.json |
| Intel QuickSync | cp docs/examples/config-intel-quicksync.json ~/.buseybox/config.json |
Then edit the file and add your Twitch stream key!
📖 Full Documentation:
💾 All Example Configs (in docs/examples/):
libx264 (software, works everywhere) or h264_v4l2m2m (Raspberry Pi hardware)~/.buseybox/twitch.env as fallback for backwards compatibilityMIT License - see LICENSE file for details.
Content type
Image
Digest
sha256:f2f3e9905…
Size
238.2 MB
Last updated
4 months ago
docker pull lancer1977/busey-box