import os import tempfile import logging import requests import discord import yt_dlp from discord.ext import commands from dotenv import load_dotenv logger = logging.getLogger(__name__) # Load environment variables load_dotenv() class Downloader(commands.Cog): def __init__(self, bot): self.bot = bot @commands.slash_command( name="download", description="Download and convert video/audio from internet" ) async def download( self, ctx: discord.ApplicationContext, url: discord.Option(str, "URL of the video to download", required=True), fformat: discord.Option(str, "Output format (mp4, mp3, wav, etc.)", required=False, default="mp4") ): """Download and convert media from a URL to the specified format""" await ctx.defer() try: logger.info(f"Downloading {url} as {fformat}") with tempfile.TemporaryDirectory() as temp_dir: base_filename = os.path.join(temp_dir, 'output') input_file = f"{base_filename}.%(ext)s" output_file = f"{base_filename}.{fformat}" # Configure yt-dlp ydl_opts = { 'outtmpl': input_file, 'format': 'bestaudio/best' if fformat in ['mp3', 'wav', 'm4a'] else 'bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best', 'merge_output_format': 'mp4', 'postprocessors': [], } # Add post-processing for audio formats if fformat in ['mp3', 'wav', 'm4a']: ydl_opts['postprocessors'].append({ 'key': 'FFmpegExtractAudio', 'preferredcodec': fformat, 'preferredquality': '192', }) elif fformat != 'mp4': # For other video formats ydl_opts['postprocessors'].append({ 'key': 'FFmpegVideoConvertor', 'preferedformat': fformat, }) with yt_dlp.YoutubeDL(ydl_opts) as ydl: ydl.download([url]) # Find the downloaded file (yt-dlp might add a number if filename exists) actual_file = None for file in os.listdir(temp_dir): if file.startswith('output') and file.endswith(fformat): actual_file = os.path.join(temp_dir, file) break if not actual_file or not os.path.exists(actual_file): raise Exception(f"{fformat} ze mno wygroł...") # Check file size and handle accordingly file_size = os.path.getsize(actual_file) if file_size < 10 * 1024 * 1024: # Under 10MB file = discord.File(actual_file, filename=f"output.{fformat}") await ctx.followup.send("pobran", file=file) else: # 10MB or larger - upload to Pixeldrain try: # Get file info filename = f"output.{fformat}" file_size_mb = file_size / (1024 * 1024) # Upload to Litterbox Catbox with open(actual_file, 'rb') as f: files = { 'reqtype': (None, 'fileupload'), 'time': (None, '24h'), 'fileToUpload': (filename, f, 'application/octet-stream') } await ctx.followup.send(f"plik jest {file_size_mb:.1f} megabajtów... wysyłanie do gorzowa...") response = requests.post( 'https://litterbox.catbox.moe/resources/internals/api.php', files=files ) if response.status_code == 200 and response.text.startswith('http'): dl_url = response.text.strip() await ctx.followup.send( f"wysyłon\n" f"pobrań: {dl_url}\n" ) else: error_msg = response.text if response.text else 'Unknown error' await ctx.followup.send(f"nie udało się wysłać pliku: {error_msg}") except Exception as upload_error: await ctx.followup.send(f"litterbox mnie nienawidzi :cccc\n {str(upload_error)}") logger.error(f"litterbox upload error: {upload_error}", exc_info=True) logger.info(f"File processed: {actual_file} ({file_size} bytes)") except Exception as e: await ctx.followup.send(f":(\n{str(e)}") logger.error(f"Error in download command: {e}", exc_info=True) def setup(bot): bot.add_cog(Downloader(bot))