From 72abc43db8f732743c65d6f6a820369ab8665766 Mon Sep 17 00:00:00 2001 From: salmonik Date: Wed, 4 Feb 2026 16:19:22 +0100 Subject: more asynchronous work and other minor improvements --- cogs/conversion.py | 181 ++++++++++++++++++++++++++++------------------------- 1 file changed, 97 insertions(+), 84 deletions(-) (limited to 'cogs/conversion.py') diff --git a/cogs/conversion.py b/cogs/conversion.py index 11f4f1b..f61d30f 100644 --- a/cogs/conversion.py +++ b/cogs/conversion.py @@ -8,8 +8,10 @@ import requests from discord.ext import commands import logging import os -import subprocess +import asyncio +import aiofiles import mimetypes +import subprocess logger = logging.getLogger(__name__) @@ -28,108 +30,119 @@ class Conversion(commands.Cog): def __init__(self, bot): self.bot = bot - @commands.slash_command(name="konwersja", description="konwertuj plik na inny format") - @discord.option( - "plik", - description="plik do konwersji", - required=True, - type=discord.Attachment - ) - @discord.option( - "format", - description="format konwersji", - required=True, - type=str - ) - async def convert(self, ctx, plik, output_format, args): - await ctx.defer() - # Save files to the temp directory inside the bot's root directory + async def _setup_file_paths(self, plik, output_format): + """Setup input and output file paths""" bot_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) temp_dir = os.path.join(bot_dir, "temp") if not os.path.exists(temp_dir): os.makedirs(temp_dir) + file_path = os.path.join(temp_dir, plik.filename) filename_noext = os.path.splitext(plik.filename)[0] await plik.save(file_path) - + input_path = file_path output_path = os.path.join(temp_dir, f"{filename_noext}k.{output_format}") - file_type = filetype(file_path) - logger.info(f"Conversion started for: {file_type}") - if file_type == "Video" or file_type == "Audio": - # Execute ffmpeg command to compress video - ffmpeg_command = f"ffmpeg -i {input_path} {args} {output_path}" + return input_path, output_path + + def _build_conversion_command(self, file_type, input_path, output_path, args): + """Build the appropriate conversion command based on file type""" + if file_type in ["Video", "Audio"]: + return f"ffmpeg -i {input_path} {args} {output_path}" elif file_type == "Image": - img_command = f"magick {input_path} {args} {output_path}" - ffmpeg_command = img_command + return f"magick {input_path} {args} {output_path}" else: - await ctx.respond("Plik jest nieobsługiwany", ephemeral=True) - logger.info("Unsupported file type") - return + return None + async def _upload_to_copyparty(self, output_path): + """Upload file to copyparty and return download URL""" try: - subprocess.run(ffmpeg_command, check=True, shell=True) - # Upload the compressed file - if os.path.getsize(output_path) > 1024*1024*10: - try: + async with aiofiles.open(output_path, 'rb') as f: + files = { + 'f': (output_path, f, 'application/octet-stream') + } + headers = { + 'Cookie': f'cppwd={os.getenv("COPYPARTY_PASSWORD")}' + } + params = { + 'j': '1', + 'ck': 'b2' + } + + base_url = "https://catbox.2137697.xyz/sperma/" + response = requests.post(base_url, files=files, headers=headers, params=params) + + if response.status_code in [200, 201]: + result = response.json() + if 'fileurl' in result: + return result['fileurl'] + else: + raise ValueError(f"Server response missing fileurl: {result}") + else: + error_msg = response.text if response.text else 'Unknown error' + raise requests.RequestException(f"HTTP {response.status_code}: {error_msg}") + + except Exception as e: + logger.error(f"copyparty upload error: {e}", exc_info=True) + raise - # Upload to Copyparty - with open(output_path, 'rb') as f: - files = { - 'f': (output_path, 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 - ) + async def _handle_file_output(self, ctx, output_path): + """Handle file output based on size""" + if os.path.getsize(output_path) > 1024*1024*10: + try: + dl_url = await self._upload_to_copyparty(output_path) + await ctx.followup.send(f"wysyłon\n{dl_url}\n") + except Exception as upload_error: + await ctx.followup.send(f"copyparty mnie nienawidzi :cccc\n {str(upload_error)}") + else: + await ctx.respond(file=discord.File(output_path)) - 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}") + def _cleanup_files(self, *file_paths): + """Clean up temporary files""" + for path in file_paths: + if os.path.exists(path): + os.remove(path) - 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.respond(file=discord.File(output_path)) + @commands.slash_command(name="konwersja", description="konwertuj plik na inny format") + @discord.option( + "plik", + description="plik do konwersji", + required=True, + type=discord.Attachment + ) + @discord.option( + "format", + description="format konwersji", + required=True, + type=str + ) + async def convert(self, ctx, plik, output_format, args): + await ctx.defer() + + try: + input_path, output_path = await self._setup_file_paths(plik, output_format) + file_type = filetype(input_path) + logger.info(f"Conversion started for: {file_type}") + + command = self._build_conversion_command(file_type, input_path, output_path, args) + if not command: + await ctx.respond("Plik jest nieobsługiwany", ephemeral=True) + logger.info("Unsupported file type") + return + + proc = await asyncio.create_subprocess_exec(*command.split()) + await proc.wait() + + await self._handle_file_output(ctx, output_path) logger.info(f"Conversion completed for: {file_type}") - # Delete compressed file - os.remove(input_path) - os.remove(output_path) + except subprocess.CalledProcessError as e: await ctx.respond(f"Conversion failed: {str(e)}", ephemeral=True) - if os.path.exists(input_path): - os.remove(input_path) - if os.path.exists(output_path): - os.remove(output_path) + except Exception as e: + await ctx.respond(f"An error occurred: {str(e)}", ephemeral=True) + finally: + if 'input_path' in locals(): + self._cleanup_files(input_path, output_path) def setup(bot): bot.add_cog(Conversion(bot)) \ No newline at end of file -- cgit v1.2.3