Download plugins/audio_features.py from Thaimozhi/RenameBot: direct link, hf CLI and curl.
- Browser
- Download file 8.67 kB
-
https://huggingface.co/spaces/Thaimozhi/RenameBot/resolve/main/plugins/audio_features.py
- Command line
-
hf download hf://spaces/Thaimozhi/RenameBot/plugins/audio_features.py
-
curl -L -o audio_features.py https://huggingface.co/spaces/Thaimozhi/RenameBot/resolve/main/plugins/audio_features.py
8.67 kB
| import os | |
| import time | |
| import asyncio | |
| from pyrogram import Client, filters, ContinuePropagation | |
| from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery | |
| from helper.utils import progress_for_pyrogram | |
| from plugins.file_rename import extract_season_episode, extract_quality | |
| # Dictionary to store ongoing audio operations | |
| audio_ops = {} | |
| async def audio_command(client, message): | |
| replied = message.reply_to_message | |
| if not (replied.video or replied.document): | |
| return await message.reply_text("Please reply to a video or document file with /audio") | |
| file_id = replied.video.file_id if replied.video else replied.document.file_id | |
| # Store message id for callback | |
| keyboard = InlineKeyboardMarkup([ | |
| [ | |
| InlineKeyboardButton("π Remove Audio", callback_data=f"aud_rm_{replied.id}"), | |
| InlineKeyboardButton("π Reorder Audio", callback_data=f"aud_re_{replied.id}") | |
| ], | |
| [ | |
| InlineKeyboardButton("βοΈ Set Default Audio", callback_data=f"aud_def_{replied.id}") | |
| ] | |
| ]) | |
| await message.reply_text( | |
| "**Audio Management Options:**\n\n" | |
| "Choose what you want to do with the audio tracks of this file.\n" | |
| "*(Note: You will be asked to enter track numbers. Track 1 = 0, Track 2 = 1)*", | |
| reply_markup=keyboard | |
| ) | |
| async def audio_callback(client, query: CallbackQuery): | |
| data = query.data.split("_") | |
| action = data[1] # rm, re, def | |
| msg_id = int(data[2]) | |
| user_id = query.from_user.id | |
| if action == "rm": | |
| text = "Reply to this message with the audio track number you want to REMOVE.\n\nExample: `1` (removes 2nd track)" | |
| elif action == "re": | |
| text = "Reply to this message with the new order of tracks (comma separated).\n\nExample: `1,0` (swaps track 1 and 2)" | |
| elif action == "def": | |
| text = "Reply to this message with the track number you want to set as DEFAULT.\n\nExample: `1` (sets 2nd track as default)" | |
| prompt = await query.message.edit_text(text) | |
| # Save state | |
| audio_ops[user_id] = { | |
| "action": action, | |
| "msg_id": msg_id, | |
| "prompt_id": prompt.id | |
| } | |
| async def process_audio_input(client, message): | |
| user_id = message.from_user.id | |
| if user_id not in audio_ops: | |
| raise ContinuePropagation | |
| op = audio_ops[user_id] | |
| if message.reply_to_message.id != op["prompt_id"]: | |
| raise ContinuePropagation | |
| action = op["action"] | |
| msg_id = op["msg_id"] | |
| user_input = message.text.strip() | |
| del audio_ops[user_id] # Clear state | |
| target_msg = await client.get_messages(message.chat.id, msg_id) | |
| if not target_msg: | |
| return await message.reply_text("Original message not found.") | |
| status = await message.reply_text("π₯ Downloading file for audio processing...") | |
| try: | |
| # Download | |
| file_name = target_msg.video.file_name if target_msg.video else target_msg.document.file_name | |
| if not file_name: | |
| file_name = "downloaded_video.mkv" | |
| download_path = f"downloads/{user_id}_{file_name}" | |
| start_time = time.time() | |
| file_path = await client.download_media( | |
| target_msg, | |
| file_name=download_path, | |
| progress=progress_for_pyrogram, | |
| progress_args=("Downloading...", status, start_time) | |
| ) | |
| await status.edit("βοΈ Processing audio with FFmpeg... This may take a while.") | |
| output_path = f"downloads/processed_{user_id}_{file_name}" | |
| # Build FFmpeg command based on action | |
| if action == "rm": | |
| track_idx = int(user_input) | |
| # Remove specific audio track (negative mapping) | |
| cmd = f'ffmpeg -i "{file_path}" -map 0 -map -0:a:{track_idx} -c copy "{output_path}" -y' | |
| elif action == "re": | |
| tracks = user_input.split(",") | |
| # Reorder: map video, then map audio tracks in specified order | |
| # Example: ffmpeg -i in.mkv -map 0:v -map 0:a:1 -map 0:a:0 -c copy out.mkv | |
| maps = "-map 0:v " + " ".join([f"-map 0:a:{t.strip()}" for t in tracks]) | |
| # Also map subtitles if any | |
| maps += " -map 0:s? " | |
| cmd = f'ffmpeg -i "{file_path}" {maps} -c copy "{output_path}" -y' | |
| elif action == "def": | |
| track_idx = int(user_input) | |
| # Set default track disposition | |
| cmd = f'ffmpeg -i "{file_path}" -map 0 -c copy -disposition:a:0 0 -disposition:a:{track_idx} default "{output_path}" -y' | |
| # Run FFmpeg | |
| process = await asyncio.create_subprocess_shell( | |
| cmd, | |
| stdout=asyncio.subprocess.PIPE, | |
| stderr=asyncio.subprocess.PIPE | |
| ) | |
| stdout, stderr = await process.communicate() | |
| if process.returncode != 0: | |
| await status.edit(f"β FFmpeg error: \n```\n{stderr.decode()[:500]}\n```") | |
| return | |
| await status.edit("π€ Uploading processed file...") | |
| # Upload | |
| start_time = time.time() | |
| await client.send_document( | |
| chat_id=message.chat.id, | |
| document=output_path, | |
| caption=f"Processed: {file_name}\nAction: {action}", | |
| file_name=file_name, | |
| progress=progress_for_pyrogram, | |
| progress_args=("Uploading...", status, start_time) | |
| ) | |
| await status.delete() | |
| # Cleanup | |
| os.remove(file_path) | |
| os.remove(output_path) | |
| except ValueError: | |
| await status.edit("β Invalid input! Please enter numbers only.") | |
| except Exception as e: | |
| await status.edit(f"β Error: {str(e)}") | |
| async def set_audio_order(client, message): | |
| if len(message.command) < 2: | |
| return await message.reply_text("Usage: /set_auto_audio_order 1,0,2\nTo reset, use /reset_auto_audio_order") | |
| order = message.command[1] | |
| from helper.database import codeflixbots | |
| await codeflixbots.set_audio_order(message.from_user.id, order) | |
| await message.reply_text(f"β Auto Uploader Audio order saved as `{order}`. It will be applied automatically to auto uploader jobs.") | |
| async def reset_audio_order(client, message): | |
| from helper.database import codeflixbots | |
| await codeflixbots.set_audio_order(message.from_user.id, None) | |
| await message.reply_text("β Auto Uploader Audio order reset to default.\n\n") | |
| async def set_leech_audio_order(client, message): | |
| if len(message.command) < 2: | |
| return await message.reply_text("Usage: /set_leech_audio_order 1,0,2\nTo reset, use /reset_leech_audio_order") | |
| order = message.command[1] | |
| from helper.database import codeflixbots | |
| await codeflixbots.set_merge_audio_order(message.from_user.id, order) | |
| await message.reply_text(f"β Leech/Rename Audio order saved as `{order}`. It will be applied automatically for normal files.") | |
| async def reset_leech_audio_order(client, message): | |
| from helper.database import codeflixbots | |
| await codeflixbots.set_merge_audio_order(message.from_user.id, None) | |
| await message.reply_text("β Leech/Rename Audio order reset to default.") | |
| async def set_default_audio(client, message): | |
| if len(message.command) < 2: | |
| return await message.reply_text("Usage: /setdefaultaudio 0\nTo reset, use /resetdefaultaudio") | |
| default_track = message.command[1] | |
| from helper.database import codeflixbots | |
| await codeflixbots.set_audio_default(message.from_user.id, default_track) | |
| await message.reply_text(f"β Default audio track set to `{default_track}`. It will be applied automatically.") | |
| async def reset_default_audio(client, message): | |
| from helper.database import codeflixbots | |
| await codeflixbots.set_audio_default(message.from_user.id, None) | |
| await message.reply_text("β Default audio track reset.") | |