From 45b2272f1aaf16bd8a2158411ba81ea7b91c7d91 Mon Sep 17 00:00:00 2001 From: mboehmlaender Date: Mon, 16 Mar 2026 09:13:54 +0000 Subject: [PATCH] 0.10.2-8 Layout --- backend/package-lock.json | 4 +- backend/package.json | 2 +- backend/src/services/pipelineService.js | 19 +++++++ frontend/package-lock.json | 4 +- frontend/package.json | 2 +- .../src/components/AudiobookConfigPanel.jsx | 29 ++++++++++- frontend/src/pages/DashboardPage.jsx | 24 +++++---- frontend/src/styles/app.css | 51 ++++++++++++++++++- package-lock.json | 4 +- package.json | 2 +- 10 files changed, 121 insertions(+), 20 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 5f93a3c..958e829 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1,12 +1,12 @@ { "name": "ripster-backend", - "version": "0.10.2-7", + "version": "0.10.2-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ripster-backend", - "version": "0.10.2-7", + "version": "0.10.2-8", "dependencies": { "archiver": "^7.0.1", "cors": "^2.8.5", diff --git a/backend/package.json b/backend/package.json index b3dfc43..1a741f0 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,6 +1,6 @@ { "name": "ripster-backend", - "version": "0.10.2-7", + "version": "0.10.2-8", "private": true, "type": "commonjs", "scripts": { diff --git a/backend/src/services/pipelineService.js b/backend/src/services/pipelineService.js index 83594d0..c9bb8f8 100644 --- a/backend/src/services/pipelineService.js +++ b/backend/src/services/pipelineService.js @@ -11562,6 +11562,7 @@ class PipelineService extends EventEmitter { { contextPatch: { outputPath: incompleteOutputPath, + completedChapterCount: index, currentChapter: { index: index + 1, total: outputFiles.length, @@ -11618,6 +11619,24 @@ class PipelineService extends EventEmitter { chapterTitle, outputPath: entry.outputPath }); + + await this.updateProgress( + 'ENCODING', + endPercent, + null, + `Audiobook-Encoding Kapitel ${index + 1}/${outputFiles.length} abgeschlossen`, + jobId, + { + contextPatch: { + completedChapterCount: index + 1, + currentChapter: { + index: index + 1, + total: outputFiles.length, + title: chapterTitle + } + } + } + ); } ffmpegRunInfo = { diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0fa20fb..016bacf 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "ripster-frontend", - "version": "0.10.2-7", + "version": "0.10.2-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "ripster-frontend", - "version": "0.10.2-7", + "version": "0.10.2-8", "dependencies": { "primeicons": "^7.0.0", "primereact": "^10.9.2", diff --git a/frontend/package.json b/frontend/package.json index 5989d71..5754c45 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "ripster-frontend", - "version": "0.10.2-7", + "version": "0.10.2-8", "private": true, "type": "module", "scripts": { diff --git a/frontend/src/components/AudiobookConfigPanel.jsx b/frontend/src/components/AudiobookConfigPanel.jsx index eb28ad7..59b345d 100644 --- a/frontend/src/components/AudiobookConfigPanel.jsx +++ b/frontend/src/components/AudiobookConfigPanel.jsx @@ -158,8 +158,13 @@ export default function AudiobookConfigPanel({ const schema = AUDIOBOOK_FORMAT_SCHEMAS[format] || AUDIOBOOK_FORMAT_SCHEMAS.mp3; const canStart = Boolean(jobId) && (state === 'READY_TO_START' || state === 'ERROR' || state === 'CANCELLED'); const isRunning = state === 'ENCODING'; + const isFinished = state === 'FINISHED'; const progress = Number.isFinite(Number(pipeline?.progress)) ? Math.max(0, Math.min(100, Number(pipeline.progress))) : 0; const outputPath = String(context?.outputPath || '').trim() || null; + const isSplitOutput = format === 'mp3' || format === 'flac'; + const currentChapter = context?.currentChapter && typeof context.currentChapter === 'object' ? context.currentChapter : null; + const completedChapterCount = Number(context?.completedChapterCount ?? -1); + const chapterTotal = Number(currentChapter?.total || editableChapters.length || 0); const statusLabel = getStatusLabel(state); const statusSeverity = getStatusSeverity(state); const description = String(metadata?.description || '').trim(); @@ -290,7 +295,29 @@ export default function AudiobookConfigPanel({ {isRunning ? (
- {Math.round(progress)}% + {Math.round(progress)}%{currentChapter ? ` | Kapitel ${currentChapter.index}/${currentChapter.total}: ${currentChapter.title}` : ''} +
+ ) : null} + + {isSplitOutput && (isRunning || isFinished) && editableChapters.length > 0 ? ( +
+ Kapitel-Status ({completedChapterCount >= 0 ? completedChapterCount : (isFinished ? editableChapters.length : 0)}/{chapterTotal || editableChapters.length} fertig) +
+ {editableChapters.map((chapter, idx) => { + const chIdx = chapter.index || idx + 1; + const isDone = isFinished || (completedChapterCount >= 0 && chIdx <= completedChapterCount); + const isActive = !isDone && currentChapter?.index === chIdx; + const statusIcon = isDone ? 'pi pi-check-circle' : isActive ? 'pi pi-spin pi-spinner' : 'pi pi-circle'; + const statusClass = isDone ? 'chapter-status-done' : isActive ? 'chapter-status-active' : 'chapter-status-pending'; + return ( +
+ + #{String(chIdx).padStart(2, '0')} + {chapter.title} +
+ ); + })} +
) : null} diff --git a/frontend/src/pages/DashboardPage.jsx b/frontend/src/pages/DashboardPage.jsx index 3085dae..59bce91 100644 --- a/frontend/src/pages/DashboardPage.jsx +++ b/frontend/src/pages/DashboardPage.jsx @@ -866,6 +866,7 @@ export default function DashboardPage({ const [insertWaitSeconds, setInsertWaitSeconds] = useState(30); const toastRef = useRef(null); const audiobookFileUploadRef = useRef(null); + const [audiobookUploadStatusVisible, setAudiobookUploadStatusVisible] = useState(false); const state = String(pipeline?.state || 'IDLE').trim().toUpperCase(); const currentPipelineJobId = normalizeJobId(pipeline?.activeJobId || pipeline?.context?.jobId); @@ -1123,6 +1124,19 @@ export default function DashboardPage({ setExpandedJobId(normalizeJobId(dashboardJobs[0]?.id)); }, [dashboardJobs, expandedJobId, currentPipelineJobId]); + useEffect(() => { + if (audiobookUploadPhase === 'idle') { + setAudiobookUploadStatusVisible(false); + return undefined; + } + setAudiobookUploadStatusVisible(true); + if (audiobookUploadPhase === 'completed') { + const timer = setTimeout(() => setAudiobookUploadStatusVisible(false), 5000); + return () => clearTimeout(timer); + } + return undefined; + }, [audiobookUploadPhase]); + useEffect(() => { if (!currentPipelineJobId || !isProcessing) { setLiveJobLog(''); @@ -2531,14 +2545,6 @@ export default function DashboardPage({ {file.name} {options.formatSize} -