Repository navigation
Conversation
Expand the UI from a compact 480px recorder into a 900px workspace with sidebar navigation, a video library page for browsing past recordings, and tabbed settings. Layout: routes moved into (app) group so the sidebar renders on all pages except the floating widget window. StatusBar shows sidecar health, active voice, and output directory. Library: new Rust module (library.rs) with list_recordings, generate_thumbnail, delete_recording, open_in_system, reveal_in_finder commands. Frontend lazy-loads thumbnails via IntersectionObserver. Drive upload per recording. Output dir resolves with fallback to system default (mirrors pipeline behavior). Meta tracking: pipeline.rs writes .meta.json sidecar alongside each MP4 on completion. google_drive.rs updates it with drive_url after upload. Library reads meta for voice profile and Drive status display. Settings: reorganized into Voice / Recording / Cloud tabs.
Shows the Text-to-Speech / Voice Conversion selector directly below the provider toggle when Local is selected, before the voice dropdown.
The preview page was always displaying the ElevenLabs selectedVoice name in the Replace Voice hint, even when using the local TTS provider. Now fetches local voice profiles on mount and shows the correct name.
If the user has an unsaved recording and navigates to Library or Settings via the sidebar, the record page now redirects back to /preview on mount instead of showing a fresh recording screen. The recording is preserved until explicitly saved or discarded.
The API key section was conditionally hidden when provider was set to 'local', making it impossible to view or manage the key. Now always visible on the Cloud tab regardless of active provider.
Both voice collections were hidden behind the provider conditional — only the active provider's voices were visible. Now both sections always render with clear "Local Voices" and "ElevenLabs Voices" headings. Local voices load on mount regardless of active provider.
Security: - Path validation on open_in_system and reveal_in_finder (match delete pattern) - Remove Linux fallback code and /tmp paths (macOS-only app) Data integrity: - Pipeline resolves local voice name from sidecar before writing meta.json (stores "MJ" not "4ad88b19-3bfe-493d-8xxx") - Settings saves config on addVoice/removeVoice/setDefault (lost with back button removal) - google_drive.rs meta update uses proper match/log instead of .ok() Reactivity: - $derived(() => ...) → $derived.by() in 4 components (RecordingCard, StatusBar, library page) - RecordingCard updates meta through libraryState.updateRecordingMeta() instead of mutating props - Library page awaits load before clearing stale flag Error handling: - RecordingCard shows error messages on delete/upload failure - All onclick handlers wrapped in try/catch (open, reveal, delete, upload) - Empty catch in preview voice name resolution now logs via logger - StatusBar sidecar poll logs failures via logger.debug - All console.* switched to logger with [VO:tag] prefix Tests: - 21 new frontend tests for library.svelte.ts (sorting, loading, deletion, meta updates, error states) - New Rust test for local provider meta (verifies name not UUID) - Coverage: 45% → 59% statements, 38% → 52% branches (all thresholds met)
…safety Settings persistence (#1): - Add onblur save to output_dir, API key, Drive client_id, and client_secret inputs. These lost their save trigger when saveAndBack() was removed. Pipeline output dir: - Pipeline now uses shared resolve_output_dir() instead of its own fallback that wrote to CWD when config was empty. resolve_output_dir replaced .expect() with graceful fallback to avoid panics. StatusBar voice name (#2): - Resolves local voice profile ID to human-readable name on mount. Meta.json type consistency (#3): - createdAt now written as u64 number, not string. Matches uploadedAt. Sidebar active state (#4): - /create-voice now highlights Settings in sidebar. Error feedback (#5, #7): - handleOpen/handleReveal set errorMessage on failure. - Library load shows user-friendly error with logger call.
serde's default only applies to missing fields, not empty strings. get_config now resets empty output_dir to ~/Movies/VoiceOver so the settings UI and pipeline always have a valid path.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (20)
📝 WalkthroughSummary by CodeRabbitRelease Notes
WalkthroughThis PR adds a comprehensive recording library system to the application. A new Rust Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Frontend
participant Backend as Backend<br/>(Tauri)
participant FS as File System
participant FFmpeg
participant Drive as Google Drive
User->>Frontend: Open Library Page
Frontend->>Backend: list_recordings()
Backend->>FS: Scan output_dir for .mp4 files
Backend->>FS: Read .meta.json companion files
Backend->>FS: Check .thumbnails/ cache
Backend-->>Frontend: RecordingInfo[] with metadata
Frontend->>User: Display recordings list
User->>Frontend: Scroll to recording
Frontend->>Frontend: IntersectionObserver triggers
alt Thumbnail not cached
Frontend->>Backend: generate_thumbnail(file_path)
Backend->>FFmpeg: Extract frame at 00:00:01
FFmpeg->>FS: Write .jpg to .thumbnails/
Backend-->>Frontend: Thumbnail path
else Thumbnail cached
Frontend->>Frontend: Use cached path
end
Frontend->>User: Display thumbnail
User->>Frontend: Upload to Drive
Frontend->>Drive: OAuth token refresh
Frontend->>Backend: Invoke Drive upload pipeline
Backend->>Drive: POST file
Drive-->>Backend: share_link
Backend->>FS: Write/update .meta.json with driveUrl
Backend-->>Frontend: Upload complete
Frontend->>User: Show Drive link
sequenceDiagram
participant Startup
participant Config as Config<br/>Module
participant FS as File System
participant Keychain
participant Backend as Lib.rs<br/>(Handler Reg.)
Startup->>Config: get_config()
Config->>FS: Load AppConfig from JSON
Config->>Keychain: Overlay keychain secrets
Config->>Config: Validate output_dir
alt output_dir empty or missing
Config->>Config: Use default_output_dir()
Config->>Config: Emit info log
end
Config-->>Backend: AppConfig (validated)
Backend->>Backend: Register library handlers<br/>(list_recordings, etc.)
Backend-->>Startup: Application ready
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
✨ Simplify code
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Summary
.meta.jsonsidecar written alongside each MP4 with voice profile name, provider, and Drive URL.Security & reliability
resolve_output_dir()— empty/missing config always falls back to~/Movies/VoiceOver, never CWDresolve_output_dirnever panics, never returns empty or relative pathsget_configresets emptyoutput_dirto default before reaching frontendlogger.tswith[VO:tag]prefix$derived.by()used correctly throughout (not$derived(() => ...))Test plan
pnpm check— 0 errorscargo clippy— 0 warnings