iq7se2 commited on
Commit
4ad87f6
·
verified ·
1 Parent(s): 21f4d9e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +121 -44
app.py CHANGED
@@ -3,58 +3,155 @@ from flask import Flask, render_template_string
3
  from playwright.sync_api import sync_playwright
4
  from PIL import Image
5
  import img2pdf
 
6
 
7
- # --- الإعدادات ---
8
  BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
 
9
  bot = telebot.TeleBot(BOT_TOKEN, threaded=False)
10
  app = Flask(__name__)
11
 
 
 
 
12
  @app.route('/')
13
- def home(): return "<h1>Manga Engine Active</h1>"
14
 
15
- def fetch_chapter_with_playwright(url):
 
16
  with sync_playwright() as p:
17
- # تشغيل متصفح مخفي (Headless)
18
  browser = p.chromium.launch(headless=True)
19
  context = browser.new_context(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
20
  page = context.new_page()
21
-
22
  try:
23
- # الذهاب للرابط والانتظار حتى يتم تحميل الشبكة بالكامل (مثل HakuNeko)
24
  page.goto(url, wait_until="networkidle", timeout=60000)
25
-
26
- # التمرير لأسفل الصفحة ببطء لضمان تحميل صور (Lazy Loading)
27
- for _ in range(5):
28
- page.mouse.wheel(0, 1000)
29
  time.sleep(1)
30
 
31
- # استخراج روابط الصور التي تنتهي بامتدادات صور معروفة
32
  images = page.query_selector_all("img")
33
- img_data_list = []
34
-
35
  for img in images:
36
  src = img.get_attribute("src") or img.get_attribute("data-src")
37
  if src and any(ext in src.lower() for ext in ['.jpg', '.jpeg', '.png', '.webp']):
38
- # تحويل الصورة إلى Bytes
39
  res = page.request.get(src)
40
- if res.status == 200 and len(res.body()) > 20000:
41
- img_data_list.append(Image.open(io.BytesIO(res.body())).convert('RGB'))
42
-
43
  browser.close()
44
- return img_data_list
45
- except Exception as e:
46
  browser.close()
47
  return []
48
 
49
- def process_engine(sample_url, start, end):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  base_part = re.sub(r'/(?:chapter-)?\d+$', '', sample_url.strip().rstrip('/'))
51
  is_azora = "azoramoon" in sample_url
52
  pdf_files = []
53
 
54
  for i in range(int(start), int(end) + 1):
55
  target_url = f"{base_part}/chapter-{i}" if is_azora else f"{base_part}/{i}"
56
- imgs = fetch_chapter_with_playwright(target_url)
57
-
58
  if imgs:
59
  fname = f"Chapter_{i}.pdf"
60
  imgs[0].save(fname, save_all=True, append_images=imgs[1:], format='PDF')
@@ -62,34 +159,14 @@ def process_engine(sample_url, start, end):
62
 
63
  if not pdf_files: return None
64
 
65
- zip_name = f"Engine_Manga_{int(time.time())}.zip"
66
  with zipfile.ZipFile(zip_name, 'w') as zipf:
67
  for f in pdf_files:
68
  zipf.write(f); os.remove(f)
69
  return zip_name
70
 
71
- @bot.message_handler(func=lambda m: True)
72
- def handle_msg(message):
73
- try:
74
- url, range_part = message.text.strip().split(' ')
75
- start, end = range_part.split('-')
76
-
77
- status = bot.reply_to(message, "🚀 جاري تشغيل محرك المحاكاة... قد يستغرق وقتاً أطول لتجاوز الحماية.")
78
- zip_path = process_engine(url, start, end)
79
-
80
- if zip_path:
81
- with open(zip_path, 'rb') as f:
82
- bot.send_document(message.chat.id, f, caption=f"✅ المحرك نجح في سحب الفصول {start}-{end}")
83
- os.remove(zip_path)
84
- bot.delete_message(message.chat.id, status.message_id)
85
- else:
86
- bot.edit_message_text("❌ المحرك لم يجد صوراً. قد تكون الحماية متطورة جداً.", message.chat.id, status.message_id)
87
- except:
88
- bot.reply_to(message, "⚠️ التنسيق: الرابط مسافة 1-5")
89
-
90
- # تشغيل البوت والسيرفر
91
  if __name__ == "__main__":
92
- # تثبيت المتصفحات المطلوبة لـ Playwright عند التشغيل الأول
93
  os.system("playwright install chromium")
94
  threading.Thread(target=lambda: bot.infinity_polling(), daemon=True).start()
95
  app.run(host="0.0.0.0", port=7860)
 
3
  from playwright.sync_api import sync_playwright
4
  from PIL import Image
5
  import img2pdf
6
+ from telebot import types
7
 
8
+ # --- الإعدادات العامة ---
9
  BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN")
10
+ ADMIN_HANDLE = "@svipfast"
11
  bot = telebot.TeleBot(BOT_TOKEN, threaded=False)
12
  app = Flask(__name__)
13
 
14
+ # تخزين مؤقت لبيانات المستخدمين
15
+ user_data = {}
16
+
17
  @app.route('/')
18
+ def home(): return "<h1>Manga Engine Professional is Running</h1>"
19
 
20
+ # --- محرك السحب (Playwright) ---
21
+ def fetch_images(url):
22
  with sync_playwright() as p:
 
23
  browser = p.chromium.launch(headless=True)
24
  context = browser.new_context(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
25
  page = context.new_page()
 
26
  try:
 
27
  page.goto(url, wait_until="networkidle", timeout=60000)
28
+ # التمرير لضمان تحميل الصور (Lazy Load)
29
+ for _ in range(4):
30
+ page.mouse.wheel(0, 1500)
 
31
  time.sleep(1)
32
 
 
33
  images = page.query_selector_all("img")
34
+ img_list = []
 
35
  for img in images:
36
  src = img.get_attribute("src") or img.get_attribute("data-src")
37
  if src and any(ext in src.lower() for ext in ['.jpg', '.jpeg', '.png', '.webp']):
 
38
  res = page.request.get(src)
39
+ if res.status == 200 and len(res.body()) > 25000:
40
+ img_list.append(Image.open(io.BytesIO(res.body())).convert('RGB'))
 
41
  browser.close()
42
+ return img_list
43
+ except:
44
  browser.close()
45
  return []
46
 
47
+ # --- واجهة البوت ---
48
+
49
+ @bot.message_handler(commands=['start'])
50
+ def send_welcome(message):
51
+ markup = types.InlineKeyboardMarkup(row_width=1)
52
+ btn1 = types.InlineKeyboardButton("📥 ابدأ تحميل مانجا", callback_data="start_download")
53
+ btn2 = types.InlineKeyboardButton("ℹ️ شرح طريقة الروابط", callback_data="how_to_url")
54
+ btn3 = types.InlineKeyboardButton("👨‍💻 تواصل مع الإدارة", url=f"https://t.me/{ADMIN_HANDLE.replace('@','')}")
55
+ markup.add(btn1, btn2, btn3)
56
+
57
+ welcome_text = (
58
+ "<b>مرحباً بك في نظام سحب المانجا الإحترافي 🚀</b>\n\n"
59
+ "هذا النظام مدعوم بمحرك محاكاة متطور لتجاوز الحماية وسحب الفصول بأعلى جودة ممكنة.\n\n"
60
+ f"للدعم الفني: {ADMIN_HANDLE}"
61
+ )
62
+ bot.send_message(message.chat.id, welcome_text, parse_mode="HTML", reply_markup=markup)
63
+
64
+ @bot.callback_query_handler(func=lambda call: True)
65
+ def callback_query(call):
66
+ if call.data == "start_download":
67
+ bot.answer_callback_query(call.id)
68
+ msg = bot.send_message(call.message.chat.id, "<b>الرجاء إرسال رابط المانجا المراد تحميلها:</b>", parse_mode="HTML")
69
+ bot.register_next_step_handler(msg, get_manga_url)
70
+
71
+ elif call.data == "how_to_url":
72
+ help_text = (
73
+ "<b>💡 كيف تحصل على الرابط الصحيح؟</b>\n\n"
74
+ "يجب أن ينتهي الرابط برقم الفصل ليعمل النظام تلقائياً:\n\n"
75
+ "✅ <b>أزورا:</b>\n<code>https://azoramoon.com/series/manga-name/chapter-1</code>\n\n"
76
+ "✅ <b>أوليمبوس:</b>\n<code>https://olympustaff.com/series/manga-name/1</code>\n\n"
77
+ "⚠️ تأكد من نسخ الرابط من المتصفح مباشرة."
78
+ )
79
+ bot.send_message(call.message.chat.id, help_text, parse_mode="HTML")
80
+
81
+ def get_manga_url(message):
82
+ url = message.text.strip()
83
+ if not url.startswith("http"):
84
+ bot.reply_to(message, "❌ الرابط غير صالح. يرجى البدء بـ http")
85
+ return
86
+
87
+ user_data[message.chat.id] = {'url': url}
88
+
89
+ markup = types.InlineKeyboardMarkup()
90
+ markup.add(types.InlineKeyboardButton("🎯 فصل واحد فقط", callback_data="type_single"),
91
+ types.InlineKeyboardButton("📦 حزمة فصول (مدى)", callback_data="type_range"))
92
+ markup.add(types.InlineKeyboardButton("⏩ تحميل 10 فصول قادمة", callback_data="type_auto_10"))
93
+
94
+ bot.send_message(message.chat.id, "<b>اختر طريقة التحميل المفضلة:</b>", parse_mode="HTML", reply_markup=markup)
95
+
96
+ @bot.callback_query_handler(func=lambda call: call.data.startswith("type_"))
97
+ def handle_type_selection(call):
98
+ chat_id = call.message.chat.id
99
+ if chat_id not in user_data: return
100
+
101
+ if call.data == "type_single":
102
+ msg = bot.send_message(chat_id, "🔢 أرسل رقم الفصل المراد تحميله:")
103
+ bot.register_next_step_handler(msg, lambda m: start_process(m, "single"))
104
+
105
+ elif call.data == "type_range":
106
+ msg = bot.send_message(chat_id, "🔢 أرسل النطاق المطلوب (مثال: 1-10):")
107
+ bot.register_next_step_handler(msg, lambda m: start_process(m, "range"))
108
+
109
+ elif call.data == "type_auto_10":
110
+ msg = bot.send_message(chat_id, "🔢 أرسل رقم الفصل الذي تريد البدء منه:")
111
+ bot.register_next_step_handler(msg, lambda m: start_process(m, "auto10"))
112
+
113
+ def start_process(message, mode):
114
+ chat_id = message.chat.id
115
+ url = user_data[chat_id]['url']
116
+
117
+ try:
118
+ if mode == "single":
119
+ start, end = message.text, message.text
120
+ elif mode == "range":
121
+ start, end = message.text.split('-')
122
+ elif mode == "auto10":
123
+ start = int(message.text)
124
+ end = start + 9
125
+
126
+ status_msg = bot.send_message(chat_id, f"<b>⏳ جاري تشغيل المحرك...</b>\n🔄 معالجة الفصول من {start} إلى {end}", parse_mode="HTML")
127
+
128
+ # تنفيذ السحب
129
+ zip_path = run_engine_logic(url, start, end)
130
+
131
+ if zip_path:
132
+ with open(zip_path, 'rb') as f:
133
+ caption = (
134
+ "<b>✅ تمت عملية السحب بنجاح</b>\n\n"
135
+ f"📂 <b>الحزمة:</b> {start} - {end}\n"
136
+ f"👤 <b>بواسطة:</b> {ADMIN_HANDLE}"
137
+ )
138
+ bot.send_document(chat_id, f, caption=caption, parse_mode="HTML")
139
+ os.remove(zip_path)
140
+ bot.delete_message(chat_id, status_msg.message_id)
141
+ else:
142
+ bot.edit_message_text(f"❌ فشل المحرك في إيجاد الصور. تواصل مع {ADMIN_HANDLE}", chat_id, status_msg.message_id)
143
+
144
+ except Exception as e:
145
+ bot.send_message(chat_id, "⚠️ حدث خطأ في إدخال البيانات. يرجى المحاولة مرة أخرى.")
146
+
147
+ def run_engine_logic(sample_url, start, end):
148
  base_part = re.sub(r'/(?:chapter-)?\d+$', '', sample_url.strip().rstrip('/'))
149
  is_azora = "azoramoon" in sample_url
150
  pdf_files = []
151
 
152
  for i in range(int(start), int(end) + 1):
153
  target_url = f"{base_part}/chapter-{i}" if is_azora else f"{base_part}/{i}"
154
+ imgs = fetch_images(target_url)
 
155
  if imgs:
156
  fname = f"Chapter_{i}.pdf"
157
  imgs[0].save(fname, save_all=True, append_images=imgs[1:], format='PDF')
 
159
 
160
  if not pdf_files: return None
161
 
162
+ zip_name = f"Manga_Pack_{int(time.time())}.zip"
163
  with zipfile.ZipFile(zip_name, 'w') as zipf:
164
  for f in pdf_files:
165
  zipf.write(f); os.remove(f)
166
  return zip_name
167
 
168
+ # --- تشغيل التطبيق ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  if __name__ == "__main__":
 
170
  os.system("playwright install chromium")
171
  threading.Thread(target=lambda: bot.infinity_polling(), daemon=True).start()
172
  app.run(host="0.0.0.0", port=7860)