Skip to content

Beta2main#186

Merged
mkdir700 merged 66 commits intomainfrom
beta2main
Sep 17, 2025
Merged

Beta2main#186
mkdir700 merged 66 commits intomainfrom
beta2main

Conversation

@mkdir700
Copy link
Owner

@mkdir700 mkdir700 commented Sep 17, 2025

Summary by CodeRabbit

  • New Features

    • FFmpeg management: in-app download/warmup, settings page, auto-detect, and prompt.
    • Smarter media info parsing with fallback strategies.
    • Startup intro with warmup progress.
    • Search overlay with live results.
    • Player: click-to-play/pause, fullscreen toggle (F key), error recovery (relocate/remove).
    • Subtitles: dictionary popover; playback-rate favorites and new shortcuts.
    • Windows ARM64 builds.
  • Improvements

    • UI polish (modal buttons, navbar padding, mac title bar), deterministic loading, better file selection.
  • Localization

    • Major updates across en, zh-CN/zh-TW, ja, ru for FFmpeg, playback, shortcuts.
  • Documentation

    • New FFmpeg Integration guide.
  • Bug Fixes

    • Robust file extension handling; reduced log noise.
  • Chores

    • License changed to AGPLv3.

Implement a clean semantic-release configuration using dedicated branches
for different release types:

- main: stable releases (v1.0.0)
- beta: beta prereleases (v1.0.0-beta.1)
- alpha: alpha prereleases (v1.0.0-alpha.1)

This replaces the complex environment variable approach with a simple
and reliable branch-based strategy that eliminates configuration errors
and makes the release process more predictable.

Resolves the issue where specified version numbers like v1.0.0-alpha.1
were being ignored in favor of package.json versions.
* fix(ci): resolve duplicate GitHub releases issue

- Remove duplicate release creation by electron-builder
- Let semantic-release handle single release creation with proper descriptions
- Configure semantic-release to upload artifacts from electron-builder
- Ensure single release with semantic description and electron artifacts

* feat(ci): optimize release workflow trigger options

- Limit manual force_version_type to dev/test only
- Auto-determine version type based on branch:
  - main branch → stable
  - beta branch → beta
  - alpha branch → alpha
- Fallback to version string detection for edge cases
- Improve workflow clarity and prevent manual errors
* refactor(ci): simplify release workflow by removing force version type

Remove force_version_type input parameter and related logic from release workflow.
Version type is now determined solely by branch name (main=stable, beta=beta, alpha=alpha).
This simplifies the workflow and removes the manual override option that was only intended for dev/test.

* fix(build): correct releaseName variable interpolation in electron-builder

Remove single quotes around releaseName to allow proper ${version} variable
interpolation. This fixes the issue where releaseName was showing literal
'EchoPlayer v${version}' instead of the actual version number.
- Replace custom labels with original artifact filenames for consistency
- Simplify asset configuration from object format to string format
- Remove platform-specific labels that obscured actual file names
- Update Windows portable archive pattern from *-win.zip to *.zip
- Remove macOS zip assets to match actual build output

This change ensures GitHub Release asset names match the actual filenames
generated by electron-builder, providing clearer identification of
downloadable artifacts without confusing custom labels.
- Add defaultValues object to centralize all configuration default values
- Replace inline default values in all getter methods with references to defaultValues
- Improve get() method to use defaultValues as fallback when defaultValue param is not provided
- Enhance maintainability and consistency of default value management
- Add alpha and beta branches to pull request triggers
- Ensures CI tests run on all main development branches
- Remove WatchedIndicator component and its associated CheckIcon
- Clean up unused styled-components for watched status display
- Simplify video thumbnail overlay by removing watch completion visual feedback
- Remove conditional rendering logic for watchProgress >= 1 state

This refactoring removes the green checkmark indicator that previously showed
on video thumbnails when watch progress reached 100%, streamlining the
video card interface and reducing visual complexity.
…tion (#97)

* refactor(db-migrate): Remove old db migrations dir

* fix: remove path unique constraint to allow duplicate video file addition

- Create database migration to remove UNIQUE constraint on files.path column
- Simplify FileManager.addFile() to directly add files without duplicate checks
- Update user feedback message to inform about duplicate file support
- Add test case for duplicate file addition functionality
- Update VideoAddButton test to use correct service method names

This resolves the issue where adding the same video file twice would fail
with a UNIQUE constraint violation. Users can now add the same video file
multiple times as separate records in the database.
* feat: replace FFmpeg with MediaInfo for video metadata extraction

- Add mediainfo.js WebAssembly support for lightweight video analysis
- Create MediaInfoService with intelligent duration format detection
- Update IPC channels and preload API for MediaInfo integration
- Implement fallback strategy: MediaInfo (preferred) -> FFmpeg (backup)
- Add comprehensive WASM file handling with vite-plugin-static-copy
- Update test cases to cover MediaInfo priority and fallback scenarios
- Improve duration parsing with smart milliseconds/seconds detection
- Reduce dependency size from ~100MB+ (FFmpeg) to ~3MB (MediaInfo WASM)
- Maintain full backward compatibility with existing FFmpegVideoInfo interface

Performance improvements:
- Faster video file processing with WebAssembly
- No external process spawning overhead
- Better error handling and detailed logging
- Streaming file reading for memory efficiency

This change addresses commercial licensing concerns with FFmpeg while
providing superior performance and maintainability.

* fix(build): resolve Windows build failure for MediaInfo WASM file

- Simplify vite-plugin-static-copy path configuration for cross-platform compatibility
- Add WASM files to electron-builder asarUnpack configuration
- Enhance MediaInfoService WASM file path resolution with multiple fallback paths
- Ensure MediaInfoModule.wasm is properly accessible at runtime on all platforms

Fixes issue where Windows CI builds failed with "No file was found to copy" error
for MediaInfoModule.wasm during vite-plugin-static-copy execution.
…test defaults (#98)

- Fix AppUpdater to respect specified channel instead of forcing LATEST channel
- Add dynamic test channel defaults based on application version (alpha/beta detection)
- Update ConfigManager with version-aware default configuration logic
- Enhance i18n translations for auto-update and test plan settings across languages

Changes:
- AppUpdater.ts: Remove hardcoded LATEST channel override, use specified channel
- ConfigManager.ts: Add getVersionBasedDefaults() for dynamic test configuration
- package.json: Version rollback for testing purposes
- i18n locales: Updated translations for auto-update and beta testing program

This fix ensures proper channel handling for alpha/beta releases and provides
appropriate default test settings based on the application version identifier
#99)

- Add useHoverMenu hook with configurable delays and event handling
- Integrate hover menu functionality across all control components (CaptionsButton, LoopControl, PauseControl, PlaybackRateControl, VolumeControl)
- Update CaptionsButton with internationalized UI text and improved accessibility
- Enhance FullscreenButton with proper i18n key paths
- Refactor control components to use ControlContainer for consistent layout
- Add comprehensive hover interaction patterns with 200ms open delay and 100ms close delay
- Maintain backward compatibility with existing click-to-toggle behavior
- Improve user experience with seamless hover-to-reveal menu functionality

Changes:
- Add useHoverMenu.ts: Generic hover menu hook with timeout management
- Update all control components to integrate hover menu behavior
- Reorganize i18n structure for better player control translations
- Enhance control styles for consistent hover menu presentation

This implementation provides a more intuitive user experience where users can
hover over control buttons to quickly access settings without requiring clicks,
while preserving the existing click behavior for primary actions.
#100)

* feat(player): implement favorite playback rates with hover menu system

- Add favorite rates database schema and migration with JSON storage
- Implement favorite rates selection in PlaybackSettings with multi-select
- Add PlaybackRateControl hover menu with favorite rate toggling (Ctrl+click)
- Integrate keyboard shortcuts (Shift+[ / Shift+]) for rate cycling
- Add comprehensive i18n support for selectedItems and favorite rates
- Extend player store with favorite rate management and persistence
- Update settings store with defaultFavoriteRates configuration

Database changes:
- Add favoriteRates column to playerSettings table (JSON array string)
- Add migration with proper rollback for SQLite compatibility
- Update schemas with JsonStringSchema validation

UI improvements:
- Visual indicators for favorite rates (warning color theme)
- Context menu and keyboard shortcuts for rate management
- Multi-select dropdown for settings configuration
- Hover menu system integration with existing controls

State management:
- Add favorite rate cycling logic with index tracking
- Persist favorite rates per video with global defaults fallback
- Integrate with existing player commands and shortcuts system

This implementation provides a complete favorite playback rates feature
allowing users to customize frequently used rates both globally and per-video,
with intuitive UI controls and keyboard shortcuts for efficient rate switching

* refactor(player): improve type safety and code maintainability

- Add explicit number type conversion for favoriteRates array elements in player store
- Refactor shortcut key mapping to use dynamic generation from key array
- Update PLAYBACK_RATE_PRESETS to explicit number[] type annotation
- Simplify PlayerSettingsSaver to use full state instead of manual slicing

Changes:
- player.store.ts: Wrap favoriteRates array access with Number() conversion to ensure type safety
- label.ts: Replace static shortcutKeyMap object with dynamic generation using reduce()
- playback.const.ts: Add explicit number[] type annotation for better type inference
- PlayerSettingsSaver.ts: Remove manual property selection in favor of full state casting

This refactoring improves type safety, reduces code duplication, and enhances
maintainability while preserving existing functionality. The dynamic key mapping
approach eliminates manual repetition and ensures consistency across i18n keys.
* feat(ui): enhance video selection clarity in library view

- Add currently playing indicator with visual feedback on video cards
- Implement blue border and shadow effects for active video
- Add subtitle information showing file directory and size
- Integrate with player session store to track current playing video
- Improve video differentiation for similar titles

Resolves user confusion when multiple similar videos exist in library

* fix: implement persistent current video tracking

- Add currentVideoId to settings store with persistence
- Replace temporary player session store usage with persistent tracking
- Update video selection to persist across page navigation
- Set currentVideoId both on player page load and video card click

Fixes issue where "currently playing" indicator disappears when
navigating back from player page to library view

* refactor: remove playing indicator overlay from video cards

- Remove text "正在播放" and play icon overlay from video thumbnails
- Keep blue border and shadow effects for selected video identification
- Simplify visual design while maintaining clear selection feedback
- Clean up unused styled components (CurrentPlayingIndicator, PlayingIcon, PlayingText)

* feat: remove current video display functionality

- Remove currentVideoId field from settings store
- Remove video selection highlighting and blue border effects
- Remove persistent current video tracking across navigation
- Clean up related code in HomePage and PlayerPage components
- Return to simple video library display without selection state

This simplifies the UI by removing the complexity of tracking and
displaying which video is currently selected/playing.
…ectly (#102)

- Add AppLifecycleService for proper resource cleanup on app exit
- Implement force pause state synchronization in VideoSurface
- Ensure video element and player engine state consistency
- Add autoPlay={false} attribute to prevent browser auto-play behavior
- Fix play/pause button icon state sync issue when re-entering video

Resolves issue where returning from homepage during playback would show
incorrect play button icon despite video being properly paused.

Changes:
- Add AppLifecycleService.ts for comprehensive resource management
- Enhance VideoSurface with multiple pause state enforcement points
- Update WindowService to notify renderer process on app quit
- Integrate lifecycle service in App.tsx and PlayerPage.tsx
- Remove mediainfo.js dependency and complex WASM handling
- Add @remotion/media-parser for lighter, more modern media parsing
- Replace MediaInfoService with MediaParserService
- Maintain API compatibility with existing FFmpegVideoInfo interface
- Remove WASM file copying from build configuration
- Update electron-builder to exclude unnecessary WASM patterns
- All tests pass and build succeeds with new implementation
…ptimization (#104)

* feat(startup): implement configurable startup intro with preloading optimization

- Add StartupLoadingState component with modern design and animations
- Add showStartupIntro setting to control startup intro visibility
- Implement HomePage data preloading during startup intro for better UX
- Add LoadingState component for HomePage initial loading state
- Refactor App.tsx with simplified state management and async data flow
- Extend video-list store with initialization tracking and data caching
- Add localization support for startup intro setting

Technical improvements:
- Replace deprecated SplashScreen with modern StartupLoadingState component
- Implement intelligent caching to avoid duplicate data loading
- Add proper loading states and initialization tracking
- Use stable useCallback references to prevent rendering loops
- Support reduced motion preferences for accessibility

This enhancement provides users with a polished startup experience while
optimizing data loading performance through strategic preloading and caching.

* chore: Reformat code
…ation (#105)

- Add useVolumeWheelControl hook for smooth volume adjustment via mouse wheel
- Integrate wheel control with existing hover menu system in VolumeControl component
- Implement intelligent acceleration based on scroll velocity and intensity
- Support configurable step sizes (min: 1%, default: 2%, max: 8%)
- Add comprehensive logging for debugging wheel control behavior
- Sync container refs between menu manager and wheel control systems
- Update volume icon logic to show mute state when volume is 0

Changes:
- VolumeControl.tsx: Integrate wheel control hook with hover menu system
- useVolumeWheelControl.ts: New hook with velocity-based smart acceleration
- Enhanced UX with immediate response and smooth volume transitions

This feature provides intuitive volume control when hovering over the volume
button, delivering a professional media player experience with fine-grained
control and intelligent acceleration for both precise and rapid adjustments.
…ll management (#106)

- Replace scattered state management with centralized state machine approach
- Add comprehensive state machine with 4 clear states: DISABLED, LOCKED_TO_CURRENT, USER_BROWSING, TRANSITIONING
- Implement 6 event triggers for predictable state transitions
- Remove complex manual scroll logic with 100+ lines of imperative code
- Simplify SubtitleListPanel component by extracting scroll behavior to dedicated hook
- Add intelligent timer management with 3-second auto-return to current subtitle
- Improve maintainability with clear separation of concerns and type safety

Changes:
- Add useSubtitleScrollStateMachine: Complete state machine implementation with transition rules
- Refactor SubtitleListPanel: Remove userScrolled, showBackToCurrent, and complex scroll logic
- Remove BackToCurrentWrapper: Temporarily simplified UI (can be re-added with state machine integration)
- Add SCROLL_CONFIG: Centralized configuration for timing and behavior parameters
- Replace imperative scroll handling with declarative state transitions

This refactor transforms complex, bug-prone scroll management into a predictable,
maintainable state machine that follows YouTube-like interaction patterns and
provides clear mental model for subtitle list behavior.
…views (#108)

- Add base_branches configuration to auto-review PRs targeting alpha, beta, and main branches
- Enable assertive review profile for detailed feedback
- Configure code quality tools (ESLint, Ruff, Gitleaks, Hadolint)
- Include code guidelines from .cursorrules files
- Maintain existing filters for WIP and draft PRs
…endencies (#109)

- Remove useTranslation dependency from SubtitleContent component
- Replace internationalized empty state messages with fixed '--Empty--' text
- Remove unnecessary aria attributes and CSS color variables for consistency
- Optimize SubtitleOverlay double-click expansion logic with centered positioning
- Simplify positioning calculation for better maintainability

Changes improve subtitle display consistency and fix positioning behavior
during double-click expansion interactions
…hlighting (#110)

- Add VideoSearchService with fuzzy matching and relevance scoring
- Create VideoSearchResult component with thumbnail, progress, and text highlighting
- Implement live search with 300ms debounce and loading states
- Add comprehensive i18n support for search UI text
- Enhance SearchOverlay with unified design and scrollable results
- Move SearchOverlay from App to Router for proper global positioning
- Update search.store with results state and async operation support

Features:
- Real-time search across video titles and subtitles
- Keyword highlighting with styled matches
- Relevance-based sorting with title priority and recency fallback
- Responsive design with hover states and smooth transitions
- Progress bar integration for partially watched videos
- Click-to-play navigation with search overlay auto-hide

This implementation provides a complete video search experience with
intelligent matching, visual feedback, and seamless navigation flow.
* fix(subtitle): improve ASS subtitle parsing for bilingual text

- Fix stripAssTags method to properly handle complex ASS style markers like {\3c&HFF8000&\fnKaiTi}{\an8}
- Add support for \h (hard space) and \n (lowercase newline) ASS markers
- Adjust script priority in splitBilingualText to correctly identify English as original text and Chinese as translated text
- Improve bilingual text splitting logic to handle ASS \N line breaks properly
- All existing tests pass, ensuring backward compatibility

Fixes the issue where ASS subtitle style markers were not properly stripped and original/translated text were incorrectly assigned.

* fix(subtitle): handle partially processed ASS style markers from subsrt library

- Add regex patterns to handle ASS style markers that are missing opening braces like \3c&HFF8000&\fnKaiTi}
- Fix issue where subsrt library partially processes ASS content but leaves style marker remnants
- Add comprehensive regex to clean up various ASS marker patterns:
  - Complete markers: {\3c&HFF8000&\fnKaiTi}
  - Partial markers: \3c&HFF8000&\fnKaiTi}
  - Orphaned markers: \fnKaiTi without closing brace
- All tests pass, ensuring backward compatibility

This fixes the remaining ASS subtitle display issue where style markers were still visible in the UI.

* test(subtitle): add comprehensive tests for ASS subtitle parsing fixes

- Add regression tests for ASS style marker cleaning issues
- Test partial ASS style markers left by subsrt library (\3c&HFF8000&\fnKaiTi})
- Test complete ASS style markers ({\3c&HFF8000&\fnKaiTi})
- Test script detection for bilingual text parsing
- Test format detection for ASS files
- Test error handling for empty files and read failures
- Ensure 449 tests pass including 7 new ASS parsing tests

These tests prevent regressions of the issues encountered with Forrest Gump ASS subtitles where style markers were not properly cleaned from displayed text.
* feat(player): implement comprehensive video error recovery with file relocation

- Add VideoErrorRecovery modal component with smart error categorization and recovery options
- Implement file existence checking via new IPC bridge (fs.checkFileExists)
- Enhance VideoSurface error handling with detailed error type detection (file-missing, unsupported-format, decode-error, network-error)
- Add file relocation workflow allowing users to reselect missing video files
- Add remove from library option for permanently unavailable videos
- Implement modal with forced interaction (no dismiss) to ensure user handles critical errors
- Improve dangerous button styling consistency across light/dark themes

Changes:
- Add VideoErrorRecovery: Modal-based error recovery interface with file browser integration
- Enhance VideoSurface: Smart error detection with file existence validation
- Add IPC bridge: fs.checkFileExists for file system validation from renderer process
- Update PlayerPage: Integrate error recovery workflow with database operations
- Fix ant.scss: Ensure dangerous button text visibility in all themes

This implementation provides a robust solution for handling missing video files,
allowing users to either relocate files or clean up their library when content
is no longer accessible, preventing broken player states and improving UX.

* feat(i18n): implement internationalization for VideoErrorRecovery component

- Add comprehensive Chinese translations for video error recovery dialogs
- Replace hardcoded Chinese strings with i18n keys in VideoErrorRecovery component
- Support all error types: file-missing, unsupported-format, decode-error, network-error, unknown
- Include translations for action buttons, dialog content, and file path labels
- Maintain existing functionality while enabling future localization support
…ns list (#115)

- Add run-name to release.yml to display version and branch info
- Shows input version or auto-generated version number
- Includes branch name for non-main branches
- Improves workflow visibility and tracking
…ism (#112)

- Add comprehensive FFmpeg bundling system with cross-platform support
- Implement automatic fallback from Remotion media-parser to FFmpeg for unsupported codecs (e.g., A_DTS)
- Add FFmpeg download script with platform detection and caching
- Configure build pipeline to automatically bundle FFmpeg binaries

Core Changes:
- MediaParserService: Add FFmpegService fallback when Remotion parsing fails
- FFmpegService: Add bundled FFmpeg path resolution with development/production support
- Add download-ffmpeg.ts script supporting win32/darwin/linux x64/arm64 platforms
- Update build configuration to automatically download and bundle FFmpeg
- Add comprehensive documentation for FFmpeg integration

Technical Implementation:
- Smart path resolution: bundled FFmpeg → system FFmpeg fallback
- Cross-platform binary management with architecture-specific builds
- Build-time FFmpeg download with caching to prevent duplicate downloads
- Production packaging includes platform-specific FFmpeg binaries

This ensures video parsing works for files with unsupported codecs like DTS audio,
automatically falling back to FFmpeg when Remotion's media-parser encounters
unknown codec errors, providing seamless compatibility across all video formats.

Platforms supported:
- Windows: x64, arm64 (GPL builds with full codec support)
- macOS: x64, arm64 (Universal binary from evermeet.cx)
- Linux: x64, arm64 (Static builds from johnvansickle.com)
Fix issue where manually triggered releases create assets with incorrect version numbers.
When manually triggering release workflow with specific version (e.g., v1.0.0-alpha.6),
the release notes show correct version but uploaded asset filenames contain old version
from package.json (e.g., alpha.5).

Solution:
- Add version sync step before build in release job
- Dynamically update package.json version from detect-version job output
- Ensure electron-builder uses correct version for artifact naming
- Maintain compatibility with automatic tag-based releases

This ensures release notes and asset filenames have consistent version numbers.
…#117)

- Replace manual version input with fully automated semantic-release workflow
- Fix version number inconsistency between build artifacts and GitHub releases
- Add 3-stage workflow: version analysis → build with correct version → release
- Support automatic triggering on main/alpha/beta branch pushes
- Ensure build artifact filenames match release version numbers
- Skip build/release when no commits need publishing
- Fix goToNextSubtitle to find next subtitle based on current time when activeCueIndex is -1
- Fix goToPreviousSubtitle to find previous subtitle based on current time when activeCueIndex is -1
- Add enhanced logging with from/to index information for better debugging
- Fix styled-components active prop to use $active prefix to avoid HTML attribute pollution

This resolves the issue where clicking "next subtitle" after app restart would jump to the first subtitle instead of the correct next subtitle based on current playback time.
…cords + i18n support (#120)

* fix(homepage): 修复删除视频记录后UI不同步的问题

- 在删除视频记录成功后同步更新store缓存
- 确保本地状态和全局缓存保持一致
- 修复删除后UI仍显示已删除记录的问题

closes: #删除视频记录UI不同步问题

* feat(i18n): 为HomePage删除功能添加国际化支持

- 在zh-cn.json中添加删除视频的翻译文本
- 更新HomePage使用useTranslation钩子
- 替换所有硬编码中文文本为i18n键值
- 支持动态视频标题插值

变更内容:
- 添加 home.delete.* 翻译键
- 确认删除对话框、按钮文本、提示消息的国际化
- 保持UI行为和样式不变
mkdir700 and others added 24 commits September 17, 2025 22:56
…138)

- Add time boundary check in useSubtitleOverlay hook
- Ensure overlay only displays when current time is within subtitle time range
- Fixes issue where overlay showed previous subtitle content after its end time
- Preserves SubtitleListPanel highlighting functionality by keeping useSubtitleEngine unchanged
* fix(player): improve play/pause button reliability

Fix intermittent play/pause failures by implementing state synchronization,
optimistic updates, and delayed verification mechanisms.

## Root Cause
- requestTogglePlay relied on videoController.isPaused() which could be
  out of sync with internal state
- Async play() operations could fail without proper error recovery
- State inconsistencies between video element and orchestrator context

## Solution
- Use internal context state as authoritative source for play/pause decisions
- Add syncPlaybackState() method to detect and fix state mismatches
- Implement optimistic updates with failure rollback
- Add delayed verification and retry mechanisms
- Enhance error handling for DOMExceptions

## Changes
- PlayerOrchestrator: Add state sync, optimistic updates, retry logic
- usePlayerCommands: Add detailed debugging logs and result verification
- Tests: Add 19 comprehensive test cases covering all scenarios

## Test Coverage
- 47 total test cases (100% pass rate)
- State synchronization scenarios
- Async operation handling
- Error recovery mechanisms
- Edge cases and boundary conditions
- Real usage scenarios (shortcuts, browser limitations)

Resolves the issue where play/pause would occasionally fail to resume
playback via keyboard shortcuts, requiring mouse click to recover.

* Update src/renderer/src/pages/player/engine/__tests__/PlayerOrchestrator.playback-reliability.test.ts
…prehensive tests (#143)

- Add dictionary API to preload layer for frontend access
- Create comprehensive test suite for DictionaryService with 18 test cases
- Test coverage includes success scenarios, error handling, HTML parsing robustness, parameter processing, and edge cases
- Verify API can handle various dictionary response formats and gracefully handle network errors
- All tests pass, demonstrating production-ready robustness

API Usage:
```typescript
const result = await window.api.dictionary.queryEudic('hello', 'greeting context');
if (result.success) {
  console.log(result.data); // { word, phonetic, definitions, examples, translations }
}
```
…ets (#145)

* fix(build): fix FFmpeg cross-platform build on macOS for Windows targets

- Add cross-env dependency for cross-platform environment variables
- Update Windows build scripts to set BUILD_TARGET_PLATFORM and BUILD_TARGET_ARCH
- Modify download-ffmpeg.ts to prioritize environment variables over command arguments
- Update vite plugin to avoid duplicate FFmpeg downloads
- Fix release scripts to download all platform FFmpeg binaries before building
- Ensure correct FFmpeg binaries are included for each target platform

Resolves issue where building Windows packages on macOS would include macOS FFmpeg binaries instead of Windows ones.

* fix(build): improve FFmpeg download in CI environments

- Replace direct tsx command with npm run for better CI compatibility
- Add CI-specific handling with proper environment variable passing
- Convert hard failures to warnings to prevent CI build blocking
- Improve error messages and debugging information

Fixes Windows CI build failure: spawn tsx ENOENT

* fix(build): ensure FFmpeg is properly downloaded in Windows CI

- Use npm run ffmpeg:download on Windows for better compatibility
- Pass environment variables to ensure correct platform detection
- Throw errors on download failure to prevent incomplete builds
- Keep direct tsx usage on Unix systems for performance

This ensures CI builds never skip FFmpeg download and always include
the correct FFmpeg binaries for the target platform.
…ion (#140)

* feat(player): add subtitle copy shortcut with Ctrl+C

- Add copy_subtitle shortcut to constants with CommandOrControl+C
- Implement copy functionality in usePlayerShortcuts hook
- Support copying selected text or current subtitle based on display mode
- Add success/error notifications for copy operations
- Remove obsolete keyboard handling from SubtitleContent component
- Add i18n label support for copy_subtitle shortcut

* fix(player): enable text selection in subtitle tokens for copy functionality

- Change WordToken user-select from 'none' to 'text' to allow native text selection
- Add debug logging to copy function to help diagnose selection issues
- This enables Ctrl+C to copy selected subtitle text properly

* fix(player): use custom subtitle selection for copy functionality

- Use selectedText from useSubtitleOverlayUI instead of window.getSelection()
- Integrate with custom selection system used by SubtitleContent component
- Restore WordToken user-select: none to maintain custom selection behavior
- Update copy logic to properly detect custom selected text vs full subtitle
- Remove window.getSelection() debugging code as it's no longer used

* debug: add logging to copy function to diagnose selectedText state

* feat(player): add DOM-based selected text detection for copy

- Add fallback to DOM query when selectedText state is empty
- Check for selected tokens by background color style
- Maintains both state-based and DOM-based selection detection
- This should fix the issue where selectedText state gets cleared before copy

* simplify: remove word selection feature, keep only full subtitle copy

- Remove all selected text detection logic (selectedText state and DOM queries)
- Simplify copy function to only copy current subtitle based on display mode
- Remove dependency on useSubtitleOverlayUI hook
- Clean up notification message to show copied character count
- This makes the copy functionality simple and reliable

* feat(player): add lightweight toast notifications for subtitle copy

- Add Ctrl+C shortcut to copy current subtitle based on display mode
- Replace intrusive NotificationService with lightweight toast positioned above subtitle overlay
- Implement custom event system for decoupled toast communication between components
- Add i18n support for copy success/failure messages in zh-cn.json
- Toast automatically hides after 2 seconds with smooth fade transition
- Support copying original, translated, or bilingual subtitle content based on current display mode
- Position toast relative to subtitle overlay for better UX during immersive video watching

This improves user experience by providing non-intrusive feedback while maintaining
clean component architecture and supporting internationalization.

* Update src/renderer/src/pages/player/components/SubtitleOverlay.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/renderer/src/pages/player/components/SubtitleOverlay.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/renderer/src/pages/player/components/SubtitleOverlay.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* 📝 Add docstrings to `copy-subtitle-shortcut` (#142)

Docstrings generation was requested by @mkdir700.

* #140 (comment)

The following files were modified:

* `src/renderer/src/pages/player/hooks/usePlayerShortcuts.ts`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update

* refactor: use design tokens in Toast components and add theming best practices

- Replace hardcoded values with design tokens in ToastContainer and ToastContent
- Use ANIMATION_DURATION, EASING, FONT_SIZES, FONT_WEIGHTS, SPACING, Z_INDEX, GLASS_EFFECT tokens
- Reduce toast display duration from 2000ms to 800ms for better UX
- Add comprehensive theming best practices to CLAUDE.md
- Document mixed approach: CSS variables for theme-related properties, JS variables for design constants

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…#152)

- Remove detail parameter from system MessageBox to prevent window overflow
- Display only essential update information with version number
- Direct users to Settings > About page for full release notes
- Remove unused formatReleaseNotes method and ReleaseNoteInfo interface

Fixes issue where long release notes caused system dialog to overflow screen height, hiding the Install button.
Remove all keyboard shortcuts for subtitle display modes:
- subtitle_mode_none (Cmd/Ctrl+1)
- subtitle_mode_original (Cmd/Ctrl+2)
- subtitle_mode_translated (Cmd/Ctrl+3)
- subtitle_mode_bilingual (Cmd/Ctrl+4)

Changes:
- Remove shortcut configurations from DEFAULT_SHORTCUTS
- Remove shortcut handlers from usePlayerShortcuts hook
- Remove i18n label references
- Clean up unused imports and fix formatting

Users can still change subtitle display modes through the UI interface.
…ncy logging (#156)

- Reduce Logger export history from 10k to 1k entries and add automatic cleanup
- Implement lightweight serialization to replace deep serialization
- Add sampling strategy for high-frequency logs (time_update, MediaClock events)
- Disable export history completely in production environment
- Optimize MediaClock logging with 5-10% sampling for duplicates and debug messages
- Reduce PlayerOrchestrator trace buffer from 200 to 50 entries
- Remove high-frequency onTimeUpdate silly logs
- Implement stricter production log levels (WARN+ for renderer, ERROR+ for main process)

This should significantly reduce memory pressure from logger-related objects
as identified in Chrome DevTools memory analysis.
…e state sync (#153)

* fix(subtitle): resolve overlay pause/seek update delays with immediate state sync

- Add immediate store updates in PlayerOrchestrator during seek/jumpToCue
- Implement UserSeeking state in PlayerSettingsSaver to prevent conflicts
- Ensure subtitle overlay UI responds instantly to user interactions
- Maintain data consistency during user-initiated time changes

* Update src/renderer/src/pages/player/engine/PlayerOrchestrator.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update src/renderer/src/services/PlayerSettingsSaver.ts

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix(player): resolve seeking event mismatch causing duplicate subtitle jumps

- Add missing mediaClock.startSeeking() call in PlayerOrchestrator.onSeeking()
- Fix SeekEventCoordinator state inconsistency between start/end seeking events
- Eliminate 'Ignoring seeked without active seeking' warnings in console
- Ensure proper event sequence for both paused and playing states
- All 66 player engine tests pass with TypeScript and lint validation

Resolves issue where users needed to press subtitle buttons twice in paused state.

* refactor(player): Use destroyOnHidden instead of destoryOnClose.

* fix(player): prevent SubtitleSyncStrategy from overriding user subtitle jumps

- Lock subtitle state machine for 2 seconds after user subtitle jump
- Prevent SubtitleSyncStrategy from immediately overriding user selection
- Add automatic unlock mechanism to restore normal subtitle sync behavior
- Ensure 'goToNextSubtitle' respects user intent in paused state
- Fix seeking event coordination in PlayerOrchestrator.onSeeking()

Resolves the core issue where clicking to jump to a subtitle would
be immediately overridden by the subtitle sync strategy, requiring
users to click twice to achieve their intended jump.

* fix(subtitle): eliminate subtitle content flickering during jumps

- Add activeCueIndex to PlayerState and StateUpdater interface
- Sync PlayerOrchestrator's activeCueIndex to store on updates
- Modify useSubtitleEngine to prioritize store's activeCueIndex over time-based calculation
- Ensure SubtitleContent component uses authoritative subtitle index
- Fix initial activeCueIndex synchronization on StateUpdater connection

Resolves flickering where subtitle content would briefly show wrong subtitle
before displaying the correct one during user-initiated subtitle jumps.

* fix(subtitle): eliminate subtitle overlay flickering during jumps

- Add smart tolerance mechanism to useSubtitleOverlay shouldShow calculation
- Display overlay when currentTime is within 2 seconds of subtitle start time
- Handles user jump delays while preserving smooth normal playback behavior
- Fixes flickering issue where overlay would briefly hide during subtitle navigation

Closes final flickering issue in subtitle navigation system.

* fix(subtitle): resolve overlay flickering through index priority and data stabilization

- Add stable subtitle data memoization in useSubtitleOverlay to prevent unnecessary re-renders
- Prioritize currentIndex over time-based checks in shouldShow calculation
- Reorder PlayerOrchestrator lock sequence to ensure SubtitleLockFSM is active during updateContext
- Implement granular dependency tracking for subtitle content changes

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
…anagement (#155)

* feat(ffmpeg): implement dynamic FFmpeg download system with runtime management

- Remove static FFmpeg bundling from build configuration
- Add FFmpegDownloadService for cross-platform binary management
- Implement automatic platform detection (Windows/macOS/Linux, x64/ARM64)
- Add IPC channels for download progress monitoring and control
- Integrate download service with existing FFmpegService architecture
- Update build scripts to remove prebuild FFmpeg requirements
- Add comprehensive test coverage for download functionality

Changes:
- electron-builder.yml: Remove extraResources FFmpeg bundling
- package.json: Remove prebuild FFmpeg download from release scripts
- FFmpegDownloadService.ts: New service with download/extract/management capabilities
- FFmpegService.ts: Enhanced with download service integration and fallback logic
- IpcChannel.ts: Add 9 new channels for download operations
- ipc.ts: Register download service handlers for renderer communication
- preload/index.ts: Expose download APIs to renderer process
- useVideoFileSelect.ts: Updated to work with dynamic FFmpeg detection

This implementation enables on-demand FFmpeg installation, reducing app bundle
size by ~200MB while maintaining cross-platform compatibility and user experience.
The system gracefully falls back to bundled → downloaded → system FFmpeg.

* feat(settings): implement FFmpeg settings UI with download management

- Add new FFmpegSettings component with status indicator and download controls
- Remove deprecated FFmpeg build plugin from electron.vite.config.ts
- Enhance IndicatorLight component with proper CSS-in-JS animation syntax
- Add comprehensive i18n support for FFmpeg management (en-us, zh-cn)
- Remove box-shadow from ant-btn components for cleaner UI appearance
- Integrate FFmpeg settings into main SettingsPage navigation

Changes:
- FFmpegSettings.tsx: Complete UI implementation with download progress, path validation, and status management
- electron.vite.config.ts: Remove build-time FFmpeg download plugin (shift to runtime approach)
- IndicatorLight.tsx: Fix styled-components animation with proper css helper
- i18n locales: Add 61 new translation keys for FFmpeg settings UI
- ant.scss: Remove button shadows for consistent design system
- SettingsPage.tsx: Add FFmpeg settings tab integration

This implements the frontend interface for the dynamic FFmpeg download system,
providing users with a comprehensive management UI for FFmpeg installation,
status monitoring, and path configuration.

* feat(ffmpeg): implement FFmpeg guidance dialog for enhanced user experience

Add comprehensive FFmpeg download guidance system that transforms technical errors
into user-friendly guidance with seamless navigation to settings and auto-download.

**Components Added:**
- FFmpegDownloadPrompt: Full-featured guidance dialog with benefits, effort info, and actions
- Comprehensive internationalization support (zh-CN, en-US)

**Hook Enhancements:**
- useVideoFileSelect: Extended with FFmpeg prompt state management
- Replaced technical error throwing with guided dialog display
- Enhanced error detection for FFmpeg missing scenarios

**Integration Updates:**
- HomePage: State management for prompt visibility and component integration
- EmptyState/VideoAddButton: Bidirectional state communication with parent
- HeaderNavbar: Props forwarding for prompt handler

**Features:**
- Benefits explanation (compatibility, performance, reliability)
- Installation effort communication
- Auto-navigation to settings with download trigger
- Seamless integration with existing video file selection workflow
- Graceful error handling with user-centric messaging

**Technical Details:**
- Styled-components with theme variables and CSS custom properties
- Modal-based UI with responsive design and accessibility
- State management across component hierarchy
- URL parameter-based auto-download triggering
- Comprehensive TypeScript interfaces

Transforms "视频处理组件未安装" technical errors into guided user experience
that educates users about FFmpeg benefits and provides immediate resolution path.

* test: fix FFmpegService mock for dynamic download system

- Add getDownloadService method to FFmpegService mock
- Include all FFmpegDownloadService interface methods in mock
- Fix 43 failing test cases caused by missing mock method
- All 554 test cases now pass successfully

Resolves test failures introduced by FFmpeg dynamic download system implementation.

* test: fix cross-platform FFmpeg executable name test

- Update test to handle platform-specific executable names (ffmpeg vs ffmpeg.exe)
- Fix Windows CI test failure where test expected 'ffmpeg' but got 'ffmpeg.exe'
- Test now correctly validates system FFmpeg fallback behavior on all platforms
- Maintains test coverage while supporting cross-platform compatibility

Resolves Windows CI test failure in FFmpegService integration tests.
- Add arm64 architecture support for Windows NSIS installer target
- Add arm64 architecture support for Windows Portable target
- Align Windows build targets with existing macOS and Linux ARM64 support
- Enable native ARM64 builds for Windows on ARM devices

This change allows the application to run natively on Windows ARM64 devices,
providing better performance and compatibility for users with ARM-based Windows machines.
- Configure Windows and Linux to use native system title bars instead of custom titleBarOverlay
- Remove excessive padding-right in Navbar component (140px for Windows, 120px for Linux)
- Maintain custom title bar for macOS with traffic light buttons integration
- Update ThemeService to only apply titleBarOverlay changes to macOS windows
- Simplify Navbar styling to use consistent 12px padding across all platforms

This change eliminates the spacing issue in the Windows header area and provides
a more native user experience on Windows and Linux platforms.

Fixes the header spacing issue reported for Windows platform.
…elease (#160)

- Remove pre-release-check.ts script with version validation and Git status checks
- Remove release.ts script with interactive version selection and build automation
- Remove rename-artifacts.ts script with platform-specific file renaming logic
- Remove version-manager.ts script with semver version bumping functionality
- Clean up package.json scripts: remove version:*, release:*, and related commands
- Retain semantic-release configuration and migrate:* database commands
- Transition from custom release tooling to standardized semantic-release workflow

The removed scripts provided manual release management including:
- Interactive version type selection (patch/minor/major/prerelease/beta)
- Git status validation and commit automation
- Cross-platform artifact renaming (Windows/macOS/Linux)
- Build orchestration and publishing workflows

This refactoring simplifies the release process by adopting semantic-release
as the single source of truth for version management and automated publishing,
reducing maintenance overhead and improving consistency with modern CI/CD practices.
- Replace find() with filter() + sort() to get the latest matching release
- Increase API request limit from 8 to 20 releases for better coverage
- Add proper sorting by published_at timestamp to ensure latest version
- Enhance logging for better debugging of version detection process

Fixes issue where alpha.10 was not detected due to find() returning
the first match instead of the latest published version.
When users relocate a missing video file through the error recovery dialog,
the new file path is now properly saved to the database instead of only
updating local state. This ensures the relocated path persists across
app sessions, eliminating the need to relocate files repeatedly.

Changes:
- Update handleFileRelocate to fetch video record and file ID
- Call db.files.updateFile() to persist new path to database
- Maintain existing local state updates for immediate UI response
- Add comprehensive error handling and logging

Fixes issue where video file relocation was temporary and required
repeated user action on subsequent app launches.
* feat(ffmpeg): add China mirror support for FFmpeg downloads

- Add IP-based region detection using ipinfo.io API
- Support China mainland, Hong Kong, Macau, Taiwan regions
- Add dedicated China mirror URLs from gitcode.com
- Implement automatic fallback from China to global mirrors
- Add comprehensive test coverage for new functionality
- Default to China mirror on detection failure for better UX

Breaking change: Service now defaults to China mirror for
better performance in Chinese regions

* fix(test): remove unused parameter in FFmpegDownloadService test

- Fix TypeScript error TS6133 for unused 'url' parameter
- Replace unused 'url' with underscore in mock implementation
… theme support (#171)

* feat(player): show inline dictionary popover

* enhance(player): improve word lookup popup UI and functionality

- Enhanced dictionary popover with better visual design
- Added pronunciation button with speech synthesis
- Improved loading and error states display
- Limited definitions display to 6 items with more indicator
- Added translation section with tags layout
- Implemented responsive design and custom scrollbar
- Enhanced fade-in animation for better UX
- Fixed ResizeObserver compatibility in test environment
- Updated tests to cover new features and error states

Fixes: Improve word lookup popup appearance and functionality

* refactor(player): optimize part-of-speech tags layout in dictionary popup

- Changed definition layout from column to row for better space usage
- Made part-of-speech tags more compact with inline layout
- Reduced vertical space occupied by multiple definitions
- Improved visual balance with fixed-width centered tags
- Enhanced readability with better alignment and spacing

Resolves space efficiency issues with multiple part-of-speech tags

* refactor(player): extract DictionaryPopover as independent component

- Created standalone DictionaryPopover component with complete UI
- Moved all dictionary-related logic and styles to separate component
- Simplified SubtitleOverlay by removing 200+ lines of dictionary code
- Maintained all existing functionality (pronunciation, loading states, error handling)
- Improved code organization and maintainability
- Enhanced component reusability and testability

Benefits:
- Better separation of concerns
- Easier to maintain and test dictionary functionality
- Reduced SubtitleOverlay complexity
- Improved code organization

* fix(player): prevent DictionaryPopover overflow on screen edges

- Added intelligent position calculation algorithm
- Implemented 6 placement modes: top/bottom with left/right/center alignment
- Automatic position adjustment based on viewport boundaries
- Prevents horizontal overflow with 10px safety margin
- Dynamic transform calculations for different placements
- Maintains optimal positioning while avoiding screen edges
- Enhanced user experience for edge-case word selections

Benefits:
- No more cutoff popover on right/left screen edges
- Smart positioning adapts to available space
- Consistent visual appearance across all positions
- Improved accessibility and usability

* feat(player): add comprehensive dictionary popover with theme support and pronunciation

- Implement new DictionaryPopover component using Ant Design Popover for intelligent positioning
- Add comprehensive pronunciation parsing with UK/US audio support and voice parameters
- Enhance dictionary service parsing to handle complex HTML structures and <i> tag formats
- Add theme compatibility using Ant Design CSS variables for light/dark mode adaptation
- Implement internationalization support with loading/error state translations
- Add robust test coverage for various dictionary HTML parsing scenarios

Features:
- Pronunciation: Extract audio URLs, phonetic symbols, and support both UK/US variants
- Parsing: Handle mixed part-of-speech formats (tagged vs plain text) with comprehensive coverage
- UI: Smart positioning, theme-aware styling, and accessibility improvements
- Testing: Edge cases for "need", mixed formats, and complex part-of-speech structures

This feature provides users with comprehensive word lookup functionality including
native pronunciation support and seamless theme integration for enhanced
subtitle reading experience.

* test(DictionaryPopover): update tests to match current data structure and remove deprecated features

- Remove phonetic field support in favor of pronunciations array structure
- Update test mocks to use pronunciations with type and phonetic properties
- Fix translation mocks to return actual Chinese translations instead of keys
- Add data-testid to error content for proper test coverage
- Remove definitions limitation logic and update test expectations accordingly
- Change test from "limits to 6 definitions" to "displays all definitions"

Changes:
- DictionaryPopover: Remove phonetic field fallback, use only pronunciations array
- Tests: Replace phonetic field with pronunciations array in mock data
- Tests: Add proper Chinese translations for dictionary keys
- Tests: Update definition display expectations to match unlimited display

This ensures tests align with the current component implementation that uses
the pronunciations array structure and displays all definitions without limitation
…nction (#172)

* fix(dictionary): support pronunciation extraction without UK/US distinction

- Update PronunciationInfo type to allow null type for unknown pronunciation
- Enhance pronunciation parsing to handle cases without explicit UK/US labels
- Add support for extracting pronunciation from `<span class="Phonitic">` without phontype
- Update DictionaryPopover to display "通用" for unknown pronunciation types
- Add comprehensive test cases for crystal-like pronunciation scenarios
- Ensure backward compatibility with existing UK/US pronunciation formats

Fixes pronunciation extraction for words like "crystal" where the HTML structure
doesn't explicitly distinguish between UK and US pronunciation types.

* refactor(dictionary): improve audio URL building and UI presentation

- Simplify audio URL parameter building logic in buildAudioUrl
- Remove voicename requirement check (only langid and txt are essential)
- Simplify pronunciation type display in DictionaryPopover
- Only show type label when type is explicitly known (uk/us)
- Default to 'uk' when calling handlePronunciation for unknown types
)

* fix(player): resolve focus loss after dictionary popup interaction

修复点击查词后焦点丢失导致快捷键失效的问题

- 阻止 DictionaryPopover 中发音按钮获得焦点
- 添加弹窗关闭时的焦点恢复机制
- 确保快捷键(如空格播放/暂停)在查词后仍能正常工作

Changes:
- 在发音按钮的 onClick 事件中调用 blur() 移除焦点
- 在发音按钮的 onMouseDown 事件中调用 preventDefault() 阻止默认焦点行为
- 在词典弹窗关闭时自动将焦点恢复到视频表面或字幕覆盖层
- 保持查词和发音功能的完整性

影响范围:
- 修复播放器快捷键在查词后失效的问题
- 提升用户交互体验
- 保持现有功能不受影响

* fix: fix type error
…on (#174)

* fix(player): resolve shortcut pause failure caused by state oscillation

Remove problematic automatic retry mechanisms in PlayerOrchestrator that were causing infinite state oscillation loops between play and pause operations.

**Problem**:
- Shortcut pause commands (spacebar) would fail and immediately resume playback
- Logs showed repeating "Video element still playing after pause() call" warnings
- Root cause: setTimeout-based verification logic in requestPlay() and requestPause() created mutual triggering loops

**Solution**:
- Remove 150ms retry logic from requestPlay() (lines 283-297)
- Remove 50ms retry logic from requestPause() (lines 320-333)
- Remove verification timeouts from requestTogglePlay() (lines 345-360)
- Trust browser's native play()/pause() API reliability

**Impact**:
- ✅ Shortcut pause now works immediately without interference
- ✅ Eliminates state oscillation loop warnings from logs
- ✅ Mouse click controls remain unaffected
- ✅ All other player functionality preserved

Fixes #170

* test: update PlayerOrchestrator tests to reflect removed retry mechanisms

Update reliability tests that previously validated automatic retry behavior:

- 'should detect play failure in delayed verification' → 'should only call play once without retry'
- 'should detect pause failure in delayed verification' → 'should only call pause once without retry'

These tests now correctly validate the simplified behavior where play() and pause()
are called exactly once without automatic retry mechanisms, aligning with the fix
that removes state oscillation loops.

All 578 tests now pass ✅
…nderer processes (#175)

- Add @sentry/electron dependency for comprehensive error tracking and performance monitoring
- Create shared TypeScript definitions for main and renderer Sentry configurations
- Implement SentryService for main process with native crash reporting and breadcrumb collection
- Implement SentryService for renderer process with web-specific error handling
- Initialize Sentry in both main index and renderer init files for full coverage
- Configure error boundaries, performance monitoring, and user context tracking
- Add support for release tracking, environment detection, and custom integrations
- Enable automatic breadcrumb collection and unhandled rejection capture

This implementation provides:
- Centralized error monitoring and crash reporting
- Performance tracking and bottleneck identification
- User session tracking with privacy-conscious defaults
- Development/production environment separation
- Comprehensive error context for debugging production issues
…xperience (#177)

- Set PRODUCTION URL to China mirror (http://release.echoplayer.z2blog.com/api/releases)
- Add CN_ALPHA and CN_BETA URLs for Chinese users' pre-release channels
- Simplify AppUpdater logic to use PRODUCTION URL for all stable releases
- Maintain GitHub URLs for non-CN users in test mode
- Improve logging to distinguish China mirror usage
…gger without description (#179)

- Add logic to automatically fetch release description from GitHub API when manual workflow trigger doesn't provide release_body
- Fallback to informative default message if release not found or has no description
- Maintain existing behavior when release_body is explicitly provided
- Improve user experience by eliminating need to manually copy descriptions
…pause (#182)

* fix(player): resolve spacebar shortcut not working after clicking to pause

- Remove duplicate onKeyDown handler from VideoSurface component that was intercepting space key events and preventing global shortcuts from working
- Add enhanced debug logging to track shortcut trigger events and focus state
- Ensure consistent play/pause behavior regardless of focus location

Fixes issue where clicking VideoSurface to pause would prevent spacebar from resuming playback

* test: fix Windows timing race conditions in VideoLibraryDAO tests

- Replace multiple Date.now() calls with fixed timestamps to prevent 1ms differences
- Use consistent FIXED_NOW and FIXED_FIRST_PLAYED_AT constants across all mock data
- Fix failing tests on Windows where Date.now() calls had microsecond variations

Resolves test failures where expected timestamps differed by 1ms from actual values
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 17, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

Branch-driven CI/CD replaces manual release flow, integrates semantic-release, and expands test triggers. Adds FFmpeg bundling/downloader, media parser strategy, Sentry integration, dictionary pronunciations/popover, player error recovery/fullscreen IPC, new DB migrations/fields, utilities (path/perf), settings/playback updates, extensive i18n additions, and numerous renderer/UI refactors.

Changes

Cohort / File(s) Summary
CI/CD Workflows
.github/workflows/release.yml, .github/workflows/sync-release-to-gitcode.yml, .github/workflows/test.yml, .releaserc.js, .coderabbit.yaml
Release triggers now on branch push with version-analysis via semantic-release; prerelease sync extended; tests trigger on more branches; GitHub release uploads assets; CodeRabbit config added.
Licensing & Docs
LICENSE, README.md, docs/FFmpeg-Integration.md
License switched to AGPLv3; README acknowledgments updated; new FFmpeg integration documentation added.
FFmpeg Core Integration
src/main/services/FFmpegService.ts, src/main/services/FFmpegDownloadService.ts, scripts/download-ffmpeg.ts, electron-builder.yml, package.json, .gitignore, packages/shared/IpcChannel.ts, src/main/ipc.ts, src/preload/index.ts
Replaces ad-hoc FFmpeg flow with bundled/system/downloaded resolution, warmup, and a download service (with mirrors, progress, cancel). IPC/preload surfaces expanded; Windows arm64 packaging enabled; scripts added; ffmpeg resources ignored.
Media Parsing Strategy
src/main/services/MediaParserService.ts, packages/shared/types/mediainfo.ts
Adds strategy-based media info retrieval (Remotion-first/FFmpeg-first) with timeouts, mapping, and existence/version checks; exports MediaInfo types.
Sentry Integration
packages/shared/types/sentry.d.ts, src/main/services/SentryService.ts, src/main/index.ts, src/renderer/src/init.ts
Adds Sentry services/types; early init in main/renderer with safe fallbacks and logger integration.
Database Migrations & Schemas
db/migrations/20250908171153_remove_path_unique_constraint.js, db/migrations/20250908220526_add_favorite_rates_fields.js, src/main/db/schemas/player-settings.ts, src/main/db/schemas/transforms.ts, packages/shared/schema.ts, src/main/db/migrations/20250829*.js (removed)
New migrations: remove unique path on files; add favoriteRates to playerSettings. Schemas updated with JsonStringSchema and favoriteRates. Old initial migrations removed.
Shared Config/Utils
packages/shared/config/constant.ts, packages/shared/utils/PathConverter.ts, packages/shared/utils/PerformanceMonitor.ts, src/main/utils/file.ts, src/main/utils/init.ts, src/main/utils/systemInfo.ts, electron.vite.config.ts
Feed URLs updated (CN endpoints, production URL); add path converter and performance monitor; robust getFileExt and app paths renamed to EchoPlayer; UA product token updated; Vite copy plugin renamed.
Renderer: FFmpeg UI & Startup
src/renderer/src/components/FFmpegDownloadPrompt.tsx, src/renderer/src/components/StartupIntro/*, src/renderer/src/App.tsx, src/renderer/src/pages/home/* (EmptyState/HeaderNavbar/HomePage/LoadingState), src/renderer/src/hooks/useVideoFileSelect.ts
Adds startup intro with FFmpeg warmup, FFmpeg download prompt flow, cached homepage preload, and updated file-select using strategy parser and new dialog extensions; propagates FFmpeg prompt visibility.
Renderer: Search
src/renderer/src/Router.tsx, src/renderer/src/components/SearchOverlay/*,
Search overlay now performs debounced async video search with results UI and item component.
Renderer: Player Error Handling & Controls
src/renderer/src/pages/player/PlayerPage.tsx, src/renderer/src/pages/player/components/VideoErrorRecovery.tsx, src/renderer/src/pages/player/components/VideoSurface.tsx, src/renderer/src/pages/player/components/SubtitleOverlay.tsx
Adds structured error recovery (relocate/remove/back), surface click play/pause, enriched error typing, file-missing detection, toast for subtitle copy, and interaction guards.
Renderer: Player Menus & Controls
src/renderer/src/pages/player/components/ControllerPanel/controls/*, src/renderer/src/pages/player/components/ControllerPanel/styles/controls.ts, src/renderer/src/pages/player/hooks/useHoverMenu.ts, src/renderer/src/pages/player/hooks/usePlayerCommands.ts, src/renderer/src/pages/player/components/index.ts
Introduces hover-driven menus for captions/loop/volume; playback-rate control uses presets and favorites; fullscreen toggles via IPC; new ControlContainer; removes setFullscreen from commands.
Renderer: Subtitles & Dictionary
src/renderer/src/pages/player/components/DictionaryPopover.tsx, src/renderer/src/pages/player/components/SubtitleContent.tsx
Adds dictionary popover with pronunciations/audio; subtitle word clicks trigger lookup; responsive font sizing and API changes in SubtitleContent.
Renderer: Subtitle List
src/renderer/src/pages/player/components/SubtitleListPanel.tsx
Replaces manual scroll logic with a state machine; removes “back to current” UI; props normalized.
Player Engine
src/renderer/src/pages/player/engine/* (MediaClock, PlayerOrchestrator, hooks/usePlayerEngine.ts, tests)
Sampling reduces log noise; orchestrator adds optimistic play/pause, sync, user-seek locks, setActiveCueIndex propagation, and updateContext API; tests added/refactored.
i18n
src/renderer/src/i18n/label.ts, src/renderer/src/i18n/locales/*.json
Adds extensive keys: FFmpeg plugin, playback, player controls, error recovery, search; new shortcuts; reorganizes sections and updates labels across en-us/ja-jp/ru-ru/zh-*.
IPC/Preload Surface
packages/shared/IpcChannel.ts, src/main/ipc.ts, src/preload/index.ts
FFmpeg channels expanded; MediaInfo IPC added; window/fullscreen IPC; fs.exists check; dictionary IPC added.
Tests
src/main/**/__tests__/*, src/renderer/**/__tests__/*
New and updated tests for FFmpeg services, dictionary parsing, DAO timing determinism, file ext on Windows, dialog extensions, FFmpeg IPC mock changes, orchestrator reliability.
Removals: Legacy Release/Version Scripts
scripts/pre-release-check.ts, scripts/release.ts, scripts/rename-artifacts.ts, scripts/version-manager.ts
Removes legacy release/version management scripts; CI now handles versioning/publishing.
Styling & Minor UI
src/renderer/src/assets/styles/ant.scss, src/renderer/src/components/IndicatorLight.tsx, src/main/services/ThemeService.ts, src/main/services/TrayService.ts, src/main/services/WindowService.ts, src/renderer/src/components/app/Navbar.tsx
Minor style tweaks (buttons shadow/text), pulsing style via css helper, macOS-only title bar overlay update, tray tooltip text to EchoPlayer, platform-aware title bar, fixed navbar padding.
Shared Types & Exports
packages/shared/types/sentry.d.ts, src/renderer/src/infrastructure/types/dictionary.ts, src/renderer/src/infrastructure/types/index.ts, src/renderer/src/infrastructure/constants/*, src/renderer/src/infrastructure/hooks/*
Adds PronunciationInfo and Mediainfo exports; explicit types; playback presets typed; hooks expose startup intro and favorite rates; useShortcutDisplay return typed.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Renderer as Renderer (Home/Player)
  participant Preload as Preload API
  participant Main as Main IPC
  participant FDL as FFmpegDownloadService
  participant FF as FFmpegService
  participant MP as MediaParserService

  rect rgba(230,245,255,0.5)
  note over Renderer: On startup
  Renderer->>Preload: ffmpeg.warmup()
  Preload->>Main: IpcChannel.Ffmpeg_Warmup
  Main->>FF: warmupFFmpeg()
  FF-->>Main: status
  Main-->>Preload: { isWarmedUp }
  Preload-->>Renderer: result
  end

  rect rgba(240,255,240,0.5)
  note over Renderer: Select video file
  Renderer->>Preload: mediainfo.getVideoInfoWithStrategy(path, 'remotion-first')
  Preload->>Main: IpcChannel.MediaInfo_GetVideoInfoWithStrategy
  Main->>MP: getVideoInfoWithStrategy(...)
  alt Remotion success
    MP-->>Main: VideoInfo
  else Fallback to FFmpeg
    MP->>FF: getVideoInfo()
    FF-->>MP: VideoInfo
  end
  Main-->>Preload: VideoInfo/null
  Preload-->>Renderer: VideoInfo/null
  end

  rect rgba(255,245,230,0.5)
  note over Renderer: If FFmpeg missing
  Renderer->>Preload: ffmpeg.getInfo()
  Preload->>Main: IpcChannel.Ffmpeg_GetInfo
  Main->>FF: getFFmpegInfo()
  FF-->>Main: { needsDownload }
  Main-->>Preload: info
  Preload-->>Renderer: info
  Renderer->>Renderer: Show FFmpegDownloadPrompt
  Renderer->>Preload: ffmpeg.download.download(platform, arch)
  Preload->>Main: IpcChannel.FfmpegDownload_Download
  Main->>FDL: downloadFFmpeg(...)
  FDL-->>Main: progress/completion
  Main-->>Preload: status
  Preload-->>Renderer: status
  end
Loading
sequenceDiagram
  autonumber
  participant Renderer as Renderer (Player)
  participant Preload as Preload API
  participant Main as Main IPC
  participant Win as BrowserWindow

  note over Renderer: Fullscreen toggle
  Renderer->>Preload: invoke(Window_ToggleFullScreen)
  Preload->>Main: IpcChannel.Window_ToggleFullScreen
  Main->>Win: setFullScreen(!isFullScreen)
  Win-->>Main: state changed
  Main-->>Preload: ok
  Preload-->>Renderer: ok
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

Poem

(_/)
( •_•) I hop through CI at dawn,
< release.yml sings a branch-born song >
FFmpeg warms, media’s parsed,
Sentry watches, errors charted.
Subtitles whisper, words pop free—
Echoes play; ship it! — signed, a happy bunny 🥕

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch beta2main

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34a5879 and c3de836.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (107)
  • .coderabbit.yaml (1 hunks)
  • .github/workflows/release.yml (4 hunks)
  • .github/workflows/sync-release-to-gitcode.yml (4 hunks)
  • .github/workflows/test.yml (1 hunks)
  • .gitignore (1 hunks)
  • .releaserc.js (2 hunks)
  • CLAUDE.md (2 hunks)
  • LICENSE (1 hunks)
  • README.md (1 hunks)
  • db/migrations/20250908171153_remove_path_unique_constraint.js (1 hunks)
  • db/migrations/20250908220526_add_favorite_rates_fields.js (1 hunks)
  • docs/FFmpeg-Integration.md (1 hunks)
  • electron-builder.yml (2 hunks)
  • electron.vite.config.ts (1 hunks)
  • package.json (4 hunks)
  • packages/shared/IpcChannel.ts (1 hunks)
  • packages/shared/config/constant.ts (1 hunks)
  • packages/shared/schema.ts (1 hunks)
  • packages/shared/types/mediainfo.ts (1 hunks)
  • packages/shared/types/sentry.d.ts (1 hunks)
  • packages/shared/utils/PathConverter.ts (1 hunks)
  • packages/shared/utils/PerformanceMonitor.ts (1 hunks)
  • scripts/download-ffmpeg.ts (1 hunks)
  • scripts/pre-release-check.ts (0 hunks)
  • scripts/release.ts (0 hunks)
  • scripts/rename-artifacts.ts (0 hunks)
  • scripts/version-manager.ts (0 hunks)
  • src/main/__tests__/DictionaryService.test.ts (1 hunks)
  • src/main/__tests__/ipc.database.test.ts (1 hunks)
  • src/main/db/dao/__tests__/VideoLibraryDAO.test.ts (7 hunks)
  • src/main/db/migrations/20250829175200_init.js (0 hunks)
  • src/main/db/migrations/20250831062000_add_player_settings.js (0 hunks)
  • src/main/db/schemas/player-settings.ts (4 hunks)
  • src/main/db/schemas/transforms.ts (1 hunks)
  • src/main/index.ts (1 hunks)
  • src/main/ipc.ts (4 hunks)
  • src/main/services/AppUpdater.ts (4 hunks)
  • src/main/services/ConfigManager.ts (6 hunks)
  • src/main/services/DictionaryService.ts (6 hunks)
  • src/main/services/FFmpegDownloadService.ts (1 hunks)
  • src/main/services/FFmpegService.ts (4 hunks)
  • src/main/services/FileStorage.ts (10 hunks)
  • src/main/services/MediaParserService.ts (1 hunks)
  • src/main/services/SentryService.ts (1 hunks)
  • src/main/services/ThemeService.ts (2 hunks)
  • src/main/services/TrayService.ts (1 hunks)
  • src/main/services/WindowService.ts (3 hunks)
  • src/main/services/__tests__/FFmpegDownloadService.test.ts (1 hunks)
  • src/main/services/__tests__/FFmpegService.integration.test.ts (1 hunks)
  • src/main/utils/__tests__/dialog-extensions.test.ts (1 hunks)
  • src/main/utils/__tests__/file.windows.test.ts (1 hunks)
  • src/main/utils/file.ts (2 hunks)
  • src/main/utils/init.ts (3 hunks)
  • src/main/utils/systemInfo.ts (1 hunks)
  • src/preload/index.ts (3 hunks)
  • src/renderer/src/App.tsx (1 hunks)
  • src/renderer/src/Router.tsx (2 hunks)
  • src/renderer/src/assets/styles/ant.scss (4 hunks)
  • src/renderer/src/components/FFmpegDownloadPrompt.tsx (1 hunks)
  • src/renderer/src/components/IndicatorLight.tsx (2 hunks)
  • src/renderer/src/components/SearchOverlay/SearchOverlay.tsx (5 hunks)
  • src/renderer/src/components/SearchOverlay/VideoSearchResult.tsx (1 hunks)
  • src/renderer/src/components/StartupIntro/StartupLoadingState.tsx (1 hunks)
  • src/renderer/src/components/StartupIntro/index.ts (1 hunks)
  • src/renderer/src/components/app/Navbar.tsx (1 hunks)
  • src/renderer/src/hooks/useVideoFileSelect.ts (6 hunks)
  • src/renderer/src/i18n/label.ts (1 hunks)
  • src/renderer/src/i18n/locales/en-us.json (3 hunks)
  • src/renderer/src/i18n/locales/ja-jp.json (2 hunks)
  • src/renderer/src/i18n/locales/ru-ru.json (2 hunks)
  • src/renderer/src/i18n/locales/zh-cn.json (8 hunks)
  • src/renderer/src/i18n/locales/zh-tw.json (2 hunks)
  • src/renderer/src/infrastructure/constants/playback.const.ts (1 hunks)
  • src/renderer/src/infrastructure/constants/shortcuts.const.ts (1 hunks)
  • src/renderer/src/infrastructure/hooks/useSettings.ts (6 hunks)
  • src/renderer/src/infrastructure/hooks/useShortcut.ts (1 hunks)
  • src/renderer/src/infrastructure/types/dictionary.ts (1 hunks)
  • src/renderer/src/infrastructure/types/index.ts (1 hunks)
  • src/renderer/src/init.ts (1 hunks)
  • src/renderer/src/pages/home/EmptyState.tsx (1 hunks)
  • src/renderer/src/pages/home/HeaderNavbar.tsx (2 hunks)
  • src/renderer/src/pages/home/HomePage.tsx (13 hunks)
  • src/renderer/src/pages/home/LoadingState.tsx (1 hunks)
  • src/renderer/src/pages/home/VideoAddButton.tsx (1 hunks)
  • src/renderer/src/pages/player/PlayerPage.tsx (5 hunks)
  • src/renderer/src/pages/player/components/ControllerPanel/controls/CaptionsButton.tsx (3 hunks)
  • src/renderer/src/pages/player/components/ControllerPanel/controls/FullscreenButton.tsx (1 hunks)
  • src/renderer/src/pages/player/components/ControllerPanel/controls/LoopControl.tsx (3 hunks)
  • src/renderer/src/pages/player/components/ControllerPanel/controls/PauseControl.tsx (3 hunks)
  • src/renderer/src/pages/player/components/ControllerPanel/controls/PlaybackRateControl.tsx (2 hunks)
  • src/renderer/src/pages/player/components/ControllerPanel/controls/VolumeControl.tsx (4 hunks)
  • src/renderer/src/pages/player/components/ControllerPanel/styles/controls.ts (2 hunks)
  • src/renderer/src/pages/player/components/DictionaryPopover.tsx (1 hunks)
  • src/renderer/src/pages/player/components/SubtitleContent.tsx (11 hunks)
  • src/renderer/src/pages/player/components/SubtitleListPanel.tsx (8 hunks)
  • src/renderer/src/pages/player/components/SubtitleOverlay.tsx (14 hunks)
  • src/renderer/src/pages/player/components/VideoErrorRecovery.tsx (1 hunks)
  • src/renderer/src/pages/player/components/VideoSurface.tsx (9 hunks)
  • src/renderer/src/pages/player/components/index.ts (1 hunks)
  • src/renderer/src/pages/player/engine/MediaClock.ts (3 hunks)
  • src/renderer/src/pages/player/engine/PlayerOrchestrator.ts (13 hunks)
  • src/renderer/src/pages/player/engine/__tests__/PlayerOrchestrator.playback-reliability.test.ts (1 hunks)
  • src/renderer/src/pages/player/engine/__tests__/PlayerOrchestrator.test.ts (1 hunks)
  • src/renderer/src/pages/player/engine/intent/IntentStrategyManager.ts (0 hunks)
  • src/renderer/src/pages/player/hooks/useHoverMenu.ts (1 hunks)
  • src/renderer/src/pages/player/hooks/usePlayerCommands.ts (4 hunks)
  • src/renderer/src/pages/player/hooks/usePlayerEngine.ts (1 hunks)
⛔ Files not processed due to max files limit (4)
  • src/renderer/src/pages/player/hooks/usePlayerShortcuts.ts
  • src/renderer/src/pages/player/hooks/useSubtitleEngine.ts
  • src/renderer/src/pages/player/hooks/useSubtitleOverlay.ts
  • src/renderer/src/pages/player/hooks/useSubtitleOverlayUI.ts

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mkdir700 mkdir700 merged commit 3e46a69 into main Sep 17, 2025
1 of 5 checks passed
@mkdir700 mkdir700 deleted the beta2main branch September 17, 2025 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant