Skip to content

Features

umutxyp edited this page Oct 17, 2026 · 1 revision

Features

What Beatra can do, and how it does it. For the list of commands see Commands; for settings see Configuration.


Sources

Source What works How it plays
YouTube Videos, Shorts, live streams, YouTube Music links, playlists, youtu.be and embed links, and plain text searches Found and downloaded with yt-dlp
Spotify Tracks, albums, playlists and artists Each song is searched on YouTube and played from there
SoundCloud SoundCloud links Through the SoundCloud plugin, downloaded through the relay
Direct links Links straight to an audio file Downloaded through the relay
Everything else yt-dlp supports For example Bandcamp, Vimeo or Twitch links Found and downloaded with yt-dlp

A few details worth knowing:

  • Text is searched on YouTube. /play daft punk plays the first YouTube result. Use /search to choose from 10 results.
  • YouTube playlists load up to MAX_PLAYLIST_SIZE songs (200 by default). Private and deleted videos are skipped.
  • YouTube mixes (auto-generated RD... lists) are endless. If the link also names a video, only that video is played.
  • Spotify without API keys loads only the first 100 songs of a large playlist. Add SPOTIFY_CLIENT_ID and SPOTIFY_CLIENT_SECRET to load more.
  • The queue holds MAX_QUEUE_SIZE songs (500 by default). A playlist that does not fit is cut, and you are told how many songs were added.
  • Age-restricted (18+) songs play only when the player panel's channel is marked age-restricted (NSFW). YouTube may also need cookies from a logged-in account for them (see YouTube Access).

How a song is played

How a song reaches your voice channel

  1. You run /play. While the song is being looked up, the bot already joins your voice channel, so both happen at the same time.
  2. The right plugin takes the request: YouTube, Spotify, SoundCloud, direct link, or the general yt-dlp plugin for every other site.
  3. yt-dlp finds the song and its audio in one call. The result is cached, so the stream can start without asking YouTube again.
  4. The local relay downloads the audio. ffmpeg never connects to the internet itself: it reads from http://127.0.0.1/..., and yt-dlp writes the audio into that connection. The relay waits for the first bytes of audio before playback starts, so a broken source is noticed early.
  5. ffmpeg decodes the audio and applies the selected filter, and the result is sent to Discord as Opus audio.
  6. The next song is prepared in the background while the current one plays, so it starts without a pause.

Why the relay? YouTube only serves its streams to clients that download them the way yt-dlp does; a plain ffmpeg request gets "403 Forbidden". yt-dlp also handles proxies (including SOCKS), cookies and HLS streams. SoundCloud and direct links go through the relay too, so your proxy applies to every download.

The console prints one line per song so you can see the speed:

Playing "Song name" from youtube: found in 3.4s, audio after 4.6s

When YouTube refuses a song

With YOUTUBE_FALLBACK=soundcloud (the default):

  • If a YouTube search fails, the same search runs on SoundCloud.
  • If a YouTube stream is refused (403, bot check, removed video), the song is searched on SoundCloud by title and artist and played from there.
  • The listener sees "YouTube did not work for this song, so it is playing from SoundCloud.", and the console says why YouTube failed.
  • After 3 refused YouTube streams in a row, the bot uses SoundCloud directly for 10 minutes, so every song does not wait for a failing attempt first. The console then suggests the cookies fix.

Set YOUTUBE_FALLBACK=off to show the YouTube error instead. The real fix for a blocked server is on YouTube Access.


Player panel

One message with everything: cover art, title with a link to the source, uploader and length, a live progress bar, who requested the song, volume, loop mode, autoplay, the active filter, the next song, and how many songs and how much time are left. Below it are two rows of buttons and the filter menu.

It is built with Discord Components V2 and uses your EMBED_COLOR as the accent color. The progress bar updates every PANEL_REFRESH seconds while music plays. All buttons are described on the Commands page.


Audio filters

Filter Option name
Bass Boost bassboost
Nightcore nightcore
Vaporwave vaporwave
8D 3d
Karaoke karaoke
Echo echo
Surround surround
Tremolo tremolo

Use /filter or the panel menu. One filter is active at a time; pick None in /filter (or No filter in the panel menu) to turn it off.


Loop and autoplay

Loop

Mode Effect
Off Every song plays once
Song (Track) The current song repeats
Queue When the queue ends it starts again from the top

Autoplay

When autoplay is on and the queue runs out, the bot keeps playing related songs. For a YouTube song they are taken from YouTube's mix of that song, and related songs shorter than 1 minute or longer than 15 minutes are skipped. Links from other yt-dlp sites (Bandcamp, Vimeo, ...) have no related songs. Songs added this way show "Added by autoplay" on the panel. If nothing related is found, the bot says "Autoplay could not find a related song."


Lyrics

/lyrics and the Lyrics button look up plain lyrics on LRCLIB. The bot cleans video titles first (it removes things like "(Official Video)", "[Lyrics]" or "ft. ...", and splits "Artist - Title"), and when several versions match it picks the one closest to the song's length. Long lyrics are split into pages with Back / Next buttons. Results are cached for 6 hours.


Resume after a restart

Every server's queue is saved to data/sessions/<server id>.json every 15 seconds and whenever it changes, and once more when the bot shuts down. On the next start the bot restores it if:

  • it was saved less than 30 minutes ago,
  • the voice channel still exists and the bot can join it, and
  • at least one person (not a bot) is in that voice channel.

The restored queue keeps its songs, the position in the current song, volume, loop mode, autoplay and filter. If a shard hits an unexpected error, it saves its queues before it restarts.


Languages

Beatra speaks 23 languages:

English (en) Türkçe (tr) Deutsch (de) Español (es)
Français (fr) Italiano (it) Nederlands (nl) Polski (pl)
Português (pt) Русский (ru) Svenska (sv) Norsk (no)
Dansk (da) Suomi (fi) Čeština (cs) 日本語 (ja)
한국어 (ko) 简体中文 (zh_CN) 繁體中文 (zh_TW) हिन्दी (hi)
Thai (th) Bahasa Indonesia (id) العربية (ar)

How the language is chosen:

For Order
Replies to a user (ephemeral answers) 1. The server language set with /language → 2. the user's own Discord language → 3. DEFAULT_LANGUAGE
Messages everyone sees (player panel, announcements) 1. The server language set with /language → 2. the server's Discord language → 3. DEFAULT_LANGUAGE

All languages except Arabic are matched to Discord's language settings automatically; Arabic can be chosen with /language. A text missing in a translation falls back to English. Slash command descriptions are also shown translated in Discord.

The language chosen with /language is saved in data/guilds/<server id>.json. No database is used.


Sharding and stability

  • The bot always runs under the discord.js sharding manager. With TOTAL_SHARDS=auto it starts as many shards as Discord recommends.
  • A shard that crashes or exits is restarted automatically (SHARD_RESPAWN).
  • Ctrl + C (or a stop signal from your host) shuts down cleanly: every shard saves its queues and leaves its voice channels.
  • /help adds up servers and active music across all shards.

Privacy and data

The bot stores only what it needs, as JSON files on your machine:

Data File Kept
Server language data/guilds/<server id>.json Until you change or delete it
Active queue (song titles and links, requester id, voice and text channel ids, position) data/sessions/<server id>.json Removed when playback stops; ignored after 30 minutes

Audio is streamed and never recorded or saved. Only two gateway intents are used: Guilds and GuildVoiceStates. See the Privacy Policy.


Next: YouTube Access · Deployment

Clone this wiki locally