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 = {} @Client.on_message(filters.private & filters.command("audio") & filters.reply) 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 ) @Client.on_callback_query(filters.regex(r"^aud_")) 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 } @Client.on_message(filters.private & filters.reply) 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)}") @Client.on_message(filters.private & filters.command(["setaudioorder", "set_auto_audio_order"])) 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.") @Client.on_message(filters.private & filters.command(["resetaudioorder", "reset_auto_audio_order"])) 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") @Client.on_message(filters.private & filters.command(["set_leech_audio_order"])) 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.") @Client.on_message(filters.private & filters.command(["reset_leech_audio_order"])) 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.") @Client.on_message(filters.private & filters.command("setdefaultaudio")) 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.") @Client.on_message(filters.private & filters.command("resetdefaultaudio")) 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.")