made changes to disconnect, began queue implementation

This commit is contained in:
Jellyfishsh 2025-04-19 00:01:53 -07:00
parent bdfec840dd
commit f63d6f2484

94
bot.py
View File

@ -1,5 +1,6 @@
# Imports # Imports
import os import os
from discord.webhook.async_ import interaction_message_response_params
import requests import requests
import discord import discord
from discord.ext import commands from discord.ext import commands
@ -47,6 +48,8 @@ bot = JellyfinBot()
async def on_ready(): async def on_ready():
print(f"🪼 Logged in as {bot.user}") print(f"🪼 Logged in as {bot.user}")
# ----- Helpful Structures ----- #
guild_queue_dict = dict()
# ----- Helper Functions ----- # # ----- Helper Functions ----- #
@ -82,15 +85,15 @@ async def make_request(url: str, params: dict, interaction: discord.Interaction)
# Play a song # Play a song
# Play function # Play function
# Plays a song with the given title in wherever the user is # Plays a song with the given title in wherever the user is
# start play ----- # start play -----
@bot.tree.command(name="play", description="Play a song from Jellyfin") @bot.tree.command(name="play", description="Play a song from Jellyfin")
@app_commands.describe(title="Song title to play") @app_commands.describe(title="Song title to play")
async def play(interaction: discord.Interaction, title: str): async def play(interaction: discord.Interaction, title: str):
# Makes the reaction visible to everyone # Makes the reaction visible to everyone
await interaction.response.defer() await interaction.response.defer()
@ -101,18 +104,16 @@ async def play(interaction: discord.Interaction, title: str):
voice_status = await interaction.user.fetch_voice() voice_status = await interaction.user.fetch_voice()
user_channel = voice_status.channel user_channel = voice_status.channel
voice_client = interaction.guild.voice_client # Enables the voice feature for the bot voice_client = interaction.guild.voice_client # Enables the voice feature for the bot
# If its not connected to a voice channel, then connect to the channel that the caller is in
if voice_client is None:
voice_client = await user_channel.connect()
# If the caller is in a channel that its not already in, move there # First check if it is already in a voice channel
elif voice_client.channel != user_channel: if voice_client.channel != user_channel:
await voice_client.move_to(user_channel) voice_client.disconnect()
voice_client = await user_channel.connect()
#Pause the music that is currently playing
if voice_client.is_playing(): if voice_client.is_playing():
voice_client.stop() voice_client.stop()
# Finally, connect
await user_channel.connect()
except discord.errors.NotFound as e: except discord.errors.NotFound as e:
print(f"Error: {e}") print(f"Error: {e}")
await interaction.followup.send("Nope! Not in a voice!") await interaction.followup.send("Nope! Not in a voice!")
@ -141,37 +142,56 @@ async def play(interaction: discord.Interaction, title: str):
print(f"Found {len(data)} items matching `{title}`.") print(f"Found {len(data)} items matching `{title}`.")
# Deconstructing the dict 'data' # Deconstructing the dict 'data'
song = data[0] query_song = data[0]
song_id = song.get('Id') query_song_id = query_song.get('Id')
song_title = song.get('Name') query_song_title = query_song.get('Name')
song_artist = song.get('AlbumArtist', ['Unknown Artist']) query_song_artist = query_song.get('AlbumArtist', ['Unknown Artist'])
# First, we make a dictionary that has a list inside.
# Then, we get the name of the guild and put that in the dictionary
# then AFTER, we put the song inside the list that the guild points to
# on the play command, we add that song to the list
try: # Check if the guild is not known guilds
#Setup for ffmpeg if guild_queue_dict.get(interaction.guild_id) == None:
audio_stream_url = f"{JELLYFIN_URL}/Audio/{song_id}/stream?static=True" # add it to the playlist dict
print(f"Stream URL: {audio_stream_url}") guild_queue_dict[interaction.guild_id] = list()
headers_str = f"-headers \"X-Emby-Token: {JELLYFIN_API_KEY}\""
# >>----- start PROBLEMS guild_queue_dict[interaction.guild_id].append((query_song_id, query_song_title, query_song_artist))
# Here is the problematic library. # If someone is already playing something, we just add to their queue.
# It might just be looking for Opus and not finding it # Probably a better way of piggybacking
source = discord.FFmpegOpusAudio(audio_stream_url, if voice_client.is_playing():
before_options=f'{headers_str} -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', await interaction.followup.send(f"Queued: **{query_song_title}** by *{query_song_artist}*")
options="-vn") return
# end PROBLEMS -----<< headers_str = f"-headers \"X-Emby-Token: {JELLYFIN_API_KEY}\""
for song in guild_queue_dict[interaction.guild_id]:
try:
# Song information from tuple
song_id = song[0]
song_title = song[1]
song_artist = song[2]
# Play the audio file audio_stream_url = f"{JELLYFIN_URL}/Audio/{song_id}/stream?static=True"
voice_client.play(source, after=lambda e: print(f"Finished playing: {e}")) source = discord.FFmpegOpusAudio(audio_stream_url,
await interaction.followup.send(f"🎶 Now playing: **{song_title}** by *{song_artist}*") before_options=f'{headers_str} -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5',
options="-vn")
# Play the grabbed audio file
voice_client.play(source, after=lambda e: print(f"Finished playing: {e}"))
await interaction.followup.send(f"Now playing: **{song_title}** by *{song_artist}*")
#Cheap way of holding the loop until its done
while voice_client.is_playing():
continue
# If the library does not exist, we fail it # Then, we get rid of this queued item
except discord.ClientException as e: guild_queue_dict[interaction.guild_id].pop(0)
await interaction.followup.send("Unable to decode your song!")
print(f"Potential FFMPEG/OPUS decoding error: {e}") except discord.ClientException as e:
await interaction.followup.send("Unable to decode your song!")
print(f"Potential FFMPEG/OPUS decoding error: {e}")
# end play ----- # end play -----
@ -215,11 +235,17 @@ async def search(interaction: discord.Interaction, title: str):
# Disconnects from the voice channel # Disconnects from the voice channel
@bot.tree.command(name="disconnect", description="Disconnects from current voice channel!") @bot.tree.command(name="disconnect", description="Disconnects from current voice channel!")
async def disconnect(interaction: discord.Interaction): async def disconnect(interaction: discord.Interaction):
# Checks if not in a voice channel
if interaction.guild.voice_client == None: if interaction.guild.voice_client == None:
await interaction.followup.send("I am not in any voice channel!") await interaction.followup.send("I am not in any voice channel!")
return return
# disconnects with a helpful message
await interaction.guild.voice_client.disconnect() await interaction.guild.voice_client.disconnect()
await interaction.followup.send("Disconnected!")
return
# Queues
# Enqueue an item