import os import tempfile import logging import requests import discord import re 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 URL_PATTERN = re.compile( r'https://(?:[A-Za-z0-9-]+\.)*[A-Za-z0-9-]{1,63}\.[A-Za-z]{2,63}/\S*' ) @commands.message_command( name="download", description="Download and convert video/audio from internet" ) async def message_download(self, ctx, message: discord.Message): # check if message has a valid url url = [m.group(0) for m in self.URL_PATTERN.finditer(message.content)] if url: for url in url: await self.download(ctx, url, "mp4") else: await ctx.respond("Brak załączników w wiadomości", ephemeral=True) @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: # Configure yt-dlp to use the original filename ydl_opts = { 'outtmpl': os.path.join(temp_dir, '%(title)s.%(ext)s'), '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 (should be the only file in the temp directory) files = [f for f in os.listdir(temp_dir) if os.path.isfile(os.path.join(temp_dir, f))] if not files: raise Exception(f"No file was downloaded") actual_file = os.path.join(temp_dir, files[0]) if not os.path.exists(actual_file): raise Exception(f"Downloaded file not found: {actual_file}") if os.path.getsize(actual_file) > 1024*1024*10: try: # Get file info filename = f"output.{fformat}" # Upload to Copyparty with open(actual_file, 'rb') as f: files = { 'f': (filename, f, 'application/octet-stream') } headers = { 'Cookie': f'cppwd={os.getenv("COPYPARTY_PASSWORD")}' } params = { 'j': '1', # Return JSON response 'ck': 'b2' # Use blake2b checksum } # Ensure the URL ends with a single slash base_url = "https://catbox.2137697.xyz/sperma/" response = requests.post( base_url, files=files, headers=headers, params=params ) if response.status_code == 200 or response.status_code == 201: try: result = response.json() if 'fileurl' in result: dl_url = result['fileurl'] await ctx.followup.send( f"wysyłon\n" f"{dl_url}\n" ) else: await ctx.followup.send( f"Odpowiedź serwera nie zawiera wymaganych danych: {result}") except ValueError: await ctx.followup.send(f"Nieprawidłowa odpowiedź z serwera: {response.text}") else: error_msg = response.text if response.text else 'Unknown error' await ctx.followup.send( f"nie udało się wysłać pliku (HTTP {response.status_code}): {error_msg}") except Exception as upload_error: await ctx.followup.send(f"copyparty mnie nienawidzi :cccc\n {str(upload_error)}") logger.error(f"copyparty upload error: {upload_error}", exc_info=True) else: await ctx.followup.send("wysyłon na discord\n", file=discord.File(actual_file)) logger.info(f"File processed: {actual_file}") 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))