0d8b2f9167a03e280569aafeaab7e9409642bb65
3 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
17de9357dd |
feat(reader): redesign the TTS control as a mini player with an expandable player sheet (#4996)
* feat(reader): add formatCountdown helper for TTS timer chips Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): extract shared TTS playback info hook Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): add TTS scrubber with buffer-ahead fill Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): add TTS speed preset chips Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): add persistent TTS mini player Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): add full TTS player sheet with voice and timer sub-views Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test(reader): cover player sheet view reset on reopen Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): replace TTS icon and popup with mini player and player sheet Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): reserve mini player clearance and retire showTTSBar setting Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: retire shipped TTS follow-ups from TODOS Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore(i18n): translate the TTS player strings Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(reader): pin mini player transport LTR and unmount the closed player sheet Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(reader): collapse sheet speed, voice, and timer controls into one row Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): stabilize timeline estimates with cumulative voice calibration Replace the per-sentence EMA with the cumulative ratio of all measured chars to all measured seconds per voice, so the estimated remainder converges instead of re-pricing on every quirky sentence. Legacy stored calibrations migrate as a small prior. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(reader): hide the mini player while the player sheet is open Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tts): clear stale highlights across sections and stop sentence flash in word mode Entering a section now scrubs the TTS highlight from every live view, not just the primary, so the outgoing section's last word no longer stays lit in the preloaded neighbor. reapplyCurrentHighlight no longer redraws the whole sentence during word-mode playback while awaiting the first word boundary. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * style(reader): move the mini player progress line to the bottom edge Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(reader): make the TTS progress bar and scrubber legible in eink mode Grey tints wash out on e-ink: the mini player track gets a 1px hairline with a solid base-content fill (buffer fill hidden), and the sheet scrubber gets a crisp 1px border marking the track extent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * style(reader): drop the player sheet header label on the main view Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
e08622b416 |
feat(sync): route library sync exclusively to the selected cloud provider (#4380) (#4975)
While WebDAV or Google Drive is the selected cloud sync backend, the native Readest Cloud book/progress/note channels are gated off and the file-sync engine owns library data end to end: - isSyncCategoryEnabled returns false for book/progress/note (and their legacy aliases) when a third-party provider is selected. A runtime override, deliberately not written into syncCategories: the user's own toggles persist and take effect again on switch-back. Account channels (settings, stats, dictionaries, fonts, textures, OPDS catalogs) always stay native. - persistActiveCloudProvider is the single write path for provider switching, used by the chooser, both connect/disconnect flows, and the Drive OAuth callback (which previously bypassed the cross-window broadcast). The broadcast carries ONLY the enabled flags plus providerSelectedAt, never credentials or sync cursors, and only on switch events, so a stale window's routine save cannot revert a switch. - buildWebDAVConnectSettings no longer pre-sets enabled: activation belongs to withActiveCloudProvider, so the fresh-connect path now gets the syncBooks auto-flip and the providerSelectedAt stamp. - Sync health: fileSyncStore records lastError per backend; the durable lastSyncedAt stays in provider settings. The SettingsMenu sync row reads Synced via provider / Sync failed and its tap (with pull to refresh and BackupWindow, all routed through pullLibrary) runs the file engine via the shared runActiveFileLibrarySync helper instead of a gated native pull that would toast undefined book(s) synced. - Mixed-fleet detection: while gated, the auto-sync interval runs a read-only probe of /api/sync since providerSelectedAt; any newer book row means another device still syncs natively, and a once-per-session notice explains the fork instead of leaving it silent. - Readest-Cloud-only affordances hide while a third-party provider is selected: the quota row becomes a caption naming the active provider, Auto Upload disappears from the menu and command palette, the BookItem upload badge and the Transfer Queue Upload All button hide. - providerSelectedAt added to both provider settings types and the backup blacklist. Stacked on the quota-decoupling change for #4959; requires the metadata-parity change so gated channels lose nothing users can see. Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |
||
|
|
42f9b8fe3c |
feat(tts): gapless Web Audio playback engine for Edge TTS with chapter timeline and seek (#4931)
* feat(tts): add PCM speech-bounds detection for sentence audio trimming Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): add WSOLA time-stretch for pitch-preserved playback rate Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): add sentence duration store with per-voice speaking-rate calibration Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(tts): serve edge audio as ArrayBuffer with in-flight fetch dedup Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): add WebAudioPlayer with gapless chunk scheduling and backpressure Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): play edge TTS through gapless Web Audio pipeline Replaces the per-sentence audio element with trimmed, time-stretched buffers scheduled on the shared AudioContext. Marks dispatch at audible time so schedule-ahead cannot run foliate's cursor past the voice; a decode failure or missing audio skips the chunk instead of wedging the session; pause and resume ride context suspend and resume with no iOS rewind hack; the object-URL cache is gone. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): add section timeline with measured and estimated sentence durations Includes the foliate-js submodule bump for the getSentences export (fork branch feat/tts-get-sentences; fork PR must merge before this lands so the pinned SHA resolves). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): expose section playback position and sentence-snapped seeking Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): surface playback position and seek in the media session Position state is clamped, never skipped, so the lock-screen scrubber stays live when estimates overshoot; seekto units map per backend (native ms, web seconds). The AudioContext warms up in the tts-speak gesture path before any await, and the silent keep-alive element now runs on all platforms so desktop hardware media keys survive the removal of the per-sentence audio element. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): add seekable chapter progress bar to the TTS panel The scrubber joins the transport cluster with a thin range-xs track and flanking tabular time labels so it cannot be misgrabbed for the chunky rate slider (which persists a global setting). States: reserved disabled slot until the lazy timeline lands, persists across chapter transitions, optimistic thumb with failure toast, monotonic position, tilde-prefixed estimated totals, sentence-event updates under e-ink. The popup grows only when a timeline-capable client is active. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: record deferred TTS listening-engine follow-ups Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: record background TTS decoupling design decisions Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * feat(tts): slim the panel scrubber to a native track with remaining time Match the footer Jump to Location slider (plain native range: thin track, small thumb) instead of the chunky daisyUI pill, show remaining time with a minus prefix on the right, and drop the This chapter caption. Popup height shrinks accordingly. Verified live in Chrome. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: pin foliate-js to merged main with getSentences export Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(tts): catch autoplay rejection from the keep-alive element Running the silent keep-alive on all platforms exposed an un-awaited play() that headless Chromium rejects without a user gesture, failing CI on unhandled rejections while every test passed. The keep-alive is best-effort; the production path is gesture-qualified. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com> |