Commit Graph

4 Commits

Author SHA1 Message Date
Keysat cb961cd2d9 Accept YouTube /live/ and /shorts/ URLs in extractVideoId
The video-id regex only matched /watch?v=, youtu.be, /embed/, and /v/
forms, so youtube.com/live/<id> and youtube.com/shorts/<id> links were
rejected with "Invalid YouTube URL". Add both forms to the server and
frontend extractors (kept in sync) and cover them with tests.

Ship as 0.2.159.
2026-06-15 23:29:57 -05:00
Keysat 373d10595b Pluggable AI providers, relay credit system, picker UX overhaul
Captures roughly forty version bumps (v0.2.6 → v0.2.47) of work that
accumulated without commits.

- Pluggable provider system under server/providers/: gemini, anthropic,
  openai, openai-compatible, ollama, whisper-compatible, relay. Mix and
  match transcription + analysis per request via the picker UI.
- Relay backend integration. Hardcoded relay URL in server/relay-default.js
  (operator-controlled at build time, not user-configurable). New
  /api/relay/{status,policy} endpoints proxy to the relay; balance pings
  populate a cached credit display.
- Per-install identity in server/install-id.js for relay credit accounting.
  Sent to the relay as X-Recap-Install-Id; persists across upgrades, lost
  on a full uninstall + reinstall. Not surfaced in the UI.
- Admin login gate (server/admin-auth.js + setAdminPassword action). Scrypt
  password hash + HMAC-signed session cookie.
- Entitlement scheme rename: pro / max (each paired with subscriptions and
  relay_pro / relay_max), replacing the misleading "core" entitlement
  that conflicted with the user-facing "Core" tier name.
- Activation screen: dynamic credit count pulled from /api/relay/policy,
  "Skip — use free mode" button, accurate paid-feature list.
- Top toolbar: inline credit-balance pill (or "BYO configured" fallback),
  Upgrade + "I have a key" buttons.
- Picker UI: per-provider sections with Save/Test/Delete buttons, sections
  collapsible by chevron, default-collapsed unless currently selected,
  "Use comped credits (reset to relay)" link when the user has strayed,
  green hint under inputs whose values are server-configured.
- Activity log: chevron-collapsible groups per video, refresh-survival via
  localStorage + a 500-entry server-side buffer, explicit Clear button.
- YouTube captions fast-path with user toggle (skips audio download + AI
  transcription when captions are available — uncheck for speaker labels).
- Cancel button: AbortController plumbed through every provider SDK call;
  retryAPI short-circuits on AbortError; cancellation events surface in
  the activity log instead of silent retries.
- Long-video analysis: auto-coalesce transcript entries before building the
  analysis prompt so local-model context windows (32k-ish) don't overflow.
  Original entries preserved for transcript display via an index map; the
  analyzer sees a coarser view but click-to-seek timestamps stay precise.
- StartOS action grouping (Setup / AI Providers) so the actions list is
  navigable.
- Manifest description rewritten to reflect multi-provider support and
  free-tier relay credits.
- Smaller fixes: summarize-button enablement no longer requires a Gemini
  key when other providers are configured; analysis fallback chain handles
  context-length and 503 capacity errors; single-segment expansion for
  providers that don't return per-segment timestamps (Parakeet et al.);
  many other UX polish items.
2026-05-11 23:46:20 -05:00
Keysat 4c3cb6a077 Module split: extract audio I/O helpers to server/audio.js
• getAudioDuration(path)         — ffprobe wrapper, returns seconds | null
  • splitAudioFile(in, dir, secs)  — ffmpeg -acodec copy chunking
  • downloadPodcastAudio(url, dst) — streams HTTP audio to disk

Also moved fetchUrl into util.js (alongside the other stateless
helpers) — it's a generic HTTP-GET-with-redirects used by RSS parsing
and channel discovery, not strictly audio.

server/index.js: 2758 → 2694 lines.

Smoke tested: server boots; /api/license-status, /api/health, /
respond. No behavior change.
2026-05-08 16:53:06 -05:00
Keysat ffc8c31130 Module split: extract pure helpers to server/util.js
First step of breaking up the 2914-line server/index.js. Pulled out the
zero-state, no-side-effects helpers:

  • sendEvent(res, event, data)         — writes one SSE frame
  • extractVideoId(url)                 — YouTube URL → 11-char id
  • formatTime(seconds)                 — seconds → 'M:SS' or 'H:MM:SS'
  • parseTimestampedTranscript(text)    — Gemini transcript text → entries[]
  • safeText(result)                    — robust .text getter for Gemini responses
  • retryGemini(fn, opts)               — 503/429/network retry with linear backoff

server/index.js: 2914 → 2828 lines.
server/util.js : new, 113 lines.

Smoke tested: server boots, /api/license-status responds. No behavior
change.
2026-05-08 16:48:40 -05:00