Download app.py from Sebebeb/Forge: direct link, hf CLI and curl.
- Browser
- Download file 6.09 kB
-
https://huggingface.co/spaces/Sebebeb/Forge/resolve/main/app.py
- Command line
-
hf download hf://spaces/Sebebeb/Forge/app.py
-
curl -L -o app.py https://huggingface.co/spaces/Sebebeb/Forge/resolve/main/app.py
6.09 kB
| import os | |
| import threading | |
| from flask import Flask, request, Response, jsonify | |
| from playwright.sync_api import sync_playwright | |
| app = Flask(__name__) | |
| VIEWPORT = {"width": 1280, "height": 800} | |
| _lock = threading.Lock() | |
| _state = {"playwright": None, "browser": None, "page": None} | |
| USER_AGENT = ( | |
| "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " | |
| "(KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36" | |
| ) | |
| STEALTH_JS = """ | |
| Object.defineProperty(navigator, 'webdriver', {get: () => undefined}); | |
| Object.defineProperty(navigator, 'plugins', {get: () => [1, 2, 3, 4, 5]}); | |
| Object.defineProperty(navigator, 'languages', {get: () => ['en-US', 'en']}); | |
| window.chrome = { runtime: {} }; | |
| const originalQuery = window.navigator.permissions.query; | |
| window.navigator.permissions.query = (parameters) => ( | |
| parameters.name === 'notifications' | |
| ? Promise.resolve({ state: Notification.permission }) | |
| : originalQuery(parameters) | |
| ); | |
| """ | |
| def get_page(): | |
| if _state["page"] is None: | |
| _state["playwright"] = sync_playwright().start() | |
| _state["browser"] = _state["playwright"].chromium.launch( | |
| headless=True, | |
| args=[ | |
| "--no-sandbox", | |
| "--disable-dev-shm-usage", | |
| "--disable-blink-features=AutomationControlled", | |
| ], | |
| ignore_default_args=["--enable-automation"], | |
| ) | |
| context = _state["browser"].new_context( | |
| viewport=VIEWPORT, | |
| user_agent=USER_AGENT, | |
| locale="en-US", | |
| timezone_id="America/New_York", | |
| ) | |
| context.add_init_script(STEALTH_JS) | |
| _state["page"] = context.new_page() | |
| _state["page"].goto("https://example.com", wait_until="domcontentloaded") | |
| return _state["page"] | |
| HOME = """<!DOCTYPE html> | |
| <html><head><meta charset="utf-8"><title>Remote Browser</title> | |
| <style> | |
| html,body{margin:0;height:100%;background:#111; | |
| font-family:-apple-system,Helvetica,Arial,sans-serif;} | |
| #bar{display:flex;gap:8px;padding:10px 14px;background:#1e1e1e;} | |
| #bar input{flex:1;padding:8px 10px;border-radius:6px;border:none;font-size:14px;} | |
| #bar button{padding:8px 16px;border-radius:6px;border:none; | |
| background:#4f8cff;color:#fff;font-size:14px;cursor:pointer;} | |
| #stage{width:100%;height:calc(100vh - 52px);overflow:auto;background:#000; | |
| display:flex;justify-content:center;} | |
| #view{cursor:pointer;max-width:100%;display:block;} | |
| </style></head> | |
| <body> | |
| <div id="bar"> | |
| <input id="url" value="https://example.com" /> | |
| <button onclick="go()">Go</button> | |
| <button onclick="back()">←</button> | |
| </div> | |
| <div id="stage"><img id="view" src="/screenshot?t=0" /></div> | |
| <script> | |
| const img = document.getElementById('view'); | |
| const urlBox = document.getElementById('url'); | |
| const vw = __VW__, vh = __VH__; | |
| function refresh() { img.src = '/screenshot?t=' + Date.now(); } | |
| async function go() { | |
| await fetch('/go', {method:'POST', headers:{'Content-Type':'application/json'}, | |
| body: JSON.stringify({url: urlBox.value})}); | |
| setTimeout(refresh, 400); | |
| } | |
| async function back() { | |
| await fetch('/back', {method:'POST'}); | |
| setTimeout(refresh, 400); | |
| } | |
| img.addEventListener('click', async (e) => { | |
| const rect = img.getBoundingClientRect(); | |
| const x = (e.clientX - rect.left) / rect.width * vw; | |
| const y = (e.clientY - rect.top) / rect.height * vh; | |
| await fetch('/click', {method:'POST', headers:{'Content-Type':'application/json'}, | |
| body: JSON.stringify({x, y})}); | |
| setTimeout(refresh, 150); | |
| }); | |
| document.addEventListener('keydown', async (e) => { | |
| if (document.activeElement === urlBox) return; | |
| e.preventDefault(); | |
| await fetch('/key', {method:'POST', headers:{'Content-Type':'application/json'}, | |
| body: JSON.stringify({key: e.key})}); | |
| refresh(); | |
| }); | |
| document.getElementById('stage').addEventListener('wheel', async (e) => { | |
| await fetch('/scroll', {method:'POST', headers:{'Content-Type':'application/json'}, | |
| body: JSON.stringify({dy: e.deltaY})}); | |
| refresh(); | |
| }); | |
| setInterval(refresh, 500); | |
| </script> | |
| </body></html>""" | |
| def home(): | |
| html = HOME.replace("__VW__", str(VIEWPORT["width"])).replace( | |
| "__VH__", str(VIEWPORT["height"]) | |
| ) | |
| return html | |
| def screenshot(): | |
| with _lock: | |
| page = get_page() | |
| try: | |
| data = page.screenshot(type="jpeg", quality=100) | |
| except Exception: | |
| data = b"" | |
| return Response(data, content_type="image/jpeg") | |
| def go(): | |
| url = (request.json or {}).get("url", "").strip() | |
| if not url: | |
| return jsonify(ok=False) | |
| if not url.startswith(("http://", "https://")): | |
| url = "https://" + url | |
| with _lock: | |
| page = get_page() | |
| try: | |
| page.goto(url, wait_until="domcontentloaded", timeout=20000) | |
| except Exception as e: | |
| return jsonify(ok=False, error=str(e)) | |
| return jsonify(ok=True) | |
| def back(): | |
| with _lock: | |
| page = get_page() | |
| try: | |
| page.go_back(timeout=10000) | |
| except Exception: | |
| pass | |
| return jsonify(ok=True) | |
| def click(): | |
| data = request.json or {} | |
| with _lock: | |
| page = get_page() | |
| try: | |
| page.mouse.click(data.get("x", 0), data.get("y", 0)) | |
| except Exception: | |
| pass | |
| return jsonify(ok=True) | |
| def key(): | |
| data = request.json or {} | |
| with _lock: | |
| page = get_page() | |
| try: | |
| page.keyboard.press(data.get("key", "")) | |
| except Exception: | |
| pass | |
| return jsonify(ok=True) | |
| def scroll(): | |
| data = request.json or {} | |
| with _lock: | |
| page = get_page() | |
| try: | |
| page.mouse.wheel(0, data.get("dy", 0)) | |
| except Exception: | |
| pass | |
| return jsonify(ok=True) | |
| if __name__ == "__main__": | |
| port = int(os.environ.get("PORT", 7860)) | |
| app.run(host="0.0.0.0", port=port, threaded=False) |