diff --git a/bot.py b/bot.py index eff54bb..7c5ba11 100644 --- a/bot.py +++ b/bot.py @@ -4,12 +4,9 @@ import discord from discord.ext import commands from discord import app_commands from dotenv import load_dotenv -import io -import asyncio load_dotenv() TOKEN = os.getenv("DISCORD_TOKEN") -GUILD_ID = discord.Object(id=1131317261202899034) JELLYFIN_URL = os.getenv("JELLYFIN_URL") JELLYFIN_API_KEY = os.getenv("JELLYFIN_API_KEY") @@ -26,8 +23,8 @@ class JellyfinBot(commands.Bot): super().__init__(command_prefix="/", intents=intents) async def setup_hook(self): - self.tree.copy_global_to(guild=GUILD_ID) - await self.tree.sync(guild=GUILD_ID) + # self.tree.copy_global_to() + await self.tree.sync() bot = JellyfinBot() @@ -35,10 +32,65 @@ bot = JellyfinBot() async def on_ready(): print(f"🪼 Logged in as {bot.user}") +@bot.tree.command(name="play", description="Play a song from Jellyfin") +@app_commands.describe(song="Song title to play") +async def play(interaction: discord.Interaction, song: str): + await interaction.response.defer(ephemeral=False) + + if not interaction.user.voice: + await interaction.response.send_message("You must be in a voice channel.") + return + + url = f"{JELLYFIN_URL}/Items" + params = { + "searchTerm": song, + "Recursive": True, + "IncludeItemTypes": "Audio", + "Limit": 5 + } + + try: + response = requests.get(url, headers=headers, params=params) + response.raise_for_status() + data = response.json().get("Items", []) + + if not data: + await interaction.followup.send(f"❌ No song found matching `{song}`.") + return + + print(f"Found {len(data)} items matching `{song}`.") + item = data[0] + item_id = item.get("Id") + stream_url = f"{JELLYFIN_URL}/Audio/{item_id}/stream?static=True" + + print(f"Stream URL: {stream_url}") + channel = interaction.user.voice.channel + voice_client = interaction.guild.voice_client + if voice_client is None: + voice_client = await channel.connect() + elif voice_client.channel != channel: + await voice_client.move_to(channel) + voice_client = await channel.connect() + + if voice_client.is_playing(): + voice_client.stop() + + headers_str = f"-headers \"X-Emby-Token: {JELLYFIN_API_KEY}\"" + source = discord.FFmpegPCMAudio(stream_url, before_options=f'{headers_str} -reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', options="-vn") + voice_client.play(source, after=lambda e: print(f"Finished playing: {e}")) + await interaction.followup.send(f"🎶 Now playing: **{item.get('Name')}** by *{item.get('AlbumArtist', ['Unknown Artist'])}*") + + except requests.RequestException as e: + await interaction.followup.send("⚠️ Failed to contact Jellyfin server.") + print(f"Error: {e}") + + + + @bot.tree.command(name="search", description="Search for a song on Jellyfin") @app_commands.describe(title="Song title to search for") async def search(interaction: discord.Interaction, title: str): - await interaction.response.defer(ephemeral=True) + await interaction.response.defer(ephemeral=False) url = f"{JELLYFIN_URL}/Items" params = { "searchTerm": title, diff --git a/output.mp3 b/output.mp3 new file mode 100644 index 0000000..5811349 Binary files /dev/null and b/output.mp3 differ