7 / app.py
iq7se2's picture
Update app.py
182e06f verified
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 (مرة واحدة)
# ════════════════════════════════
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)
# 🧠 cache
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)