Skip to content

feat(serve): built-in web remote UI with live SSE updates - #5

Closed
pseudoshell wants to merge 7 commits into
huntfrom
gobble
Closed

pseudoshell wants to merge 7 commits into
huntfrom
gobble

Conversation

@pseudoshell

Copy link
Copy Markdown
Owner

No description provided.

Serve a self-contained, zero-dependency web remote from torhunt serve.
The shell (src/daemon/assets/ui.html) mirrors the TUI's Electric Cyan
design language and works on desktop and mobile: add magnets or info
hashes, watch live progress with per-torrent speed/peers/ETA,
pause/resume/delete downloads, stop seeding, and browse the completed
archive.

Server side: new src/daemon/webui.ts holds the asset locator, the
server-sent-event stream manager (initial snapshot + push-on-update +
keepalive + self-cleanup), and an Origin-vs-Host cross-site guard for
state-changing requests. serve.ts gains GET / and /ui (secretless HTML
shell), token-authenticated GET /events (EventSource-friendly
query-param token), and read-only GET /history; statusPayload now
includes totalBytes/downloadedBytes/eta additively. The request handler
is extracted into createServeHandler so tests can drive a real HTTP
server against a fake runtime.

The TUI is untouched. postbuild ships dist/ui.html beside the bundle;
runServe delegates to the shared handler. 45 daemon tests pass (9 new
webui unit tests, 10 new integration tests); full suite 348 green;
typecheck clean.
The web remote could only accept magnets; searching still required the
terminal. This wires the same source adapters the TUI uses into the
headless server.

New src/daemon/websearch.ts runs every source in parallel under one
deadline (15s per source, matching the TUI hook), dedupes shared
infoHashes keeping the healthiest row, orders seeders-first like the
results view, caps the payload at 60 rows, and degrades unreachable
sources to a per-source `failed` list instead of failing the request.

serve.ts gains GET /search?q=&cat= (auth-protected, category validated
against Games/Movies/TV/Anime), with both handleApi and
createServeHandler taking an injectable search function so tests never
touch the network.

The web UI gets a Search tab as its default view: query input, category
select, results with size/seeder/leecher/source metadata, and one-click
Download buttons that enqueue via POST /add and flip to "Queued".
Unreachable sources are reported inline in the status line.

9 new tests (6 websearch unit tests, 3 search API/integration); full
suite 357 green; typecheck clean.
Three web remote polish fixes:

- Font: load JetBrains Mono from Google Fonts (400/500/700, swap) with
  the previous ui-monospace stack kept as an offline fallback.
- Background: the radial glow tiled every 1200x500px because background
  images repeat by default — scrolling showed duplicated glow blocks.
  The body backgrounds are now no-repeat and viewport-fixed, with a
  solid shade-deep fallback color beneath. Also theme-matched
  scrollbars (webkit + scrollbar-color).
- Layout: long release names could push a row wider than its panel and
  clip the action buttons. row-top is now a contained flex box
  (min-width:0, max-width:100%, nowrap) with the name ellipsized inside
  it, and action buttons can neither grow nor force overflow
  (flex:none, wrap allowed as last resort). Completed-tab rows no
  longer show a misleading PAUSED chip; they get a neutral done chip.
The web remote leaned on emoji where it should have used real UI
elements. All of them are gone:

- The header bolt emoji is replaced by a geometric download-tray SVG
  mark inside the accent tile; the token gate drops its padlock; search
  results label seeders/leech in plain text instead of triangle glyphs;
  the queued button reads "Queued" instead of a check character.
- Header: tighter type scale, uppercase letterspaced subtitle, and the
  connection indicator becomes a bordered pill that tints green when
  live.
- Panels: titles gain a small glowing accent tick before the label.
- Chips: subtle tinted backgrounds per state instead of bare outlines;
  stats use tabular numerals with smaller tracked labels.
- Rows get a faint hover response; meters slim to 5px; tabs dim when
  inactive with hover feedback.
Complete visual rebuild of the web remote shell around a proper design
token system instead of the TUI-derived neon theme. Same single file,
same zero dependencies, same instant load.

Tokens: shadcn-style zinc scale as CSS custom properties (--background,
--foreground, --card, --muted, --border, --ring, --primary, semantic
success/warning/destructive/blue), with full light and dark palettes.
Theme follows prefers-color-scheme on first load, persists the user's
explicit choice, and is applied pre-paint by an inline head script so
there is no flash. A header icon button toggles sun/moon.

Components, hand-rolled in the same idiom: hairline-bordered cards with
xs shadows and section headers with live counts; solid high-contrast
primary buttons plus outline/small/destructive variants (destructive
keeps its two-step confirm); segmented control tabs; badge component
with dot + tinted variants per status; 5px progress meters that fill
with foreground and turn red on failure; focused inputs with ring
shadows; inverted toast; centered modal for the token gate.

Typography: Geist sans for UI, JetBrains Mono kept only where
monospace is meaningful (the magnet input, source tags). Tabular
numerals on all counters.

Structure: search card and quick-add card always visible up top;
Downloads/Seeding/Completed switch below via the segmented tabs. All
existing behavior is preserved — SSE with polling fallback, token gate,
search with categories, one-click download, pause/resume/delete,
stop-seed, history.
The web remote no longer invents its own light/dark themes, and the
category filter no longer falls back to the browser's native select.

Theme mirroring: /health now reports the configured TUI theme (id, name,
full palette) read fresh from disk on every call, so a theme switched in
the terminal reaches a running daemon without a restart. The web shell
polls /health every few seconds and, on change, maps the theme's palette
onto its design tokens: shade -> background, text -> foreground, rule ->
borders, accent -> primary/ring, good/warn/bad -> semantic colors,
sprout -> info. Derived surfaces (card, muted, glass) are computed by
mixing the theme colors, so all ten TUI themes render coherently through
the same shadcn-style components. The static fallback palette in the
stylesheet mirrors Electric Cyan. The sun/moon toggle and its
localStorage theme are removed — the terminal is the source of truth.

Category dropdown: replaced the native select with a custom listbox
matching the design system — bordered trigger button with rotating
chevron, floating menu card with hover rows, a glowing accent dot on the
selected option, outside-click and Escape to dismiss, and correct
listbox/option ARIA attributes.
The shadcn re-skin had switched body text to Geist; restore JetBrains Mono as the single UI typeface (400/500/600/700), dropping the unused Geist download. Base size steps down to 12.5px to balance mono glyph width.
@coderabbitai

coderabbitai Bot commented Sep 13, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Advanced

Run ID: 4415aef3-48b1-45ff-b698-e3c707f857fd

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@github-actions

Copy link
Copy Markdown

ThreatCrush Security Scan

0 finding(s)

No findings.

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