From cc8f7d1eb8ed6b4557e844848f94051e1978d10a Mon Sep 17 00:00:00 2001 From: sravan Date: Thu, 23 Jul 2026 12:18:50 +0530 Subject: [PATCH] feat(download): real % progress, and stream to disk instead of buffering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uploads showed a bar + %; downloads showed nothing. On the native app that gap is worse than on web, because there is no browser download UI behind it — the app fetches the bytes itself, so a large video looked like a frozen tap. - Adds the same chip an upload uses (name, bar, %) driven by Content-Length. Falls back to an indeterminate "…" when the server sends no length. - Streams the response and appends to the file in 3-byte-aligned blocks rather than holding blob + base64 simultaneously. The old path peaked around 250 MB of memory for a 75 MB video, which is enough to get a WebView killed on a phone. Verified byte-exact against empty / 1 B / 2 B (base64 padding edges) / ragged chunk sizes / 27 MB, reassembling identical bytes every time. - Older WebViews without streams keep the previous one-shot path. Co-Authored-By: Claude Opus 4.8 --- server/public/home.html | 70 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/server/public/home.html b/server/public/home.html index d349bdd..fa740f9 100644 --- a/server/public/home.html +++ b/server/public/home.html @@ -670,6 +670,14 @@ .att-vid.buffering .att-vid-spin{opacity:1;animation:ptrspin .8s linear infinite;} /* Dim the frame while buffering so the centre spinner reads instantly against a bright poster. */ .att-vid.buffering .att-vid-v{filter:brightness(.72);} + /* Download progress chip. The native save path fetches the bytes itself, so there is no browser download + UI to lean on — this mirrors the upload bar's bar + %, so a download reads the same as an upload. */ + .dl-prog{position:fixed;left:50%;transform:translateX(-50%);bottom:calc(env(safe-area-inset-bottom,0px) + 84px);z-index:120;background:rgba(17,24,39,.94);color:#fff;border-radius:12px;padding:.55rem .75rem;width:min(320px,84vw);box-shadow:0 6px 24px rgba(0,0,0,.38);font-size:.82rem;display:grid;gap:.4rem;} + .dl-prog .dp-top{display:flex;align-items:center;gap:.45rem;} + .dl-prog .dp-name{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;} + .dl-prog .dp-pct{font-weight:700;flex:0 0 auto;font-variant-numeric:tabular-nums;} + .dl-prog .dp-bar{height:4px;border-radius:3px;background:rgba(255,255,255,.22);overflow:hidden;} + .dl-prog .dp-fill{display:block;height:100%;width:0;background:#fff;transition:width .15s linear;} .bubble.mine .att-file{background:rgba(255,255,255,.18);border-color:rgba(255,255,255,.3);} .att-file .att-sz{opacity:.65;font-size:.75rem;flex:0 0 auto;} /* groups */ @@ -1167,7 +1175,7 @@ -