diff options
| author | salmonik <raisersoft@proton.me> | 2026-04-17 15:36:12 +0200 |
|---|---|---|
| committer | salmonik <raisersoft@proton.me> | 2026-04-17 15:36:12 +0200 |
| commit | d135265798da8c2698f363237f4cb74b682f3f9e (patch) | |
| tree | bca914d297e74a6188478a773ba7333c10fe4a34 /cogs/music/media_processing.py | |
| parent | Merge branch 'main' of https://codeberg.org/salmonik/senator-sperma (diff) | |
| download | senator-sperma-d135265798da8c2698f363237f4cb74b682f3f9e.tar.gz senator-sperma-d135265798da8c2698f363237f4cb74b682f3f9e.zip | |
make voice great again
Signed-off-by: salmonik <raisersoft@proton.me>
Diffstat (limited to '')
| -rw-r--r-- | cogs/music/media_processing.py | 67 |
1 files changed, 40 insertions, 27 deletions
diff --git a/cogs/music/media_processing.py b/cogs/music/media_processing.py index 430b51f..e04911c 100644 --- a/cogs/music/media_processing.py +++ b/cogs/music/media_processing.py | |||
| @@ -3,26 +3,26 @@ | |||
| 3 | # Copyright (C) 2026 Salmonik @ salmonik@tuta.io | 3 | # Copyright (C) 2026 Salmonik @ salmonik@tuta.io |
| 4 | # https://codeberg.org/salmonik/senator-sperma | 4 | # https://codeberg.org/salmonik/senator-sperma |
| 5 | 5 | ||
| 6 | import os | ||
| 7 | import asyncio | 6 | import asyncio |
| 8 | import logging | 7 | import logging |
| 9 | from pathlib import Path | 8 | import os |
| 10 | 9 | ||
| 11 | import yt_dlp | 10 | import yt_dlp |
| 12 | from youtubesearchpython import VideosSearch | 11 | from youtubesearchpython import VideosSearch |
| 13 | 12 | ||
| 14 | logger = logging.getLogger(__name__) | 13 | logger = logging.getLogger(__name__) |
| 15 | 14 | ||
| 15 | |||
| 16 | class MediaDownloader: | 16 | class MediaDownloader: |
| 17 | """Handles downloading media from various sources.""" | 17 | """Handles downloading media from various sources.""" |
| 18 | 18 | ||
| 19 | @staticmethod | 19 | @staticmethod |
| 20 | async def download(ctx, url): | 20 | async def download(ctx, url): |
| 21 | """Download audio from YouTube URL.""" | 21 | """Download audio from YouTube URL.""" |
| 22 | # Create temp directory if it doesn't exist | 22 | # Create temp directory if it doesn't exist |
| 23 | temp_dir = os.path.join('cogs', 'temp', 'music') | 23 | temp_dir = os.path.join("cogs", "temp", "music") |
| 24 | os.makedirs(temp_dir, exist_ok=True) | 24 | os.makedirs(temp_dir, exist_ok=True) |
| 25 | 25 | ||
| 26 | ytdl_opts = { | 26 | ytdl_opts = { |
| 27 | "outtmpl": os.path.join(temp_dir, "%(title)s.%(ext)s"), | 27 | "outtmpl": os.path.join(temp_dir, "%(title)s.%(ext)s"), |
| 28 | "postprocessors": [ | 28 | "postprocessors": [ |
| @@ -62,9 +62,10 @@ class MediaDownloader: | |||
| 62 | await ctx.respond("nic ni ma", ephemeral=True) | 62 | await ctx.respond("nic ni ma", ephemeral=True) |
| 63 | return None | 63 | return None |
| 64 | 64 | ||
| 65 | |||
| 65 | class AudioCompressor: | 66 | class AudioCompressor: |
| 66 | """Handles audio compression using FFmpeg.""" | 67 | """Handles audio compression using FFmpeg.""" |
| 67 | 68 | ||
| 68 | @staticmethod | 69 | @staticmethod |
| 69 | async def compress(ctx, filename): | 70 | async def compress(ctx, filename): |
| 70 | """Compress audio file to opus format.""" | 71 | """Compress audio file to opus format.""" |
| @@ -73,51 +74,63 @@ class AudioCompressor: | |||
| 73 | return None | 74 | return None |
| 74 | 75 | ||
| 75 | # Create temp directory if it doesn't exist | 76 | # Create temp directory if it doesn't exist |
| 76 | temp_dir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), 'temp', 'compressed') | 77 | temp_dir = os.path.join( |
| 78 | os.path.dirname(os.path.dirname(os.path.abspath(__file__))), | ||
| 79 | "temp", | ||
| 80 | "compressed", | ||
| 81 | ) | ||
| 77 | os.makedirs(temp_dir, exist_ok=True) | 82 | os.makedirs(temp_dir, exist_ok=True) |
| 78 | 83 | ||
| 79 | # Create a temporary output filename in the temp directory | 84 | # Create a temporary output filename in the temp directory |
| 80 | base_name = os.path.basename(filename) | 85 | base_name = os.path.basename(filename) |
| 81 | output_filename = os.path.join(temp_dir, f"{os.path.splitext(base_name)[0]}_compressed.opus") | 86 | output_filename = os.path.join( |
| 82 | 87 | temp_dir, f"{os.path.splitext(base_name)[0]}_compressed.opus" | |
| 88 | ) | ||
| 89 | |||
| 83 | # Ensure the output directory exists | 90 | # Ensure the output directory exists |
| 84 | os.makedirs(os.path.dirname(output_filename) or '.', exist_ok=True) | 91 | os.makedirs(os.path.dirname(output_filename) or ".", exist_ok=True) |
| 85 | 92 | ||
| 86 | # Use proper quoting for filenames with spaces | 93 | # Use proper quoting for filenames with spaces |
| 87 | ffmpeg_command = [ | 94 | ffmpeg_command = [ |
| 88 | 'ffmpeg', | 95 | "ffmpeg", |
| 89 | '-y', # Overwrite output file if it exists | 96 | "-y", # Overwrite output file if it exists |
| 90 | '-i', filename, | 97 | "-i", |
| 91 | '-ac', '1', # Mono audio | 98 | filename, |
| 92 | '-b:a', '500', # 500k bitrate | 99 | "-ac", |
| 93 | '-acodec', 'libopus', | 100 | "1", # Mono audio |
| 94 | output_filename | 101 | "-b:a", |
| 102 | "500", # 500k bitrate | ||
| 103 | "-acodec", | ||
| 104 | "libopus", | ||
| 105 | output_filename, | ||
| 95 | ] | 106 | ] |
| 96 | 107 | ||
| 97 | try: | 108 | try: |
| 98 | logger.info(f"Running FFmpeg command: {' '.join(ffmpeg_command)}") | 109 | logger.info(f"Running FFmpeg command: {' '.join(ffmpeg_command)}") |
| 99 | process = await asyncio.create_subprocess_exec( | 110 | process = await asyncio.create_subprocess_exec( |
| 100 | *ffmpeg_command, | 111 | *ffmpeg_command, |
| 101 | stdout=asyncio.subprocess.PIPE, | 112 | stdout=asyncio.subprocess.PIPE, |
| 102 | stderr=asyncio.subprocess.PIPE | 113 | stderr=asyncio.subprocess.PIPE, |
| 103 | ) | 114 | ) |
| 104 | 115 | ||
| 105 | _, stderr = await process.communicate() | 116 | _, stderr = await process.communicate() |
| 106 | 117 | ||
| 107 | if process.returncode != 0: | 118 | if process.returncode != 0: |
| 108 | error_msg = stderr.decode() | 119 | error_msg = stderr.decode() |
| 109 | logger.error(f"FFmpeg error ({process.returncode}): {error_msg}") | 120 | logger.error(f"FFmpeg error ({process.returncode}): {error_msg}") |
| 110 | await ctx.respond("eror kompresujync pilk", ephemeral=True) | 121 | await ctx.respond("eror kompresujync pilk", ephemeral=True) |
| 111 | return None | 122 | return None |
| 112 | 123 | ||
| 113 | if not os.path.exists(output_filename): | 124 | if not os.path.exists(output_filename): |
| 114 | logger.error(f"Output file was not created: {output_filename}") | 125 | logger.error(f"Output file was not created: {output_filename}") |
| 115 | await ctx.respond("eror kompresujync pilk - output file not created", ephemeral=True) | 126 | await ctx.respond( |
| 127 | "eror kompresujync pilk - output file not created", ephemeral=True | ||
| 128 | ) | ||
| 116 | return None | 129 | return None |
| 117 | 130 | ||
| 118 | logger.info(f"Successfully compressed file: {output_filename}") | 131 | logger.info(f"Successfully compressed file: {output_filename}") |
| 119 | return output_filename | 132 | return output_filename |
| 120 | 133 | ||
| 121 | except Exception as e: | 134 | except Exception as e: |
| 122 | logger.error(f"Error compressing file: {str(e)}", exc_info=True) | 135 | logger.error(f"Error compressing file: {str(e)}", exc_info=True) |
| 123 | await ctx.respond(f"eror kompresujync pilk: {str(e)}", ephemeral=True) | 136 | await ctx.respond(f"eror kompresujync pilk: {str(e)}", ephemeral=True) |
