#!/usr/bin/env python3.11 """ R10 worker - tam otomatik (ekransiz). Giris: kullanici adi + sifre ile login, gerekirse TOTP ile 2FA. Cloudflare'i gercek tarayici cozer. Kalici profil oturumu saklar. Kurulum (root): python3.11 -m pip install playwright pyotp python3.11 -m playwright install chromium Cron: * * * * * cd /root/r10 && xvfb-run -a python3.11 worker.py >> /root/r10/worker.log 2>&1 """ import json, random, urllib.request, urllib.parse from datetime import datetime import pyotp from playwright.sync_api import sync_playwright # ===================== AYARLAR ===================== PANEL_API = "https://upgrade.poensis.org/api.php" API_KEY = "r10up_9fK3xQ7mWv2ZpL8cR4tB6nY1sD5hJ0aE2gU" # config.php ile AYNI PROFILE_DIR = "/root/r10/r10_profile" # R10 giris bilgileri R10_USERNAME = "Buborium" R10_PASSWORD = "11223344Aa." TOTP_SECRET = "QC72TMNSMUVQEDCKVR7M7UNRXBTHZYRM" # R10 2FA gizli anahtari (base32) # =================================================== def log(msg): print(f"[{datetime.now():%Y-%m-%d %H:%M:%S}] {msg}", flush=True) def api_due(): url = f"{PANEL_API}?key={urllib.parse.quote(API_KEY)}&do=due" with urllib.request.urlopen(url, timeout=30) as r: return json.loads(r.read().decode("utf-8")).get("topics", []) def api_report(tid, ok, status): data = urllib.parse.urlencode({"id": tid, "ok": "1" if ok else "0", "status": status}).encode() url = f"{PANEL_API}?key={urllib.parse.quote(API_KEY)}&do=report" urllib.request.urlopen(urllib.request.Request(url, data=data), timeout=30).read() def logged_in(page): """Gercek giris kontrolu: 'Giris Yap' / 'Giris yapmadiniz' yoksa girisli.""" low = (page.content() or "").lower() if "giriş yapmadınız" in low or "giris yapmadiniz" in low: return False # navbar'da kullanici adi alani gorunuyorsa girisli degil if 'name="vb_login_username"' in low and "girisModal".lower() in low and "do=logout" not in low: # login formu sayfada acik olabilir; do=logout yoksa girisli degil say return "do=logout" in low return "do=logout" in low def do_login(page): """Login formunu doldurur, gerekirse 2FA TOTP girer.""" log("Giris yapiliyor...") page.goto("https://www.r10.net/login.php", wait_until="domcontentloaded", timeout=60000) page.wait_for_timeout(3000) try: page.fill('input[name="vb_login_username"]', R10_USERNAME, timeout=8000) page.fill('input[name="vb_login_password"]', R10_PASSWORD, timeout=8000) try: page.check('input[name="cookieuser"]', timeout=3000) except Exception: pass # submit butonuna bas for sel in ['input[type="submit"]', 'button[type="submit"]', 'form button']: try: page.click(sel, timeout=3000) break except Exception: continue page.wait_for_load_state("domcontentloaded", timeout=30000) page.wait_for_timeout(3000) except Exception as e: log(f"login formu hatasi: {e}") # 2FA? if "otpauth" in (page.content() or "").lower(): log("2FA ekrani, TOTP giriliyor...") code = pyotp.TOTP(TOTP_SECRET).now() for i, d in enumerate(code, start=1): try: page.fill(f'input[name="otp{i}"]', d, timeout=4000) except Exception: pass for sel in ['#otpauth button[type="submit"]', 'button.loginBtn', 'form#otpauth button']: try: page.click(sel, timeout=2500) break except Exception: continue try: page.wait_for_load_state("domcontentloaded", timeout=30000) except Exception: pass page.wait_for_timeout(3000) def ensure_login(page): page.goto("https://www.r10.net/", wait_until="domcontentloaded", timeout=60000) page.wait_for_timeout(3000) if logged_in(page): return True do_login(page) page.goto("https://www.r10.net/", wait_until="domcontentloaded", timeout=60000) page.wait_for_timeout(2000) return logged_in(page) def up_topic(page, url): page.goto(url, wait_until="domcontentloaded", timeout=60000) page.wait_for_timeout(3000) try: page.wait_for_selector('form[name="threadadminform"]', timeout=30000) except Exception: body = (page.content() or "").lower() if "otpauth" in body: return False, "2FA gerekiyor" if "giriş yapmadınız" in body or "giris yapmadiniz" in body: return False, "Oturum yok (giris basarisiz)" if "just a moment" in body: return False, "Cloudflare gecilemedi" return False, "UP formu yok (cooldown olabilir)" res = page.evaluate("""() => { const f = document.querySelector('form[name="threadadminform"]'); if (!f) return 'noform'; const r = f.querySelector('input[name="tur"][value="5"]'); if (!r) return 'noup'; r.checked = true; if (typeof f.requestSubmit === 'function') f.requestSubmit(); else f.submit(); return 'ok'; }""") if res == 'noup': return False, "Yukari Tasi secenegi yok (cooldown)" if res != 'ok': return False, f"Form gonderilemedi ({res})" try: page.wait_for_load_state("domcontentloaded", timeout=60000) except Exception: pass page.wait_for_timeout(2500) body = (page.content() or "").lower() for err in ["yetkiniz yok", "henüz", "beklem", "daha sonra", "hata olu", "son taşıma", "işlem yapamaz"]: if err in body: return False, "Reddedildi (cooldown/yetki)" return True, "UP basarili" def main(): try: due = api_due() except Exception as e: log(f"API due hatasi: {e}") return if not due: log("Sirada konu yok.") return log(f"{len(due)} konu sirada.") with sync_playwright() as p: ctx = p.chromium.launch_persistent_context( PROFILE_DIR, headless=False, args=["--disable-blink-features=AutomationControlled", "--no-sandbox"], ) page = ctx.pages[0] if ctx.pages else ctx.new_page() page.on("dialog", lambda d: d.accept()) ok_login = ensure_login(page) log("Giris durumu: " + ("OK" if ok_login else "BASARISIZ")) if not ok_login: log("Giris yapilamadi, cikiliyor. Kullanici adi/sifre/TOTP dogru mu?") ctx.close() return for t in due: label = t.get("label") or t["url"] try: ok, status = up_topic(page, t["url"]) except Exception as e: ok, status = False, f"Hata: {e}" log(f"#{t['id']} {label}: {status}") try: api_report(t["id"], ok, status) except Exception as e: log(f"report hatasi #{t['id']}: {e}") page.wait_for_timeout(random.randint(3000, 8000)) ctx.close() log("Worker bitti.") if __name__ == "__main__": main()