Jonathan Jara d7a0068c05 readme
2025-04-18 15:10:48 -07:00

122 lines
3.9 KiB
Python

import os
import requests
import discord
from discord.ext import commands
from discord import app_commands
from dotenv import load_dotenv
load_dotenv()
TOKEN = os.getenv("DISCORD_TOKEN")
JELLYFIN_URL = os.getenv("JELLYFIN_URL")
JELLYFIN_API_KEY = os.getenv("JELLYFIN_API_KEY")
headers= {
"X-Emby-Token": JELLYFIN_API_KEY
}
intents = discord.Intents.default()
intents.message_content = True
intents.voice_states = True
class JellyfinBot(commands.Bot):
def __init__(self):
super().__init__(command_prefix="/", intents=intents)
async def setup_hook(self):
await self.tree.sync()
bot = JellyfinBot()
@bot.event
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=False)
url = f"{JELLYFIN_URL}/Items"
params = {
"searchTerm": title,
"Recursive": True,
"IncludeItemTypes": "Audio",
"Limit": 5
}
try:
response = requests.get(url, headers=headers, params=params)
response.raise_for_status()
data = response.json()
items = data.get("Items", [])
if not items:
await interaction.followup.send(f"❌ No song found matching `{title}`.")
return
lines = []
for item in items:
title = item.get("Name")
artist = item.get("AlbumArtist", ["Unknown Artist"])
lines.append(f"✅ **{title}** by *{artist}*")
await interaction.followup.send("\n".join(lines))
except requests.RequestException as e:
await interaction.followup.send("⚠️ Failed to contact Jellyfin server.")
print(f"Error: {e}")
bot.run(TOKEN)