diff options
| author | salmonik <raisersoft@proton.me> | 2026-02-04 16:19:22 +0100 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-02-04 16:19:22 +0100 |
| commit | 72abc43db8f732743c65d6f6a820369ab8665766 (patch) | |
| tree | 094fafdb0baf2e06a02045b1b2c0be88931a379a /cogs/conversion.py | |
| parent | refactor music (diff) | |
| download | senator-sperma-72abc43db8f732743c65d6f6a820369ab8665766.tar.gz senator-sperma-72abc43db8f732743c65d6f6a820369ab8665766.zip | |
more asynchronous work and other minor improvements
Diffstat (limited to 'cogs/conversion.py')
| -rw-r--r-- | cogs/conversion.py | 181 |
1 files changed, 97 insertions, 84 deletions
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 | |||
| 8 | from discord.ext import commands | 8 | from discord.ext import commands |
| 9 | import logging | 9 | import logging |
| 10 | import os | 10 | import os |
| 11 | import subprocess | 11 | import asyncio |
| 12 | import aiofiles | ||
| 12 | import mimetypes | 13 | import mimetypes |
| 14 | import subprocess | ||
| 13 | 15 | ||
| 14 | logger = logging.getLogger(__name__) | 16 | logger = logging.getLogger(__name__) |
| 15 | 17 | ||
| @@ -28,108 +30,119 @@ class Conversion(commands.Cog): | |||
| 28 | def __init__(self, bot): | 30 | def __init__(self, bot): |
| 29 | self.bot = bot | 31 | self.bot = bot |
| 30 | 32 | ||
| 31 | @commands.slash_command(name="konwersja", description="konwertuj plik na inny format") | 33 | async def _setup_file_paths(self, plik, output_format): |
| 32 | @discord.option( | 34 | """Setup input and output file paths""" |
| 33 | "plik", | ||
| 34 | description="plik do konwersji", | ||
| 35 | required=True, | ||
| 36 | type=discord.Attachment | ||
| 37 | ) | ||
| 38 | @discord.option( | ||
| 39 | "format", | ||
| 40 | description="format konwersji", | ||
| 41 | required=True, | ||
| 42 | type=str | ||
| 43 | ) | ||
| 44 | async def convert(self, ctx, plik, output_format, args): | ||
| 45 | await ctx.defer() | ||
| 46 | # Save files to the temp directory inside the bot's root directory | ||
| 47 | bot_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) | 35 | bot_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) |
| 48 | temp_dir = os.path.join(bot_dir, "temp") | 36 | temp_dir = os.path.join(bot_dir, "temp") |
| 49 | if not os.path.exists(temp_dir): | 37 | if not os.path.exists(temp_dir): |
| 50 | os.makedirs(temp_dir) | 38 | os.makedirs(temp_dir) |
| 39 | |||
| 51 | file_path = os.path.join(temp_dir, plik.filename) | 40 | file_path = os.path.join(temp_dir, plik.filename) |
| 52 | filename_noext = os.path.splitext(plik.filename)[0] | 41 | filename_noext = os.path.splitext(plik.filename)[0] |
| 53 | await plik.save(file_path) | 42 | await plik.save(file_path) |
| 54 | 43 | ||
| 55 | input_path = file_path | 44 | input_path = file_path |
| 56 | output_path = os.path.join(temp_dir, f"{filename_noext}k.{output_format}") | 45 | output_path = os.path.join(temp_dir, f"{filename_noext}k.{output_format}") |
| 57 | file_type = filetype(file_path) | 46 | return input_path, output_path |
| 58 | logger.info(f"Conversion started for: {file_type}") | 47 | |
| 59 | if file_type == "Video" or file_type == "Audio": | 48 | def _build_conversion_command(self, file_type, input_path, output_path, args): |
| 60 | # Execute ffmpeg command to compress video | 49 | """Build the appropriate conversion command based on file type""" |
| 61 | ffmpeg_command = f"ffmpeg -i {input_path} {args} {output_path}" | 50 | if file_type in ["Video", "Audio"]: |
| 51 | return f"ffmpeg -i {input_path} {args} {output_path}" | ||
| 62 | elif file_type == "Image": | 52 | elif file_type == "Image": |
| 63 | img_command = f"magick {input_path} {args} {output_path}" | 53 | return f"magick {input_path} {args} {output_path}" |
| 64 | ffmpeg_command = img_command | ||
| 65 | else: | 54 | else: |
| 66 | await ctx.respond("Plik jest nieobsługiwany", ephemeral=True) | 55 | return None |
| 67 | logger.info("Unsupported file type") | ||
| 68 | return | ||
| 69 | 56 | ||
| 57 | async def _upload_to_copyparty(self, output_path): | ||
| 58 | """Upload file to copyparty and return download URL""" | ||
| 70 | try: | 59 | try: |
| 71 | subprocess.run(ffmpeg_command, check=True, shell=True) | 60 | async with aiofiles.open(output_path, 'rb') as f: |
| 72 | # Upload the compressed file | 61 | files = { |
| 73 | if os.path.getsize(output_path) > 1024*1024*10: | 62 | 'f': (output_path, f, 'application/octet-stream') |
| 74 | try: | 63 | } |
| 64 | headers = { | ||
| 65 | 'Cookie': f'cppwd={os.getenv("COPYPARTY_PASSWORD")}' | ||
| 66 | } | ||
| 67 | params = { | ||
| 68 | 'j': '1', | ||
| 69 | 'ck': 'b2' | ||
| 70 | } | ||
| 71 | |||
| 72 | base_url = "https://catbox.2137697.xyz/sperma/" | ||
| 73 | response = requests.post(base_url, files=files, headers=headers, params=params) | ||
| 74 | |||
| 75 | if response.status_code in [200, 201]: | ||
| 76 | result = response.json() | ||
| 77 | if 'fileurl' in result: | ||
| 78 | return result['fileurl'] | ||
| 79 | else: | ||
| 80 | raise ValueError(f"Server response missing fileurl: {result}") | ||
| 81 | else: | ||
| 82 | error_msg = response.text if response.text else 'Unknown error' | ||
| 83 | raise requests.RequestException(f"HTTP {response.status_code}: {error_msg}") | ||
| 84 | |||
| 85 | except Exception as e: | ||
| 86 | logger.error(f"copyparty upload error: {e}", exc_info=True) | ||
| 87 | raise | ||
| 75 | 88 | ||
| 76 | # Upload to Copyparty | 89 | async def _handle_file_output(self, ctx, output_path): |
| 77 | with open(output_path, 'rb') as f: | 90 | """Handle file output based on size""" |
| 78 | files = { | 91 | if os.path.getsize(output_path) > 1024*1024*10: |
| 79 | 'f': (output_path, f, 'application/octet-stream') | 92 | try: |
| 80 | } | 93 | dl_url = await self._upload_to_copyparty(output_path) |
| 81 | headers = { | 94 | await ctx.followup.send(f"wysyłon\n{dl_url}\n") |
| 82 | 'Cookie': f'cppwd={os.getenv("COPYPARTY_PASSWORD")}' | 95 | except Exception as upload_error: |
| 83 | } | 96 | await ctx.followup.send(f"copyparty mnie nienawidzi :cccc\n {str(upload_error)}") |
| 84 | params = { | 97 | else: |
| 85 | 'j': '1', # Return JSON response | 98 | await ctx.respond(file=discord.File(output_path)) |
| 86 | 'ck': 'b2' # Use blake2b checksum | ||
| 87 | } | ||
| 88 | |||
| 89 | # Ensure the URL ends with a single slash | ||
| 90 | base_url = "https://catbox.2137697.xyz/sperma/" | ||
| 91 | |||
| 92 | response = requests.post( | ||
| 93 | base_url, | ||
| 94 | files=files, | ||
| 95 | headers=headers, | ||
| 96 | params=params | ||
| 97 | ) | ||
| 98 | 99 | ||
| 99 | if response.status_code == 200 or response.status_code == 201: | 100 | def _cleanup_files(self, *file_paths): |
| 100 | try: | 101 | """Clean up temporary files""" |
| 101 | result = response.json() | 102 | for path in file_paths: |
| 102 | if 'fileurl' in result: | 103 | if os.path.exists(path): |
| 103 | dl_url = result['fileurl'] | 104 | os.remove(path) |
| 104 | await ctx.followup.send( | ||
| 105 | f"wysyłon\n" | ||
| 106 | f"{dl_url}\n" | ||
| 107 | ) | ||
| 108 | else: | ||
| 109 | await ctx.followup.send( | ||
| 110 | f"Odpowiedź serwera nie zawiera wymaganych danych: {result}") | ||
| 111 | except ValueError: | ||
| 112 | await ctx.followup.send(f"Nieprawidłowa odpowiedź z serwera: {response.text}") | ||
| 113 | else: | ||
| 114 | error_msg = response.text if response.text else 'Unknown error' | ||
| 115 | await ctx.followup.send( | ||
| 116 | f"nie udało się wysłać pliku (HTTP {response.status_code}): {error_msg}") | ||
| 117 | 105 | ||
| 118 | except Exception as upload_error: | 106 | @commands.slash_command(name="konwersja", description="konwertuj plik na inny format") |
| 119 | await ctx.followup.send(f"copyparty mnie nienawidzi :cccc\n {str(upload_error)}") | 107 | @discord.option( |
| 120 | logger.error(f"copyparty upload error: {upload_error}", exc_info=True) | 108 | "plik", |
| 121 | else: | 109 | description="plik do konwersji", |
| 122 | await ctx.respond(file=discord.File(output_path)) | 110 | required=True, |
| 111 | type=discord.Attachment | ||
| 112 | ) | ||
| 113 | @discord.option( | ||
| 114 | "format", | ||
| 115 | description="format konwersji", | ||
| 116 | required=True, | ||
| 117 | type=str | ||
| 118 | ) | ||
| 119 | async def convert(self, ctx, plik, output_format, args): | ||
| 120 | await ctx.defer() | ||
| 121 | |||
| 122 | try: | ||
| 123 | input_path, output_path = await self._setup_file_paths(plik, output_format) | ||
| 124 | file_type = filetype(input_path) | ||
| 125 | logger.info(f"Conversion started for: {file_type}") | ||
| 126 | |||
| 127 | command = self._build_conversion_command(file_type, input_path, output_path, args) | ||
| 128 | if not command: | ||
| 129 | await ctx.respond("Plik jest nieobsługiwany", ephemeral=True) | ||
| 130 | logger.info("Unsupported file type") | ||
| 131 | return | ||
| 132 | |||
| 133 | proc = await asyncio.create_subprocess_exec(*command.split()) | ||
| 134 | await proc.wait() | ||
| 135 | |||
| 136 | await self._handle_file_output(ctx, output_path) | ||
| 123 | logger.info(f"Conversion completed for: {file_type}") | 137 | logger.info(f"Conversion completed for: {file_type}") |
| 124 | # Delete compressed file | 138 | |
| 125 | os.remove(input_path) | ||
| 126 | os.remove(output_path) | ||
| 127 | except subprocess.CalledProcessError as e: | 139 | except subprocess.CalledProcessError as e: |
| 128 | await ctx.respond(f"Conversion failed: {str(e)}", ephemeral=True) | 140 | await ctx.respond(f"Conversion failed: {str(e)}", ephemeral=True) |
| 129 | if os.path.exists(input_path): | 141 | except Exception as e: |
| 130 | os.remove(input_path) | 142 | await ctx.respond(f"An error occurred: {str(e)}", ephemeral=True) |
| 131 | if os.path.exists(output_path): | 143 | finally: |
| 132 | os.remove(output_path) | 144 | if 'input_path' in locals(): |
| 145 | self._cleanup_files(input_path, output_path) | ||
| 133 | 146 | ||
| 134 | def setup(bot): | 147 | def setup(bot): |
| 135 | bot.add_cog(Conversion(bot)) \ No newline at end of file | 148 | bot.add_cog(Conversion(bot)) \ No newline at end of file |
