2023-07-31 23:07:33 -04:00
import asyncio
import re
2023-07-31 21:35:15 -04:00
import discord
2023-08-01 00:03:00 -04:00
import os
2023-07-31 23:07:33 -04:00
from yt_dlp import YoutubeDL
2023-07-31 21:35:15 -04:00
from redbot . core import commands , checks , Config , data_manager
class MusicDownloader ( commands . Cog ) :
def __init__ ( self , bot ) :
self . bot = bot
self . config = Config . get_conf ( self , identifier = 475728338 )
self . config . register_global (
2023-08-01 00:03:00 -04:00
save_directory = str ( data_manager . cog_data_path ( ) ) + f " { os . sep } MusicDownloader "
2023-07-31 21:35:15 -04:00
)
@commands.command ( )
async def change_data_path ( self , ctx : commands . Context , data_path : str = None ) :
""" This command changes the data path this cog outputs to. """
old_path = await self . config . save_directory ( )
2023-08-01 00:03:00 -04:00
if os . path . isdir ( data_path ) :
2023-07-31 21:35:15 -04:00
await self . config . save_directory . set ( data_path )
embed = discord . Embed ( color = await self . bot . get_embed_color ( None ) , description = f " The save directory has been set to ` { data_path } `. \n It was previously set to ` { old_path } `. " )
await ctx . send ( embed = embed )
2023-08-01 00:03:00 -04:00
elif os . path . isfile ( data_path ) :
2023-07-31 21:35:15 -04:00
await ctx . send ( " The path you ' ve provided leads to a file, not a directory! " )
2023-08-01 00:03:00 -04:00
elif os . path . exists ( data_path ) is False :
2023-07-31 21:35:15 -04:00
await ctx . send ( " The path you ' ve provided doesn ' t exist! " )
2023-07-31 23:07:33 -04:00
@commands.command ( aliases = [ " dl " ] )
async def download ( self , ctx : commands . Context , url : str , subfolder : str = None ) :
""" This command downloads a YouTube Video as an MP3 to the local music directory. """
def youtube_download ( self , url : str , path : str , message : discord . Message ) :
""" This function does the actual downloading of the YouTube Video. """
class Logger :
def debug ( self , msg ) :
if msg . startswith ( ' [debug] ' ) :
pass
else :
self . info ( msg )
def info ( self , msg ) :
pass
def warning ( self , msg ) :
pass
def error ( self , msg ) :
print ( msg )
message . edit ( msg )
def hook ( d ) :
if d [ ' status ' ] == ' finished ' :
2023-08-01 00:03:23 -04:00
message . edit ( content = ' YouTube Downloader completed! ' )
2023-07-31 23:07:33 -04:00
ydl_opts = {
' logger ' : Logger ( ) ,
' progress_hooks ' : [ hook ] ,
' format ' : ' m4a/bestaudio/best ' ,
' postprocessors ' : [ { ' key ' : ' FFmpegExtractAudio ' , ' preferredcodec ' : ' m4a ' , } ] ,
2023-07-31 23:41:51 -04:00
' paths ' : { ' home ' : path }
2023-07-31 23:07:33 -04:00
}
with YoutubeDL ( ydl_opts ) as ydl :
2023-08-01 00:07:30 -04:00
info = ydl . extract_info ( url = url , download = True )
2023-08-01 00:03:48 -04:00
title = info [ ' title ' ]
return title
2023-07-31 23:07:33 -04:00
data_path = await self . config . save_directory ( )
if subfolder :
2023-08-01 00:03:00 -04:00
data_path = os . path . join ( data_path , subfolder )
2023-07-31 23:07:33 -04:00
illegal_chars = r ' <>: " / \ |?* '
if any ( char in illegal_chars for char in subfolder ) :
pattern = " [ " + re . escape ( illegal_chars ) + " ] "
modified_subfolder = re . sub ( pattern , r ' __** \ g<0>**__ ' , subfolder )
await ctx . send ( f " Your subfolder contains illegal characters: ` { modified_subfolder } ` " )
return
2023-08-01 00:03:00 -04:00
elif os . path . isfile ( data_path ) :
2023-07-31 23:07:33 -04:00
await ctx . send ( " Your ' subfolder ' is a file, not a directory! " )
return
2023-08-01 00:03:00 -04:00
elif os . path . exists ( data_path ) is False :
2023-07-31 23:07:33 -04:00
message = await ctx . send ( " Your subfolder does not exist yet, would you like to continue? It will be automatically created. " )
def check ( message ) :
return message . author == ctx . author and message . content . lower ( ) in [ ' yes ' , ' ye ' , ' y ' ]
try :
await self . bot . wait_for ( ' message ' , check = check , timeout = 60 ) # Timeout after 60 seconds
except asyncio . TimeoutError :
await message . edit ( " You took too long to respond. " )
else :
await message . edit ( " Confirmed! " )
try :
2023-08-01 00:03:00 -04:00
os . makedirs ( data_path )
2023-07-31 23:07:33 -04:00
except OSError as e :
await message . edit ( f " Encountered an error attempting to create the subfolder! \n ` { e } ` " )
2023-07-31 23:24:28 -04:00
msg = message . edit
2023-07-31 23:22:59 -04:00
else :
2023-07-31 23:24:28 -04:00
msg = ctx . send
message = await msg ( " YouTube Downloader started! " )
2023-08-01 00:03:48 -04:00
title = youtube_download ( self , url , data_path , message )
matching_files = [ file for file in os . listdir ( data_path ) if file . startswith ( title ) ]
if len ( matching_files ) == 1 :
full_filename = os . path . join ( data_path , matching_files [ 0 ] )
with open ( full_filename , ' r ' ) as file :
await ctx . send ( content = " Downloaded file: " , file = discord . File ( file , f ' { title } .m4a ' ) )