From 6d61482216ea86357b4ac3683f88dcc6c2f53ce2 Mon Sep 17 00:00:00 2001 From: neoarz Date: Wed, 10 Dec 2025 13:19:43 -0500 Subject: [PATCH] chore: rm download --- README.md | 2 +- cogs/media/__init__.py | 19 +- cogs/media/download.py | 531 ----------------------------------------- docker-compose.yml | 1 - requirements.txt | 1 - 5 files changed, 2 insertions(+), 552 deletions(-) delete mode 100644 cogs/media/download.py diff --git a/README.md b/README.md index 36f35d8..400de37 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ | events | `baitbot` | | miscellaneous | `keanu`, `labubu`, `piracy`, `tryitandsee`, `rickroll`, `dontasktoask`, `support`, `depart`, `docs` `sigma`, `duck`, `silly`, `color` | | utilities | `translate`, `codepreview`, `dictionary` | -| media | `download`, `mcquote`, `img2gif`, `tweety`, `tts` | +| media | `mcquote`, `img2gif`, `tweety`, `tts` | ## Download diff --git a/cogs/media/__init__.py b/cogs/media/__init__.py index 3acbddd..255c6ca 100644 --- a/cogs/media/__init__.py +++ b/cogs/media/__init__.py @@ -4,7 +4,6 @@ from discord.ext import commands from discord.ext.commands import Context from typing import Optional -from .download import download_command from .mcquote import mcquote_command from .img2gif import img2gif_command from .tweety import tweety_command @@ -63,15 +62,12 @@ class Media(commands.GroupCog, name="media"): ) embed.add_field( name="Available", - value="download, mcquote, img2gif, tweety, tts", + value="mcquote, img2gif, tweety, tts", inline=False, ) await context.send(embed=embed) async def _invoke_hybrid(self, context: Context, name: str, *args, **kwargs): - if name == "download": - await self.download(context, url=kwargs.get("url", "")) - return if name == "mcquote": await self.mcquote(context, text=kwargs.get("text", "")) return @@ -86,10 +82,6 @@ class Media(commands.GroupCog, name="media"): return await context.send(f"Unknown media command: {name}") - @media_group.command(name="download") - async def media_group_download(self, context: Context, *, url: str): - await self._invoke_hybrid(context, "download", url=url) - @media_group.command(name="mcquote") async def media_group_mcquote(self, context: Context, *, text: str): await self._invoke_hybrid(context, "mcquote", text=text) @@ -108,14 +100,6 @@ class Media(commands.GroupCog, name="media"): async def media_group_tts(self, context: Context, *, text: str = None): await self._invoke_hybrid(context, "tts", text=text) - @commands.check(_require_group_prefix) - @commands.hybrid_command( - name="download", - description="Download a video from a URL using yt-dlp.", - ) - async def download(self, context, *, url: str): - return await download_command()(self, context, url=url) - @commands.check(_require_group_prefix) @commands.hybrid_command( name="mcquote", @@ -153,7 +137,6 @@ async def setup(bot) -> None: cog = Media(bot) await bot.add_cog(cog) - bot.logger.info("Loaded extension 'media.download'") bot.logger.info("Loaded extension 'media.mcquote'") bot.logger.info("Loaded extension 'media.img2gif'") bot.logger.info("Loaded extension 'media.tweety'") diff --git a/cogs/media/download.py b/cogs/media/download.py deleted file mode 100644 index a974acd..0000000 --- a/cogs/media/download.py +++ /dev/null @@ -1,531 +0,0 @@ -import asyncio -import os -import tempfile -import discord -from discord.ext import commands -import yt_dlp -from urllib.parse import urlparse -import aiohttp -import logging - -logger = logging.getLogger("discord_bot") - - -def download_command(): - @commands.hybrid_command( - name="download", - description="Download a video from a URL using yt-dlp.", - ) - @commands.cooldown(1, 30, commands.BucketType.user) - async def download(self, context, *, url: str): - if isinstance(context.channel, discord.DMChannel): - embed = discord.Embed( - title="Error", - description="This command can only be used in servers.", - color=0xE02B2B, - ) - embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - interaction = getattr(context, "interaction", None) - if interaction is not None: - if not interaction.response.is_done(): - await interaction.response.send_message(embed=embed, ephemeral=True) - else: - await interaction.followup.send(embed=embed, ephemeral=True) - else: - await context.send(embed=embed, ephemeral=True) - return - - if isinstance(context.channel, discord.PartialMessageable): - embed = discord.Embed( - title="Error", - description="The bot needs the `send messages` permission in this channel.", - color=0xE02B2B, - ) - embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - interaction = getattr(context, "interaction", None) - if interaction is not None: - if not interaction.response.is_done(): - await interaction.response.send_message(embed=embed, ephemeral=True) - else: - await interaction.followup.send(embed=embed, ephemeral=True) - else: - await context.send(embed=embed, ephemeral=True) - return - - if not url: - embed = discord.Embed( - title="Error", - description="Please provide a valid URL to download.", - color=0xE02B2B, - ) - embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - interaction = getattr(context, "interaction", None) - if interaction is not None: - if not interaction.response.is_done(): - await interaction.response.send_message(embed=embed, ephemeral=True) - else: - await interaction.followup.send(embed=embed, ephemeral=True) - else: - await context.send(embed=embed, ephemeral=True) - return - - # Check if bot has send messages permission before starting download - try: - test_embed = discord.Embed(title="Testing permissions...", color=0x7289DA) - test_embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - await context.channel.send(embed=test_embed, delete_after=0.1) - except discord.Forbidden: - embed = discord.Embed( - title="Permission Error", - description="The bot needs the `send messages` permission to execute this command.", - color=0xE02B2B, - ) - embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - interaction = getattr(context, "interaction", None) - if interaction is not None: - if not interaction.response.is_done(): - await interaction.response.send_message(embed=embed, ephemeral=True) - else: - await interaction.followup.send(embed=embed, ephemeral=True) - else: - await context.send(embed=embed, ephemeral=True) - return - - try: - parsed_url = urlparse(url) - if not parsed_url.scheme or not parsed_url.netloc: - embed = discord.Embed( - title="Error", - description="Please provide a valid URL.", - color=0xE02B2B, - ) - embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - interaction = getattr(context, "interaction", None) - if interaction is not None: - if not interaction.response.is_done(): - await interaction.response.send_message( - embed=embed, ephemeral=True - ) - else: - await interaction.followup.send(embed=embed, ephemeral=True) - else: - await context.send(embed=embed, ephemeral=True) - return - except Exception: - embed = discord.Embed( - title="Error", - description="Please provide a valid URL.", - color=0xE02B2B, - ) - embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - interaction = getattr(context, "interaction", None) - if interaction is not None: - if not interaction.response.is_done(): - await interaction.response.send_message(embed=embed, ephemeral=True) - else: - await interaction.followup.send(embed=embed, ephemeral=True) - else: - await context.send(embed=embed, ephemeral=True) - return - - processing_embed = discord.Embed( - title="Download (Processing)", - description=" Downloading video... This may take a moment.", - color=0x7289DA, - ) - processing_embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - interaction = getattr(context, "interaction", None) - if interaction is not None: - if not interaction.response.is_done(): - await interaction.response.send_message( - embed=processing_embed, ephemeral=True - ) - else: - await interaction.followup.send(embed=processing_embed, ephemeral=True) - else: - processing_msg = await context.send(embed=processing_embed) - - temp_dir = tempfile.mkdtemp() - - # Try Docker path first, fallback to local path for development - cookie_path = "/bot/cogs/media/files/cookies.txt" - if not os.path.exists(cookie_path): - cookie_path = os.path.join( - os.path.dirname(__file__), "files", "cookies.txt" - ) - - ydl_opts = { - "format": "bestvideo[filesize<200M]+bestaudio[filesize<200M]/best[filesize<200M]/bestvideo+bestaudio/best", - "outtmpl": os.path.join(temp_dir, "%(title)s.%(ext)s"), - "noplaylist": True, - "extract_flat": False, - "writesubtitles": False, - "writeautomaticsub": False, - "writethumbnail": False, - "ignoreerrors": False, - "merge_output_format": "mp4", - "cookiefile": cookie_path, - } - - try: - with yt_dlp.YoutubeDL(ydl_opts) as ydl: - info = await asyncio.get_event_loop().run_in_executor( - None, lambda: ydl.extract_info(url, download=True) - ) - - if not info: - raise Exception("Could not extract video information") - - video_title = info.get("title", "Unknown Title") - video_duration_seconds = int(info.get("duration") or 0) - video_uploader = info.get("uploader", "Unknown") - video_url = info.get("webpage_url") or info.get("original_url") or url - platform = ( - info.get("extractor") or info.get("extractor_key") or "Unknown" - ) - view_count = info.get("view_count") - - files = [ - f - for f in os.listdir(temp_dir) - if os.path.isfile(os.path.join(temp_dir, f)) - ] - - if not files: - raise Exception("No video file was downloaded") - - video_file = os.path.join(temp_dir, files[0]) - file_size = os.path.getsize(video_file) - logger.info( - f"File size: {file_size} bytes ({file_size / (1024 * 1024):.2f} MB)" - ) - - if file_size > 24 * 1024 * 1024: # 24MB limit - logger.info("File is over 24MB, uploading to Catbox") - - async def upload_to_catbox(path: str) -> str: - try: - file_size_bytes = os.path.getsize(path) - except Exception: - file_size_bytes = -1 - logger.info( - f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}" - ) - form = aiohttp.FormData() - form.add_field("reqtype", "fileupload") - form.add_field( - "fileToUpload", - open(path, "rb"), - filename=os.path.basename(path), - ) - timeout = aiohttp.ClientTimeout(total=600) - async with aiohttp.ClientSession(timeout=timeout) as session: - async with session.post( - "https://catbox.moe/user/api.php", data=form - ) as resp: - text = await resp.text() - logger.info( - f"Catbox response: status={resp.status} body_len={len(text)}" - ) - if resp.status == 200 and text.startswith("https://"): - url_text = text.strip() - logger.info( - f"Catbox upload success: url={url_text}" - ) - return url_text - logger.error( - f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}" - ) - raise RuntimeError(f"Upload failed: {text.strip()}") - - try: - link = await upload_to_catbox(video_file) - minutes, seconds = divmod(video_duration_seconds, 60) - duration_str = f"{minutes}:{seconds:02d}" - description_text = ( - f"### **[{video_title}]({video_url})**" - if video_url - else f"### **{video_title}**" - ) - embed = discord.Embed( - title="Download", - description=description_text, - color=0x7289DA, - ) - embed.set_author( - name="Media", - icon_url="https://yes.nighty.works/raw/y5SEZ9.webp", - ) - embed.add_field( - name="Uploader", - value=video_uploader or "Unknown", - inline=True, - ) - embed.add_field( - name="Duration", value=duration_str, inline=True - ) - embed.add_field(name="Platform", value=platform, inline=True) - embed.set_footer( - text=f"Requested by {context.author.name}", - icon_url=context.author.display_avatar.url, - ) - - if interaction is not None: - await context.channel.send(embed=embed) - await context.channel.send(link) - try: - await interaction.delete_original_response() - except: - pass - else: - await processing_msg.delete() - await context.channel.send(embed=embed) - await context.channel.send(link) - return - except Exception as upload_error: - logger.exception(f"Catbox upload exception: {upload_error}") - error_msg = str(upload_error) - if "greater than 200mb" in error_msg.lower(): - description = "The video is too large to upload. The file exceeds 200MB (Catbox limit) and cannot be sent via Discord (25MB limit)." - else: - description = f"The video is over 25MB and upload to hosting failed: {upload_error}" - - embed = discord.Embed( - title="Error", - description=description, - color=0xE02B2B, - ) - embed.set_author( - name="Media", - icon_url="https://yes.nighty.works/raw/y5SEZ9.webp", - ) - - if interaction is not None: - try: - await interaction.delete_original_response() - except: - pass - await interaction.followup.send(embed=embed, ephemeral=True) - else: - await processing_msg.delete() - await context.send(embed=embed, ephemeral=True) - return - else: - logger.info("File is under 24MB, sending directly to Discord") - minutes, seconds = divmod(video_duration_seconds, 60) - duration_str = f"{minutes}:{seconds:02d}" - description_text = ( - f"### **[{video_title}]({video_url})**" - if video_url - else f"### **{video_title}**" - ) - embed = discord.Embed( - title="Download", - description=description_text, - color=0x7289DA, - ) - embed.set_author( - name="Media", - icon_url="https://yes.nighty.works/raw/y5SEZ9.webp", - ) - embed.add_field( - name="Uploader", value=video_uploader or "Unknown", inline=True - ) - embed.add_field(name="Duration", value=duration_str, inline=True) - embed.add_field(name="Platform", value=platform, inline=True) - embed.set_footer( - text=f"Requested by {context.author.name}", - icon_url=context.author.display_avatar.url, - ) - - try: - with open(video_file, "rb") as f: - file = discord.File(f, filename=files[0]) - - if interaction is not None: - await context.channel.send(embed=embed) - await context.channel.send(file=file) - try: - await interaction.delete_original_response() - except: - pass - else: - await processing_msg.delete() - await context.channel.send(embed=embed) - await context.channel.send(file=file) - except discord.HTTPException as e: - if e.status == 413: - logger.info( - "Discord rejected file (413), falling back to Catbox upload" - ) - - async def upload_to_catbox(path: str) -> str: - try: - file_size_bytes = os.path.getsize(path) - except Exception: - file_size_bytes = -1 - logger.info( - f"Catbox upload start: name={os.path.basename(path)} size={file_size_bytes}" - ) - form = aiohttp.FormData() - form.add_field("reqtype", "fileupload") - form.add_field( - "fileToUpload", - open(path, "rb"), - filename=os.path.basename(path), - ) - timeout = aiohttp.ClientTimeout(total=600) - async with aiohttp.ClientSession( - timeout=timeout - ) as session: - async with session.post( - "https://catbox.moe/user/api.php", data=form - ) as resp: - text = await resp.text() - logger.info( - f"Catbox response: status={resp.status} body_len={len(text)}" - ) - if resp.status == 200 and text.startswith( - "https://" - ): - url_text = text.strip() - logger.info( - f"Catbox upload success: url={url_text}" - ) - return url_text - logger.error( - f"Catbox upload failed: status={resp.status} body={text.strip()[:500]}" - ) - raise RuntimeError( - f"Upload failed: {text.strip()}" - ) - - try: - link = await upload_to_catbox(video_file) - description_text_with_link = ( - f"### **[{video_title}]({video_url})**\n\n{link}" - if video_url - else f"### **{video_title}**\n\n{link}" - ) - embed = discord.Embed( - title="Download", - description=description_text, - color=0x7289DA, - ) - embed.set_author( - name="Media", - icon_url="https://yes.nighty.works/raw/y5SEZ9.webp", - ) - embed.add_field( - name="Uploader", - value=video_uploader or "Unknown", - inline=True, - ) - embed.add_field( - name="Duration", value=duration_str, inline=True - ) - embed.add_field( - name="Platform", value=platform, inline=True - ) - embed.set_footer( - text=f"Requested by {context.author.name}", - icon_url=context.author.display_avatar.url, - ) - - if interaction is not None: - await context.channel.send(embed=embed) - await context.channel.send(link) - try: - await interaction.delete_original_response() - except: - pass - else: - await processing_msg.delete() - await context.channel.send(embed=embed) - await context.channel.send(link) - except Exception as upload_error: - logger.exception( - f"Catbox upload exception: {upload_error}" - ) - embed = discord.Embed( - title="Error", - description=f"Discord rejected the file and Catbox upload failed: {upload_error}", - color=0xE02B2B, - ) - embed.set_author( - name="Media", - icon_url="https://yes.nighty.works/raw/y5SEZ9.webp", - ) - - if interaction is not None: - try: - await interaction.delete_original_response() - except: - pass - await interaction.followup.send( - embed=embed, ephemeral=True - ) - else: - await processing_msg.delete() - await context.send(embed=embed, ephemeral=True) - else: - raise e - - except Exception as e: - embed = discord.Embed( - title="Error", - description=f"Failed to download video: {str(e)}", - color=0xE02B2B, - ) - embed.set_author( - name="Media", icon_url="https://yes.nighty.works/raw/y5SEZ9.webp" - ) - - if interaction is not None: - try: - await interaction.delete_original_response() - except: - pass - await interaction.followup.send(embed=embed, ephemeral=True) - else: - try: - await processing_msg.delete() - except: - pass - await context.send(embed=embed, ephemeral=True) - - finally: - for file in os.listdir(temp_dir): - try: - os.remove(os.path.join(temp_dir, file)) - except: - pass - try: - os.rmdir(temp_dir) - except: - pass - - return download diff --git a/docker-compose.yml b/docker-compose.yml index f7c276b..c99e68c 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -7,7 +7,6 @@ services: volumes: - ./database:/bot/database - ./discord.log:/bot/discord.log - - ./cogs/media/files:/bot/cogs/media/files # Alternatively you can set the environment variables as such: # /!\ The token shouldn't be written here, as this file is not ignored from Git /!\ diff --git a/requirements.txt b/requirements.txt index bacb642..15ff17f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,6 @@ aiohttp aiosqlite discord.py python-dotenv -yt-dlp Pillow pillow-heif pytz