play from yt

This commit is contained in:
tavo-wasd 2024-04-07 23:44:22 -06:00
parent ba1ec53753
commit f693dd07ff
2 changed files with 64 additions and 31 deletions

View file

@ -5,6 +5,7 @@
. ./bin/activate ; . ./bin/activate ;
pip install discord ; pip install discord ;
pip install PyNaCl ; pip install PyNaCl ;
pip install fuzzywuzzy ;
pip install python-dotenv ; pip install python-dotenv ;
pip install ytmusicapi ;
pip install yt_dlp ;
) )

92
main.py
View file

@ -2,39 +2,65 @@ import discord
from discord.ext import commands from discord.ext import commands
import asyncio import asyncio
import os import os
from fuzzywuzzy import process
from dotenv import load_dotenv from dotenv import load_dotenv
import yt_dlp
from ytmusicapi import YTMusic
load_dotenv() load_dotenv()
songs_dir = os.getenv("SONGS_DIR")
intents = discord.Intents.default() intents = discord.Intents.default()
intents.message_content = True intents.message_content = True
intents.voice_states = True intents.voice_states = True
bot = commands.Bot(command_prefix='!', intents=intents) bot = commands.Bot(command_prefix='!', intents=intents)
queued_songs = [] queued_songs = []
voice_client = None # Global variable to track voice client voice_client = None
def find_song(query, songs_dir): def search_song(query):
best_match = None ytmusic = YTMusic()
best_confidence = 0 search_results = ytmusic.search(query, filter='songs', limit=1)
if search_results:
song_id = search_results[0]['videoId']
return song_id
else:
return None
def search_video(query):
ydl_opts = {
'default_search': 'auto',
'format': 'best',
'quiet': True
}
for root, dirs, files in os.walk(songs_dir): with yt_dlp.YoutubeDL(ydl_opts) as ydl:
for file in files: try:
if file.endswith(".mp3"): result = ydl.extract_info(query, download=False)
song_path = os.path.join(root, file) if 'entries' in result:
song_name = os.path.splitext(file)[0] # Take the first result
full_song_name = os.path.relpath(song_path, start=songs_dir) video_id = result['entries'][0]['id']
return video_id
else:
return None
except yt_dlp.DownloadError:
return None
confidence = process.extractOne(query, [song_name.replace("_", " ")])[1] def download_song(query):
if confidence > best_confidence: song_id = search_video(query)
best_match = song_path ydl_opts = {
best_confidence = confidence 'format': 'bestaudio/best',
'outtmpl': f'{songs_dir}/%(title)s.%(ext)s',
confidence = process.extractOne(query, [full_song_name.replace("_", " ")])[1] 'postprocessors': [{
if confidence > best_confidence: 'key': 'FFmpegExtractAudio',
best_match = song_path 'preferredcodec': 'mp3',
best_confidence = confidence 'preferredquality': '192',
}],
return best_match, best_confidence }
if not os.path.exists(songs_dir):
os.makedirs(songs_dir)
with yt_dlp.YoutubeDL(ydl_opts) as ydl:
info = ydl.extract_info(f'https://music.youtube.com/watch?v={song_id}', download=True)
filename = ydl.prepare_filename(info)
filename = os.path.splitext(filename)[0] + '.mp3'
return filename
@bot.command() @bot.command()
async def play(ctx, *, query): async def play(ctx, *, query):
@ -53,6 +79,10 @@ async def skip(ctx):
@bot.command() @bot.command()
async def stop(ctx): async def stop(ctx):
global voice_client global voice_client
for file in os.listdir(songs_dir):
file_path = os.path.join(songs_dir, file)
if os.path.isfile(file_path):
os.unlink(file_path)
if voice_client and voice_client.is_connected(): if voice_client and voice_client.is_connected():
queued_songs.clear() queued_songs.clear()
if voice_client.is_playing(): if voice_client.is_playing():
@ -63,11 +93,10 @@ async def stop(ctx):
async def add_to_queue(ctx, query): async def add_to_queue(ctx, query):
global voice_client global voice_client
songs_dir = os.getenv("SONGS_DIR") song_path = download_song(query)
# Find the closest match to the query print(song_path)
song_path, confidence = find_song(query, songs_dir)
if confidence >= 70 and song_path: # Adjust confidence threshold as needed if song_path:
song_name = os.path.relpath(song_path, start=songs_dir) # Get the song name relative to songs_dir song_name = os.path.relpath(song_path, start=songs_dir) # Get the song name relative to songs_dir
queued_songs.append((song_path, song_name)) queued_songs.append((song_path, song_name))
await ctx.send(f"**Added to queue:** `{song_name}`") await ctx.send(f"**Added to queue:** `{song_name}`")
@ -78,11 +107,10 @@ async def connect_and_play(ctx, query):
global voice_client global voice_client
voice_channel = ctx.author.voice.channel voice_channel = ctx.author.voice.channel
if voice_channel: if voice_channel:
songs_dir = os.getenv("SONGS_DIR") song_path = download_song(query)
# Find the closest match to the query print(song_path)
song_path, confidence = find_song(query, songs_dir)
if confidence >= 70 and song_path: # Adjust confidence threshold as needed if song_path:
song_name = os.path.relpath(song_path, start=songs_dir) # Get the song name relative to songs_dir song_name = os.path.relpath(song_path, start=songs_dir) # Get the song name relative to songs_dir
queued_songs.append((song_path, song_name)) queued_songs.append((song_path, song_name))
voice_client = await play_queued_songs(ctx, voice_channel) voice_client = await play_queued_songs(ctx, voice_channel)
@ -99,6 +127,10 @@ async def play_queued_songs(ctx, voice_channel):
while voice_client and voice_client.is_playing(): # Check if voice_client is not None while voice_client and voice_client.is_playing(): # Check if voice_client is not None
await asyncio.sleep(1) await asyncio.sleep(1)
if voice_client: if voice_client:
for file in os.listdir(songs_dir):
file_path = os.path.join(songs_dir, file)
if os.path.isfile(file_path):
os.unlink(file_path)
await voice_client.disconnect() await voice_client.disconnect()
bot.run(os.getenv("DISCORD_TOKEN")) bot.run(os.getenv("DISCORD_TOKEN"))