| import os, time, threading, zipfile, io, re, telebot, requests |
| from flask import Flask, render_template_string |
| from playwright.sync_api import sync_playwright |
| from PIL import Image |
| import img2pdf |
| from telebot import types |
|
|
| |
| BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") |
| ADMIN_HANDLE = "@svipfast" |
| bot = telebot.TeleBot(BOT_TOKEN, threaded=False) |
| app = Flask(__name__) |
|
|
| |
| user_states = {} |
|
|
| @app.route('/') |
| def home(): return "<h1>Manga Engine Professional is Running</h1>" |
|
|
| |
| def fetch_images_engine(url): |
| with sync_playwright() as p: |
| browser = p.chromium.launch(headless=True) |
| context = browser.new_context(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36") |
| page = context.new_page() |
| try: |
| page.goto(url, wait_until="networkidle", timeout=60000) |
| |
| for _ in range(5): |
| page.mouse.wheel(0, 1200) |
| time.sleep(0.8) |
| |
| images = page.query_selector_all("img") |
| img_list = [] |
| for img in images: |
| src = img.get_attribute("src") or img.get_attribute("data-src") or img.get_attribute("data-lazy-src") |
| if src and any(ext in src.lower() for ext in ['.jpg', '.jpeg', '.png', '.webp', '.avif']): |
| if "logo" in src.lower() or "banner" in src.lower(): continue |
| try: |
| res = page.request.get(src) |
| if res.status == 200 and len(res.body()) > 25000: |
| img_list.append(Image.open(io.BytesIO(res.body())).convert('RGB')) |
| except: continue |
| browser.close() |
| return img_list |
| except: |
| browser.close() |
| return [] |
|
|
| |
| @bot.message_handler(commands=['start']) |
| def welcome(message): |
| user_states[message.chat.id] = {} |
| markup = types.InlineKeyboardMarkup(row_width=1) |
| btn_start = types.InlineKeyboardButton("📥 إرسال رابط جديد", callback_data="new_order") |
| btn_help = types.InlineKeyboardButton("💡 كيف أحصل على الرابط؟", callback_data="help_link") |
| btn_admin = types.InlineKeyboardButton("👨💻 المطور", url=f"https://t.me/{ADMIN_HANDLE.replace('@','')}") |
| markup.add(btn_start, btn_help, btn_admin) |
| |
| bot.send_message(message.chat.id, |
| f"<b>مرحباً بك في بوت سحب المانجا الإحترافي 🚀</b>\n\n" |
| f"النظام يعمل بمحرك محاكاة لتجاوز الحمايات.\n" |
| f"المطور المسؤول: {ADMIN_HANDLE}", |
| parse_mode="HTML", reply_markup=markup) |
|
|
| |
| @bot.callback_query_handler(func=lambda call: True) |
| def handle_query(call): |
| chat_id = call.message.chat.id |
| |
| if call.data == "new_order": |
| msg = bot.send_message(chat_id, "<b>الآن، أرسل رابط المانجا (رابط أي فصل):</b>", parse_mode="HTML") |
| bot.register_next_step_handler(msg, process_url_step) |
| |
| elif call.data == "help_link": |
| help_txt = ( |
| "<b>طريقة إرسال الرابط الصحيحة:</b>\n\n" |
| "انسخ رابط الفصل من الموقع مباشرة، مثال:\n" |
| "<code>https://olympustaff.com/series/manga-name/1</code>" |
| ) |
| bot.send_message(chat_id, help_txt, parse_mode="HTML") |
|
|
| |
| elif call.data.startswith("mode_"): |
| mode = call.data.split("_")[1] |
| user_states[chat_id]['mode'] = mode |
| |
| if mode == "single": |
| msg = bot.send_message(chat_id, "🔢 أرسل <b>رقم الفصل</b> فقط:") |
| elif mode == "range": |
| msg = bot.send_message(chat_id, "🔢 أرسل <b>المدى</b> (مثال: 1-10):") |
| elif mode == "auto10": |
| msg = bot.send_message(chat_id, "🔢 أرسل <b>رقم الفصل</b> الذي سنبدأ التحميل منه:") |
| |
| bot.register_next_step_handler(msg, final_execution_step) |
| |
| bot.answer_callback_query(call.id) |
|
|
| |
| def process_url_step(message): |
| url = message.text.strip() |
| if not url.startswith("http"): |
| bot.send_message(message.chat.id, "❌ الرابط غير صحيح، أرسل رابط يبدأ بـ http") |
| return |
| |
| user_states[message.chat.id] = {'url': url} |
| |
| |
| markup = types.InlineKeyboardMarkup(row_width=2) |
| markup.add( |
| types.InlineKeyboardButton("🎯 فصل واحد", callback_data="mode_single"), |
| types.InlineKeyboardButton("📦 حزمة فصول", callback_data="mode_range"), |
| types.InlineKeyboardButton("⏩ تحميل 10 فصول", callback_data="mode_auto10") |
| ) |
| bot.send_message(message.chat.id, "<b>ممتاز! اختر الآن طريقة التحميل:</b>", parse_mode="HTML", reply_markup=markup) |
|
|
| |
| def final_execution_step(message): |
| chat_id = message.chat.id |
| state = user_states.get(chat_id) |
| if not state or 'url' not in state: |
| bot.send_message(chat_id, "⚠️ حدث خطأ، يرجى البدء من جديد عبر /start") |
| return |
|
|
| text = message.text.strip() |
| mode = state['mode'] |
| url = state['url'] |
|
|
| try: |
| if mode == "single": |
| start, end = int(text), int(text) |
| elif mode == "range": |
| start, end = map(int, text.split('-')) |
| elif mode == "auto10": |
| start = int(text) |
| end = start + 9 |
| |
| status_msg = bot.send_message(chat_id, f"<b>🔄 جاري تشغيل المحرك الذكي...</b>\n📦 سحب الفصول: {start} ⬅️ {end}", parse_mode="HTML") |
| |
| |
| zip_path = run_manga_engine(url, start, end) |
| |
| if zip_path: |
| with open(zip_path, 'rb') as f: |
| caption = ( |
| f"<b>✅ اكتملت عملية السحب بنجاح</b>\n\n" |
| f"📂 <b>النطاق:</b> {start} إلى {end}\n" |
| f"👨💻 <b>بواسطة:</b> {ADMIN_HANDLE}" |
| ) |
| bot.send_document(chat_id, f, caption=caption, parse_mode="HTML") |
| os.remove(zip_path) |
| bot.delete_message(chat_id, status_msg.message_id) |
| else: |
| bot.edit_message_text(f"❌ لم ينجح المحرك في سحب الصور.\nتواصل مع الإدارة: {ADMIN_HANDLE}", chat_id, status_msg.message_id) |
| |
| except Exception as e: |
| bot.send_message(chat_id, "⚠️ خطأ في إدخال الأرقام. يرجى التأكد من كتابتها بشكل صحيح (مثال: 1-5).") |
|
|
| |
| def run_manga_engine(sample_url, start, end): |
| base_part = re.sub(r'/(?:chapter-)?\d+$', '', sample_url.strip().rstrip('/')) |
| is_azora = "azoramoon" in sample_url |
| pdf_files = [] |
|
|
| for i in range(start, end + 1): |
| target_url = f"{base_part}/chapter-{i}" if is_azora else f"{base_part}/{i}" |
| imgs = fetch_images_engine(target_url) |
| if imgs: |
| fname = f"Chapter_{i}.pdf" |
| imgs[0].save(fname, save_all=True, append_images=imgs[1:], format='PDF') |
| pdf_files.append(fname) |
| |
| if not pdf_files: return None |
| |
| zip_name = f"Manga_Pack_{int(time.time())}.zip" |
| with zipfile.ZipFile(zip_name, 'w') as zipf: |
| for f in pdf_files: |
| zipf.write(f) |
| os.remove(f) |
| return zip_name |
|
|
| |
| if __name__ == "__main__": |
| |
| os.system("playwright install chromium") |
| threading.Thread(target=lambda: bot.infinity_polling(), daemon=True).start() |
| app.run(host="0.0.0.0", port=7860) |