The engine and the CLI do — they are Python + aiohttp + curl_cffi, plus Playwright for
datanodes. start.bat is Windows-only, and the GUI needs a Chromium browser to host the
--app window, so on macOS/Linux run python moon_bridge.py --serve and open the URL.
datanodes also needs a real Chrome/Edge for Turnstile; find_chrome() already looks in
the usual macOS and Linux locations.
Removed in V2. It was a second interface to maintain for the same engine, and it was
also the file moon_engine.py used to be generated from — which made the legacy GUI the
source of truth for the modern engine. The generator went with it; moon_engine.py is a
normal module you can edit.
No. It was until 14.4, and the extraction rewrite ended that: moon_extract.py holds the
extraction layer, moon_bridge.py hosts the GUI, web/ is the GUI, and moon_cli.py
is still standalone-runnable, which was the actual point of the old rule.
Cloudflare fingerprints the TLS ClientHello. aiohttp's scores as a bot and gets a 403 on
every link no matter which headers it sends; curl_cffi impersonates Chrome's and gets
through. Downloads stay on aiohttp — dl.fuckingfast.co serves the file with full Range
support and no impersonation needed.
Turnstile does not issue a token to a headless build: the challenge platform answers 401
and cf-turnstile-response stays empty. It also rejects Playwright's Chromium, which is
not a Google-branded build. So the app spawns a real Chrome with a persistent profile and
drives it over CDP — the profile is the point, because the clearance survives between
links.
No, since V2. moon_extract.BrowserGate launches on the first datanodes link and never
before — not even the Playwright driver's node process. python test_no_chrome.py asserts
it for the engine and the CLI, and checks both sources.
Same engine, two front-ends.
moon_bridge.py+web/+moon_engine.py— the GUI: loopback HTTP, Edge/Chrome--appwindowmoon_cli.py— argparse CLI, prints to stdout, for scripting and headless boxes
Parallel extraction workers. It has not meant "one browser each" since 14.7: datanodes
runs on one shared Chrome window, and Pages (1–8) bounds how many tabs may be open
on it at once. fuckingfast opens nothing at all.
No. Drop a proxies.txt next to the scripts to enable rotation:
ip:port:user:pass
http://user:pass@ip:port
The status bar shows how many were loaded.
With a datanodes premium API key, yes — extraction becomes one JSON GET, no browser,
no Turnstile. Set it in the GUI or MOON_DN_API_KEY. Free keys get 403 on direct_link
and fall back to Chrome.
Yes — write the extractor in moon_extract.py, then dispatch on the domain in
moon_engine.py and moon_cli.py. Ask BrowserGate.get() for a browser inside the branch
that needs it, never before. docs/PROVIDERS.md has the full checklist.
datanodes needs a visible, real Chrome for Turnstile, which is exactly what a container is bad at. A fuckingfast-only container would work (no browser at all) — nothing is published yet.
Bug report template.
Attach moontech_*.log (GUI) or moontech_cli_*.log (CLI) from the failed session.