File size: 3,852 Bytes
bcb31ef 0472279 bcb31ef 0472279 bcb31ef 0472279 bcb31ef 9b2da3f bcb31ef 9b2da3f bcb31ef 0472279 bcb31ef 0472279 bcb31ef 9b2da3f bcb31ef 9b2da3f bcb31ef 0472279 9b2da3f | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | 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) |