Remove legacy TTS segment manifest and audio endpoints in favor of new presigned and fallback audio URL approach. Update segment manifest structure to include `audioPresignUrl` and `audioFallbackUrl` fields, deprecating the previous `audioUrl`. Refactor segment ensure logic and TTS context to utilize the new playback source model. Add server utilities for generating presigned S3 URLs and introduce new API routes for presign and fallback audio retrieval. Clean up obsolete client API functions and types to reflect the new manifest format.
Expand and clarify documentation for TTS segment storage, including key layout, cleanup, and CLI access in object storage. Add details on the `tts_segments` schema and migration process. Revise local development and Docker quick start guides with improved prerequisites, platform-specific setup instructions, and updated TTS provider references. Document new usage of `AUTH_SECRET` for TTS segment text fingerprinting.
Introduce TTS segment support with new database tables and migrations for both Postgres and SQLite. Implement segment ensure, audio, and manifest API endpoints, segment storage in S3, and segment authorization logic. Update TTS context and client API to use segment-based synthesis and retrieval. Add server-side helpers for segment ID, settings hash, locator normalization, and audio probing. Extend user data cleanup and teardown logic to remove TTS segment objects. Add unit tests for segment helpers.
BREAKING CHANGE: TTS synthesis now uses segment-based storage and APIs; database migrations required.
Document observed S3 `InternalError` regressions with SeaweedFS 4.19 in
object storage, local development, and Docker quick start guides. Clarify that
version 4.18 is pinned in CI and Docker builds for reliability while
compatibility is investigated.
Update CI workflow and Dockerfile to use chrislusf/seaweedfs:4.18 instead of
latest. This avoids upload regressions observed with version 4.19 and ensures
consistent builds.
Introduce pauseActiveHowl to centralize audio pause logic, ensuring consistent
cleanup and media session state updates. Update pause and togglePlay to use the
new helper, enabling accurate resume of paused audio and improved error
handling. Enhance Howl onpause event to synchronize playback state and clear
timeouts.
Move resolveVoices and resolveReplicateVoiceInputKey to a new server-side
voice-resolution module to improve separation of concerns and reduce shared
bundle size. Update all imports and related tests to use the new module.
Remove unused LRUMap and related caches from shared catalog. Update Replicate
cooldown logic to use per-scope LRU cache for improved concurrency handling.
Move getUpstreamStatus and getUpstreamRetryAfterSeconds to a shared utility
module for consistent upstream error handling across TTS endpoints. Strengthen
audiobook chapter API by introducing runtime validation for incoming settings
payloads, ensuring type safety and error reporting for malformed requests.
Replace in-memory Map caches with LRUMap for Replicate voice and schema
lookups, improving memory management and eviction logic.
Align default Replicate model to the versioned Kokoro model across UI, docs,
and server logic. Refactor TTS settings merging for audiobooks to ensure
consistent normalization. Improve Retry-After header handling for upstream
rate limits. Expand Replicate voice resolution to use model schemas when
available, with test coverage for custom and built-in models.
Update documentation to reflect new Replicate defaults, model selection,
and configuration guidance.
- Updated environment variables documentation to include Replicate as a TTS provider option.
- Added Replicate to the sidebar for TTS provider guides.
- Included Replicate as a dependency in package.json and pnpm-lock.yaml.
- Enhanced audiobook chapter generation to normalize native speed settings based on the TTS provider.
- Improved error handling in TTS API routes to provide retry information for rate-limited responses.
- Updated AudiobookExportModal to reflect native speed support for Replicate models.
- Modified SettingsModal to set default model for Replicate.
- Enhanced SpeedControl component to conditionally render native speed controls based on provider support.
- Updated TTSContext to utilize effective native speed for TTS requests.
- Implemented Replicate request handling in the TTS generation logic.
- Added new documentation for configuring Replicate as a TTS provider.
Add support for a persistent "custom" theme that users can edit and preview in settings.
- add CustomThemeColors type and storage helpers (getCustomThemeColors, setCustomThemeColors)
- apply custom CSS variables at runtime and provide applyCustomColors to live-update variables
- include fallback CSS for html.custom to avoid flash before hydration
- add ColorPicker component with curated swatches for each color role
- extend SettingsModal to support editing, previewing, and persisting custom theme colors; exclude 'custom' from regular theme lists and read custom colors when rendering previews
- tighten theme detection logic to treat custom background luminance as light/dark when needed
This enables users to define, persist, and see live updates for custom color palettes.
Centralized TTS provider/catalog and resolver utilities.
New audiobook generation pipeline with EPUB and PDF source adapters.
TTS settings view model and config-update helpers for synced preferences.
Improvements
Generalized TTS instruction support and provider/model-aware voice defaults.
Audiobook export delegated to pipeline for consistent progress, retry, and cancel handling.
UI test IDs added to privacy and migration modals.
Tests
New unit tests for TTS catalog and config helpers; export readiness and onboarding dismissal added to tests.
Chores
Package version bumped to 2.1.1.
Make voice-fetching more robust by always clearing the request timeout and stricter type-checking of remote data.
- move clearTimeout into finally blocks for Deepinfra and custom OpenAI voice fetches to guarantee the timeout is cleared on success, failure, or abort
- validate that custom endpoint returns an array of strings before accepting voices; otherwise fall back to defaults
This reduces potential timer leaks and avoids accepting malformed voice lists from custom endpoints.
Improve robustness across audiobook pipeline, TTS catalog, and preferences comparison.
- audiobooks: centralize abort creation with createAudiobookAbortError and replace repeated ad-hoc throws with it; avoid reprocessing non-completed chapters when collecting existing indices; update progress accounting by advancing processedLength and emitting onProgress after saving a chapter.
- tts: add a 10s AbortController timeout when fetching custom OpenAI voices, wire the signal to fetch, and ensure the timeout is cleared on success or failure; fall back cleanly when endpoint doesn't support voices.
- config: harden deepEqual by checking mismatched array vs object shapes early to avoid incorrect comparisons.
No user-visible behavior changes besides improved cancellation, progress reporting, and more resilient remote voice discovery.
Refactor test helpers to reliably dismiss onboarding and migration modals during
UI flows. Replace ad-hoc Settings-only dismissal with a unified dismissOnboardingModals
routine that targets privacy, migration, and settings dialogs via testids,
interacts with visible controls (checkbox, continue/skip/save buttons) and waits
for dialogs to hide. Increase resilience by repeating checks, adding short
settle delays, and tightening timeouts.
Also add data-testid attributes to PrivacyModal, SettingsModal and
DexieMigrationModal to make the selectors deterministic and reduce flakiness in
export/upload tests.
No production behavior changes.
- Move TTS provider resolution and voice-fetch logic into shared catalog and make
remote fetches more resilient (timeouts, abort handling, baseUrl normalization,
treat explicit empty custom-openai responses as valid).
- Add continuation guard to TTS feature set and update API voices endpoint error
logging to better surface auth/session failures.
- Extract and stabilize ebook pipeline and epub adapter:
- Cache prepared EPUB chapters to avoid repeated parsing and handle missing/empty
chapter titles safely.
- Fail early when created chapter lacks a bookId.
- Improve config/preferences handling:
- Replace JSON stringify comparisons with a deepEqual utility to compare defaults.
- Tighten ConfigContext effect dependencies and consolidate synced preference
queuing logic to include additional keys.
- Harden end-to-end test helpers and unit tests:
- Make settings dialog dismissal deterministic (use Enter/Escape and explicit
visibility/enabled checks) and simplify upload retry behavior.
- Add unit test to ensure custom-openai empty voice lists are preserved.
Why: Reduce runtime and test flakiness, centralize TTS logic for easier maintenance,
and make EPUB processing and preference diffing more robust. Breaking changes: none.
- Add waitForBackendDownloadReady helper to tests/export.spec.ts to wait for backend
chapter metadata and enabled full-download UI before attempting combines/downloads.
Use it in two export tests to reduce flakiness related to eventual backend storage visibility.
- Improve uploadAndDisplay helper in tests/helpers.ts to retry link click when transient
"intercepts pointer events" errors occur, ensuring test clicks succeed under flaky UI conditions.
Add dismissSettingsModalIfVisible to detect and close the Settings dialog before interacting
with page links (click Save or press Escape, wait for dialog to hide).
- Update SettingsModal.tsx useEffect dependencies to avoid referencing checkFirstVist in the
local state sync effect and add separate effect for checkFirstVist for clearer lifecycle.
Why: Reduce end-to-end test flakiness by waiting for backend readiness and making UI interactions
more robust; simplify SettingsModal effect dependencies to prevent unnecessary re-runs. Breaking changes: none.
- Introduce a shared tts-provider-catalog to centralize provider/model/voice defaults
and feature flags (supportsTtsInstructions, providerSupportsCustomModel, resolveProviderModels,
getDefaultVoices, etc.). Replace ad-hoc provider logic across server and client with catalog calls.
- Replace inline voice/model UI logic in SettingsModal, AudiobookExportModal, TTSContext,
generate server code, and voice hook to use catalog helpers (resolveTtsSettingsViewModel,
supportsTtsInstructions, getDefaultVoices).
- Extract audiobook generation responsibilities into a small client-side pipeline:
- Add createEpubAudiobookSourceAdapter and createPdfAudiobookSourceAdapter adapter modules
to prepare chapters from EPUB/PDF sources.
- Add runAudiobookGeneration and regenerateAudiobookChapter pipeline functions to handle
chapter preparation, progress tracking, request header construction, and retry/abort behavior.
- Wire adapters/pipeline into EPUBContext and PDFContext to simplify and centralize audiobook flow.
- Move config preference helpers out of ConfigContext into dedicated client modules:
- buildSyncedPreferencePatch (lib/client/config/preferences.ts)
- applyConfigUpdate and getVoicePreferenceKey (lib/client/config/updates.ts)
- Use these helpers in ConfigContext to keep update logic small and testable.
- Add TTS settings view model resolver (lib/client/settings/tts-settings.ts) and tests
for the tts-provider catalog and config helpers (tests/unit/tts-provider-catalog.spec.ts).
- Minor usages updated: AudiobookExportModal, SettingsModal, useVoiceManagement, TTSContext,
server tts generation, and various context files to consume the new modules.
Why: Reduce duplication, improve testability, and separate concerns for provider metadata,
UI view-model logic, and audiobook generation flow. Breaking changes: none.
Introduce safeguards for continuation handling in TTS flow to prevent looping and over-carrying text. Add constants to limit carried characters and words, and loop-guard thresholds. Implement normalizeBlockFingerprint to create compact fingerprints of page-first blocks and store them in pageFirstBlockFingerprintRef. Use fingerprint comparison and progress threshold to skip to next page when a loop is detected. Cap continuation slices by characters and words and ensure carried text matches the returned addition.
test(ui): make settings save button click more robust
In tests/helpers.ts wait for the Settings Save button to become visible (with a short timeout) before attempting to open Settings, and click the Settings button with force to avoid intermittent pointer-interception failures. Improve stability of setupTest by handling enter transitions and overlays.
Add a test to verify selected voice persists instead of resetting to default.
Also refactors export tests to be UI-driven rather than backend-dependent.
- Removed unused imports and types from TTS route.
- Consolidated TTS buffer generation logic into a new module.
- Implemented caching for TTS audio buffers using LRU cache.
- Updated TTS request handling to support instructions for specific models.
- Refactored audiobook chapter creation to use new TTS generation logic.
- Simplified error handling and response management in TTS API.
- Enhanced client-side logic to manage TTS requests and retries.
- Updated types to reflect changes in TTS request payload structure.
Add five new light theme options (lavender, rose, sand, sky, slate) with dedicated color palettes. Redesign Settings modal with sidebar navigation replacing tabs, add visual theme color selector showing preview swatches, and introduce new icons (KeyIcon, PaletteIcon, UserIcon, DocumentIcon). Also update PrivacyModal to render conditionally based on authEnabled and add privacy policy link. Update tests to reflect new UI structure.