This is an old revision of the document!
Table of Contents
π΅ Ambient Lo-Fi Discord Music Bot β Installation & Usage
This bot plays ambient lo-fi music automatically in your Discord voice channel. It starts with shuffle, continues playing without stopping, and can be controlled via simple commands.
π¦ Requirements
- Python 3.10 or newer
- FFmpeg installed (`sudo apt install ffmpeg`)
- A Discord Bot Token
- MP3 files placed in the `music/` directory
- Optional: systemd for autostart on boot
π οΈ Installation
- Clone or copy the bot code into a directory, e.g. `/var/www/mbot/`
- Create a `music/` folder and add your MP3 tracks
- Install required Python packages:
`pip install discord`
π Insert Your Bot Token
Open `bot.py` and replace:
`bot.run("your-bot-token-here")`
with your actual Discord bot token.
π€ Creating a Discord Bot
- Click New Application, give it a name
- Go to Bot tab β click Add Bot
- Under Privileged Gateway Intents, enable:
- Message Content Intent
- Server Members Intent
- Copy the token and paste it into `bot.py`
π Invite the Bot to Your Server
Go to the OAuth2 β URL Generator tab:
- Scopes: `bot`
- Bot Permissions:
- Connect
- Speak
- Send Messages
- Read Message History
Copy the generated URL and open it in your browser to invite the bot.
π Starting the Bot
To start manually: `python3 ./bot.py`
Or set up a systemd service:
sudo adduser musikbot sudo chown -R musikbot:musikbot /var/www/mbot
Autostart on server start
sudo nano /etc/systemd/system/musicbot.service
[Unit] Description=Discord Music Bot After=network.target [Service] ExecStart=/usr/bin/python3 /var/www/mbot/bot.py WorkingDirectory=/var/www/mbot Restart=always User=musikbot [Install] WantedBy=multi-user.target
Enable and start the service: `sudo systemctl daemon-reload` `sudo systemctl enable musicbot` `sudo systemctl start musicbot`
π§ Discord Commands
- `!join` β Bot joins your voice channel and starts shuffle playback
- `!leave` β Bot leaves the voice channel
- `!list` β Lists all available MP3 files
- `!play [filename]` β Plays a specific file or a random one if none is given
- `!next` β Skips to the next track
- `!shuffle` β Shuffles the playlist and starts playback
- `!pause` β Pauses playback
- `!resume` β Resumes playback
- `!stop` β Stops playback
- `!help` β Displays all available commands
π§ Notes
- The bot plays continuously without stopping after each track
- Volume is set to 100%
- Make sure the bot has βSpeakβ permissions in the voice channel
- Works best in standard voice channels (not Stage Channels)
π Folder Structure
/var/www/mbot/ βββ bot.py βββ .env βββ music/ β βββ track1.mp3 β βββ track2.mp3
π bot.py
import discord
from discord.ext import commands
import os
import random
from dotenv import load_dotenv
# π Token laden
load_dotenv()
TOKEN = os.getenv("DISCORD_TOKEN")
# π― Gezielte Intents
intents = discord.Intents.default()
intents.message_content = True
intents.voice_states = True
# π€ Bot-Setup
bot = commands.Bot(command_prefix="!", intents=intents, help_command=None)
# π Musikverzeichnis & Steuerung
MUSIC_DIR = "music"
playlist = []
current_index = -1
autoplay_enabled = True
# π Bot ist bereit
@bot.event
async def on_ready():
print(f"π΅ Bot ist online als {bot.user}")
# π Wrapper fΓΌr asynchrone Wiedergabe
def play_next_track_wrapper(ctx):
async def inner():
await play_next_track(ctx)
bot.loop.create_task(inner())
# βΆοΈ NΓ€chsten Track abspielen
async def play_next_track(ctx):
global playlist, current_index, autoplay_enabled
vc = ctx.voice_client
if not vc or not vc.is_connected() or not playlist or not autoplay_enabled:
return
current_index = (current_index + 1) % len(playlist)
filepath = os.path.join(MUSIC_DIR, playlist[current_index])
source = discord.FFmpegPCMAudio(filepath, options="-filter:a volume=1.0")
vc.play(source, after=lambda e: play_next_track_wrapper(ctx))
embed = discord.Embed(
title="βΆοΈ NΓ€chster Track",
description=playlist[current_index],
color=discord.Color.blue()
)
await ctx.send(embed=embed)
# π Shuffle starten
async def start_shuffle(ctx):
global playlist, current_index, autoplay_enabled
vc = ctx.voice_client
if not vc or not vc.is_connected():
await ctx.send("β Bot ist nicht im Sprachkanal.")
return
autoplay_enabled = True
playlist = [f for f in os.listdir(MUSIC_DIR) if f.endswith(".mp3")]
if not playlist:
await ctx.send("π Keine Musikdateien vorhanden.")
return
random.shuffle(playlist)
current_index = 0
filepath = os.path.join(MUSIC_DIR, playlist[current_index])
source = discord.FFmpegPCMAudio(filepath, options="-filter:a volume=1.0")
vc.play(source, after=lambda e: play_next_track_wrapper(ctx))
embed = discord.Embed(
title="π Shuffle gestartet",
description=playlist[current_index],
color=discord.Color.green()
)
await ctx.send(embed=embed)
# π‘ Sprachkanal beitreten
@bot.command()
async def join(ctx):
member = ctx.author
if member.voice and member.voice.channel:
channel = member.voice.channel
if not ctx.voice_client:
await channel.connect()
await ctx.send(f"β
Verbunden mit {channel.name}")
await start_shuffle(ctx)
else:
await ctx.send("β Du bist in keinem Sprachkanal.")
# π Sprachkanal verlassen
@bot.command()
async def leave(ctx):
if ctx.voice_client:
await ctx.voice_client.disconnect()
await ctx.send("π Bot hat den Sprachkanal verlassen.")
else:
await ctx.send("β Bot ist nicht verbunden.")
# π Liste der Musikdateien
@bot.command()
async def list(ctx):
files = [f for f in os.listdir(MUSIC_DIR) if f.endswith(".mp3")]
if not files:
await ctx.send("π Keine Musikdateien gefunden.")
else:
msg = "\n".join(f"{i+1}. {f}" for i, f in enumerate(files))
await ctx.send(f"πΆ VerfΓΌgbare Tracks:\n{msg}")
# βΆοΈ Musik abspielen
@bot.command()
async def play(ctx, filename=None):
global playlist, current_index, autoplay_enabled
vc = ctx.voice_client
if not vc or not vc.is_connected():
await ctx.send("β Bot ist nicht im Sprachkanal. Nutze zuerst !join.")
return
autoplay_enabled = True
if filename:
filepath = os.path.join(MUSIC_DIR, filename)
if not os.path.isfile(filepath):
await ctx.send("β Datei nicht gefunden.")
return
playlist = [filename]
current_index = 0
else:
playlist = [f for f in os.listdir(MUSIC_DIR) if f.endswith(".mp3")]
if not playlist:
await ctx.send("π Keine Musikdateien vorhanden.")
return
current_index = random.randint(0, len(playlist) - 1)
filepath = os.path.join(MUSIC_DIR, playlist[current_index])
source = discord.FFmpegPCMAudio(filepath, options="-filter:a volume=1.0")
vc.play(source, after=lambda e: play_next_track_wrapper(ctx))
embed = discord.Embed(
title="βΆοΈ Spiele",
description=playlist[current_index],
color=discord.Color.orange()
)
await ctx.send(embed=embed)
# βοΈ NΓ€chsten Track manuell starten
@bot.command()
async def next(ctx):
global autoplay_enabled
vc = ctx.voice_client
if not vc or not vc.is_connected():
await ctx.send("β Bot ist nicht im Sprachkanal.")
return
autoplay_enabled = True
vc.stop()
await ctx.send("βοΈ NΓ€chster Track wird gespielt.")
# βΉοΈ Wiedergabe stoppen und Autoplay deaktivieren
@bot.command()
async def stop(ctx):
global autoplay_enabled
vc = ctx.voice_client
if vc and vc.is_playing():
autoplay_enabled = False
vc.stop()
await ctx.send("βΉοΈ Wiedergabe gestoppt und Autoplay deaktiviert.")
else:
await ctx.send("β Keine Wiedergabe aktiv.")
# βΈοΈ Wiedergabe pausieren
@bot.command()
async def pause(ctx):
vc = ctx.voice_client
if vc and vc.is_playing():
vc.pause()
await ctx.send("βΈοΈ Wiedergabe pausiert.")
else:
await ctx.send("β Keine Wiedergabe aktiv.")
# βΆοΈ Wiedergabe fortsetzen
@bot.command()
async def resume(ctx):
vc = ctx.voice_client
if vc and vc.is_paused():
vc.resume()
await ctx.send("βΆοΈ Wiedergabe fortgesetzt.")
else:
await ctx.send("β Nichts zum Fortsetzen.")
# βΉοΈ Hilfe anzeigen
@bot.command()
async def help(ctx):
embed = discord.Embed(
title="π΅ Musikbot Befehle",
color=discord.Color.purple()
)
embed.add_field(name="!join", value="Bot tritt deinem Sprachkanal bei und startet Shuffle", inline=False)
embed.add_field(name="!leave", value="Bot verlΓ€sst den Sprachkanal", inline=False)
embed.add_field(name="!list", value="Zeigt alle verfΓΌgbaren MP3-Dateien", inline=False)
embed.add_field(name="!play [Dateiname]", value="Spielt eine bestimmte Datei oder zufΓ€llig", inline=False)
embed.add_field(name="!next", value="Spielt den nΓ€chsten Track", inline=False)
embed.add_field(name="!shuffle", value="Mischt die Playlist und startet Wiedergabe", inline=False)
embed.add_field(name="!pause", value="Pausiert die Wiedergabe", inline=False)
embed.add_field(name="!resume", value="Setzt die Wiedergabe fort", inline=False)
embed.add_field(name="!stop", value="Stoppt die Wiedergabe und deaktiviert Autoplay", inline=False)
await ctx.send(embed=embed)
# π Bot starten
bot.run(TOKEN)
π Support & Extensions
You can expand the bot anytime β with volume control, queue management, or even a web interface. For questions or ideas, feel free to reach out!
