import os import threading import time import logging from datetime import datetime from fastapi import FastAPI from fastapi.responses import HTMLResponse, JSONResponse import uvicorn from keep_alive import start_ping_server from renewer import load_accounts, save_accounts, renew_account, run_renewals logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s') logger = logging.getLogger(__name__) app = FastAPI() SCHEDULER_RUNNING = False SCHEDULER_THREAD = None LOG_LINES = [] def add_log(msg): ts = datetime.utcnow().strftime("%H:%M:%S") LOG_LINES.append(f"[{ts}] {msg}") if len(LOG_LINES) > 200: LOG_LINES.pop(0) logger.info(msg) HTML = open("index.html", encoding="utf-8").read() @app.get("/", response_class=HTMLResponse) async def index(): return HTML @app.get("/api/accounts") async def get_accounts(): accounts = load_accounts() # لا نُرجع كلمة المرور أبداً safe = [] for a in accounts: safe.append({ "username": a["username"], "host": a.get("host", "—"), "last_renewed": a.get("last_renewed"), "next_renewal": a.get("next_renewal"), "last_results": a.get("last_results", []), }) return safe @app.post("/api/renew") async def renew_all(): add_log("🚀 بدء تجديد جميع الحسابات...") def do(): accs = run_renewals() if accs: for a in accs: for r in (a.get("last_results") or []): add_log(f" [{a['username']}] {r['domain']} → {r['status']}") add_log("✅ انتهى التجديد.") threading.Thread(target=do, daemon=True).start() return {"ok": True} @app.post("/api/renew/{username}") async def renew_one(username: str): accounts = load_accounts() account = next((a for a in accounts if a["username"] == username), None) if not account: return JSONResponse({"ok": False, "message": f"⚠️ لم يُعثر على {username} في الـ Secrets"}) account["next_renewal"] = None def do(): add_log(f"🔄 تجديد {username}...") success, results = renew_account(account) save_accounts(accounts) for r in results: add_log(f" [{username}] {r['domain']} → {r['status']}") add_log(f"{'✅' if success else '❌'} {'تم' if success else 'فشل'} تجديد {username}") threading.Thread(target=do, daemon=True).start() return {"ok": True} @app.post("/api/scheduler") async def toggle_scheduler(): global SCHEDULER_RUNNING, SCHEDULER_THREAD if not SCHEDULER_RUNNING: SCHEDULER_RUNNING = True def loop(): while SCHEDULER_RUNNING: run_renewals() time.sleep(3600) SCHEDULER_THREAD = threading.Thread(target=loop, daemon=True) SCHEDULER_THREAD.start() add_log("⏰ المجدول التلقائي شغّال — يجدد كل 10 أيام") else: SCHEDULER_RUNNING = False add_log("⏹ تم إيقاف المجدول التلقائي") return {"running": SCHEDULER_RUNNING} @app.get("/api/log") async def get_log(): return {"lines": LOG_LINES[-100:]} @app.get("/health") async def health(): return {"status": "alive"} if __name__ == "__main__": start_ping_server(port=8080) add_log("🚀 PythonAnywhere Manager started") # عرض الحسابات المحملة عند البدء accounts = load_accounts() if accounts: add_log(f"📋 تم تحميل {len(accounts)} حساب من Secrets: {[a['username'] for a in accounts]}") else: add_log("⚠️ لم يتم العثور على حسابات — أضف ACCOUNTS في Secrets") uvicorn.run(app, host="0.0.0.0", port=7860)