openreader/src/types/tts.ts
Richard R cb9ca37500 refactor(epub): unify TTS segment planning with canonical windowing
Consolidate EPUB TTS segment planning around a single canonical windowing model.
Introduce `epub-canonical-window.ts` to provide stable, viewport-independent
segment windows for both playback and sidebar. Refactor segment planning,
prefetching, and playback handoff to use canonical ordinals and keys, ensuring
that segments straddling page breaks are uniquely identified and never replayed
across pages. Update TTSContext, SegmentsSidebar, and related hooks to support
windowed canonical segments and precise ordinal continuity. Extend types and
interfaces to carry canonical segment metadata and windowing context.

Add comprehensive unit tests for canonical window selection, segment
materialization, and cache behavior.

BREAKING CHANGE: EPUB TTS segment planning, playback, and sidebar now rely on
canonical windowing, affecting segment key generation and playback logic.
2026-06-08 18:35:18 -06:00

70 lines
2.1 KiB
TypeScript

import type { CanonicalTtsSegment } from '@/lib/shared/tts-segment-plan';
export type {
TTSAudioBuffer,
TTSAudioBytes,
TTSSentenceAlignment,
TTSSentenceWord,
} from '@openreader/compute-core/types';
export type TTSLocation = string | number;
// Core playback state exposed by the TTS context
export interface TTSPlaybackState {
isPlaying: boolean;
isProcessing: boolean;
currentSentence: string;
currentSegment?: CanonicalTtsSegment | null;
currDocPage: TTSLocation;
currDocPageNumber: number;
currDocPages?: number;
}
// Estimate for when a visual page/section turn should occur during audio playback
export interface TTSPageTurnEstimate {
location: TTSLocation;
sentenceIndex: number;
fraction: number;
}
interface EpubRenderedLocationWalkItem {
/** Page-start CFI from the rendition — best-effort jump hint only. */
cfi: string;
/** Plain text content of the rendered page chunk. */
text: string;
/** Spine item href the chunk belongs to (stable across viewports). */
spineHref: string;
/** Ordinal of the spine item within the book (stable across viewports). */
spineIndex: number;
/**
* Offset (in normalized character space) of this chunk's start inside the
* spine item's plain text. Stable across viewports.
*/
chunkOffset: number;
/**
* Canonical segments for this chunk, windowed from the chapter's canonical
* plan and attached after the raw walk. Present → prefetch uses
* viewport-independent segments with identical keys to playback; absent →
* preview-based fallback planning.
*/
segments?: CanonicalTtsSegment[];
}
export type EpubRenderedLocationWalker = (
startCfi: string,
depth: number,
signal: AbortSignal,
) => Promise<EpubRenderedLocationWalkItem[]>;
// Supported output formats for generated audiobooks
export type TTSAudiobookFormat = 'mp3' | 'm4b';
// Metadata for an audiobook chapter
export interface TTSAudiobookChapter {
index: number;
title: string;
duration?: number;
status: 'pending' | 'generating' | 'completed' | 'error';
bookId?: string;
format?: TTSAudiobookFormat;
}