| import os, time, threading, zipfile, io, re, json, hashlib, gc |
| from flask import Flask |
| import telebot |
| from telebot import types |
| from playwright.sync_api import sync_playwright |
| from PIL import Image |
|
|
| |
| |
| |
|
|
| BOT_TOKEN = os.getenv("TELEGRAM_BOT_TOKEN") |
| ARCHIVE_CHANNEL = os.getenv("ARCHIVE_CHANNEL_ID") |
| ADMIN_HANDLE = "@svipfast" |
|
|
| bot = telebot.TeleBot(BOT_TOKEN, threaded=False) |
| app = Flask(__name__) |
|
|
| archive_index = {} |
| archive_cache = {} |
| processing_now = set() |
|
|
| |
| |
| |
|
|
| def make_key(url, chapter): |
| raw = f"{url}|{chapter}" |
| return hashlib.md5(raw.encode()).hexdigest() |
|
|
| |
| |
| |
|
|
| def load_archive(): |
| global archive_index, archive_cache |
| try: |
| chat = bot.get_chat(ARCHIVE_CHANNEL) |
| if chat.pinned_message: |
| archive_index = json.loads(chat.pinned_message.text) |
| archive_cache = archive_index.copy() |
| print(f"✅ Loaded archive: {len(archive_index)}") |
| except: |
| print("ℹ️ New archive will be created") |
|
|
| def save_archive(): |
| try: |
| text = json.dumps(archive_index) |
| chat = bot.get_chat(ARCHIVE_CHANNEL) |
| if chat.pinned_message: |
| bot.edit_message_text(text, ARCHIVE_CHANNEL, chat.pinned_message.message_id) |
| else: |
| msg = bot.send_message(ARCHIVE_CHANNEL, text) |
| bot.pin_chat_message(ARCHIVE_CHANNEL, msg.message_id) |
| except Exception as e: |
| print("❌ Save error:", e) |
|
|
| def add_to_archive(key, file_path, caption): |
| try: |
| with open(file_path, 'rb') as f: |
| msg = bot.send_document(ARCHIVE_CHANNEL, f, caption=caption) |
| archive_index[key] = msg.message_id |
| archive_cache[key] = msg.message_id |
| save_archive() |
| return msg.message_id |
| except: |
| return None |
|
|
| |
| |
| |
|
|
| playwright = sync_playwright().start() |
| browser = playwright.chromium.launch(headless=True) |
|
|
| def fetch_images(url): |
| context = browser.new_context() |
| 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.5) |
|
|
| images = page.query_selector_all("img") |
| img_list = [] |
|
|
| for img in images: |
| src = img.get_attribute("src") or img.get_attribute("data-src") |
| if src and any(ext in src.lower() for ext in ['.jpg','.png','.webp']): |
| try: |
| res = page.request.get(src) |
| if res.status == 200 and len(res.body()) > 20000: |
| img_list.append(Image.open(io.BytesIO(res.body())).convert('RGB')) |
| except: |
| continue |
|
|
| context.close() |
| return img_list |
| except: |
| context.close() |
| return [] |
|
|
| def safe_fetch(url): |
| for _ in range(3): |
| imgs = fetch_images(url) |
| if imgs: |
| return imgs |
| return [] |
|
|
| |
| |
| |
|
|
| user_states = {} |
|
|
| @app.route('/') |
| def home(): |
| return "✅ Bot Running" |
|
|
| @bot.message_handler(commands=['start']) |
| def start(msg): |
| markup = types.InlineKeyboardMarkup() |
| markup.add(types.InlineKeyboardButton("📥 إرسال رابط", callback_data="new")) |
| bot.send_message(msg.chat.id, "🚀 أرسل رابط الفصل", reply_markup=markup) |
|
|
| @bot.callback_query_handler(func=lambda c: True) |
| def handle(c): |
| if c.data == "new": |
| m = bot.send_message(c.message.chat.id, "🔗 أرسل الرابط") |
| bot.register_next_step_handler(m, get_url) |
|
|
| def get_url(msg): |
| user_states[msg.chat.id] = {"url": msg.text} |
| m = bot.send_message(msg.chat.id, "🔢 اكتب رقم الفصل") |
| bot.register_next_step_handler(m, process) |
|
|
| def process(msg): |
| chat_id = msg.chat.id |
| url = user_states[chat_id]["url"] |
| chapter = int(msg.text) |
|
|
| key = make_key(url, chapter) |
|
|
| |
| if key in archive_cache: |
| bot.send_message(chat_id, "⚡ من الأرشيف") |
| bot.forward_message(chat_id, ARCHIVE_CHANNEL, archive_cache[key]) |
| return |
|
|
| |
| if key in processing_now: |
| bot.send_message(chat_id, "⏳ يتم معالجته...") |
| return |
|
|
| processing_now.add(key) |
|
|
| bot.send_message(chat_id, "🔄 جاري السحب...") |
|
|
| base = re.sub(r'/\d+$', '', url) |
| target = f"{base}/{chapter}" |
|
|
| imgs = safe_fetch(target) |
|
|
| if imgs: |
| pdf = f"ch_{chapter}.pdf" |
| imgs[0].save(pdf, save_all=True, append_images=imgs[1:]) |
|
|
| zip_name = f"ch_{chapter}.zip" |
| with zipfile.ZipFile(zip_name, 'w', compression=zipfile.ZIP_DEFLATED) as z: |
| z.write(pdf) |
|
|
| msg_id = add_to_archive(key, zip_name, f"Chapter {chapter}") |
|
|
| if msg_id: |
| bot.forward_message(chat_id, ARCHIVE_CHANNEL, msg_id) |
|
|
| os.remove(pdf) |
| os.remove(zip_name) |
| gc.collect() |
|
|
| else: |
| bot.send_message(chat_id, "❌ فشل السحب") |
|
|
| processing_now.remove(key) |
|
|
| |
| |
| |
|
|
| if __name__ == "__main__": |
| os.system("playwright install chromium") |
| load_archive() |
| threading.Thread(target=lambda: bot.infinity_polling(), daemon=True).start() |
| app.run(host="0.0.0.0", port=7860) |