Spaces:
Running
Running
File size: 37,711 Bytes
ef6cae2 1e97884 ef6cae2 1e97884 ef6cae2 1e97884 c3cc7ce 1e97884 ef6cae2 1e97884 c3cc7ce c1d5bd6 c3cc7ce dcfdb06 c1d5bd6 dcfdb06 c1d5bd6 3c727b4 5ebc955 e1ff18c 782ab56 1203b34 c1d5bd6 54844e5 c1d5bd6 dc6242c c1d5bd6 dc6242c c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 67eed4e c1d5bd6 67eed4e c1d5bd6 67eed4e c1d5bd6 67eed4e c1d5bd6 c3cc7ce c1d5bd6 c3cc7ce c1d5bd6 c3cc7ce c1d5bd6 c3cc7ce c1d5bd6 c3cc7ce c1d5bd6 9b345f9 c1d5bd6 9b345f9 c1d5bd6 9b345f9 c1d5bd6 9b345f9 1203b34 9b345f9 1203b34 c1d5bd6 54844e5 86a7364 54844e5 86a7364 54844e5 86a7364 54844e5 86a7364 54844e5 86a7364 54844e5 c1d5bd6 9b345f9 c1d5bd6 9b345f9 c1d5bd6 9b345f9 5ebc955 1203b34 9b345f9 1203b34 c1d5bd6 9b345f9 c1d5bd6 54844e5 c1d5bd6 54844e5 86a7364 54844e5 67eed4e 54844e5 67eed4e 54844e5 67eed4e 54844e5 c1d5bd6 9b345f9 54844e5 c1d5bd6 9b345f9 c1d5bd6 87df0c1 c1d5bd6 5d01f97 c1d5bd6 5d01f97 c1d5bd6 5d01f97 1203b34 5d01f97 1203b34 5425774 bb24ba7 1203b34 5d01f97 bb24ba7 d724deb 5d01f97 1203b34 c1d5bd6 5d01f97 1203b34 5d01f97 1203b34 5d01f97 e1ff18c 5d01f97 1203b34 5d01f97 c1d5bd6 a5f0793 c1d5bd6 3c727b4 1203b34 d724deb bb24ba7 3c727b4 c1d5bd6 a5f0793 c1d5bd6 a5f0793 c1d5bd6 a5f0793 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 87df0c1 c1d5bd6 79aad23 31868d9 ef6cae2 31868d9 ef6cae2 31868d9 ef6cae2 31868d9 79aad23 c1d5bd6 31868d9 79aad23 31868d9 c1d5bd6 54844e5 c1d5bd6 54844e5 c1d5bd6 54844e5 31868d9 c1d5bd6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 | import socket
import os
# --- Hugging Face Ultra-Robust DNS Patch Start ---
# 1. Proxylarni o'chirish (HF dagi noto'g'ri sozlangan proxylarni chetlab o'tish)
os.environ.pop('HTTP_PROXY', None)
os.environ.pop('HTTPS_PROXY', None)
os.environ.pop('http_proxy', None)
os.environ.pop('https_proxy', None)
# 2. DNS Monkey Patch
TELEGRAM_IPS = ['149.154.167.220', '149.154.167.189', '149.154.167.50']
_original_getaddrinfo = socket.getaddrinfo
def _patched_getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
# httpx va boshqalar hostni bytes shaklida yuborishi mumkin
is_telegram = False
if isinstance(host, str) and host == "api.telegram.org":
is_telegram = True
elif isinstance(host, bytes) and host == b"api.telegram.org":
is_telegram = True
if is_telegram:
# Barcha oilalarni (IPv6 bo'lsa ham) IPv4 ga majburlaymiz
return [(socket.AF_INET, socket.SOCK_STREAM, 6, '', (ip, port)) for ip in TELEGRAM_IPS]
return _original_getaddrinfo(host, port, family, type, proto, flags)
socket.getaddrinfo = _patched_getaddrinfo
# --- Hugging Face Ultra-Robust DNS Patch End ---
import logging
import asyncio
import collections
import gc
import time
import threading
from datetime import datetime, timedelta
from dotenv import load_dotenv
from http.server import BaseHTTPRequestHandler, HTTPServer
from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup, constants
from telegram.ext import (
ApplicationBuilder,
CommandHandler,
MessageHandler,
filters,
ContextTypes,
CallbackQueryHandler
)
from filters import (
apply_retro_filter, upscale_image, apply_face_restore, apply_auto_enhance,
process_video_retro, process_video_upscale, process_video_slowmo,
process_video_bw, process_video_color_correct, process_video_remove_audio,
process_video_trim, process_video_face_fix, process_video_auto_enhance,
process_video_fps_boost, apply_nudenet_filter, process_video_nnsfw,
process_video_subtitle, process_video_stabilize,
apply_glitch_filter, apply_mirror_filter, apply_watermark, apply_bg_remove,
apply_style_transfer, apply_quality_boost,
process_video_glitch, process_video_mirror, process_video_watermark,
process_video_subtitle_translate
)
# Admin sozlamalari
ADMIN_ID = int(os.environ.get("ADMIN_ID", 6309900880))
BROADCAST_MODE = {} # {admin_id: True}
from database import db
from concurrent.futures import ThreadPoolExecutor
from apscheduler.schedulers.asyncio import AsyncIOScheduler
# muhit o'zgaruvchilari
load_dotenv()
TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
# Loglarni sozlash
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
logger = logging.getLogger(__name__)
# Global media storage
media_storage = {}
processing_semaphore = asyncio.Semaphore(2)
executor = ThreadPoolExecutor(max_workers=4)
base_dir = os.path.dirname(os.path.abspath(__file__))
# Rate Limit (Spam himoyasi)
user_active_tasks = {} # {user_id: timestamp}
RATE_LIMIT_SECONDS = 5 # Minimum kutish vaqti (soniya)
def check_rate_limit(user_id):
"""Foydalanuvchi spam qilayotganini tekshiradi. True = ruxsat, False = bloklangan."""
now = time.time()
last_time = user_active_tasks.get(user_id)
if last_time and (now - last_time) < RATE_LIMIT_SECONDS:
return False
user_active_tasks[user_id] = now
return True
# Scheduler for cleanup
scheduler = AsyncIOScheduler()
async def post_init(application):
"""Bot ishga tushgandan so'ng bajariladigan amallar."""
scheduler.add_job(cleanup_old_files, 'interval', minutes=30)
scheduler.start()
logger.info("Scheduler va tozalash tizimi ishga tushdi.")
async def cleanup_old_files():
"""Eski fayllarni, vaqtinchalik fayllarni va xotirani tozalash."""
now = datetime.now()
# 1. Eskirgan media_storage yozuvlarini tozalash
to_delete = [k for k, v in media_storage.items() if (now - v.get('timestamp', now)) > timedelta(hours=1)]
for k in to_delete:
media_storage.pop(k, None)
# 2. Eskirgan user_active_tasks ni tozalash
stale_users = [uid for uid, ts in user_active_tasks.items() if (time.time() - ts) > 300]
for uid in stale_users:
user_active_tasks.pop(uid, None)
# 3. in_/out_/tmp_ fayllarni tozalash
for f in os.listdir(base_dir):
fpath = os.path.join(base_dir, f)
if (f.startswith("in_") or f.startswith("out_") or f.startswith("tmp_")):
try:
file_age = now - datetime.fromtimestamp(os.path.getmtime(fpath))
if file_age > timedelta(minutes=30):
os.remove(fpath)
logger.info(f"Tozalandi: {f}")
except: pass
gc.collect()
logger.info(f"Tozalash yakunlandi. media_storage: {len(media_storage)}, active_tasks: {len(user_active_tasks)}")
# --- UI Helpers ---
def get_main_menu_keyboard(user_id=None):
"""Asosiy menyu tugmalari. Admin uchun qo'shimcha tugma qo'shiladi."""
keyboard = [
[
InlineKeyboardButton("π Tarix", callback_data="nav|history"),
InlineKeyboardButton("βοΈ Sozlamalar", callback_data="nav|settings")
],
[
InlineKeyboardButton("βΉοΈ Yordam", callback_data="nav|help")
]
]
# Faqat admin uchun tugma
if user_id == ADMIN_ID:
keyboard.append([InlineKeyboardButton("π Admin Panel", callback_data="admin_main")])
return InlineKeyboardMarkup(keyboard)
async def show_main_menu(update_or_query, context):
"""Asosiy menyuni ko'rsatish."""
text = (
"β¨ **Mukammal Filtr Botga xush kelibsiz!**\n\n"
"Menga rasm yoki video yuboring, so'ngra mo''jizani ko'ring. π¨β¨\n\n"
"π‘ *Pastdagi tugmalar orqali botni boshqarishingiz mumkin:*"
)
if isinstance(update_or_query, Update):
user_id = update_or_query.effective_user.id
await update_or_query.message.reply_text(text, reply_markup=get_main_menu_keyboard(user_id), parse_mode=constants.ParseMode.MARKDOWN)
else:
user_id = update_or_query.from_user.id
await update_or_query.edit_message_text(text, reply_markup=get_main_menu_keyboard(user_id), parse_mode=constants.ParseMode.MARKDOWN)
# --- Handlers ---
async def settings_command(update_or_query, context: ContextTypes.DEFAULT_TYPE):
"""Sozlamalar menyusi."""
if isinstance(update_or_query, Update):
user_id = update_or_query.effective_user.id
else:
user_id = update_or_query.from_user.id
current_filter = db.get_user_settings(user_id)
text = (
"βοΈ **Sozlamalar**\n\n"
f"Joriy standart filtr: **{current_filter.upper()}**\n"
"Yangi standart filtrni tanlang:"
)
keyboard = [
[
InlineKeyboardButton("π Retro", callback_data="set|retro"),
InlineKeyboardButton("π Ultra HD", callback_data="set|upscale")
],
[
InlineKeyboardButton("π€ Face Fix", callback_data="set|face_fix"),
InlineKeyboardButton("β¨ Auto-Enhance", callback_data="set|auto_enhance")
],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
if isinstance(update_or_query, Update):
await update_or_query.message.reply_text(text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
else:
await update_or_query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
async def settings_callback_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Filtrni tanlash callbacki."""
query = update.callback_query
await query.answer()
filter_type = query.data.split("|")[1]
db.set_default_filter(query.from_user.id, filter_type)
name_map = {"retro": "RETRO", "upscale": "ULTRA HD", "face_fix": "FACE FIX", "auto_enhance": "AUTO-ENHANCE"}
display_name = name_map.get(filter_type, filter_type.upper())
await query.edit_message_text(
f"β
Standart filtr **{display_name}** ga o'zgartirildi!",
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("π Orqaga", callback_data="nav|settings")]]),
parse_mode=constants.ParseMode.MARKDOWN
)
async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""/start buyrug'i."""
user = update.effective_user
db.add_user(user.id, user.username, user.first_name)
await show_main_menu(update, context)
async def handle_photo(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Rasmlarni qabul qilish va Kategoriyalangan Menyuni ko'rsatish."""
try:
photo = update.message.photo[-1]
file_id = photo.file_id
short_id = str(update.message.message_id)
media_storage[short_id] = {"file_id": file_id, "type": "photo", "timestamp": datetime.now()}
# 1. Haqiqiy Xiralikni tekshirish (Laplacian Variance)
is_blurry = False
try:
file = await context.bot.get_file(file_id)
input_path = os.path.join(base_dir, f"tmp_chk_{short_id}.jpg")
await file.download_to_drive(input_path)
import cv2
img_chk = cv2.imread(input_path, cv2.IMREAD_GRAYSCALE)
if img_chk is not None:
variance = cv2.Laplacian(img_chk, cv2.CV_64F).var()
if variance < 100: # Odatda 100 dan pasti xira hisoblanadi
is_blurry = True
if os.path.exists(input_path):
os.remove(input_path)
except Exception as filter_err:
logger.warning(f"Xiralikni tekshirish xatosi: {filter_err}")
text = "πΌ **Rasm qabul qilindi!**\nO'zingizga kerakli bo'limni tanlang π"
if is_blurry:
text = "π **Tahlil:** Rasm xiraroq ko'rinmoqda. 'AI Asboblar' bo'limidan sifatni oshirish tavsiya etiladi!\n\n" + text
# KATEGORIYALANGAN MENYU (Asosiy)
keyboard = [
[
InlineKeyboardButton("πͺ Effektlar", callback_data=f"cat_fx|p|{short_id}"),
InlineKeyboardButton("π€ AI Asboblar", callback_data=f"cat_ai|p|{short_id}")
],
[
InlineKeyboardButton("π¨ Fon (Tahrirlash)", callback_data=f"cat_bg|p|{short_id}"),
InlineKeyboardButton("ποΈ Badiiy Uslublar", callback_data=f"cat_st|p|{short_id}")
],
[
InlineKeyboardButton("π Bekor qilish", callback_data="nav|main")
]
]
await update.message.reply_text(text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
except Exception as e:
logger.error(f"Error in handle_photo: {e}")
await update.message.reply_text("β Xatolik yuz berdi.")
async def handle_text(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Matn xabarlarini qabul qilish (broadcast uchun)."""
# Agar admin xabar tarqatish rejimida bo'lsa
if update.effective_user.id == ADMIN_ID and BROADCAST_MODE.get(ADMIN_ID):
BROADCAST_MODE[ADMIN_ID] = False
text_to_send = update.message.text
users = db.get_all_users()
count = 0
failed = 0
status_msg = await update.message.reply_text(f"π Xabar tarqatish boshlandi (0/{len(users)})...")
for u_id in users:
try:
await context.bot.send_message(u_id, text_to_send)
count += 1
if count % 10 == 0:
await status_msg.edit_text(f"π Xabar tarqatish davom etmoqda ({count}/{len(users)})...")
except Exception:
failed += 1
await status_msg.edit_text(f"β
Xabar tarqatish yakunlandi.\nβοΈ Yuborildi: {count} ta\nβ Xato: {failed} ta")
return
# Oddiy foydalanuvchilar uchun β hech narsa qilmaymiz
# (rasm yoki video yuboring degan javob keraksiz, chunki ortiqcha xabar beradi)
return
async def handle_video(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Videolarni qabul qilish va Kategoriyalangan Menyuni ko'rsatish."""
try:
message = update.message
video = message.video or message.animation or message.document
if message.document and not (message.document.mime_type or "").startswith('video/'):
return
file_id = getattr(video, 'file_id', None)
if not file_id: return
if getattr(video, 'file_size', 0) > 50 * 1024 * 1024:
await message.reply_text("β οΈ Video juda katta (max 50MB).")
return
short_id = str(message.message_id)
media_storage[short_id] = {"file_id": file_id, "type": "video", "timestamp": datetime.now()}
# KATEGORIYALANGAN MENYU (Video uchun)
keyboard = [
[
InlineKeyboardButton("πͺ Effektlar", callback_data=f"cv_fx|v|{short_id}"),
InlineKeyboardButton("π€ AI Kadrlar", callback_data=f"cv_ai|v|{short_id}")
],
[
InlineKeyboardButton("π Uzunlik va Ovoz", callback_data=f"cv_ed|v|{short_id}"),
InlineKeyboardButton("π Subtitr va Tarjima", callback_data=f"cv_sb|v|{short_id}")
],
[
InlineKeyboardButton("π Bekor qilish", callback_data="nav|main")
]
]
await update.message.reply_text("π₯ **Video qabul qilindi!**\nQanday mo'jiza yaratamiz? π", reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
except Exception as e:
logger.error(f"Error in handle_video: {e}")
await update.message.reply_text("β Xatolik yuz berdi.")
async def navigation_handler(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Navigatsiya tugmalari (Menu, History, Settings)."""
query = update.callback_query
await query.answer()
data = query.data.split("|")[1]
if data == "main":
await show_main_menu(query, context)
elif data == "history":
history = db.get_user_history(query.from_user.id)
if not history:
text = "π Tarix bo'sh."
else:
text = "π **Sizning oxirgi 5 ta amalingiz:**\n\n"
for i, (m_type, f_type, dt) in enumerate(history, 1):
dt_obj = datetime.fromisoformat(dt).strftime("%H:%M %d.%m")
text += f"{i}. {'πΌ' if m_type == 'photo' else 'π₯'} {f_type.upper()} - {dt_obj}\n"
keyboard = [[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]]
await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
elif data == "settings":
await settings_command(query, context)
elif data == "help":
text = (
"βΉοΈ **Yordam**\n\n"
"1. Rasm yoki Video yuboring.\n"
"2. Tugmalar orqali filtrni tanlang.\n"
"3. Progress bar orqali jarayonni kuzating.\n"
"4. Natijani yuklab oling!"
)
keyboard = [[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]]
await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
async def admin_panel(update: Update, context: ContextTypes.DEFAULT_TYPE):
"""Faqat admin ko'ra oladigan boshqaruv paneli."""
if update.effective_user.id != ADMIN_ID:
return
keyboard = [
[
InlineKeyboardButton("π Statistika", callback_data="admin_stats"),
InlineKeyboardButton("π Bazani yuklab olish", callback_data="admin_db")
],
[
InlineKeyboardButton("π’ Xabar tarqatish", callback_data="admin_broadcast")
]
]
reply_markup = InlineKeyboardMarkup(keyboard)
await update.message.reply_text("π **Admin Panel**\n\nBotni boshqarish uchun kerakli bo'limni tanlang:",
reply_markup=reply_markup, parse_mode=constants.ParseMode.MARKDOWN)
async def handle_callback(update: Update, context: ContextTypes.DEFAULT_TYPE):
query = update.callback_query
await query.answer()
if query.data.startswith("admin_"):
if update.effective_user.id != ADMIN_ID:
return
if query.data == "admin_stats":
stats = db.get_stats()
text = (f"π **Bot Statistikasi**\n\n"
f"π₯ Jami foydalanuvchilar: {stats['total_users']}\n"
f"π Jami tahrirlangan media: {stats['total_processed']}\n"
f"π Oxirgi 24 soatdagi faollik: {stats['daily_active']}")
await query.edit_message_text(text, parse_mode=constants.ParseMode.MARKDOWN,
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("β¬
οΈ Orqaga", callback_data="admin_back")]]))
elif query.data == "admin_db":
try:
with open(db.db_path, 'rb') as db_file:
await query.message.reply_document(document=db_file, caption="π Bot ma'lumotlar bazasi zaxira nusxasi.")
except Exception as e:
logger.error(f"Admin DB yuklash xatosi: {e}")
await query.message.reply_text("β Bazani yuklashda xatolik.")
elif query.data == "admin_broadcast":
BROADCAST_MODE[ADMIN_ID] = True
await query.edit_message_text("π **Xabar tarqatish rejimi**\n\nBarcha foydalanuvchilarga yubormoqchi bo'lgan matningizni kiriting:",
reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("β Bekor qilish", callback_data="admin_back")]]))
elif query.data == "admin_back" or query.data == "admin_main":
BROADCAST_MODE[ADMIN_ID] = False
keyboard = [
[InlineKeyboardButton("π Statistika", callback_data="admin_stats"),
InlineKeyboardButton("π Bazani yuklab olish", callback_data="admin_db")],
[InlineKeyboardButton("π’ Xabar tarqatish", callback_data="admin_broadcast")],
[InlineKeyboardButton("π Asosiy Menyu", callback_data="nav|main")]
]
await query.edit_message_text("π **Admin Panel**\n\nBo'limni tanlang:",
reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
return
# KATEGORIYA MENYULARINI QAYTA ISHLASH (Sub-menyular)
if query.data.startswith("cat_") or query.data.startswith("cv_"):
data_parts = query.data.split("|")
cat_type = data_parts[0]
m_type = data_parts[1]
short_id = data_parts[2]
keyboard = []
text = "Tanlang π"
# --- RASM KATEGORIYALARI ---
if cat_type == "cat_fx":
text = "πͺ **Rasm Effektlari:**"
keyboard = [
[InlineKeyboardButton("πΈ Retro Kamera", callback_data=f"r|p|{short_id}"), InlineKeyboardButton("πͺ Glitch", callback_data=f"gl|p|{short_id}")],
[InlineKeyboardButton("πͺ Oyna", callback_data=f"mr|p|{short_id}"), InlineKeyboardButton("π± Suv belgisi", callback_data=f"wm|p|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
elif cat_type == "cat_ai":
text = "π€ **AI Asboblar:**"
keyboard = [
[InlineKeyboardButton("β¨ Sifat (Ultra HD)", callback_data=f"u|p|{short_id}"), InlineKeyboardButton("π€ Yuz (Face Fix)", callback_data=f"f|p|{short_id}")],
[InlineKeyboardButton("πͺ Avto-Tahrir", callback_data=f"a|p|{short_id}"), InlineKeyboardButton("π Sifat+ (Pro)", callback_data=f"qb|p|{short_id}")],
[InlineKeyboardButton("π‘οΈ Media Qalqon", callback_data=f"n|p|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
elif cat_type == "cat_bg":
text = "π¨ **Fonni Tahrirlash (AI):**"
keyboard = [
[InlineKeyboardButton("π¨ Shaffof", callback_data=f"bg_t|p|{short_id}"), InlineKeyboardButton("β¬ Oq Fon", callback_data=f"bg_w|p|{short_id}")],
[InlineKeyboardButton("β¬ Qora Fon", callback_data=f"bg_k|p|{short_id}"), InlineKeyboardButton("π«οΈ Blur", callback_data=f"bg_b|p|{short_id}")],
[InlineKeyboardButton("π Gradient", callback_data=f"bg_c|p|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
elif cat_type == "cat_st":
text = "ποΈ **Badiiy Uslublar (AI):**"
keyboard = [
[InlineKeyboardButton("ποΈ Anime", callback_data=f"st_anime|p|{short_id}"), InlineKeyboardButton("ποΈ Qalam", callback_data=f"st_sketch|p|{short_id}")],
[InlineKeyboardButton("ποΈ Moybo'yoq", callback_data=f"st_oil|p|{short_id}"), InlineKeyboardButton("ποΈ Multfilm", callback_data=f"st_cart|p|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
# --- VIDEO KATEGORIYALARI ---
elif cat_type == "cv_fx":
text = "πͺ **Video Effektlari:**"
keyboard = [
[InlineKeyboardButton("ποΈ Retro", callback_data=f"r|v|{short_id}"), InlineKeyboardButton("β« Oq-Qora", callback_data=f"bw|v|{short_id}")],
[InlineKeyboardButton("πͺ Glitch", callback_data=f"gl|v|{short_id}"), InlineKeyboardButton("πͺ Oyna", callback_data=f"mr|v|{short_id}")],
[InlineKeyboardButton("π¨ Rang Tahrir", callback_data=f"cc|v|{short_id}"), InlineKeyboardButton("π± Suv belgisi", callback_data=f"wm|v|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
elif cat_type == "cv_ai":
text = "π€ **Video AI Kadrlar:**"
keyboard = [
[InlineKeyboardButton("β¨ Sifatni Oshirish", callback_data=f"u|v|{short_id}"), InlineKeyboardButton("π€ Yuzni Tiniqlash", callback_data=f"vf|v|{short_id}")],
[InlineKeyboardButton("πͺ Avto-Tahrir", callback_data=f"va|v|{short_id}"), InlineKeyboardButton("π‘οΈ Media Qalqon", callback_data=f"n|v|{short_id}")],
[InlineKeyboardButton("πΉ Stabilizatsiya", callback_data=f"stb|v|{short_id}")],
[InlineKeyboardButton("π 30 FPS", callback_data=f"fps30|v|{short_id}"), InlineKeyboardButton("π 60 FPS", callback_data=f"fps60|v|{short_id}")],
[InlineKeyboardButton("π 120 FPS", callback_data=f"fps120|v|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
elif cat_type == "cv_ed":
text = "π **Uzunlik va Ovoz:**"
keyboard = [
[InlineKeyboardButton("π’ Sekinlashtirish", callback_data=f"s|v|{short_id}"), InlineKeyboardButton("βοΈ Kesish", callback_data=f"t|v|{short_id}")],
[InlineKeyboardButton("π Ovozni O'chirish", callback_data=f"ra|v|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
elif cat_type == "cv_sb":
text = "π **Subtitr va Tarjima (AI):**"
keyboard = [
[InlineKeyboardButton("π Avto-Taglavha (Asl)", callback_data=f"sub|v|{short_id}")],
[InlineKeyboardButton("π Sub+O'zbek", callback_data=f"stuz|v|{short_id}"), InlineKeyboardButton("π Sub+Rus", callback_data=f"stru|v|{short_id}")],
[InlineKeyboardButton("π Sub+English", callback_data=f"sten|v|{short_id}")],
[InlineKeyboardButton("π Orqaga", callback_data="nav|main")]
]
await query.edit_message_text(text, reply_markup=InlineKeyboardMarkup(keyboard), parse_mode=constants.ParseMode.MARKDOWN)
return
# [Avvalgi button_handler mantiqi davom etadi...]
try:
data = query.data.split("|")
action, m_type, short_id = data[0], data[1], data[2]
if short_id not in media_storage:
await query.edit_message_text("β οΈ Media ma'lumotlari xotiradan tozalangan. Iltimos, aserni qayta yuboring.")
return
# Spam himoyasi: foydalanuvchi juda tez-tez so'rov yuborsa bloklash
user_id = query.from_user.id
if not check_rate_limit(user_id):
await query.edit_message_text("β³ Sizda tugallanmagan jarayon bor yoki juda tez so'rov yuboryapsiz. Biroz kuting!")
return
async with processing_semaphore:
media_info = media_storage[short_id]
file_id = media_info["file_id"]
msg = await query.edit_message_text("β³ Jarayon boshlanmoqda...")
file = await context.bot.get_file(file_id, read_timeout=300)
ext = "mp4" if m_type == "v" else "jpg"
input_path = os.path.join(base_dir, f"in_{short_id}.{ext}")
output_path = os.path.join(base_dir, f"out_{short_id}.{ext}")
await file.download_to_drive(input_path, read_timeout=300)
last_percent = [0]
async def progress(p):
# Faqat 10% dan oshganda xabarni yangilash (Telegram API ni qiynamaslik uchun)
if p - last_percent[0] >= 10 or p == 99:
last_percent[0] = p
bar = "β" * (p // 10) + "β" * (10 - p // 10)
try: await query.edit_message_text(f"βοΈ Qayta ishlanmoqda...\n[{bar}] {p}%")
except: pass
loop = asyncio.get_event_loop()
callback = lambda p: asyncio.run_coroutine_threadsafe(progress(p), loop)
success_path = None
logger.info(f"Processing started: {action} on {m_type} for {short_id}")
if m_type == "p":
func = None
# Style Transfer uchun alohida mantiq
if action.startswith("st_"):
try: await query.edit_message_text("ποΈ AI uslubiga o'girilmoqda...\n(Birinchi ishlashda 20 soniyagacha vaqt olishi mumkin)")
except: pass
style = action.replace("st_", "").replace("cart", "cartoon")
success_path = await loop.run_in_executor(
executor, apply_style_transfer, input_path, output_path, style
)
elif action == "u":
try: await query.edit_message_text("π AI Ultra HD sifatga oshirilmoqda...\n(Bu jarayon bir oz vaqt olishi mumkin)")
except: pass
success_path = await loop.run_in_executor(executor, upscale_image, input_path, output_path)
elif action.startswith("bg_"):
bg_mode_map = {
"bg_t": "transparent", "bg_w": "white",
"bg_k": "black", "bg_b": "blur", "bg_c": "gradient"
}
bg_mode = bg_mode_map.get(action, "transparent")
mode_names = {"bg_t": "π¨ Shaffof fon", "bg_w": "β¬ Oq fon", "bg_k": "β¬ Qora fon", "bg_b": "π«οΈ Blur fon", "bg_c": "π Gradient fon"}
try: await query.edit_message_text(f"βοΈ {mode_names.get(action, 'Fon')} tayyorlanmoqda...\n(AI tahlil + Edge Refinement)")
except: pass
success_path = await loop.run_in_executor(
executor, apply_bg_remove, input_path, output_path, bg_mode
)
else:
func = {
"r": apply_retro_filter, "u": upscale_image,
"f": apply_face_restore, "a": apply_auto_enhance,
"n": apply_nudenet_filter,
"gl": apply_glitch_filter, "mr": apply_mirror_filter,
"wm": apply_watermark,
"qb": apply_quality_boost,
}.get(action)
if not func:
logger.error(f"Unknown action: {action}")
await context.bot.send_message(query.message.chat_id, "β Noma'lum amal.")
return
success_path = await loop.run_in_executor(executor, func, input_path, output_path)
else:
# FPS Boost uchun alohida mantiq
if action in ("fps30", "fps60", "fps120"):
fps_map = {"fps30": 30, "fps60": 60, "fps120": 120}
target = fps_map[action]
success_path = await loop.run_in_executor(
executor, process_video_fps_boost, input_path, output_path, target, callback
)
else:
func = None
# Subtitle Tarjima uchun alohida mantiq
if action in ("stuz", "stru", "sten"):
try: await query.edit_message_text("π Ovoz aniqlanib tarjima qilinmoqda...\n(Bu jarayon video uzunligiga qarab bir oz vaqt oladi)")
except: pass
lang_map = {"stuz": "uz", "stru": "ru", "sten": "en"}
target = lang_map[action]
success_path = await loop.run_in_executor(
executor, process_video_subtitle_translate, input_path, output_path, target, callback
)
else:
video_funcs = {
"r": process_video_retro, "u": process_video_upscale,
"s": process_video_slowmo, "bw": process_video_bw,
"cc": process_video_color_correct, "ra": process_video_remove_audio,
"t": process_video_trim, "vf": process_video_face_fix,
"va": process_video_auto_enhance, "n": process_video_nnsfw,
"sub": process_video_subtitle, "gl": process_video_glitch,
"mr": process_video_mirror, "wm": process_video_watermark,
"stb": process_video_stabilize
}
func = video_funcs.get(action)
if not func:
logger.error(f"Unknown video action: {action}")
await context.bot.send_message(query.message.chat_id, "β Noma'lum video amali.")
return
success_path = await loop.run_in_executor(executor, func, input_path, output_path, callback)
logger.info(f"Processing finished. Success path: {success_path}")
if success_path and os.path.exists(success_path):
# Extentsionni tiklash (rembg kabi png yaratuvchilar uchun)
final_ext = str(success_path).split('.')[-1]
f_name = {
"r": "retro", "u": "4k", "f": "face fix", "a": "auto enhance",
"s": "slow motion", "bw": "oq-qora", "cc": "rang fix",
"ra": "ovoz olib tashlash", "t": "kesish", "vf": "video face fix",
"va": "video auto enhance", "fps30": "30 FPS boost",
"fps60": "60 FPS boost", "fps120": "120 FPS boost",
"n": "media shield",
"sub": "auto-subtitle",
"gl": "glitch", "mr": "mirror",
"wm": "watermark", "bg": "fon o'chirish",
"st_anime": "AI anime", "st_sketch": "AI sketch",
"st_oil": "AI oil paint", "st_cart": "AI cartoon",
"stuz": "sub+o'zbek", "stru": "sub+rus", "sten": "sub+english",
"qb": "sifat+ pro", "stb": "stabilizatsiya",
"bg_t": "shaffof fon", "bg_w": "oq fon",
"bg_k": "qora fon", "bg_b": "blur fon", "bg_c": "gradient fon"
}.get(action, f"filter_{action}")
db.log_history(query.from_user.id, "photo" if m_type == "p" else "video", f_name, file_id)
with open(success_path, 'rb') as f:
caption = f"β
<b>{f_name.upper()}</b> muvaffaqiyatli qo'llanildi!\n⨠@editfiltrbot orqali maxsus tayyorlandi!"
try: await query.edit_message_text("β
Tayyor! Yuklanmoqda...")
except: pass
if m_type == "p":
if final_ext in ["png", "webp"]:
await context.bot.send_document(query.message.chat_id, f, caption=caption, parse_mode=constants.ParseMode.HTML, read_timeout=300, write_timeout=300)
else:
await context.bot.send_photo(query.message.chat_id, f, caption=caption, parse_mode=constants.ParseMode.HTML, read_timeout=300, write_timeout=300)
else:
await context.bot.send_video(query.message.chat_id, f, caption=caption, parse_mode=constants.ParseMode.HTML, read_timeout=300, write_timeout=300)
else:
logger.error(f"Processing failed for {short_id}. Action: {action}")
await context.bot.send_message(query.message.chat_id, "β Afsuski, ishlov berishda xatolik yuz berdi yoki natija topilmadi.")
await query.delete_message()
except Exception as e:
logger.error(f"Global button_handler error: {e}")
try: await context.bot.send_message(query.message.chat_id, f"β Tizimli xatolik: {e}")
except: pass
finally:
# Rate limit tozalash
try:
user_active_tasks.pop(query.from_user.id, None)
except: pass
# Fayllarni tozalash
for cleanup_path in [locals().get('input_path'), locals().get('output_path')]:
if cleanup_path and os.path.exists(cleanup_path):
try: os.remove(cleanup_path)
except: pass
# media_storage dan eskirgan yozuvlarni tozalash
if short_id in media_storage:
media_storage.pop(short_id, None)
# Xotirani majburiy tozalash (RAM to'lishini oldini oladi)
gc.collect()
class HealthCheckHandler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/html")
self.end_headers()
self.wfile.write(b"Bot ishlamoqda!")
def log_message(self, format, *args):
pass
def run_dummy_server():
try:
server = HTTPServer(("0.0.0.0", 7860), HealthCheckHandler)
server.serve_forever()
except Exception as e:
logger.error(f"Dummy server xatosi: {e}")
def wait_for_internet(host="api.telegram.org", port=443, timeout=60):
"""Internet ulanishini, DNS va IP orqali ulanishni kutish."""
start_time = time.time()
logger.info(f"Tarmoq kutilmoqda: {host}...")
# Sinab ko'rish uchun manzillar ro'yxati
targets = [(host, port)] + [(ip, port) for ip in TELEGRAM_IPS]
while time.time() - start_time < timeout:
for target_host, target_port in targets:
try:
socket.create_connection((target_host, target_port), timeout=5)
logger.info(f"Tarmoq tayyor! {target_host} ga ulanish muvaffaqiyatli.")
return True
except Exception:
continue
time.sleep(2)
logger.warning("Tarmoq ulanishida muammo bo'lishi mumkin, lekin davom etamiz...")
return False
if __name__ == '__main__':
if not TOKEN:
logger.error("TELEGRAM_BOT_TOKEN topilmadi! Iltimos, Secrets bo'limini tekshiring.")
else:
# 1. Dummy serverni fonda ishga tushirish
threading.Thread(target=run_dummy_server, daemon=True).start()
# 2. Tarmoqni kutish
wait_for_internet()
# 3. Botni qurish (IPv4 ni majburiy qilish uchun request sozlamalari bilan)
from telegram.request import HTTPXRequest
# Hugging Face da IPv6 xatolarini chetlab o'tish uchun IPv4 ni majburlash
request = HTTPXRequest(connection_pool_size=8, read_timeout=30, write_timeout=30, connect_timeout=30)
app = ApplicationBuilder().token(TOKEN).request(request).post_init(post_init).build()
app.add_handler(CommandHandler("start", start))
app.add_handler(CommandHandler("admin", admin_panel))
app.add_handler(CallbackQueryHandler(navigation_handler, pattern=r"^nav\|"))
app.add_handler(CallbackQueryHandler(settings_callback_handler, pattern=r"^set\|"))
app.add_handler(CallbackQueryHandler(handle_callback)) # This now handles all callbacks, including admin and regular buttons
app.add_handler(MessageHandler(filters.PHOTO, handle_photo))
app.add_handler(MessageHandler(filters.VIDEO | filters.ANIMATION | filters.Document.ALL, handle_video))
app.add_handler(MessageHandler(filters.TEXT & ~filters.COMMAND, handle_text)) # Handle general text messages
logger.info("Bot polling rejimi ishga tushmoqda...")
app.run_polling()
|