Skip to content

fix(ui): status pill overflowing into the progress column - #21

Closed
arousi wants to merge 8 commits into
billysams21:devfrom
arousi:fix/status-pill
Closed

fix(ui): status pill overflowing into the progress column#21
arousi wants to merge 8 commits into
billysams21:devfrom
arousi:fix/status-pill

Conversation

@arousi

@arousi arousi commented Aug 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Long STATUS labels (e.g. "Solving CAPTCHA...") overflowed the pill past the STATUS column into PROGRESS, because the pill width was computed purely from text with no clamp.

Fix

Clamp the pill to the column width and elide the label to fit.

Stacked

On top of #20#19#18; merge in order (afterwards this PR's diff is just the pill change). Delegate-paint UI change, verified visually.

arousi added 8 commits August 22, 2026 06:16
The old modal UpdateDownloaderDialog streamed the whole release zip while
flooding the GUI thread with per-chunk cross-thread progress calls; on a
large (205MB) release, concurrent with the live-graph update_ui, it could
crash the app mid-download.

Route updates through the existing, proven download engine instead:
- an available update is added to the normal queue as a DownloadTask
  (is_update); the user starts it and can pause/resume (Range-resume) it
  like any other download
- update tasks bypass the Cloudflare/CAPTCHA direct-link step and are never
  auto-extracted
- on completion the app offers Install now (restart) or Install on next
  open; a deferred update is applied via _check_pending_update on launch
- execute_update -> _apply_downloaded_update(zip_path): the robust
  extract -> robocopy swap -> marker-verify -> rollback flow is unchanged,
  it just consumes the already-downloaded zip

Removes the crash-prone modal download path entirely.
Root cause of the 'added but never progresses / connection timed out':
the queued update task ran through download_worker on a manager-spawned
thread and reused the shared curl_cffi self.dl_session. That session
(built on the main thread) hangs with curl (28) for a plain request that
never went through the nodriver/get_direct_link path first — normal
downloads work only because get_direct_link runs before the transfer.

Route update tasks through a dedicated _download_update_file() using urllib
(stdlib): supports Range-resume, pause/cancel, progress, and a 416
already-complete short-circuit. Confirmed progressing via the real manager
path where curl deterministically hung. Also stop a previously failed
update task from blocking a fresh re-offer.
Update downloads were written to a hidden ~/.silverspoon_updates folder, so
users couldn't find the completed file. Download to the same Save-To
directory as every other download (…/SilverSpoon Update <version>/), so it's
visible, consistent, and persists for an install-on-next-open.
Guard the completion prompt and the re-offer dedup on os.path.exists(filepath)
so a stale Completed update task (file deleted/moved) neither fires a phantom
install prompt nor blocks re-downloading.
…aNodes

Normalize the download path: any link whose host isn't a Turnstile/CAPTCHA
host now downloads straight over HTTP via urllib (the same robust path used
for app updates), with resume/pause/progress. FuckingFast and DataNodes
links still go through get_direct_link (the nodriver Turnstile solver) + the
curl transport exactly as before.

- add needs_resolution(link) + RESOLVER_HOSTS = (fuckingfast.co, datanodes.to)
- download_worker routes non-resolver hosts (and updates) to the renamed,
  now host-agnostic _download_direct_file()
- broaden the paste-box hint to mention direct URLs

Verified: general URL downloads without invoking the solver; a fuckingfast
link still invokes get_direct_link exactly once.
When the solver couldn't load the download page (Cloudflare/flagged IP, or a
host the dev-branch solver doesn't support), _resolve_direct_link_async did
close->respawn->navigate and, if that also failed, raised WITHOUT closing —
leaving a broken browser that the next call reused and re-spawned, so Chrome
kept spawning and never reached the page.

- wrap resolution in _resolve_with_cleanup: any failure tears the browser
  down (under the lock) so a broken instance is never reused
- don't auto-retry a CAPTCHA timeout (re-solving immediately just respawns
  the browser and rarely helps)

Manual test only (nodriver browser can't be exercised headlessly).
The STATUS pill width was purely text-based with no column clamp, so long
statuses (e.g. 'Solving CAPTCHA...') overflowed into the PROGRESS column.
Clamp the pill to the cell width and elide the label.
@arousi

arousi commented Sep 8, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by #27, which carries this change together with the other four fixes on top of v1.5.1 as a single PR from my fork's main.

@arousi arousi closed this Sep 8, 2026
@arousi
arousi deleted the fix/status-pill branch September 8, 2026 17:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant