Your TV's remote is now Telegram
A bot that turns any Linux box plugged into a TV into an mpv-powered media center you control from the couch โ or the other side of the world. No port forwarding, no VPN, no smart-TV apps โ by default it only makes outbound connections.
on the planet
X11 / Wayland session
nothing else installed
Features
Around 40 commands behind a Telegram user-ID allowlist โ these are the highlights.
Categories โ playlists as inline buttons, full-text search, an episode picker and chapter jumps.
Send a YouTube / SoundCloud / any yt-dlp URL โ it plays on the TV, subtitles fetched automatically.
Drop-in site plugins, plus an optional headless-Chromium fallback that sniffs the stream from JavaScript-only players.
/yt lofi beats โ top results with thumbnails, tap one to play.
Any Telegram video plays on the TV โ up to 2 GB with a local Bot API server.
The now-playing panel rides on every "โถ Playing" message: pause, seek, %-jump, volume, mute, speed, tracks, ๐ธ shot, โบ clip, ๐ฅ upload, ๐ close.
One tap sends the current file โ or the downloaded stream, with a live progress bar โ to the chat. Up to 2 GB with a local Bot API server.
Capture what's playing to an H.264 mp4, or the radio to a voice message, and get it right in the chat โ tap once to start, again to stop.
Last 20 played, paginated. Tap the title to replay (streams resume from the saved position), tap the icon to copy the URL/path, tap ๐ to remove the entry.
"โญ Now playing: 6/12" on episode change, "โ
Finished" at the end. /sleep 45m for bedtime.
The full SomaFM catalog and friends as presets, plus search across ~50k stations โ tuned in about a second.
/iptv BBC searches 50 000+ channels from the iptv-org catalogue โ tap a result to stream live on the TV.
Opt-in POST /play sends a link to the TV (or a whole list, played one after another), GET /status reads what's playing and POST /ctl pauses, seeks or changes the volume โ behind a bearer token, from a script, a phone shortcut or another app, no Telegram needed. Off until you set a token.
Auto-updating yt-dlp, playlist doctor & repair, disk GC, one-screen health check.
# needs uv โ https://docs.astral.sh/uv/
git clone https://github.com/antlis/tg-mpv-bot
cd tg-mpv-bot && uv sync
cp .env.example .env # BOT_TOKEN + ALLOWED_USERS
set -a; source .env; set +a
uv run bot.py
yay -S tg-mpv-bot-git
install -m600 /usr/share/doc/tg-mpv-bot/env.example \
~/.config/tg-mpv-bot.env
$EDITOR ~/.config/tg-mpv-bot.env
systemctl --user enable --now tg-mpv-bot
docker pull ghcr.io/antlis/tg-mpv-bot:latest
# host networking + X11 bind mounts โ
# see docker-compose.yml in the repo
# BOT_TOKEN + ALLOWED_USERS in the environment
nix run github:antlis/tg-mpv-bot
# Chromium fallback: nix build .#with-browser
# home-manager: import homeManagerModules.default,
# services.tg-mpv-bot.enable = true;
On Docker, mpv runs inside the container and renders onto the host's X11 display โ GPU passthrough, audio socket ownership and window-focus glue all have sharp edges worth reading before you debug them the hard way: see Docker gotchas in the README.
Commands
Every command the bot understands โ plus two that aren't commands at all: just send a link or a video file.
Browse & play
/library/play <query>/mpv works too)/search [cat] <text>/random [category]/last/historyStreaming & files
(send a link)(send a video file)/url <link>/yt <search>/radio [search]/iptv [search]Transport
/info/toggle/pause, /unpause)/fwd ยท /back/goto <pos>1:23:45, 90 (s) or 75%/speed [x]1.5/quitPlaylist navigation
/next ยท /prev/ep [n]/chapters/shuffle/loopSound & subtitles
/volup ยท /voldown/mute to silence)/audio/sub/sub_toggle to hide)/nightComfort
/sleep <time>45m / 1.5h (off cancels)/notify/shot/recordLibrary & maintenance
/scan/doctor/fix/health/update_ytdlp/help