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!