Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 45 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

# 🌙 Moon Downloader

### **V2**
### **V3**

**Bulk file downloader** — real-Chrome extraction for datanodes.to, pure-HTTP extraction for fuckingfast.co, aiohttp streaming, and a GUI that runs on Edge WebView2.

Expand Down Expand Up @@ -36,8 +36,17 @@ Built with Python · Playwright · aiohttp · curl_cffi

<img src="docs/gui_speed.png" width="920"/>

<sub>**195.7 MB/s** · 124 fuckingfast links · 8 DL streams · 12.63 GB in 1m23s · ETA 3m35s —
and **not one browser window**, because no datanodes link was in the batch.</sub>
<sub>The rate is the figure being watched, so it gets the left side and the plot underneath;
completed, downloaded and ETA are reference and sit small. Every row shows which host it came
from. <b>Rendered from the page's own mock engine</b> — the numbers are synthetic, which is what
the <code>demo</code> chip in the corner says.</sub>

<br><br>

<img src="docs/gui_boot.png" width="640"/>

<sub>The cold open: the mark draws itself on, the wordmark resolves out of a blur, and the card
cascade is held until it hands over. Under two seconds, and any key or click ends it.</sub>

<br><br>

Expand All @@ -52,6 +61,9 @@ and **not one browser window**, because no datanodes link was in the batch.</sub
</tr>
</table>

<sub>Filter box and state chips over the list; what is moving gets room and a brighter name, what
has finished tightens and recedes.</sub>

</div>

---
Expand Down Expand Up @@ -83,7 +95,34 @@ files done, 0 failed, no browser window opened. Method and instrumentation in

---

## ⚡ What V2 is
## 🌗 What V3 is

**The interface, rebuilt.** The engine is untouched — extraction, downloading and the CLI are the
same code they were in 2.1, and that is deliberate: this release changes what you look at, not what
it does.

| | before | V3 |
|:--|:--|:--|
| **Launch** | the window simply appeared | a cold open under two seconds, skippable, removed from the DOM when done |
| **Mark** | a 512px PNG | an SVG whose crescent and orbit move independently |
| **Headline** | four equal stat cards | one hero band; the rate is a 49px figure, the rest is reference |
| **Settings column** | five floating cards | one surface, hairline sections, Start built in |
| **Transfer rows** | all identical weight | provider chip per row, weight follows state |
| **Finding a file** | scrolling | filter box, state chips, `/` to focus |
| **Getting links in** | the Load button | drag and drop anywhere, appended not replacing |
| **After a run** | the list, as it was | a summary that can copy every failed link |

Keyboard: `Ctrl+Enter` start or stop · `Ctrl+O` load a `.txt` · `/` filter · `?` the shortcut panel ·
`Esc` close or clear.

**On motion.** The GUI animates for everyone; there is no `prefers-reduced-motion` exception, and
that is a stated choice rather than an oversight. Nothing flashes and every loop is slow. If you
want a motion preference, [open an issue](https://github.com/LeyckerS/moondownloader/issues/new) —
it is a small change.

---

## ⚡ How the two providers differ

The two providers stopped having anything in common, so the app stopped pretending they did.

Expand All @@ -97,8 +136,7 @@ The two providers stopped having anything in common, so the app stopped pretendi

A batch of fuckingfast links **never launches Chrome** — not even the Playwright driver's node process.
A batch that contains one datanodes link opens exactly one shared Chrome, on demand, no matter how many
extractors are running. The screenshot above is that fix, visible: 124 fuckingfast links moving at
195.7 MB/s with no browser window anywhere.
extractors are running.

One `BrowserGate` in `moon_extract.py` owns that decision, so the GUI and the CLI behave the same
way — `tests/test_no_chrome.py` asserts it for both.
Expand Down Expand Up @@ -226,7 +264,7 @@ Full write-up: **[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md)**.
| [CLI](docs/CLI.md) | every flag, exit codes, scripting examples |
| [Configuration](docs/CONFIGURATION.md) | every setting, every environment variable, the Chrome profile |
| [Providers](docs/PROVIDERS.md) | how each host is extracted, and how to add another |
| [Architecture](docs/ARCHITECTURE.md) | how V2 is built, feature by feature |
| [Architecture](docs/ARCHITECTURE.md) | how the engine is built, feature by feature |
| [Engineering notes](docs/ENGINEERING_NOTES.md) | the measurements behind the design decisions |
| [Troubleshooting](docs/TROUBLESHOOTING.md) | 403s, Turnstile failures, CDP conflicts, stalls |
| [FAQ](docs/FAQ.md) | why curl_cffi is mandatory, what `--browsers` means |
Expand Down
13 changes: 9 additions & 4 deletions docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,14 +183,19 @@ top right says what is in use: `auto` / `chrome` / `api key`.
**FUCKINGFAST.CO** — no knobs, and it says so: pure HTTP, opens no browser, has no
captcha. It only reports whether `curl_cffi` is present.

**The four cards** — `SPEED` (3 s rolling window + an SVG sparkline with a glow),
`COMPLETED`, `DOWNLOADED` (`ok / ko / kill`), `ETA` (estimated on bytes, not on files).
**The hero band** — `SPEED` (3 s rolling window) is the figure being watched, so it is set
at 49px with the sparkline spanning the card underneath; `COMPLETED`, `DOWNLOADED`
(`ok / ko / kill`) and `ETA` (estimated on bytes, not on files) are reference and sit small
to its right. Four equal cards gave four equal weights to numbers that are not equal.
`PIPELINE` keeps extraction and download separate, because they run at the same time.

**ACTIVE FILES** — one row per file: SVG progress ring, state
(`queue / extracting / downloading / saved / failed / restart`), percentage, instantaneous
speed, and a bar along the foot. `content-visibility: auto`, so a 400-row list costs
nothing while it is off screen.
speed, the provider it came from (read off the source URL, which is the row key), and a bar
along the foot. Row weight follows state: what is moving gets room and a brighter name,
what has finished tightens and recedes. `content-visibility: auto`, so a 400-row list costs
nothing while it is off screen. Above the list, a filter box and state chips hide rows
without touching any count the engine owns.

**LOG** — the same lines as always, same tags and colours, capped at 2000.

Expand Down
Binary file added docs/gui_boot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gui_log.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gui_speed.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified docs/gui_transfers.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions web/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -1110,7 +1110,7 @@ async function boot() {
try {
const info = await bridge.api.hello();
if (info) {
$("#version").textContent = info.version || "v2.0";
$("#version").textContent = info.version || "v3.0";
if (info.have_curl === false) {
const line = $("#curlLine");
line.dataset.i18n = "ff_missing";
Expand Down Expand Up @@ -1138,7 +1138,7 @@ class MockApi {
this.extracted = 6;
this.bytes = 2.6 * 2 ** 30;
this.log = [
["▶ 85 links · 16 extractors · 8 streams · 3 retries · v2.0", "info"],
["▶ 85 links · 16 extractors · 8 streams · 3 retries · v3.0", "info"],
[" fuckingfast: direct HTTP · datanodes: 8 pages, captcha 30s", "dim"],
[" chrome: C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", "dim"],
[" proxies: 12 loaded — rotating per download", "info"],
Expand Down Expand Up @@ -1185,7 +1185,7 @@ class MockApi {
}

async hello() {
return { version: "v2.0 · preview", have_curl: true, settings: {
return { version: "v3.0 · preview", have_curl: true, settings: {
out_folder: "E:\\blackops3", mode: "download", workers: 16, dl_streams: 8, retries: 3,
dn_pages: 8, dn_captcha: 30,
dn_chrome: "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
Expand Down