@@ -681,11 +838,11 @@ export function AudiobookExportModal({
)}
{chapters.length === 0 && !isGenerating && !isLoadingExisting && (
-
+
- Generation will use current TTS playback options.
-
- Individual chapters will appear here as they are generated.
+ Audiobook settings are fixed after generation. Chapters will appear here as they are ready.
+
+ You can close this dialog while the audiobook is being generated. But returning to the home screen will cancel the generation.
)}
diff --git a/src/components/DocumentSettings.tsx b/src/components/DocumentSettings.tsx
index 515d300..3434417 100644
--- a/src/components/DocumentSettings.tsx
+++ b/src/components/DocumentSettings.tsx
@@ -8,7 +8,8 @@ import { useEPUB } from '@/contexts/EPUBContext';
import { usePDF } from '@/contexts/PDFContext';
import { AudiobookExportModal } from '@/components/AudiobookExportModal';
import { useParams } from 'next/navigation';
-import type { TTSAudiobookChapter, TTSAudiobookFormat } from '@/types/tts';
+import type { TTSAudiobookChapter } from '@/types/tts';
+import type { AudiobookGenerationSettings } from '@/types/client';
const isDev = process.env.NEXT_PUBLIC_NODE_ENV !== 'production' || process.env.NODE_ENV == null;
@@ -82,25 +83,25 @@ export function DocumentSettings({ isOpen, setIsOpen, epub, html }: {
onProgress: (progress: number) => void,
signal: AbortSignal,
onChapterComplete: (chapter: TTSAudiobookChapter) => void,
- format: TTSAudiobookFormat
+ settings: AudiobookGenerationSettings
) => {
if (epub) {
- return createEPUBAudioBook(onProgress, signal, onChapterComplete, id as string, format);
+ return createEPUBAudioBook(onProgress, signal, onChapterComplete, id as string, settings.format, settings);
} else {
- return createPDFAudioBook(onProgress, signal, onChapterComplete, id as string, format);
+ return createPDFAudioBook(onProgress, signal, onChapterComplete, id as string, settings.format, settings);
}
}, [epub, createEPUBAudioBook, createPDFAudioBook, id]);
const handleRegenerateChapter = useCallback(async (
chapterIndex: number,
bookId: string,
- format: TTSAudiobookFormat,
+ settings: AudiobookGenerationSettings,
signal: AbortSignal
) => {
if (epub) {
- return regenerateEPUBChapter(chapterIndex, bookId, format, signal);
+ return regenerateEPUBChapter(chapterIndex, bookId, settings.format, signal, settings);
} else {
- return regeneratePDFChapter(chapterIndex, bookId, format, signal);
+ return regeneratePDFChapter(chapterIndex, bookId, settings.format, signal, settings);
}
}, [epub, regenerateEPUBChapter, regeneratePDFChapter]);
diff --git a/src/components/Footer.tsx b/src/components/Footer.tsx
index f319e2e..904d843 100644
--- a/src/components/Footer.tsx
+++ b/src/components/Footer.tsx
@@ -91,6 +91,7 @@ export function Footer() {
-e API_BASE=http://kokoro-tts:8880/v1 \\
-p 3003:3003 \\
-v openreader_docstore:/app/docstore \\
+-v /path/to/your/library:/app/docstore/library:ro \\
ghcr.io/richardr1126/openreader-webui:latest`
}
diff --git a/src/components/ProgressCard.tsx b/src/components/ProgressCard.tsx
index 4f330d2..8bab973 100644
--- a/src/components/ProgressCard.tsx
+++ b/src/components/ProgressCard.tsx
@@ -2,7 +2,7 @@ interface ProgressCardProps {
progress: number;
estimatedTimeRemaining?: string;
onCancel: (e?: React.MouseEvent) => void;
- operationType?: 'sync' | 'load' | 'audiobook';
+ operationType?: 'sync' | 'load' | 'library' | 'audiobook';
cancelText?: string;
currentChapter?: string;
completedChapters?: number;
@@ -22,6 +22,7 @@ export function ProgressCard({
const getOperationLabel = () => {
if (operationType === 'sync') return 'Saving to Server';
if (operationType === 'load') return 'Loading from Server';
+ if (operationType === 'library') return 'Importing Library';
if (operationType === 'audiobook') return 'Generating Audiobook';
return null;
};
diff --git a/src/components/ProgressPopup.tsx b/src/components/ProgressPopup.tsx
index 7f37269..4e0c7db 100644
--- a/src/components/ProgressPopup.tsx
+++ b/src/components/ProgressPopup.tsx
@@ -8,7 +8,7 @@ interface ProgressPopupProps {
estimatedTimeRemaining?: string;
onCancel: () => void;
statusMessage?: string;
- operationType?: 'sync' | 'load' | 'audiobook';
+ operationType?: 'sync' | 'load' | 'library' | 'audiobook';
cancelText?: string;
onClick?: () => void;
currentChapter?: string;
@@ -65,4 +65,4 @@ export function ProgressPopup({
);
-}
\ No newline at end of file
+}
diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx
index ea5a770..cbbba06 100644
--- a/src/components/SettingsModal.tsx
+++ b/src/components/SettingsModal.tsx
@@ -22,7 +22,7 @@ import {
import { useTheme } from '@/contexts/ThemeContext';
import { useConfig } from '@/contexts/ConfigContext';
import { ChevronUpDownIcon, CheckIcon, SettingsIcon } from '@/components/icons/Icons';
-import { syncDocumentsToServer, loadDocumentsFromServer, getFirstVisit, setFirstVisit } from '@/lib/dexie';
+import { syncDocumentsToServer, loadDocumentsFromServer, importDocumentsFromLibrary, getFirstVisit, setFirstVisit } from '@/lib/dexie';
import { useDocuments } from '@/contexts/DocumentContext';
import { ConfirmDialog } from '@/components/ConfirmDialog';
import { ProgressPopup } from '@/components/ProgressPopup';
@@ -51,9 +51,10 @@ export function SettingsModal() {
const [localTTSInstructions, setLocalTTSInstructions] = useState(ttsInstructions);
const [isSyncing, setIsSyncing] = useState(false);
const [isLoading, setIsLoading] = useState(false);
+ const [isImportingLibrary, setIsImportingLibrary] = useState(false);
const [showProgress, setShowProgress] = useState(false);
const [statusMessage, setStatusMessage] = useState('');
- const [operationType, setOperationType] = useState<'sync' | 'load'>('sync');
+ const [operationType, setOperationType] = useState<'sync' | 'load' | 'library'>('sync');
const [abortController, setAbortController] = useState