4 / app.py
iq7se2's picture
Update app.py
89438fd verified
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>"
# --- محرك السحب (Playwright) ---
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__":
# تنصيب متصفح Playwright
os.system("playwright install chromium")
threading.Thread(target=lambda: bot.infinity_polling(), daemon=True).start()
app.run(host="0.0.0.0", port=7860)