Add Playlist function
This commit is contained in:
parent
91ce4aa22c
commit
f488c67c3c
1 changed files with 80 additions and 19 deletions
99
skullbot.py
99
skullbot.py
|
@ -148,6 +148,68 @@ async def hallo(ctx):
|
|||
"""Simple hello command."""
|
||||
await ctx.send(f"Hello {ctx.author.mention}! 👋")
|
||||
|
||||
# =====================
|
||||
# PLAYLIST QUEUE
|
||||
# =====================
|
||||
playlist_queue = [] # Liste from Dicts: { 'url':..., 'title':..., 'data':... }
|
||||
is_playing = False
|
||||
|
||||
async def play_next(ctx):
|
||||
global is_playing
|
||||
if playlist_queue:
|
||||
next_track = playlist_queue.pop(0)
|
||||
player = await YTDLSource.from_url(next_track['url'], loop=bot.loop, stream=True)
|
||||
ctx.voice_client.play(
|
||||
player,
|
||||
after=lambda e: asyncio.run_coroutine_threadsafe(play_next(ctx), bot.loop)
|
||||
)
|
||||
await ctx.send(f"🎶 Now playing: **{player.title}**")
|
||||
is_playing = True
|
||||
else:
|
||||
is_playing = False
|
||||
await ctx.send("✅ Playlist finished.")
|
||||
|
||||
@bot.command(name="add")
|
||||
async def add(ctx, *, url):
|
||||
"""
|
||||
Fügt einen Song oder eine komplette YouTube-Playlist zur Warteschlange hinzu.
|
||||
"""
|
||||
# Playlist oder Einzelvideo abrufen
|
||||
data = await asyncio.get_event_loop().run_in_executor(
|
||||
None, lambda: ytdl.extract_info(url, download=False)
|
||||
)
|
||||
|
||||
added_titles = []
|
||||
|
||||
if 'entries' in data:
|
||||
for entry in data['entries']:
|
||||
playlist_queue.append({'url': entry['url'], 'title': entry['title'], 'data': entry})
|
||||
added_titles.append(entry['title'])
|
||||
else:
|
||||
playlist_queue.append({'url': data['url'], 'title': data['title'], 'data': data})
|
||||
added_titles.append(data['title'])
|
||||
|
||||
await ctx.send(f"✅ Added {len(added_titles)} track(s) to the playlist:\n" +
|
||||
"\n".join(f"- {t}" for t in added_titles[:10]) +
|
||||
(f"\n… +{len(added_titles)-10} more" if len(added_titles) > 10 else ""))
|
||||
|
||||
if not ctx.voice_client and ctx.author.voice:
|
||||
await ctx.author.voice.channel.connect()
|
||||
|
||||
if ctx.voice_client and not ctx.voice_client.is_playing():
|
||||
await play_next(ctx)
|
||||
|
||||
@bot.command(name="playlist")
|
||||
async def playlist_cmd(ctx):
|
||||
"""
|
||||
Zeigt die aktuelle Playlist/Warteschlange an.
|
||||
"""
|
||||
if not playlist_queue:
|
||||
await ctx.send("🎵 Die Playlist ist leer.")
|
||||
else:
|
||||
text = "\n".join([f"{idx+1}. {track['title']}" for idx, track in enumerate(playlist_queue[:20])])
|
||||
await ctx.send(f"🎵 **Aktuelle Playlist:**\n{text}")
|
||||
|
||||
# =====================
|
||||
# YTDL / FFMPEG SETUP
|
||||
# =====================
|
||||
|
@ -165,10 +227,6 @@ ffmpeg_options = {
|
|||
ytdl = youtube_dl.YoutubeDL(ytdl_format_options)
|
||||
|
||||
class YTDLSource(discord.PCMVolumeTransformer):
|
||||
"""
|
||||
Handles downloading and streaming audio from YouTube.
|
||||
"""
|
||||
|
||||
def __init__(self, source, *, data, volume=0.5):
|
||||
super().__init__(source, volume)
|
||||
self.data = data
|
||||
|
@ -177,13 +235,19 @@ class YTDLSource(discord.PCMVolumeTransformer):
|
|||
@classmethod
|
||||
async def from_url(cls, url, *, loop=None, stream=False):
|
||||
loop = loop or asyncio.get_event_loop()
|
||||
data = await loop.run_in_executor(
|
||||
None, lambda: ytdl.extract_info(url, download=not stream)
|
||||
)
|
||||
try:
|
||||
data = await loop.run_in_executor(
|
||||
None, lambda: ytdl.extract_info(url, download=not stream)
|
||||
)
|
||||
except Exception as e:
|
||||
return None, e
|
||||
|
||||
if "entries" in data:
|
||||
data = data["entries"][0]
|
||||
|
||||
filename = data["url"] if stream else ytdl.prepare_filename(data)
|
||||
return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data)
|
||||
return cls(discord.FFmpegPCMAudio(filename, **ffmpeg_options), data=data), None
|
||||
|
||||
|
||||
# =====================
|
||||
# VOICE / MUSIC COMMANDS
|
||||
|
@ -208,24 +272,23 @@ async def leave(ctx):
|
|||
|
||||
@bot.command(name="play")
|
||||
async def play(ctx, *, url):
|
||||
"""
|
||||
Streams audio from a given YouTube URL to the connected voice channel.
|
||||
Adds interactive buttons to control playback.
|
||||
"""
|
||||
# Connect to voice channel if not already connected
|
||||
"""Streams Audio von einer YouTube URL"""
|
||||
if not ctx.voice_client:
|
||||
if ctx.author.voice:
|
||||
await ctx.author.voice.channel.connect()
|
||||
else:
|
||||
await ctx.send("You are not in a voice channel!")
|
||||
await ctx.send("Du bist in keinem Sprachkanal!")
|
||||
return
|
||||
|
||||
# Start streaming
|
||||
player = await YTDLSource.from_url(url, loop=bot.loop, stream=True)
|
||||
player, error = await YTDLSource.from_url(url, loop=bot.loop, stream=True)
|
||||
if error or not player:
|
||||
await ctx.send("⚠️ Konnte den Titel nicht abspielen. "
|
||||
"YouTube Restrictions blockieren möglicherweise den Zugriff.")
|
||||
return
|
||||
|
||||
ctx.voice_client.stop()
|
||||
ctx.voice_client.play(player)
|
||||
|
||||
# Create interactive buttons
|
||||
stop_button = Button(label="Stop", style=discord.ButtonStyle.red)
|
||||
pause_button = Button(label="Pause", style=discord.ButtonStyle.gray)
|
||||
resume_button = Button(label="Resume", style=discord.ButtonStyle.green)
|
||||
|
@ -245,12 +308,10 @@ async def play(ctx, *, url):
|
|||
ctx.voice_client.resume()
|
||||
await interaction.response.defer()
|
||||
|
||||
# Attach callbacks
|
||||
stop_button.callback = stop_callback
|
||||
pause_button.callback = pause_callback
|
||||
resume_button.callback = resume_callback
|
||||
|
||||
# Build and send view
|
||||
view = View()
|
||||
view.add_item(stop_button)
|
||||
view.add_item(pause_button)
|
||||
|
|
Loading…
Add table
Reference in a new issue