diff options
Diffstat (limited to '')
| -rw-r--r-- | cogs/compression.py | 76 |
1 files changed, 55 insertions, 21 deletions
diff --git a/cogs/compression.py b/cogs/compression.py index d235c6d..1fcefb5 100644 --- a/cogs/compression.py +++ b/cogs/compression.py | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | import mimetypes | 6 | import mimetypes |
| 7 | import os | 7 | import os |
| 8 | import subprocess | 8 | import asyncio |
| 9 | from typing import List, Optional | 9 | from typing import List, Optional |
| 10 | from os import PathLike | 10 | from os import PathLike |
| 11 | import discord | 11 | import discord |
| @@ -32,6 +32,38 @@ class Compression(commands.Cog): | |||
| 32 | if not os.path.exists(self.temp_dir): | 32 | if not os.path.exists(self.temp_dir): |
| 33 | os.makedirs(self.temp_dir) | 33 | os.makedirs(self.temp_dir) |
| 34 | 34 | ||
| 35 | def _process_video(self, file_path: str, output_path: str) -> str: | ||
| 36 | """Process video compression""" | ||
| 37 | command = f"ffmpeg -y -i {file_path} -c:v libx264 -crf 51 -b:v 100 -vf 'fps=10,scale=trunc(iw*0.5/2)*2:trunc(ih*0.5/2)*2' -preset ultrafast -c:a libopus -b:a 500 {output_path}" | ||
| 38 | return command | ||
| 39 | |||
| 40 | def _process_audio(self, file_path: str, output_path: str) -> str: | ||
| 41 | """Process audio compression""" | ||
| 42 | if output_path.lower().endswith('.mp3'): | ||
| 43 | output_path = os.path.splitext(output_path)[0] + os.path.splitext(output_path)[1].replace('.mp3', '') | ||
| 44 | if not output_path.lower().endswith('.ogg'): | ||
| 45 | output_path = os.path.splitext(output_path)[0] + '.ogg' | ||
| 46 | command = f"ffmpeg -y -i {file_path} -c:a libopus -b:a 500 -ar 12000 -ac 1 {output_path}" | ||
| 47 | return command | ||
| 48 | |||
| 49 | def _process_image(self, file_path: str, output_path: str) -> tuple[str, str]: | ||
| 50 | """Process image compression""" | ||
| 51 | ext = os.path.splitext(file_path)[1].lower() | ||
| 52 | if ext in [".jpg", ".jpeg"]: | ||
| 53 | command = f"magick {file_path} -strip -resize 30% -quality 5 {output_path}" | ||
| 54 | elif ext == ".gif": | ||
| 55 | command = f"magick {file_path} -coalesce -resize 30% -colors 32 -strip -layers Optimize {output_path}" | ||
| 56 | else: | ||
| 57 | output_path = os.path.splitext(output_path)[0] + ".jpg" | ||
| 58 | command = f"magick {file_path} -strip -resize 30% -quality 5 {output_path}" | ||
| 59 | return command, output_path | ||
| 60 | |||
| 61 | async def _execute_compression(self, command: str) -> bool: | ||
| 62 | """Execute compression command""" | ||
| 63 | proc = await asyncio.create_subprocess_exec(command) | ||
| 64 | await proc.wait() | ||
| 65 | return proc.returncode == 0 | ||
| 66 | |||
| 35 | async def _compress_attachment(self, attachment: discord.Attachment) -> Optional[discord.File]: | 67 | async def _compress_attachment(self, attachment: discord.Attachment) -> Optional[discord.File]: |
| 36 | """Compress a single attachment and return the compressed file""" | 68 | """Compress a single attachment and return the compressed file""" |
| 37 | file_path = PathLike[str] | 69 | file_path = PathLike[str] |
| @@ -46,32 +78,23 @@ class Compression(commands.Cog): | |||
| 46 | file_type = filetype(file_path) | 78 | file_type = filetype(file_path) |
| 47 | logger.info(f"Compression started for: {file_type}") | 79 | logger.info(f"Compression started for: {file_type}") |
| 48 | 80 | ||
| 49 | if file_type == "Video": | 81 | command = self._get_compression_command(file_type, file_path, output_path) |
| 50 | command = f"ffmpeg -y -i {file_path} -c:v libx264 -crf 51 -b:v 100 -vf 'fps=10,scale=trunc(iw*0.5/2)*2:trunc(ih*0.5/2)*2' -preset ultrafast -c:a libopus -b:a 500 {output_path}" | 82 | if command is None: |
| 51 | elif file_type == "Audio": | ||
| 52 | if output_path.lower().endswith('.mp3'): | ||
| 53 | output_path = os.path.splitext(output_path)[0] + os.path.splitext(output_path)[1].replace('.mp3', '') | ||
| 54 | if not output_path.lower().endswith('.ogg'): | ||
| 55 | output_path = os.path.splitext(output_path)[0] + '.ogg' | ||
| 56 | command = f"ffmpeg -y -i {file_path} -c:a libopus -b:a 500 -ar 12000 -ac 1 {output_path}" | ||
| 57 | elif file_type == "Image": | ||
| 58 | ext = os.path.splitext(file_path)[1].lower() | ||
| 59 | if ext in [".jpg", ".jpeg"]: | ||
| 60 | command = f"magick {file_path} -strip -resize 30% -quality 5 {output_path}" | ||
| 61 | elif ext == ".gif": | ||
| 62 | command = f"magick {file_path} -coalesce -resize 30% -colors 32 -strip -layers Optimize {output_path}" | ||
| 63 | else: | ||
| 64 | output_path = os.path.splitext(output_path)[0] + ".jpg" | ||
| 65 | command = f"magick {file_path} -strip -resize 30% -quality 5 {output_path}" | ||
| 66 | else: | ||
| 67 | logger.info(f"Unsupported file type: {file_type}") | 83 | logger.info(f"Unsupported file type: {file_type}") |
| 68 | os.remove(file_path) | 84 | os.remove(file_path) |
| 69 | return None | 85 | return None |
| 70 | 86 | ||
| 87 | # Update output_path if it was modified | ||
| 88 | if file_type == "Image": | ||
| 89 | command, output_path = command | ||
| 90 | elif file_type == "Audio": | ||
| 91 | # output_path is already modified in _process_audio | ||
| 92 | pass | ||
| 93 | |||
| 71 | # Run the compression | 94 | # Run the compression |
| 72 | subprocess.run(command, check=True, shell=True) | 95 | success = await self._execute_compression(command) |
| 73 | 96 | ||
| 74 | if os.path.exists(output_path): | 97 | if success and os.path.exists(output_path): |
| 75 | logger.info(f"Successfully compressed: {attachment.filename}") | 98 | logger.info(f"Successfully compressed: {attachment.filename}") |
| 76 | return discord.File(output_path, filename=f"compressed_{attachment.filename}") | 99 | return discord.File(output_path, filename=f"compressed_{attachment.filename}") |
| 77 | return None | 100 | return None |
| @@ -84,6 +107,17 @@ class Compression(commands.Cog): | |||
| 84 | # Clean up temporary files | 107 | # Clean up temporary files |
| 85 | if 'file_path' in locals() and os.path.exists(file_path): | 108 | if 'file_path' in locals() and os.path.exists(file_path): |
| 86 | os.remove(file_path) | 109 | os.remove(file_path) |
| 110 | |||
| 111 | def _get_compression_command(self, file_type: str, file_path: str, output_path: str): | ||
| 112 | """Get the appropriate compression command based on file type""" | ||
| 113 | if file_type == "Video": | ||
| 114 | return self._process_video(file_path, output_path) | ||
| 115 | elif file_type == "Audio": | ||
| 116 | return self._process_audio(file_path, output_path) | ||
| 117 | elif file_type == "Image": | ||
| 118 | return self._process_image(file_path, output_path) | ||
| 119 | else: | ||
| 120 | return None | ||
| 87 | 121 | ||
| 88 | async def _compress_attachments(self, attachments: List[discord.Attachment]) -> List[discord.File]: | 122 | async def _compress_attachments(self, attachments: List[discord.Attachment]) -> List[discord.File]: |
| 89 | """Compress multiple attachments and return list of compressed files""" | 123 | """Compress multiple attachments and return list of compressed files""" |
