From 61d721b51439a3e2bb40557a8f1d684790f57f8e Mon Sep 17 00:00:00 2001 From: YOLANDO Date: Thu, 26 Mar 2026 09:05:08 +0700 Subject: [PATCH] approver --- .env | 3 +- __pycache__/yt_engine.cpython-312.pyc | Bin 6801 -> 6794 bytes bot.py | 161 ++++++++++++++++---------- cookies.txt | 10 +- yt_engine.py | 2 +- 5 files changed, 110 insertions(+), 66 deletions(-) diff --git a/.env b/.env index 90890e9..ec5bb42 100644 --- a/.env +++ b/.env @@ -1,6 +1,7 @@ # --- TELEGRAM BOT --- BOT_TOKEN=8747085830:AAHsOTdZbK40daE1Lxmjvw5CcKHY_A7sucI -AUTHORIZED_USER_IDS=951506682 +ADMIN_ID=951506682 +AUTHORIZED_USER_IDS= # --- POSTGRESQL --- # Gunakan 'localhost' jika aplikasi jalan langsung di VPS (tanpa Docker), diff --git a/__pycache__/yt_engine.cpython-312.pyc b/__pycache__/yt_engine.cpython-312.pyc index e4ec8192aefa1a06b6c66548a1717aaafcb43f90..36d6801a70c36f45ba8c765c39d0061cb20fb162 100644 GIT binary patch delta 80 zcmbPe+GWannwOW00SFo untuk mulai mencari lagu.", parse_mode="Markdown") + except: pass + else: + await callback.message.edit_text(f"āŒ User `{target_id}` telah **DITOLAK**.", parse_mode="Markdown") + try: + await bot.send_message(target_id, "āŒ **AKSES DITOLAK.**\nAdmin tidak memberikan izin untuk menggunakan bot ini.", parse_mode="Markdown") + except: pass + def extract_video_id(query): match = re.search(r"(?:v=|\/)([0-9A-Za-z_-]{11}).*", query) return match.group(1) if match else None -# --- FUNGSI PEMBUAT TOMBOL PAGING --- def get_search_keyboard(chat_id, page=0): data = user_searches.get(chat_id) if not data: return None - results = data['results'] start_idx = page * 10 end_idx = start_idx + 10 @@ -72,29 +146,20 @@ def get_search_keyboard(chat_id, page=0): kb = [] for rec in page_results: - # Tampilkan Judul | Nama Channel (Biar tahu itu lagu asli atau cover) - display_text = f"šŸŽµ {rec['title']} | {rec['uploader']}" + display_text = f"šŸŽµ {rec['title']} | {rec.get('uploader', 'YT')}" short_text = display_text[:55] + "..." if len(display_text) > 55 else display_text - - # Menggunakan format callback "play_" agar otomatis masuk antrean download kb.append([InlineKeyboardButton(text=short_text, callback_data=f"play_{rec['id']}")]) - # Tombol Navigasi Next/Prev nav_buttons = [] - if page > 0: - nav_buttons.append(InlineKeyboardButton(text="ā¬…ļø Prev", callback_data=f"page_{page-1}")) - if end_idx < len(results): - nav_buttons.append(InlineKeyboardButton(text="Next āž”ļø", callback_data=f"page_{page+1}")) - - if nav_buttons: - kb.append(nav_buttons) + if page > 0: nav_buttons.append(InlineKeyboardButton(text="ā¬…ļø Prev", callback_data=f"page_{page-1}")) + if end_idx < len(results): nav_buttons.append(InlineKeyboardButton(text="Next āž”ļø", callback_data=f"page_{page+1}")) + if nav_buttons: kb.append(nav_buttons) return InlineKeyboardMarkup(inline_keyboard=kb) -# --- COMMANDS --- @dp.message(Command("start")) async def cmd_start(message: types.Message): - await message.answer("šŸŽ§ **Music Bot Ready!**\nKirim format: `/play `", parse_mode="Markdown") + await message.answer("šŸŽ§ **Music Bot VIP Ready!**\nKirim format: `/play `", parse_mode="Markdown") @dp.message(Command("play")) async def cmd_play(message: types.Message): @@ -102,60 +167,41 @@ async def cmd_play(message: types.Message): if not query: return await message.answer("āš ļø Masukkan judul lagu.") status_msg = await message.answer("šŸ” *Mencari daftar lagu...*", parse_mode="Markdown") - - # Ambil 30 hasil sekaligus results = await search_youtube_list(query, max_results=30) - if not results: - return await status_msg.edit_text("āŒ Lagu tidak ditemukan.") + if not results: return await status_msg.edit_text("āŒ Lagu tidak ditemukan.") - # Simpan ke memori sementara untuk paging user_searches[message.chat.id] = { - 'query': query, + 'header': f"šŸ”Ž Hasil pencarian: **{query}**", 'results': results } - # Tampilkan halaman pertama (index 0) kb = get_search_keyboard(message.chat.id, page=0) - await status_msg.edit_text( - text=f"šŸ”Ž Hasil pencarian: **{query}**\n_Pilih lagu untuk diunduh:_", - reply_markup=kb, - parse_mode="Markdown" - ) + await status_msg.edit_text(text=f"{user_searches[message.chat.id]['header']}\n_Halaman 1_", reply_markup=kb, parse_mode="Markdown") -# --- HANDLER TOMBOL PAGING (NEXT/PREV) --- @dp.callback_query(F.data.startswith("page_")) async def handle_page_click(callback: CallbackQuery): chat_id = callback.message.chat.id if chat_id not in user_searches: - return await callback.answer("Pencarian kadaluarsa. Ketik /play lagi.", show_alert=True) + return await callback.answer("Sesi kadaluarsa. Ketik /play lagi.", show_alert=True) page = int(callback.data.split("_")[1]) kb = get_search_keyboard(chat_id, page) if kb: - query = user_searches[chat_id]['query'] - await callback.message.edit_text( - text=f"šŸ”Ž Hasil pencarian: **{query}**\n_Halaman {page+1}_", - reply_markup=kb, - parse_mode="Markdown" - ) + header = user_searches[chat_id]['header'] + await callback.message.edit_text(text=f"{header}\n_Halaman {page+1}_", reply_markup=kb, parse_mode="Markdown") await callback.answer() -# --- HANDLER DOWNLOAD LAGU --- @dp.callback_query(F.data.startswith("play_")) async def handle_suggestion_click(callback: CallbackQuery): video_id = callback.data.split("_", 1)[1] - - # Opsional: Jika tidak mau layarnya penuh tombol setelah diklik, hapus tombolnya await callback.message.edit_reply_markup(reply_markup=None) - status_msg = await bot.send_message(callback.message.chat.id, "ā³ Mengunduh lagu pilihanmu...") query_url = f"https://www.youtube.com/watch?v={video_id}" await music_queue.put((query_url, callback.message.chat.id, status_msg.message_id)) await callback.answer("Siapp! Diproses...") -# --- CORE LOGIC (DOWNLOAD & S3 CACHE) --- async def process_music_request(query: str, chat_id: int, status_msg_id: int): local_file = None try: @@ -169,22 +215,18 @@ async def process_music_request(query: str, chat_id: int, status_msg_id: int): s3_object_name = cached_data.get('s3_object_key', f"{video_id}.m4a") ext = s3_object_name.split('.')[-1] local_file = f"downloads/cache_{video_id}.{ext}" - await bot.edit_message_text("⚔ Mengambil dari Cache...", chat_id, status_msg_id) await download_audio(s3_object_name, local_file) if not cached_data: await bot.edit_message_text("šŸ” Mengunduh dari YouTube...", chat_id, status_msg_id) yt_result = await process_youtube_request(query) - if yt_result["status"] == "error": return await bot.edit_message_text(f"āŒ Gagal: {yt_result['message']}", chat_id, status_msg_id) - video_id = yt_result["video_id"] title = yt_result["title"] local_file = yt_result["file_path"] s3_object_name = f"{video_id}.{yt_result['ext']}" - await bot.edit_message_text("ā˜ļø Menyimpan ke Server...", chat_id, status_msg_id) if local_file and os.path.exists(local_file): await upload_audio(local_file, s3_object_name) @@ -196,15 +238,16 @@ async def process_music_request(query: str, chat_id: int, status_msg_id: int): await bot.send_audio(chat_id=chat_id, audio=audio, title=title, performer="Music Bot", request_timeout=300) if status_msg_id: await bot.delete_message(chat_id, status_msg_id) - # --- TETAP TAMPILKAN 5 SUGGESTION SETELAH LAGU SELESAI DIPUTAR --- + # --- TAMPILKAN 30 REKOMENDASI DENGAN PAGING --- recs = await get_recommendations(video_id) if recs: - kb = [] - for rec in recs[:5]: - short_title = rec['title'][:55] + "..." if len(rec['title']) > 55 else rec['title'] - kb.append([InlineKeyboardButton(text=f"ā–¶ļø {short_title}", callback_data=f"play_{rec['id']}")]) - reply_markup = InlineKeyboardMarkup(inline_keyboard=kb) - await bot.send_message(chat_id, text=f"šŸ’” **Rekomendasi dari:**\n_{title}_", reply_markup=reply_markup, parse_mode="Markdown") + user_searches[chat_id] = { + 'header': f"šŸ’” Rekomendasi lanjutan dari: **{title}**", + 'results': recs + } + kb = get_search_keyboard(chat_id, page=0) + if kb: + await bot.send_message(chat_id, text=f"{user_searches[chat_id]['header']}\n_Halaman 1_", reply_markup=kb, parse_mode="Markdown") except Exception as e: logger.error(f"Error: {e}") @@ -223,7 +266,7 @@ async def main(): scheduler = AsyncIOScheduler() scheduler.add_job(cleanup_expired_cache, 'cron', hour=3, minute=0) scheduler.start() - logger.info("šŸš€ Bot Music V3 (Search & Paging) Berjalan!") + logger.info("šŸš€ Bot Music V4 (Admin Approval & Super Paging) Berjalan!") await bot.delete_webhook(drop_pending_updates=True) await dp.start_polling(bot) diff --git a/cookies.txt b/cookies.txt index 43d043f..3b6ec77 100644 --- a/cookies.txt +++ b/cookies.txt @@ -3,12 +3,12 @@ .youtube.com TRUE / TRUE 2147483647 __Secure-1PAPISID jX9HIeAZEXX3bP9f/AopL252XpVmN6w-fU .youtube.com TRUE / TRUE 2147483647 __Secure-1PSID g.a0008AhqPQ4vlKVPuJB4BY8zzdimzFGpjCZI3PtorsbzCvPCb3-UNiEKAu2Nem3IRBTeL7M4jQACgYKAWsSARESFQHGX2MiBR4lu_TMGVkDg6nuR2v3KxoVAUF8yKpUhZ9s0gTmijqUQGCrrAbz0076 -.youtube.com TRUE / TRUE 1806026268 __Secure-1PSIDCC AKEyXzX-CL1XOf6OeNeSLRiwwlfwxttYfujFl_Cgwant9zdr6x0pJNiNPlM3ehq1FGS36kyC +.youtube.com TRUE / TRUE 1806026697 __Secure-1PSIDCC AKEyXzVzj8BHVLDosFha11ymmFBOV4r1hRS1ta4nWZcHgZkBacg6rhh1hkprOJcA7YSDScfX .youtube.com TRUE / TRUE 2147483647 __Secure-1PSIDRTS sidts-CjYBWhotCR9GvMAvgfIj2VO7w2GS8jUm45hvgjK75mkpM7qlEO-z2RIGvuP3FX0ApZ3UEnRHAaIQAA .youtube.com TRUE / TRUE 2147483647 __Secure-1PSIDTS sidts-CjYBWhotCR9GvMAvgfIj2VO7w2GS8jUm45hvgjK75mkpM7qlEO-z2RIGvuP3FX0ApZ3UEnRHAaIQAA .youtube.com TRUE / TRUE 2147483647 __Secure-3PAPISID jX9HIeAZEXX3bP9f/AopL252XpVmN6w-fU .youtube.com TRUE / TRUE 2147483647 __Secure-3PSID g.a0008AhqPQ4vlKVPuJB4BY8zzdimzFGpjCZI3PtorsbzCvPCb3-UVw0LJPNy1xBeKd3GjL_nrgACgYKAd8SARESFQHGX2Mi4oiwDW0agUlDxti69hv6zBoVAUF8yKqTGo8oCprmktCz7NrkNVpx0076 -.youtube.com TRUE / TRUE 1806026268 __Secure-3PSIDCC AKEyXzV4asU3xodaOGcneKNBezILDXAjNbLEZhJZv479YWYlAECeXq-5QgNsMibF-b3qu2d33g +.youtube.com TRUE / TRUE 1806026697 __Secure-3PSIDCC AKEyXzURj6FH3Hh60cp98zUCM49GiTZJ9mcBkypQpiCq5neND5iTw7dWvfmk3CCUrnyqDksmyw .youtube.com TRUE / TRUE 2147483647 __Secure-3PSIDRTS sidts-CjYBWhotCR9GvMAvgfIj2VO7w2GS8jUm45hvgjK75mkpM7qlEO-z2RIGvuP3FX0ApZ3UEnRHAaIQAA .youtube.com TRUE / TRUE 2147483647 __Secure-3PSIDTS sidts-CjYBWhotCR9GvMAvgfIj2VO7w2GS8jUm45hvgjK75mkpM7qlEO-z2RIGvuP3FX0ApZ3UEnRHAaIQAA .youtube.com TRUE / TRUE 2147483647 __Secure-ROLLOUT_TOKEN CMbM-7XNqZzV5QEQmYbS_rO8kwMY5PKr_7O8kwM%3D @@ -18,6 +18,6 @@ .youtube.com TRUE / TRUE 2147483647 LOGIN_INFO AFmmF2swRAIgDHRqApvISbyAZq7Jw7ACZDaYENyiLfRJhkSxgsaSzHUCIDBqEp7Lla6YL_9yHKzX5OuwRv6eSuDP7wN4eu2h8boE:QUQ3MjNmenlDUldaUlpCVmlMc2ZFdWxtWVlzX2lVRTRic2o4djgzSlJiaHhHYnN4dmh0YTU2NFdpS1lRSkZIUlN3RVBRWmZMTFdTU1pjQ3gtU09LTmRUX3l6WEpCWGdpeFpiVkptS1BHRlBlQXU1R0RXZjR3cnR4LW94YlREbzFITzdOaWctTEJLcjN5UWpCM3VXVTQzUWZiMl9RLXhNRERR .youtube.com TRUE / TRUE 2147483647 NID 530=J1je9vBs7k1AZSF4I6E-32SX_vniEVSvWt6vRJC19rznxuHBniKAUk91MSxJ9KY6sPEIGqw29RYQvsglruzNcyGUpG4RIb4Fk50UUrFHbXG28v34nj9rkikmhXi7N84D_-1l8im9-Qm9zkPfxKaL8V8xBaBjK6a1p2et2q3_n5wM0hOI7R24Gw4hQbX9Rcj-oUTuBbvIxb_VevmQ .youtube.com TRUE / FALSE 0 PREF hl=en&tz=UTC -.youtube.com TRUE / TRUE 0 YSC T0iFTYMzz_E -.youtube.com TRUE / TRUE 1790042268 VISITOR_INFO1_LIVE fHx_hZBK2nA -.youtube.com TRUE / TRUE 1790042268 VISITOR_PRIVACY_METADATA CgJJRBIEGgAgQw%3D%3D +.youtube.com TRUE / TRUE 0 YSC 6K5oY8QB4bs +.youtube.com TRUE / TRUE 1790042697 VISITOR_INFO1_LIVE JbfxjpcD228 +.youtube.com TRUE / TRUE 1790042697 VISITOR_PRIVACY_METADATA CgJJRBIEGgAgXw%3D%3D diff --git a/yt_engine.py b/yt_engine.py index ec9dd8f..6bef4bd 100644 --- a/yt_engine.py +++ b/yt_engine.py @@ -25,7 +25,7 @@ def generate_netscape_cookies(): print(f"Error parsing cookies: {e}") return False -def fetch_recommendations_sync(video_id: str, limit: int = 5): +def fetch_recommendations_sync(video_id: str, limit: int = 30): ydl_opts_recs = { 'quiet': True, 'extract_flat': True,