1 GrumpyMusic EN
darksoon edited this page 2026-05-13 21:03:08 +02:00

Music — Internet Radio in Voice Channels

GrumpyMusic streams internet radio (SHOUTcast / Icecast) into a voice channel — either interactively (a user starts it from their voice channel) or passively (the bot lives permanently in a fixed channel and pauses when nobody is listening).

On track changes, the bot shows "🎵 Station · Artist - Title" as the voice channel status below the channel name — visible in the voice list.


Activation

In configs/config.yml:

addons:
  music: true

channels:
  radio: "VOICE_CHANNEL_ID"   # Optional — fallback channel for passive mode

On first start, configs/modules/music.yml is created from the template. Then run /radio reload or restart the bot.


music.yml

configs/modules/music.yml:

enabled: true
autoLeaveSeconds: 60         # Interactive: how long to stay when all listeners leave
defaultVolume: 80            # Volume 0-200 (Discord scale; 100 = original volume)

presets:
  - id: technobase
    label: TechnoBase.FM
    url: https://listen.technobase.fm/tunein-mp3
    description: Hands Up & Dance — the classic
    color: '#FF1F4A'
  - id: hardbase
    label: HardBase.FM
    url: https://listen.hardbase.fm/tunein-mp3
    description: Hardstyle / Hardcore — no mercy
    color: '#FF6F00'
  - id: housetime
    label: HouseTime.FM
    url: https://listen.housetime.fm/tunein-mp3
    description: House — relaxed to driving
    color: '#1E88E5'
  - id: trancebase
    label: TranceBase.FM
    url: https://listen.trancebase.fm/tunein-mp3
    description: Trance — epic & uplifting
    color: '#7B1FA2'
  - id: clubtime
    label: ClubTime.FM
    url: https://listen.clubtime.fm/tunein-mp3
    description: Club & EDM — party sound
    color: '#E91E63'
  - id: coretime
    label: CoreTime.FM
    url: https://listen.coretime.fm/tunein-mp3
    description: Hardcore & Frenchcore
    color: '#B71C1C'
  - id: replayfm
    label: ReplayFM
    url: https://listen.replay.fm/tunein-mp3
    description: 90s/2000s Throwback Hits
    color: '#00897B'

passive:
  enabled: false
  channelId: "0"            # 0 = falls back to channels.radio from config.yml
  stationId: technobase
  pauseWhenEmpty: true

Fields

Field Default Meaning
enabled true Master toggle. Even if addons.music: true, the module can be disabled here.
autoLeaveSeconds 60 Interactive mode: how long the bot stays when nobody is in the channel (0 = leave immediately).
defaultVolume 80 Volume 0-200 (Discord scale; 100 = original volume).
presets 7 default stations List of available radio stations (see above). Can be extended freely.
presets[].id Unique ID for /radio start (lowercase, no spaces).
presets[].url Direct stream URL (Icecast/SHOUTcast — .mp3/.aac).
presets[].color Hex color #RRGGBB for the embed color.
passive.enabled false Enable passive mode (bot lives permanently in a channel).
passive.channelId "0" Voice channel for passive mode. 0 → uses channels.radio from config.yml.
passive.stationId technobase Which preset station is played continuously.
passive.pauseWhenEmpty true Pauses the stream when nobody is listening — saves CPU and bandwidth.

Modes

Interactive

A user joins a voice channel and runs /radio start <station> — the bot joins the same channel and plays the stream. Once the channel is empty, autoLeaveSeconds counts down and the bot disconnects automatically.

1. User in #voice-3 → /radio start station: technobase
2. Bot joins #voice-3, plays TechnoBase.FM
3. User leaves → 60s timer starts
4. Nobody returns → bot disconnects, status cleared

Passive

The bot lives permanently in the configured channel and always plays the passive stream. pauseWhenEmpty: true pauses the stream when nobody is listening and resumes when someone joins.

Control:

/radio passive enable channel: <voice-channel> station: technobase
/radio passive disable
/radio passive status

/radio passive enable writes the settings to music.yml and joins the channel immediately.


Commands

Command Permission Function
/radio start <station> Everyone (must be in a voice channel) Start a stream in the current voice channel
/radio stop Everyone Stop the stream and clear the channel status
/radio info Everyone Current stream + now playing
/radio list Everyone List all available stations
/radio reload Manage Server Reload music.yml
/radio passive enable channel:<ch> station:<id> Manage Server Enable passive mode
/radio passive disable Manage Server Disable passive mode, bot disconnects
/radio passive status Manage Server Current passive mode status

Voice Channel Status (Now Playing)

On every track change, the bot updates the voice channel status to:

🎵 TechnoBase.FM · Cascada - Everytime We Touch

The status appears below the channel name in the Discord voice list — no additional text message needed. The status is cleared when /radio stop is run.

Permission: The bot needs SET_VOICE_CHANNEL_STATUS (1<<48) for the channel or server. Without this permission, radio continues to work normally — only the now-playing status is missing.

Track info comes from the Icecast inline metadata stream (icy-metaint header). The bot reads metadata frames in parallel with the audio.


Robustness

GrumpyMusic is designed for unstable streams:

  • 1 MB pre-buffer (≈ 60s @ 128 kbps) absorbs CDN jitter — playback stays smooth even if the stream briefly stutters.
  • Browser user-agent on HTTP fetch. Some CDNs block ffmpeg's default Lavf/... UA — the bot presents itself as a normal player.
  • Exponential backoff on stream errors: 1s → 2s → 4s → 8s → 16s. Maximum 5 attempts in a 60s window, then stop with a log entry.
  • Per-guild start lock: If someone runs /radio start multiple times quickly, the race condition is locked — no leaked voice connections.
  • Color-coded embeds: Each station has its own color — embeds for /radio start, /radio info, etc. are immediately visually identifiable.

Permissions

The bot needs the following in the voice channel:

Permission Required? Reason
View Channel See the channel
Connect Join the channel
Speak Send audio
Set Voice Channel Status (1<<48) Optional Now-playing status — audio works normally without it

FAQ

What happens if the station URL returns a 403/404? The bot logs the error, retries 5 times with exponential backoff, then gives up. /radio info shows the last error.

Can I add custom stations? Yes — add a new block to presets:, then run /radio reload. Important: id must be unique (lowercase, no spaces).

Does it work with YouTube / Spotify? No — GrumpyMusic is explicitly designed for internet radio streams (Icecast/SHOUTcast). No search, no queue, no YouTube integration. For those use cases, SinusBot or a dedicated music bot is a better fit.

What happens on bot restart in passive mode? The bot automatically rejoins the configured channel and restarts the stream — no manual intervention required.

How do I change the passive channel? Run /radio passive enable channel: <new-channel> station: <id> — the bot disconnects from the old channel and joins the new one.