Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
# Import necessary libraries for Discord bot, HuggingFace integration, and UI | |
import discord | |
from discord.ext import commands | |
from huggingface_hub import hf_hub_download | |
import gradio as gr | |
from dotenv import load_dotenv | |
import os | |
import threading | |
import asyncio | |
import spotipy | |
from spotipy.oauth2 import SpotifyClientCredentials | |
import yt_dlp | |
# Load environment variables from .env file | |
load_dotenv() | |
# Create assets directory and download sample music if not exists | |
if os.path.exists('assets') is False: | |
os.makedirs('assets', exist_ok=True) | |
hf_hub_download("not-lain/assets", "sample.mp3", repo_type="dataset",local_dir="assets") | |
# Set up Discord bot with necessary intents | |
intents = discord.Intents.default() | |
intents.message_content = True | |
bot = commands.Bot(command_prefix='!', intents=intents) | |
# Initialize Spotify client | |
spotify = spotipy.Spotify(client_credentials_manager=SpotifyClientCredentials( | |
client_id=os.getenv('SPOTIFY_CLIENT_ID'), | |
client_secret=os.getenv('SPOTIFY_CLIENT_SECRET') | |
)) | |
# Class to handle music playback functionality | |
class MusicBot: | |
def __init__(self): | |
# Initialize bot state variables | |
self.is_playing = False | |
self.voice_client = None | |
self.ydl_opts = { | |
'format': 'bestaudio/best', | |
'postprocessors': [{ | |
'key': 'FFmpegExtractAudio', | |
'preferredcodec': 'mp3', | |
'preferredquality': '192', | |
}], | |
} | |
async def join_voice(self, ctx): | |
# Method to join voice channel or move to user's channel | |
if ctx.author.voice: | |
channel = ctx.author.voice.channel | |
if self.voice_client is None: | |
self.voice_client = await channel.connect() | |
else: | |
await self.voice_client.move_to(channel) | |
else: | |
await ctx.send("You need to be in a voice channel!") | |
async def play_next(self, ctx): | |
# Method to play audio and handle playback completion | |
if not self.is_playing: | |
self.is_playing = True | |
try: | |
# Create audio source from local file | |
audio_source = discord.FFmpegPCMAudio("assets/sample.mp3") | |
def after_playing(e): | |
# Callback function when song ends | |
self.is_playing = False | |
if e: | |
print(f"Playback error: {e}") | |
# Test loop by default | |
asyncio.run_coroutine_threadsafe(self.play_next(ctx), bot.loop) | |
self.voice_client.play(audio_source, after=after_playing) | |
except Exception as e: | |
print(f"Error playing file: {e}") | |
await ctx.send("Error playing the song.") | |
self.is_playing = False | |
async def play_spotify(self, ctx, track_url): | |
if not self.is_playing: | |
self.is_playing = True | |
try: | |
# Extract Spotify track ID | |
track_id = track_url.split('/')[-1].split('?')[0] | |
track_info = spotify.track(track_id) | |
search_query = f"{track_info['name']} {track_info['artists'][0]['name']}" | |
# Use yt-dlp to find and download the audio | |
with yt_dlp.YoutubeDL(self.ydl_opts) as ydl: | |
# Search YouTube for the song | |
info = ydl.extract_info(f"ytsearch:{search_query}", download=False) | |
url = info['entries'][0]['url'] | |
# Play the audio | |
FFMPEG_OPTIONS = { | |
'before_options': '-reconnect 1 -reconnect_streamed 1 -reconnect_delay_max 5', | |
'options': '-vn', | |
} | |
audio_source = discord.FFmpegPCMAudio(url, **FFMPEG_OPTIONS) | |
def after_playing(e): | |
self.is_playing = False | |
if e: | |
print(f"Playback error: {e}") | |
self.voice_client.play(audio_source, after=after_playing) | |
return track_info['name'] | |
except Exception as e: | |
print(f"Error playing Spotify track: {e}") | |
await ctx.send("Error playing the song.") | |
self.is_playing = False | |
return None | |
# Create instance of MusicBot | |
music_bot = MusicBot() | |
async def on_ready(): | |
# Event handler for when bot is ready and connected | |
print(f'Bot is ready! Logged in as {bot.user}') | |
print("Syncing commands...") | |
try: | |
await bot.tree.sync(guild=None) # Set to None for global sync | |
print("Successfully synced commands globally!") | |
except discord.app_commands.errors.CommandSyncFailure as e: | |
print(f"Failed to sync commands: {e}") | |
except Exception as e: | |
print(f"An error occurred while syncing commands: {e}") | |
async def play(interaction: discord.Interaction, url: str): | |
# Command to start playing music | |
await interaction.response.defer() | |
ctx = await commands.Context.from_interaction(interaction) | |
if not url.startswith('https://open.spotify.com/track/'): | |
await interaction.followup.send('Please provide a valid Spotify track URL!') | |
return | |
await music_bot.join_voice(ctx) | |
if not music_bot.is_playing: | |
song_name = await music_bot.play_spotify(ctx, url) | |
if song_name: | |
await interaction.followup.send(f'Playing {song_name} from Spotify!') | |
else: | |
await interaction.followup.send('Failed to play the song!') | |
else: | |
await interaction.followup.send('Already playing!') | |
async def skip(interaction: discord.Interaction): | |
# Command to skip current playing song | |
if music_bot.voice_client: | |
music_bot.voice_client.stop() | |
await interaction.response.send_message('Skipped current song!') | |
else: | |
await interaction.response.send_message('No song is currently playing!') | |
async def leave(interaction: discord.Interaction): | |
# Command to disconnect bot from voice channel | |
if music_bot.voice_client: | |
await music_bot.voice_client.disconnect() | |
music_bot.voice_client = None | |
music_bot.queue = [] | |
music_bot.is_playing = False | |
await interaction.response.send_message('Bot disconnected!') | |
else: | |
await interaction.response.send_message('Bot is not in a voice channel!') | |
def run_discord_bot(): | |
# Function to start the Discord bot | |
bot.run(os.getenv('DISCORD_TOKEN')) | |
# Create Gradio interface for web control | |
with gr.Blocks() as iface: | |
# Set up simple web interface | |
gr.Markdown("# Discord Music Bot Control Panel") | |
gr.Markdown("Bot is running in background") | |
if __name__ == "__main__": | |
# Main entry point: start bot in background thread and launch web interface | |
bot_thread = threading.Thread(target=run_discord_bot, daemon=True) | |
bot_thread.start() | |
# Launch Gradio interface in main thread | |
iface.launch(debug=True) |