Play your Plex music in Discord with style. Alpha 0.5
PlexBot streams your Plex music library into Discord voice channels. It has a visual player with album art and labelled controls, Plex's sonic features (similar tracks, radio, and sonic adventures), and a help menu with screenshots.
PlexBot has two player styles, set with visualPlayer.useModernPlayer in config.fds:
| Modern (default) | Classic |
|---|---|
![]() |
![]() |
Under the progress bar, a status line shows the volume and repeat mode as text, for example Volume 20% · Repeat off.
For the full button list and the repeat cycle, see the Commands guide. More on the player is in the Player UI guide.
- Plex library playback. Play a track, a search result, or a whole playlist. Tracks load in the background, so a 90-track playlist starts at once.
- A player that looks like an app. Album art, labelled buttons with custom emoji, and volume and repeat shown as text.
- Sonic features. Similar tracks (paged, 25 at a time), radio from any track (optionally endless), and sonic adventures between two songs. These use Plex's audio analysis.
- Search by mood, genre, or radio station, as well as by name.
- Queue controls. Pages of the queue, shuffle, clear, and skip.
- Static player channel. Dedicate one channel to a player that is always there.
- Help inside Discord.
/helpopens a menu of topics. Each topic has step-by-step pages with screenshots. - Extensions. Add sources or commands with the extensions system.
- Docker install. The install script runs PlexBot and Lavalink together.
Extensions add music sources and slash commands without changing PlexBot's core. Each one is a folder in Extensions/ with its own .csproj. At startup the bot builds each enabled folder with the .NET SDK (the Docker image includes it), loads it, and registers its commands. To switch one off, rename its folder with a .disabled suffix.
Official extensions
- YouTube Music Provider adds YouTube to
/searchand plays YouTube links through Lavalink's YouTube plugin, which the extension configures itself. It needs Lavalink 4, which the Docker stack already runs. Its optional sign-in (OAuth) is off by default; read its OAuth notes before you turn it on.
To install YouTube (recommended):
-
In
config.fds, set the switch in theyoutubesection (copyRenameMe.config.fdstoconfig.fdsfirst if you haven't yet):youtube: enabled: true
The shipped template has
enabled: false, so a fresh install does not pull YouTube until you change it. -
Run the start script:
Install/start.sh --buildon Linux, orInstall\win-install.baton Windows. It clones the extension and downloads theyoutube-pluginLavalink plugin for you.
Manual alternative:
-
Clone the extension yourself into
Extensions/PlexBot-YouTube-MusicProvider:git clone https://github.com/kalebbroo/PlexBot-YouTube-MusicProvider.git Extensions/PlexBot-YouTube-MusicProvider
-
Put
youtube-plugin-1.18.2.jarinInstall/Docker/plugins/. The version is the one the extension'slavalink.plugin.ymlpins. -
Before you run the script, edit
config.fds(copyRenameMe.config.fdsto it first if you don't have one) and remove theenabledline from theyoutubesection, or comment it out. The scripts then leave your clone alone. Withenabled: false, which is what the template ships with, they rename the folder to.disabled. -
Run the start script as above. It regenerates the Lavalink config.
For YouTube, use the switch rather than renaming the folder by hand. Renaming it to .disabled is undone on the next start while enabled is true. The switch is described in Configuration. Turning it off renames the folder and deletes nothing.
- Build your own extension (tutorial) is a step-by-step guide that builds a working
/hellocommand from nothing. - Full extension guide is the complete reference.
Four steps from the channel to the queue. Type /play with a song name to skip the menus.
- Search. Type
/search, pick Plex Library, then type a name, artist or album. - Pick a result. Choose an artist, then an album. An album queues all its tracks and starts playback.
- Use the player. Its buttons control playback, volume and the queue. See The player.
- Check the queue. Press Queue. ⏳ marks a track still loading from Plex.
- Ask for help.
/helpopens a menu with a Show me button for each topic. Each page has the steps, a screenshot, and Previous and Next buttons.
Search modes. Plex Library searches your library by name. Find by Mood and Find by Genre use Plex's sonic tags and need sonic analysis on the server. Radio Station builds stations from a track. YouTube appears when its extension is loaded. Results over 25 page with Previous and Next.
Albums queue tracks. Picking an album from the album menu queues every track on it and starts playback.
Press Queue on the player to see what's coming up, ten tracks a page. Shuffle and Clear are on the Queue Options message. Shuffle's result stays private, and Clear leaves the track that's playing.
A static channel keeps one player in one channel. The player is always there, and playback started from any channel
appears in it. Each server can have its own static channel, listed under channelIds. Servers without one keep the normal player.
Idle card (nothing playing): the banner, then Play (a song, artist, album or link), Search (your Plex library), one button for each loaded search source (YouTube when its extension is loaded), Radio and Adventure. Radio and Adventure ask for a track first.
Playing card (static channel only): the playback controls, then Play, Search and the source buttons. Radio and Adventure stay in the controls and use the current track. Everything joins the voice channel you're in. After Stop (or when the bot leaves voice), the card returns to the idle card.
To turn it on:
-
Create or pick a text channel for the player.
-
Right-click the channel and choose Copy Channel ID. You may need Developer Mode in Discord's Advanced settings.
-
Repeat for each server the bot is in. In
config.fds, list the channel IDs, comma-separated:visualPlayer: staticChannel: enabled: true channelIds: 123456789012345678, 234567890123456789 # one channel per server
-
Restart the bot. If
enabledistruebut no channel is listed, the bot skips static setup and logs a warning. A server with no listed channel uses the normal player.
Heads up: when the bot starts, it deletes its own old messages in the static channel, then posts the idle card. Use a channel for the player only.
These need a Plex track playing and sonic analysis enabled on your Plex server. Radio and Similar are on the player's second row, and Adventure is on the last row.
| Button | What it does |
|---|---|
| Radio | Replace the queue, add to the queue, or list similar tracks, starting from the current track |
| Similar | Show sonically similar tracks. The list pages 25 at a time, with Previous and Next. |
| Adventure | Ask where the path should end, then build a path from the current track to that one |
| Command | What it does |
|---|---|
/play [query] [next] |
Play a track by name or link. Queues it, or with next plays it after the current track. |
/playlist [playlist] [shuffle] [next] |
Queue a Plex playlist, optionally shuffled, or with next play it after the current track. |
/search [mode] [query] |
Search: Plex Library, Find by Mood, Find by Genre, or Radio Station. Extension sources appear here when loaded. |
/help |
The help menu. Only you see it. |
Search examples
/search mode:Plex Library query:"The Beatles"/search mode:Find by Mood query:Happy/search mode:Radio Station query:Library Radio
| Button | Action |
|---|---|
| Pause / Resume | Toggle playback |
| Back | Go to the track played before this one (the current track is queued to play next) |
| Skip | Next track |
| Repeat | Off → Repeat All → Repeat 1 → Off |
| Shuffle | Shuffle the queue |
| Queue | Show the queue, with shuffle and clear |
| Vol - / Vol + | Change the volume by 10% |
| Radio, Similar, Adventure | Sonic features (above) |
| Stop | Stop, clear the queue, and leave voice |
Buttons have a two-second cooldown, so a repeated click is ignored.
You need:
- Docker and Docker Compose (Docker Desktop is easiest)
- A Discord bot token from the Developer Portal
- Your Plex server URL and token (how to find your token)
git clone https://github.com/kalebbroo/PlexBot.git
cd PlexBot-
Secrets. Copy
RenameMe.env.txtto.envand fill it in:DISCORD_TOKEN=your-discord-bot-token PLEX_URL=http://your-plex-ip:32400 PLEX_TOKEN=your-plex-token
-
Settings (optional). Copy
RenameMe.config.fdstoconfig.fdsand edit it to change the player or behaviour. If the file is missing, the install script makes the copy itself. To install YouTube, set its switch inconfig.fdsbefore you run the script (see Extensions). -
Run the install script.
Install\win-install.baton Windows, orbash Install/linux-install.shon Linux. It createsconfig.fdsif it's missing, syncs the extensions listed inInstall/extensions.txtwith their switches, downloads the Lavalink plugins they need, writes the Lavalink config, builds the Docker images, and starts the bot.
For the full walkthrough see the Installation guide and the Docker guide.
PlexBot reads two files:
| File | Holds | Template |
|---|---|---|
.env |
Secrets and infrastructure: tokens, URLs, passwords | RenameMe.env.txt (copy it) |
config.fds |
Settings: the player, Plex behaviour, logging | RenameMe.config.fds (created if missing) |
| Variable | Description | Required |
|---|---|---|
DISCORD_TOKEN |
Discord bot token | Yes |
PLEX_URL |
Plex server URL with port, e.g. http://192.168.1.50:32400 |
Yes |
PLEX_TOKEN |
Plex token | Yes |
LAVALINK_HOST |
Lavalink host. Lavalink for the Docker install. |
No (default Lavalink) |
LAVALINK_SERVER_PORT |
Lavalink port | No (default 2333) |
LAVALINK_SERVER_PASSWORD |
Lavalink password | No (default youshallnotpass) |
LAVALINK_SECURE |
true for HTTPS/WSS to a remote Lavalink |
No (default false) |
Uses Frenetic Data Syntax, a YAML-like format. You only need to set what you want to change.
Visual player
| Key | Default | What it does |
|---|---|---|
visualPlayer.useModernPlayer |
true |
true for the album-art player, false for the classic embed |
visualPlayer.inactivityTimeout |
2.0 |
Minutes of inactivity before the bot leaves voice |
visualPlayer.buttonCooldownSeconds |
2.0 |
Seconds a person must wait between presses of the same button. 0 turns it off. |
visualPlayer.staticChannel.enabled |
false |
Keep the player in one channel (see Static player channel) |
visualPlayer.staticChannel.channelId |
0 |
One channel's ID (a single server) |
visualPlayer.staticChannel.channelIds |
(empty) | Comma-separated channel IDs, one per server |
visualPlayer.progressBar.enabled |
true |
Live progress bar. Turn off to make fewer Discord edits. |
visualPlayer.progressBar.size |
medium |
small, medium or large |
visualPlayer.progressBar.emoji.* |
(empty) | Optional IDs for the 30-piece smooth progress bar. Empty uses ▓░. See Custom emoji. |
Plex
| Key | Default | What it does |
|---|---|---|
plex.stream.maxConcurrentLoads |
2 |
Plex file loads at once. Lower it if tracks fail to load. |
plex.stream.retryDelaysSeconds |
2, 5, 15 |
Waits before each retry of a failed load |
plex.stream.resolveAhead |
3 |
Queued tracks loaded ahead of the one playing |
plex.resolveCacheSize |
500 |
Resolved tracks kept in memory |
plex.resolveCacheMinutes |
60 |
How long a resolved track is reused |
plex.radio.infinite |
false |
Keep radio going: when the queue runs low, the bot queues more tracks from the same seed |
plex.radio.refillThreshold |
5 |
Refill when fewer than this many tracks are queued |
plex.radio.batchSize |
30 |
Tracks fetched per radio request, for the first batch and each refill |
With infinite radio on, a radio session runs until you press Stop or the bot leaves voice. Tracks it has already queued are not queued again, and each refill continues from the last track Plex returned.
Logging and bot
| Key | Default | What it does |
|---|---|---|
logging.level |
INFO |
Console level: VERBOSE, DEBUG, INFO, WARN, ERROR |
logging.saveToFile |
true |
Write log files (every level) |
logging.path |
logs/plex-bot-[year]-[month]-[day].log |
Log file path |
bot.environment |
(empty) | Development registers slash commands per server, which updates faster |
bot.transientMessageSeconds |
30 |
Seconds before status messages (Track Added, No Results, Track Skipped) remove themselves. 0 keeps them. |
YouTube extension (read by the install scripts, not the bot)
| Key | Default | What it does |
|---|---|---|
youtube.enabled |
false |
true clones the YouTube extension (or restores it from .disabled) and fetches its plugin on the next install or start. false renames it to .disabled. Unset clones it only if its folder is missing, and otherwise leaves it as it is. See Extensions. |
The player and its panels use 23 emoji. The bot uploads them to its own Discord application on first start, so they work in every server the bot is in and use no emoji slots.
If an emoji can't be used, the bot shows a plain unicode symbol instead, and everything still works. To change the
art, edit the PNG in Images/Emoji and restart. See the Custom Emoji guide for
the full set and how to make your own.
The smooth progress bar uses 30 separate emoji that you set up by hand. See the Configuration guide.
By default the install runs Lavalink in Docker next to PlexBot. To use a Lavalink on another machine, change these in .env:
LAVALINK_HOST=192.168.1.100 # Lavalink's IP or hostname
LAVALINK_SERVER_PORT=2333 # Must match Lavalink's application.yml
LAVALINK_SERVER_PASSWORD=mypassword # Must match Lavalink's application.yml
LAVALINK_SECURE=false # true if it sits behind SSLThen remove the lavalink service and its depends_on block from Install/Docker/docker-compose.yml. You are responsible
for running Lavalink (Java 17 or later, its jar, and its application.yml). See the Lavalink docs.
If playback stutters, especially when other programs use the same machine, Lavalink's audio thread is being interrupted. PlexBot doesn't touch the audio stream, so these settings are for Lavalink.
- Garbage collection. Set
_JAVA_OPTIONSin.envto use ZGC, which keeps pauses under 1 ms:This uses 10–20% more memory and needs Java 21 or later (the Lavalink 4 image has it)._JAVA_OPTIONS=-XX:+UseZGC -XX:+ZGenerational -Xms256m -Xmx512m
- CPU pinning. Uncomment
cpusetandcpu_sharesinInstall/Docker/docker-compose.ymlto give Lavalink dedicated cores.
Only enable these if you hear stuttering.
- More music sources. Spotify, SoundCloud, and other integrations.
- User playlists. Save, manage and share playlists in Discord.
- More player styles and command panels.
MIT License. See LICENSE.
DOWNLOADING OR USING THIS SOFTWARE CONSTITUTES ACCEPTANCE OF THE TERMS AND CONDITIONS OF THE MIT LICENSE. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED.
PlexBot is not affiliated with Plex, YouTube, or Discord. PlexBot and Kaalebbroo.Dev are affiliated with Hartsy.AI (Allowing artists to control how their work is used)









