feat(ffmpeg): implement dynamic FFmpeg download system with runtime management#155
feat(ffmpeg): implement dynamic FFmpeg download system with runtime management#155
Conversation
…anagement - 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.
- 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.
…rience 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.
WalkthroughRemoves build-time FFmpeg bundling and related scripts/config; adds a runtime FFmpeg download service, IPC channels, preload APIs, renderer UI (prompt + settings), service tests, i18n entries, and wiring to invoke/download/manage FFmpeg at runtime. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Renderer as Renderer (React)
participant Preload as Preload (window.api.ffmpeg)
participant Main as Main (IPC handlers)
participant DL as FFmpegDownloadService
participant Net as Network
participant FS as FileSystem
User->>Renderer: Open Settings or click Download Prompt
Renderer->>Preload: getInfo()
Preload->>Main: invoke(Ffmpeg_GetInfo)
Main->>Main: ffmpegService.getFFmpegInfo()
Main-->>Preload: info {isDownloaded, isSystemFFmpeg, needsDownload, path}
Preload-->>Renderer: info
alt needsDownload
User->>Renderer: Click Download
Renderer->>Preload: download.download(platform?, arch?)
Preload->>Main: invoke(FfmpegDownload_Download, platform, arch)
Main->>DL: downloadFFmpeg(platform, arch)
DL->>Net: stream archive
DL->>DL: extract -> locate binary
DL->>FS: install binary & set permissions
DL-->>Main: success
Main-->>Preload: true
Preload-->>Renderer: success
else already available
Renderer-->>User: show status/actions (warmup/uninstall)
end
sequenceDiagram
autonumber
participant Renderer
participant Preload
participant Main
participant DL as FFmpegDownloadService
Renderer->>Preload: autoDetectAndDownload()
Preload->>Main: invoke(Ffmpeg_AutoDetectAndDownload)
Main->>Main: ffmpegService.autoDetectAndDownload()
Main-->>Preload: {available, needsDownload, downloadTriggered}
Preload-->>Renderer: result
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60–90 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
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 |
There was a problem hiding this comment.
Actionable comments posted: 29
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (12)
src/renderer/src/pages/settings/SettingsPage.tsx (1)
93-93: Syntax error in styled component.There’s an extra
]before the template literal terminator that will break compilation.Apply:
-]` +`src/renderer/src/pages/home/HomePage.tsx (4)
151-159: Remove dangerouslySetInnerHTML and emoji; use safe markup and lucide icon.
dangerouslySetInnerHTMLwith interpolatedvideo.titlerisks XSS. Also, guidelines disallow emoji as icons in TSX; use lucide-react.Apply:
- <p - dangerouslySetInnerHTML={{ - __html: t('home.delete.confirm_content', { title: video.title }) - }} - /> - <p style={{ color: 'var(--color-status-warning)', fontSize: '14px', marginTop: '8px' }}> - ⚠️ {t('home.delete.confirm_warning')} - </p> + <p>{t('home.delete.confirm_content', { title: video.title })}</p> + <WarningNote> + <AlertTriangle size={14} /> + <span>{t('home.delete.confirm_warning')}</span> + </WarningNote>Add imports and styled component:
+ import { AlertTriangle } from 'lucide-react'// place near other styled components const WarningNote = styled.div` display: flex; align-items: center; gap: 6px; color: var(--color-status-warning); font-size: 14px; margin-top: 8px; `
257-265: Ensure tooltip styles apply by setting overlayClassName.
VideoTitleTooltipstyles target.video-title-tooltip, but the instance doesn’t set it. AddoverlayClassName.- <VideoTitleTooltip + <VideoTitleTooltip title={video.title} mouseEnterDelay={0.6} placement="top" - getPopupContainer={() => document.body} + getPopupContainer={() => document.body} + overlayClassName="video-title-tooltip" >
316-338: Consider flex over CSS grid to match guideline defaults.Cards grid is fine, but guideline prefers flex as default. Keep grid if you have concrete benefits; otherwise consider flex with wrap.
Would you like a quick flex-based layout diff?
75-85: Use single-field Zustand selectors in HomePage.tsxFile: src/renderer/src/pages/home/HomePage.tsx (lines 75–85). Replace object-returning useStore calls with individual selectors to avoid unnecessary re-renders — selectors already exist in settings.store.ts and video-list.store.ts.
- const { videoListViewMode, setVideoListViewMode } = useSettingsStore() - const { - refreshTrigger, - isLoading, - isInitialized, - cachedVideos, - setLoading, - setInitialized, - setCachedVideos - } = useVideoListStore() + const videoListViewMode = useSettingsStore((s) => s.videoListViewMode) + const setVideoListViewMode = useSettingsStore((s) => s.setVideoListViewMode) + const refreshTrigger = useVideoListStore((s) => s.refreshTrigger) + const isLoading = useVideoListStore((s) => s.isLoading) + const isInitialized = useVideoListStore((s) => s.isInitialized) + const cachedVideos = useVideoListStore((s) => s.cachedVideos) + const setLoading = useVideoListStore((s) => s.setLoading) + const setInitialized = useVideoListStore((s) => s.setInitialized) + const setCachedVideos = useVideoListStore((s) => s.setCachedVideos)src/main/ipc.ts (1)
311-314: Avoid shadowing Nodepathimport.Parameter named
pathshadows the importedpathmodule. Rename the parameter todirPathfor clarity.- ipcMain.handle(IpcChannel.App_IsNotEmptyDir, async (_, path: string) => { - return fs.readdirSync(path).length > 0 + ipcMain.handle(IpcChannel.App_IsNotEmptyDir, async (_, dirPath: string) => { + return fs.readdirSync(dirPath).length > 0src/preload/index.ts (1)
572-574: Do not use console in TS/JS; route errors via loggerService IPCPer guidelines, replace
console.errorwith the unified logger IPC to main, and avoid eslint ignores.Apply:
- // eslint-disable-next-line no-restricted-syntax - console.error('[Preload]Failed to expose APIs:', error as Error) + void ipcRenderer.invoke( + IpcChannel.App_LogToMain, + { module: 'preload', scope: 'expose' } as unknown as LogSourceWithContext, + LogLevel.Error, + '[Preload] Failed to expose APIs', + [{ error }] + )src/main/services/FFmpegService.ts (5)
185-206: System FFmpeg detection is inconsistent with existence checks
getFFmpegPath()may return the bare executable'ffmpeg', butcheckFFmpegExists()later uses filesystem checks that will always fail for PATH-resolved binaries. This leads to false “needs download” states and failed warmups.See the
checkFFmpegExists()refactor below to probe PATH with a shortffmpeg -versionspawn when the path is not absolute.
295-347: Refactor existence check to handle PATH binaries and cache both outcomesCurrent logic only caches negatives and relies on
fs.existsSync, which fails for PATH-based ffmpeg. Probe via spawn and update cache for both true/false.Apply:
public async checkFFmpegExists(useCache = true): Promise<boolean> { const startTime = Date.now() const ffmpegPath = this.getFFmpegPath() - // 检查缓存 + // 检查缓存 if (useCache) { const cached = FFmpegService.ffmpegAvailabilityCache[ffmpegPath] const cacheTime = FFmpegService.ffmpegCacheTimestamp[ffmpegPath] if (cached !== undefined && cacheTime && Date.now() - cacheTime < FFmpegService.CACHE_TTL) { logger.info('📋 使用缓存的 FFmpeg 可用性结果', { ffmpegPath, cached, 缓存时间: `${Date.now() - cacheTime}ms前` }) return cached } } - logger.info('🔍 开始检查 FFmpeg 是否存在', { + logger.info('🔍 开始检查 FFmpeg 是否存在', { ffmpegPath, platform: process.platform, useCache }) try { - const fastCheckPassed = this.fastCheckFFmpegExists() - if (!fastCheckPassed) { - // 快速检查失败,直接缓存结果并返回 - FFmpegService.ffmpegAvailabilityCache[ffmpegPath] = false - FFmpegService.ffmpegCacheTimestamp[ffmpegPath] = Date.now() - - const totalTime = Date.now() - startTime - logger.warn(`❌ FFmpeg 快速检查失败,总耗时: ${totalTime}ms`, { ffmpegPath }) - return false - } - return true + const isAbsolute = path.isAbsolute(ffmpegPath) || ffmpegPath.includes(path.sep) + const exists = isAbsolute + ? this.fastCheckFFmpegExists() + : await this.probeFFmpegOnPath(ffmpegPath, 3000) + + const totalTime = Date.now() - startTime + FFmpegService.ffmpegAvailabilityCache[ffmpegPath] = exists + FFmpegService.ffmpegCacheTimestamp[ffmpegPath] = Date.now() + + if (exists) { + logger.info(`✅ FFmpeg 可用性检查通过,耗时: ${totalTime}ms`, { ffmpegPath }) + } else { + logger.warn(`❌ FFmpeg 不可用,总耗时: ${totalTime}ms`, { ffmpegPath }) + } + return exists } catch (error) { const totalTime = Date.now() - startTime // 缓存异常结果 FFmpegService.ffmpegAvailabilityCache[ffmpegPath] = false FFmpegService.ffmpegCacheTimestamp[ffmpegPath] = Date.now() logger.warn(`FFmpeg 检查异常,耗时: ${totalTime}ms`, { ffmpegPath, error: error instanceof Error ? error.message : String(error), 总耗时: `${totalTime}ms` }) return false } }Add this helper (outside the selected range):
// Probe PATH-resolved ffmpeg by invoking `-version` with a short timeout. private async probeFFmpegOnPath(cmd: string, timeoutMs = 3000): Promise<boolean> { return new Promise<boolean>((resolve) => { const child = spawn(cmd, ['-version']) let settled = false const t = setTimeout(() => { if (!settled) { settled = true child.kill('SIGKILL') resolve(false) } }, timeoutMs) child.on('close', (code) => { if (!settled) { settled = true clearTimeout(t) resolve(code === 0) } }) child.on('error', () => { if (!settled) { settled = true clearTimeout(t) resolve(false) } }) }) }
41-114: Excessive, privacy-sensitive logging during file URL conversionDirectory listing and filename heuristics (including hardcoded strings like “老友记”, “h265”) are noisy and risk PII leakage. Keep logs minimal and remove directory scans.
Apply:
- // 添加详细的调试信息 - logger.info('🔄 URL路径转换详情', { - 原始路径: inputPath, - 'URL.pathname': url.pathname, - 解码前路径: url.pathname, - 解码后路径: localPath, - 平台: process.platform, - 文件是否存在: fs.existsSync(localPath) - }) - - // 额外验证:尝试列出目录内容来确认文件是否真的存在 - if (!fs.existsSync(localPath)) { - const dirPath = path.dirname(localPath) - const fileName = path.basename(localPath) - logger.info('🔍 文件不存在,检查目录内容', { - 目录路径: dirPath, - 期望文件名: fileName, - 目录是否存在: fs.existsSync(dirPath) - }) - if (fs.existsSync(dirPath)) { - try { - const filesInDir = fs.readdirSync(dirPath) - logger.info('📁 目录中的文件', { - 目录路径: dirPath, - 文件列表: filesInDir, - 文件数量: filesInDir.length - }) - // 查找可能的匹配文件(大小写不敏感匹配) - const matchingFiles = filesInDir.filter( - (file) => - file.toLowerCase().includes('老友记') || - file.toLowerCase().includes('h265') || - file.toLowerCase().includes(fileName.toLowerCase()) - ) - if (matchingFiles.length > 0) { - logger.info('🎯 找到可能匹配的文件', { matchingFiles }) - } - } catch (error) { - logger.error( - '无法读取目录内容:', - error instanceof Error ? error : new Error(String(error)) - ) - } - } - } + logger.info('🔄 URL路径转换', { + 原始路径: inputPath, + 解码后路径: localPath, + 平台: process.platform, + 文件是否存在: fs.existsSync(localPath) + })
12-14: UnusedforceKillTimeoutfield
forceKillTimeoutis never assigned. Remove or wire it to an actual force-kill path.
447-455: Bitrate unit handling is misleading
bitrateMatch[1] + '000'yields a string and assumes 1 kb = 1000 b. Prefer returning a number (bps) or keepkbpsexplicitly to avoid confusion.- const bitrate = bitrateMatch ? bitrateMatch[1] + '000' : '0' // 转换为 bits/s + const bitrate = bitrateMatch ? Number(bitrateMatch[1]) * 1000 : 0 // bits/s (number)Also adjust the return type accordingly.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (22)
electron-builder.yml(0 hunks)electron.vite.config.ts(0 hunks)package.json(2 hunks)packages/shared/IpcChannel.ts(1 hunks)src/main/ipc.ts(1 hunks)src/main/services/FFmpegDownloadService.ts(1 hunks)src/main/services/FFmpegService.ts(7 hunks)src/main/services/__tests__/FFmpegDownloadService.test.ts(1 hunks)src/main/services/__tests__/FFmpegService.integration.test.ts(1 hunks)src/preload/index.ts(1 hunks)src/renderer/src/assets/styles/ant.scss(1 hunks)src/renderer/src/components/FFmpegDownloadPrompt.tsx(1 hunks)src/renderer/src/components/IndicatorLight.tsx(2 hunks)src/renderer/src/hooks/useVideoFileSelect.ts(4 hunks)src/renderer/src/i18n/locales/en-us.json(2 hunks)src/renderer/src/i18n/locales/zh-cn.json(6 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(5 hunks)src/renderer/src/pages/home/VideoAddButton.tsx(1 hunks)src/renderer/src/pages/settings/FFmpegSettings.tsx(1 hunks)src/renderer/src/pages/settings/SettingsPage.tsx(3 hunks)
💤 Files with no reviewable changes (2)
- electron-builder.yml
- electron.vite.config.ts
🧰 Additional context used
📓 Path-based instructions (8)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: 在组件/Hook 中避免硬编码尺寸和时长,优先使用 useTheme() 的 token(如 motionDurationMid、borderRadiusSM/MD 等)或集中定义的样式变量
定制 antd 组件样式时优先使用 styled-components(styled(Component) 包装),避免通过全局 SCSS 与全局 className 覆盖
项目使用 Zustand 结合 Immer 中间件与自定义中间件栈(持久化、DevTools、订阅选择器)进行状态管理
Files:
src/main/services/__tests__/FFmpegService.integration.test.tssrc/renderer/src/components/IndicatorLight.tsxsrc/renderer/src/hooks/useVideoFileSelect.tssrc/renderer/src/components/FFmpegDownloadPrompt.tsxsrc/renderer/src/pages/settings/FFmpegSettings.tsxsrc/renderer/src/pages/home/EmptyState.tsxpackages/shared/IpcChannel.tssrc/main/ipc.tssrc/main/services/__tests__/FFmpegDownloadService.test.tssrc/renderer/src/pages/home/HeaderNavbar.tsxsrc/preload/index.tssrc/main/services/FFmpegService.tssrc/renderer/src/pages/home/HomePage.tsxsrc/renderer/src/pages/home/VideoAddButton.tsxsrc/main/services/FFmpegDownloadService.tssrc/renderer/src/pages/settings/SettingsPage.tsx
**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{tsx,ts}: Zustand 必须在组件/Hook 顶层使用 selector(useStore(selector));禁止在 useMemo/useEffect 内部调用 store Hook
避免使用返回对象的 useStore 选择器(如 useStore(s => ({ a: s.a, b: s.b }))),应使用单字段选择器或配合 shallow 比较器
Files:
src/main/services/__tests__/FFmpegService.integration.test.tssrc/renderer/src/components/IndicatorLight.tsxsrc/renderer/src/hooks/useVideoFileSelect.tssrc/renderer/src/components/FFmpegDownloadPrompt.tsxsrc/renderer/src/pages/settings/FFmpegSettings.tsxsrc/renderer/src/pages/home/EmptyState.tsxpackages/shared/IpcChannel.tssrc/main/ipc.tssrc/main/services/__tests__/FFmpegDownloadService.test.tssrc/renderer/src/pages/home/HeaderNavbar.tsxsrc/preload/index.tssrc/main/services/FFmpegService.tssrc/renderer/src/pages/home/HomePage.tsxsrc/renderer/src/pages/home/VideoAddButton.tsxsrc/main/services/FFmpegDownloadService.tssrc/renderer/src/pages/settings/SettingsPage.tsx
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
测试使用 vitest 作为测试框架
Files:
src/main/services/__tests__/FFmpegService.integration.test.tssrc/main/services/__tests__/FFmpegDownloadService.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: 统一使用 loggerService 记录日志,禁止使用 console
logger 使用示例:logger.error('Error in :', { error }); 第二个参数必须是对象字面量 {}
Files:
src/main/services/__tests__/FFmpegService.integration.test.tssrc/renderer/src/components/IndicatorLight.tsxsrc/renderer/src/hooks/useVideoFileSelect.tssrc/renderer/src/components/FFmpegDownloadPrompt.tsxsrc/renderer/src/pages/settings/FFmpegSettings.tsxsrc/renderer/src/pages/home/EmptyState.tsxpackages/shared/IpcChannel.tssrc/main/ipc.tssrc/main/services/__tests__/FFmpegDownloadService.test.tssrc/renderer/src/pages/home/HeaderNavbar.tsxsrc/preload/index.tssrc/main/services/FFmpegService.tssrc/renderer/src/pages/home/HomePage.tsxsrc/renderer/src/pages/home/VideoAddButton.tsxsrc/main/services/FFmpegDownloadService.tssrc/renderer/src/pages/settings/SettingsPage.tsx
**/*.{tsx,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{tsx,jsx}: 图标统一使用 lucide-react,不使用 emoji 作为图标
优先使用 antd 组件库;如组件可被 antd 复用则优先用 antd 而非自研
Files:
src/renderer/src/components/IndicatorLight.tsxsrc/renderer/src/components/FFmpegDownloadPrompt.tsxsrc/renderer/src/pages/settings/FFmpegSettings.tsxsrc/renderer/src/pages/home/EmptyState.tsxsrc/renderer/src/pages/home/HeaderNavbar.tsxsrc/renderer/src/pages/home/HomePage.tsxsrc/renderer/src/pages/home/VideoAddButton.tsxsrc/renderer/src/pages/settings/SettingsPage.tsx
**/*.{tsx,jsx,css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
布局实现优先使用 flex,避免将 grid 作为默认方案
Files:
src/renderer/src/components/IndicatorLight.tsxsrc/renderer/src/components/FFmpegDownloadPrompt.tsxsrc/renderer/src/pages/settings/FFmpegSettings.tsxsrc/renderer/src/assets/styles/ant.scsssrc/renderer/src/pages/home/EmptyState.tsxsrc/renderer/src/pages/home/HeaderNavbar.tsxsrc/renderer/src/pages/home/HomePage.tsxsrc/renderer/src/pages/home/VideoAddButton.tsxsrc/renderer/src/pages/settings/SettingsPage.tsx
src/renderer/src/assets/styles/**/*.{css,scss}
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/src/assets/styles/**/*.{css,scss}: 优先使用 CSS 变量,而不是硬编码样式值(在样式文件中)
CSS/SCSS 样式文件应位于 src/renderer/src/assets/styles 目录下进行集中管理
Files:
src/renderer/src/assets/styles/ant.scss
src/renderer/src/assets/styles/**/*.scss
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/src/assets/styles/**/*.scss: assets/styles 目录下的 SCSS(含 ant.scss)为全局引入,修改将全局生效,谨慎引入全局选择器与覆盖
禁止使用全局 SCSS 覆盖 antd 组件样式,避免样式污染与架构不一致
Files:
src/renderer/src/assets/styles/ant.scss
🧠 Learnings (3)
📚 Learning: 2025-09-07T16:43:49.564Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-07T16:43:49.564Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : 测试使用 vitest 作为测试框架
Applied to files:
src/main/services/__tests__/FFmpegService.integration.test.tssrc/main/services/__tests__/FFmpegDownloadService.test.ts
📚 Learning: 2025-09-07T16:43:49.564Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-07T16:43:49.564Z
Learning: Applies to src/renderer/src/assets/styles/**/*.scss : assets/styles 目录下的 SCSS(含 ant.scss)为全局引入,修改将全局生效,谨慎引入全局选择器与覆盖
Applied to files:
src/renderer/src/assets/styles/ant.scss
📚 Learning: 2025-09-07T16:43:49.564Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-07T16:43:49.564Z
Learning: Applies to src/renderer/src/assets/styles/**/*.scss : 禁止使用全局 SCSS 覆盖 antd 组件样式,避免样式污染与架构不一致
Applied to files:
src/renderer/src/assets/styles/ant.scss
🧬 Code graph analysis (9)
src/renderer/src/components/FFmpegDownloadPrompt.tsx (1)
src/renderer/src/infrastructure/styles/theme.ts (4)
SPACING(43-58)BORDER_RADIUS(61-72)FONT_SIZES(25-40)FONT_WEIGHTS(11-22)
src/renderer/src/pages/settings/FFmpegSettings.tsx (4)
src/renderer/src/services/Logger.ts (1)
loggerService(743-743)src/renderer/src/contexts/theme.context.tsx (1)
useTheme(124-124)src/renderer/src/pages/settings/AboutSettings.tsx (1)
SettingRowTitle(412-424)src/renderer/src/infrastructure/styles/theme.ts (6)
SPACING(43-58)BORDER_RADIUS(61-72)ANIMATION_DURATION(91-100)EASING(103-114)FONT_WEIGHTS(11-22)FONT_SIZES(25-40)
src/renderer/src/pages/home/EmptyState.tsx (1)
src/renderer/src/hooks/useVideoFileSelect.ts (1)
useVideoFileSelect(40-230)
src/main/ipc.ts (1)
src/main/services/FFmpegDownloadService.ts (1)
ffmpegDownloadService(591-591)
src/main/services/__tests__/FFmpegDownloadService.test.ts (1)
src/main/services/FFmpegDownloadService.ts (1)
FFmpegDownloadService(120-588)
src/main/services/FFmpegService.ts (1)
src/main/services/FFmpegDownloadService.ts (1)
ffmpegDownloadService(591-591)
src/renderer/src/pages/home/HomePage.tsx (2)
src/renderer/src/pages/home/EmptyState.tsx (1)
EmptyState(15-71)src/renderer/src/components/FFmpegDownloadPrompt.tsx (1)
FFmpegDownloadPrompt(23-123)
src/renderer/src/pages/home/VideoAddButton.tsx (1)
src/renderer/src/hooks/useVideoFileSelect.ts (1)
useVideoFileSelect(40-230)
src/main/services/FFmpegDownloadService.ts (1)
src/renderer/src/services/Logger.ts (2)
loggerService(743-743)error(436-438)
🪛 GitHub Check: test (macos-latest, 20)
src/main/ipc.ts
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该处理删除文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该成功删除文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该处理类型查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该返回空数组当没有匹配类型的文件时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该根据类型查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该返回undefined当文件不存在时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该处理路径查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该根据路径查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该处理添加文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该成功添加文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
🪛 GitHub Check: test (ubuntu-latest, 20)
src/main/ipc.ts
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该处理删除文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该成功删除文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该处理类型查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该返回空数组当没有匹配类型的文件时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该根据类型查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该返回undefined当文件不存在时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该处理路径查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该根据路径查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该处理添加文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该成功添加文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
🔇 Additional comments (27)
package.json (2)
74-74: Keep “ffmpeg:test” relevant to runtime flowThis test script should validate the new dynamic path (IPC + download service), not the old bundled path. If it still probes packaged binaries, update it accordingly.
51-55: Verify CI/docs for FFmpeg predownload referencesRelease scripts no longer predownload FFmpeg — confirm CI workflows, docs, and packaging configs (electron-builder / electron.vite) don't depend on that step. Run a broad search for ffmpeg references, e.g.:
rg -n --glob '!node_modules' -C2 -e 'ffmpeg' .github scripts package.json electron-builder.yml electron.vite.config.ts README* docs || true
packages/shared/IpcChannel.ts (1)
80-91: FFmpeg IPC handlers and preload bridges present — approving.
ipcMain handlers are implemented in src/main/ipc.ts (IpcChannel.Ffmpeg_* handlers, ~lines 477–521) and preload ipcRenderer wrappers exist in src/preload/index.ts (~lines 195–217).src/renderer/src/i18n/locales/en-us.json (1)
202-204: Shortcuts labels—LGTMsrc/main/services/FFmpegDownloadService.ts (1)
120-129: Confirm main-process LoggerService importEnsure './LoggerService' imported by src/main/services/FFmpegDownloadService.ts (lines 120–129) resolves to the main-process logger implementation (not a renderer-side module). My search returned no matches — run: rg -n "\bLoggerService\b" -g '!node_modules' src and confirm the resolved path.
src/renderer/src/pages/home/HeaderNavbar.tsx (1)
36-36: Correctly passes the callback to child.No issues.
src/renderer/src/pages/home/EmptyState.tsx (4)
12-13: New callback prop is fine.Matches the new prompt flow.
15-18: Component props wiring LGTM.No issues.
20-24: Hook return usage OK.No issues.
25-29: Propagate prompt state to parent—good.This effect is correct and minimal.
src/renderer/src/pages/home/VideoAddButton.tsx (4)
10-12: Prop addition aligns with prompt flow.Looks good.
14-14: Component signature update—OK.No issues.
17-19: Hook usage updated—OK.Matches the expanded hook API.
21-25: Upstream prompt state propagation—OK.Effect is correct.
src/renderer/src/hooks/useVideoFileSelect.ts (2)
20-22: Return type expansion is fine.Exposing
showFFmpegPromptand its setter makes sense for the new flow.
45-45: Local state for prompt visibility—OK.No issues.
src/renderer/src/components/FFmpegDownloadPrompt.tsx (1)
37-46: LGTM overall.Modal config, i18n keys, and navigation flow look correct.
src/renderer/src/pages/home/HomePage.tsx (1)
288-290: LGTM: Prompt wiring.FFmpeg prompt state and close handler are correctly connected.
src/main/services/__tests__/FFmpegService.integration.test.ts (1)
167-173: LGTM: verifies download service surface.Good coverage ensuring the download service instance exposes required methods.
src/main/ipc.ts (1)
458-476: FFmpeg info/download IPC additions look good.Handlers are consistent with service API; return types are JSON-serializable.
Also applies to: 477-483
src/main/services/__tests__/FFmpegDownloadService.test.ts (2)
150-180: LGTM: removeFFmpeg paths and error handling covered well.Good assertions on
fs.rmSyncand failure paths.
121-125: Solid platform matrix checks.Coverage for version discovery and aggregate configs is sufficient.
Also applies to: 127-148
src/renderer/src/pages/settings/FFmpegSettings.tsx (1)
355-463: UI logic looks sound.Status indicator, download CTA, cancel, warmup, and uninstall flows align with the new IPC surface and tokens.
src/preload/index.ts (1)
186-201: Align preload API types with main service return shapeConfirm
getInfo()/autoDetectAndDownload()payloads matchFFmpegService.getFFmpegInfo()andautoDetectAndDownload()exactly (field names/types), or renderer consumers will subtly break when destructuring. If they differ, adjust here first.src/main/services/FFmpegService.ts (1)
753-755: Potentially missing await on async cleanupIf
ffmpegDownloadService.cleanupTempFiles()is async, not awaiting may swallow errors and exit early on app shutdown.If it returns a Promise, change to:
- ffmpegDownloadService.cleanupTempFiles() + await ffmpegDownloadService.cleanupTempFiles()src/renderer/src/i18n/locales/zh-cn.json (2)
27-35: Avoid raw HTML in translations unless using i18n-safe components
confirm_contentcontains<strong>. Ensure the renderer uses i18n components (e.g., i18next Trans with element whitelist) to prevent XSS. Otherwise switch to placeholders and style in code.
47-71: Keyboard hint formatting consistencyFor labels with shortcuts like “(Ctrl+4)”, ensure all similar entries follow the same pattern across display modes and controls.
| // FFmpeg 下载服务 | ||
| const ffmpegDownloadService = ffmpegService.getDownloadService() | ||
| ipcMain.handle( | ||
| IpcChannel.FfmpegDownload_CheckExists, | ||
| async (_, platform?: string, arch?: string) => { | ||
| return ffmpegDownloadService.checkFFmpegExists(platform as any, arch as any) | ||
| } | ||
| ) | ||
| ipcMain.handle( | ||
| IpcChannel.FfmpegDownload_GetVersion, | ||
| async (_, platform?: string, arch?: string) => { | ||
| return ffmpegDownloadService.getFFmpegVersion(platform as any, arch as any) | ||
| } | ||
| ) | ||
| ipcMain.handle( | ||
| IpcChannel.FfmpegDownload_Download, | ||
| async (_, platform?: string, arch?: string) => { | ||
| return await ffmpegDownloadService.downloadFFmpeg(platform as any, arch as any) | ||
| } | ||
| ) | ||
| ipcMain.handle( | ||
| IpcChannel.FfmpegDownload_GetProgress, | ||
| async (_, platform?: string, arch?: string) => { | ||
| return ffmpegDownloadService.getDownloadProgress(platform as any, arch as any) | ||
| } | ||
| ) | ||
| ipcMain.handle(IpcChannel.FfmpegDownload_Cancel, async (_, platform?: string, arch?: string) => { | ||
| return ffmpegDownloadService.cancelDownload(platform as any, arch as any) | ||
| }) | ||
| ipcMain.handle(IpcChannel.FfmpegDownload_Remove, async (_, platform?: string, arch?: string) => { | ||
| return ffmpegDownloadService.removeFFmpeg(platform as any, arch as any) | ||
| }) | ||
| ipcMain.handle(IpcChannel.FfmpegDownload_GetAllVersions, async () => { | ||
| return ffmpegDownloadService.getAllSupportedVersions() | ||
| }) | ||
| ipcMain.handle(IpcChannel.FfmpegDownload_CleanupTemp, async () => { | ||
| return ffmpegDownloadService.cleanupTempFiles() | ||
| }) |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix test failures: avoid calling ffmpegService.getDownloadService(); use the exported singleton.
CI fails with “getDownloadService is not a function”. Import the singleton ffmpegDownloadService and use it directly. Also, strongly type platform/arch to avoid any.
Apply within this block:
- // FFmpeg 下载服务
- const ffmpegDownloadService = ffmpegService.getDownloadService()
+ // FFmpeg 下载服务
+ // Use the singleton to avoid method-shape drift and simplify testing.
+ const ffmpegDl = ffmpegDownloadService
ipcMain.handle(
IpcChannel.FfmpegDownload_CheckExists,
async (_, platform?: string, arch?: string) => {
- return ffmpegDownloadService.checkFFmpegExists(platform as any, arch as any)
+ return ffmpegDl.checkFFmpegExists(platform as Platform, arch as Arch)
}
)
ipcMain.handle(
IpcChannel.FfmpegDownload_GetVersion,
async (_, platform?: string, arch?: string) => {
- return ffmpegDownloadService.getFFmpegVersion(platform as any, arch as any)
+ return ffmpegDl.getFFmpegVersion(platform as Platform, arch as Arch)
}
)
ipcMain.handle(
IpcChannel.FfmpegDownload_Download,
async (_, platform?: string, arch?: string) => {
- return await ffmpegDownloadService.downloadFFmpeg(platform as any, arch as any)
+ return await ffmpegDl.downloadFFmpeg(platform as Platform, arch as Arch)
}
)
ipcMain.handle(
IpcChannel.FfmpegDownload_GetProgress,
async (_, platform?: string, arch?: string) => {
- return ffmpegDownloadService.getDownloadProgress(platform as any, arch as any)
+ return ffmpegDl.getDownloadProgress(platform as Platform, arch as Arch)
}
)
- ipcMain.handle(IpcChannel.FfmpegDownload_Cancel, async (_, platform?: string, arch?: string) => {
- return ffmpegDownloadService.cancelDownload(platform as any, arch as any)
+ ipcMain.handle(IpcChannel.FfmpegDownload_Cancel, async (_, platform?: string, arch?: string) => {
+ return ffmpegDl.cancelDownload(platform as Platform, arch as Arch)
})
- ipcMain.handle(IpcChannel.FfmpegDownload_Remove, async (_, platform?: string, arch?: string) => {
- return ffmpegDownloadService.removeFFmpeg(platform as any, arch as any)
+ ipcMain.handle(IpcChannel.FfmpegDownload_Remove, async (_, platform?: string, arch?: string) => {
+ return ffmpegDl.removeFFmpeg(platform as Platform, arch as Arch)
})
ipcMain.handle(IpcChannel.FfmpegDownload_GetAllVersions, async () => {
- return ffmpegDownloadService.getAllSupportedVersions()
+ return ffmpegDl.getAllSupportedVersions()
})
ipcMain.handle(IpcChannel.FfmpegDownload_CleanupTemp, async () => {
- return ffmpegDownloadService.cleanupTempFiles()
+ return ffmpegDl.cleanupTempFiles()
})Add supporting imports (outside this hunk):
import { ffmpegDownloadService, type Platform, type Arch } from './services/FFmpegDownloadService'Optional validation: reject unexpected inputs at IPC boundary to prevent misuse.
const isValidPlatform = (p?: string): p is Platform => !!p && ['win32','darwin','linux'].includes(p)
const isValidArch = (a?: string): a is Arch => !!a && ['x64','arm64'].includes(a)🧰 Tools
🪛 GitHub Check: test (macos-latest, 20)
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该处理删除文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该成功删除文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该处理类型查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该返回空数组当没有匹配类型的文件时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该根据类型查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该返回undefined当文件不存在时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该处理路径查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该根据路径查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该处理添加文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该成功添加文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
🪛 GitHub Check: test (ubuntu-latest, 20)
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该处理删除文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Delete > 应该成功删除文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该处理类型查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该返回空数组当没有匹配类型的文件时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByType > 应该根据类型查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该返回undefined当文件不存在时
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该处理路径查找文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_FindByPath > 应该根据路径查找文件
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该处理添加文件时的错误
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
[failure] 485-485: src/main/tests/ipc.database.test.ts > IPC Database Handlers > Files DAO IPC Handlers > DB_Files_Add > 应该成功添加文件并记录日志
TypeError: ffmpegService.getDownloadService is not a function
❯ Module.registerIpc src/main/ipc.ts:485:47
❯ src/main/tests/ipc.database.test.ts:228:5
🤖 Prompt for AI Agents
In src/main/ipc.ts around lines 484 to 521, the code calls
ffmpegService.getDownloadService() which causes CI errors because the module
exports a singleton; replace calls to ffmpegService.getDownloadService() with
the exported singleton ffmpegDownloadService (import it from
./services/FFmpegDownloadService), and strongly type the IPC handler parameters
as Platform and Arch instead of using any; update handlers to call methods
directly on ffmpegDownloadService, ensure you add the import line for
ffmpegDownloadService and the Platform/Arch types at the top of the file, and
optionally add simple validation at the IPC boundary to reject invalid
platform/arch values before invoking the service.
| describe('Error handling', () => { | ||
| it('should handle filesystem errors gracefully', () => { | ||
| vi.mocked(fs.existsSync).mockImplementation(() => { | ||
| throw new Error('Filesystem error') | ||
| }) | ||
|
|
||
| expect(() => { | ||
| const exists = ffmpegService.fastCheckFFmpegExists() | ||
| expect(exists).toBe(false) | ||
| }).not.toThrow() | ||
| }) | ||
|
|
||
| it('should handle missing download service gracefully', () => { | ||
| expect(() => { | ||
| const downloadService = ffmpegService.getDownloadService() | ||
| expect(downloadService).toBeDefined() | ||
| }).not.toThrow() | ||
| }) | ||
| }) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Add a case asserting auto-detect triggers no download when bundled exists.
Minor: already implied, but asserting that downloadTriggered stays false under bundled-available scenario strengthens regression safety.
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines
213 to 231, add a new test case that verifies auto-detection does not start a
download when a bundled ffmpeg exists: mock fs.existsSync (or the specific check
used by ffmpegService.fastCheckFFmpegExists/auto-detect) to return true, set
up/spy the download service or a downloadTriggered flag, call the auto-detect or
initialization routine that would trigger a download, and assert that
downloadTriggered remains false (or that the download method was not called).
Ensure the test cleans up mocks so other tests are unaffected.
| export interface DownloadProgress { | ||
| percent: number | ||
| downloaded: number | ||
| total: number | ||
| speed: number | ||
| remainingTime: number | ||
| status: 'downloading' | 'extracting' | 'verifying' | 'completed' | 'error' | ||
| } | ||
|
|
||
| // 下载状态枚举 | ||
| export enum DownloadStatus { | ||
| NOT_STARTED = 'not_started', | ||
| DOWNLOADING = 'downloading', | ||
| EXTRACTING = 'extracting', | ||
| VERIFYING = 'verifying', | ||
| COMPLETED = 'completed', | ||
| ERROR = 'error', | ||
| CANCELLED = 'cancelled' | ||
| } |
There was a problem hiding this comment.
Status typing inconsistency: enum includes CANCELLED but DownloadProgress doesn’t
DownloadStatus has CANCELLED, but DownloadProgress.status union lacks 'cancelled'. Also no path sets status to cancelled on abort.
Apply:
-export interface DownloadProgress {
+export interface DownloadProgress {
percent: number
downloaded: number
total: number
speed: number
remainingTime: number
- status: 'downloading' | 'extracting' | 'verifying' | 'completed' | 'error'
+ status: 'downloading' | 'extracting' | 'verifying' | 'completed' | 'error' | 'cancelled'
}And set progress.status = 'cancelled' when aborting (see cancel handler and catch block).
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export interface DownloadProgress { | |
| percent: number | |
| downloaded: number | |
| total: number | |
| speed: number | |
| remainingTime: number | |
| status: 'downloading' | 'extracting' | 'verifying' | 'completed' | 'error' | |
| } | |
| // 下载状态枚举 | |
| export enum DownloadStatus { | |
| NOT_STARTED = 'not_started', | |
| DOWNLOADING = 'downloading', | |
| EXTRACTING = 'extracting', | |
| VERIFYING = 'verifying', | |
| COMPLETED = 'completed', | |
| ERROR = 'error', | |
| CANCELLED = 'cancelled' | |
| } | |
| export interface DownloadProgress { | |
| percent: number | |
| downloaded: number | |
| total: number | |
| speed: number | |
| remainingTime: number | |
| status: 'downloading' | 'extracting' | 'verifying' | 'completed' | 'error' | 'cancelled' | |
| } | |
| // 下载状态枚举 | |
| export enum DownloadStatus { | |
| NOT_STARTED = 'not_started', | |
| DOWNLOADING = 'downloading', | |
| EXTRACTING = 'extracting', | |
| VERIFYING = 'verifying', | |
| COMPLETED = 'completed', | |
| ERROR = 'error', | |
| CANCELLED = 'cancelled' | |
| } |
🤖 Prompt for AI Agents
In src/main/services/FFmpegDownloadService.ts around lines 28 to 46, the
DownloadProgress.status union is missing the 'cancelled' value present in the
DownloadStatus enum which causes a typing inconsistency; update the
DownloadProgress.status to include 'cancelled' (or better yet, type it as
DownloadStatus) so types align, and modify the abort/cancel handler and the
relevant catch block to set progress.status = 'cancelled' when an operation is
aborted so runtime state matches the enum and typings.
| // FFmpeg 配置 - 使用稳定版本 | ||
| const FFMPEG_VERSIONS: Record<Platform, Record<Arch, FFmpegVersion>> = { | ||
| win32: { | ||
| x64: { | ||
| version: '6.1', | ||
| platform: 'win32', | ||
| arch: 'x64', | ||
| url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip', | ||
| size: 89 * 1024 * 1024, // 约 89MB | ||
| extractPath: 'ffmpeg-master-latest-win64-gpl/bin/ffmpeg.exe' | ||
| }, | ||
| arm64: { | ||
| version: '6.1', | ||
| platform: 'win32', | ||
| arch: 'arm64', | ||
| url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-winarm64-gpl.zip', | ||
| size: 85 * 1024 * 1024, // 约 85MB | ||
| extractPath: 'ffmpeg-master-latest-winarm64-gpl/bin/ffmpeg.exe' | ||
| } |
There was a problem hiding this comment.
Windows URL points to “master-latest” (unreproducible) while comment says stable
Use pinned series builds (e.g., n6.1-latest) or a fixed tag to keep downloads reproducible and aligned with “稳定版本”.
- url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip',
+ url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n6.1-latest-win64-gpl.zip',
...
- url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-winarm64-gpl.zip',
+ url: 'https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-n6.1-latest-winarm64-gpl.zip',Optionally expose version in config to update to FFmpeg 7.x later without code changes.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/services/FFmpegDownloadService.ts around lines 48 to 66, the Windows
FFmpeg URLs use "master-latest" (non-reproducible) despite the comment saying
stable; replace those URLs with pinned-series or fixed-tag downloads (e.g., use
`n6.1-latest` or a specific release tag) so downloads are reproducible, and
instead of hardcoding the version string in the map, expose the FFmpeg
version/series as a configurable constant or env-backed config value used to
build the URL and version fields so future upgrades (e.g., 7.x) can be performed
by changing config rather than code.
| public async downloadFFmpeg( | ||
| platform = process.platform as Platform, | ||
| arch = process.arch as Arch, | ||
| onProgress?: (progress: DownloadProgress) => void | ||
| ): Promise<boolean> { | ||
| const key = `${platform}-${arch}` | ||
|
|
||
| // 检查是否已存在 | ||
| if (this.checkFFmpegExists(platform, arch)) { | ||
| logger.info('FFmpeg 已存在,跳过下载', { platform, arch }) | ||
| return true | ||
| } | ||
|
|
||
| // 检查是否正在下载 | ||
| if (this.downloadProgress.has(key)) { | ||
| logger.warn('FFmpeg 正在下载中', { platform, arch }) | ||
| return false | ||
| } | ||
|
|
There was a problem hiding this comment.
Cancellation and cleanup semantics
- Concurrent call returns
falsewith only a warning—OK—but on cancel you don’t mark progress as cancelled nor clean temp dir/files if in error path. - In
catch, set status appropriately and clean uptempDirand partialdownloadPath.
- } catch (error) {
- progress.status = 'error'
+ } catch (error) {
+ if ((error as Error)?.message === '下载已取消') {
+ progress.status = 'cancelled'
+ } else {
+ progress.status = 'error'
+ }
onProgress?.(progress)
logger.error('FFmpeg 下载失败', {
platform,
arch,
error: error instanceof Error ? error.message : String(error)
})
- return false
+ // cleanup
+ try { this.cleanupTempDir(tempDir) } catch {}
+ return false
} finally {
this.downloadProgress.delete(key)
this.downloadController.delete(key)
}And in cancelDownload, update progress map entry (if present) to 'cancelled'.
Also applies to: 228-236, 294-308
| // 当关闭FFmpeg提示时,重置状态 | ||
| useEffect(() => { | ||
| if (!showFFmpegPrompt) { | ||
| setShowFFmpegPrompt(false) | ||
| } | ||
| }, [showFFmpegPrompt, setShowFFmpegPrompt]) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Remove redundant reset effect.
Same no-op pattern as in EmptyState; safe to delete.
Apply:
- // 当关闭FFmpeg提示时,重置状态
- useEffect(() => {
- if (!showFFmpegPrompt) {
- setShowFFmpegPrompt(false)
- }
- }, [showFFmpegPrompt, setShowFFmpegPrompt])
+📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // 当关闭FFmpeg提示时,重置状态 | |
| useEffect(() => { | |
| if (!showFFmpegPrompt) { | |
| setShowFFmpegPrompt(false) | |
| } | |
| }, [showFFmpegPrompt, setShowFFmpegPrompt]) |
🤖 Prompt for AI Agents
In src/renderer/src/pages/home/VideoAddButton.tsx around lines 26 to 31, there
is a redundant useEffect that resets showFFmpegPrompt to false when
showFFmpegPrompt is already false; remove this entire no-op effect (the
useEffect block) to clean up dead code and dependency noise.
| // 下载进度轮询 | ||
| useEffect(() => { | ||
| let progressInterval: NodeJS.Timeout | null = null | ||
|
|
||
| if (isDownloading) { | ||
| progressInterval = setInterval(async () => { | ||
| try { | ||
| const progress = await window.api.ffmpeg.download.getProgress() | ||
| setDownloadProgress(progress || {}) | ||
|
|
||
| // 检查下载是否完成 | ||
| const currentStatus = await window.api.ffmpeg.getInfo() | ||
| if ( | ||
| currentStatus.isDownloaded && | ||
| !currentStatus.needsDownload && | ||
| !isCompletionHandledRef.current | ||
| ) { | ||
| // 标记已处理,防止重复 | ||
| isCompletionHandledRef.current = true | ||
|
|
||
| // 立即停止轮询 | ||
| if (progressInterval) { | ||
| clearInterval(progressInterval) | ||
| progressInterval = null | ||
| } | ||
|
|
||
| // 先显示成功状态 | ||
| setShowSuccessState(true) | ||
| message.success(t('settings.plugins.ffmpeg.download.success')) | ||
|
|
||
| // 2秒后恢复正常状态 | ||
| setTimeout(() => { | ||
| setIsDownloading(false) | ||
| setShowSuccessState(false) | ||
| setFFmpegStatus(currentStatus) | ||
| // 更新 FFmpeg 路径为下载后的路径 | ||
| setFFmpegPath(currentStatus.path) | ||
| // 自动开始预热 | ||
| handleWarmup() | ||
| }, 2000) | ||
| } | ||
| } catch (error) { | ||
| logger.error('获取下载进度失败:', { error }) | ||
| } | ||
| }, 2000) | ||
| } | ||
|
|
||
| return () => { | ||
| if (progressInterval) { | ||
| clearInterval(progressInterval) | ||
| } | ||
| } | ||
| }, [handleWarmup, isDownloading, t]) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Polling loop is safely cleaned up; consider debouncing status calls.
You call getInfo() every 2s in addition to progress. Optional: only refetch getInfo() when progress reaches ≥ 99% to reduce IPC traffic.
🤖 Prompt for AI Agents
In src/renderer/src/pages/settings/FFmpegSettings.tsx around lines 118 to 170,
you're currently calling window.api.ffmpeg.getInfo() every 2s alongside
getProgress(), which causes extra IPC traffic; change the polling so you always
fetch progress every interval but only call getInfo() when the reported progress
indicates near-completion (e.g., progress.percent >= 99 or progress.completed
=== true), and keep the existing completion-handling logic (set
isCompletionHandledRef, clearInterval, show success, set states, call
handleWarmup). Ensure you still handle errors from both calls and clear the
interval on unmount/cleanup; this reduces IPC calls while preserving correct
completion detection.
| const handleBrowsePath = useCallback(async () => { | ||
| try { | ||
| const result = await window.api.select({ | ||
| title: t('settings.plugins.ffmpeg.path.browse_title'), | ||
| properties: ['openFile'], | ||
| filters: [{ name: 'FFmpeg 可执行文件', extensions: ['exe', 'app', '*'] }] | ||
| }) | ||
|
|
||
| if (result && result.filePaths && result.filePaths.length > 0) { | ||
| setFFmpegPath(result.filePaths[0]) | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Fix App_Select return-type mismatch; treat result as a string path.
ipcMain.handle(IpcChannel.App_Select) returns a single string (or null), but here you expect { filePaths: string[] }. This breaks browsing.
Apply:
- const result = await window.api.select({
+ const result = await window.api.select({
title: t('settings.plugins.ffmpeg.path.browse_title'),
properties: ['openFile'],
filters: [{ name: 'FFmpeg 可执行文件', extensions: ['exe', 'app', '*'] }]
})
- if (result && result.filePaths && result.filePaths.length > 0) {
- setFFmpegPath(result.filePaths[0])
- }
+ if (typeof result === 'string' && result) {
+ setFFmpegPath(result)
+ }Alternatively, change the IPC to return { canceled, filePaths } everywhere for consistency.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const handleBrowsePath = useCallback(async () => { | |
| try { | |
| const result = await window.api.select({ | |
| title: t('settings.plugins.ffmpeg.path.browse_title'), | |
| properties: ['openFile'], | |
| filters: [{ name: 'FFmpeg 可执行文件', extensions: ['exe', 'app', '*'] }] | |
| }) | |
| if (result && result.filePaths && result.filePaths.length > 0) { | |
| setFFmpegPath(result.filePaths[0]) | |
| } | |
| const handleBrowsePath = useCallback(async () => { | |
| try { | |
| const result = await window.api.select({ | |
| title: t('settings.plugins.ffmpeg.path.browse_title'), | |
| properties: ['openFile'], | |
| filters: [{ name: 'FFmpeg 可执行文件', extensions: ['exe', 'app', '*'] }] | |
| }) | |
| if (typeof result === 'string' && result) { | |
| setFFmpegPath(result) | |
| } |
🤖 Prompt for AI Agents
In src/renderer/src/pages/settings/FFmpegSettings.tsx around lines 231-241, the
code assumes window.api.select returns { filePaths: string[] } but the IPC
handler actually returns a single string path (or null); update the handler here
to treat result as a string: check for a non-null string and call
setFFmpegPath(result) instead of accessing result.filePaths, or alternatively
change the IPC implementation to consistently return { canceled, filePaths } and
adapt this component to use that object shape—pick one approach and make the
component and IPC return shape consistent.
| <MenuItemLink to="/settings/plugins"> | ||
| <MenuItem className={isRoute('/settings/plugins')}> | ||
| <Monitor size={18} /> | ||
| {t('settings.plugins.title')} | ||
| </MenuItem> | ||
| </MenuItemLink> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Add i18n key and avoid hardcoded icon size.
Confirm settings.plugins.title exists in all locales. Also consider using a shared token/const for icon size instead of 18 to align with the “no hardcoded sizes” guideline.
Apply:
- <Monitor size={18} />
+ <Monitor size={ICON_SIZE_SM} />And define once near the top:
+const ICON_SIZE_SM = 18📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <MenuItemLink to="/settings/plugins"> | |
| <MenuItem className={isRoute('/settings/plugins')}> | |
| <Monitor size={18} /> | |
| {t('settings.plugins.title')} | |
| </MenuItem> | |
| </MenuItemLink> | |
| const ICON_SIZE_SM = 18 | |
| <MenuItemLink to="/settings/plugins"> | |
| <MenuItem className={isRoute('/settings/plugins')}> | |
| <Monitor size={ICON_SIZE_SM} /> | |
| {t('settings.plugins.title')} | |
| </MenuItem> | |
| </MenuItemLink> |
🤖 Prompt for AI Agents
In src/renderer/src/pages/settings/SettingsPage.tsx around lines 55-60, the
MenuItem uses a hardcoded icon size (18) and references an i18n key
settings.plugins.title which must exist across locales; replace the literal 18
with a shared constant (define const ICON_SIZE = <shared token or import from
your design tokens near the top of the file and use it for the Monitor
component) and verify/import the translations so settings.plugins.title is
present in all locale files (add the key to any missing locale JSONs or provide
a fallback translation import if applicable).
| <Route path="general" element={<GeneralSettings />} /> | ||
| <Route path="shortcut" element={<ShortcutSettings />} /> | ||
| <Route path="playback" element={<PlaybackSettings />} /> | ||
| <Route path="plugins" element={<FFmpegSettings />} /> |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Lazy-load FFmpegSettings to keep Settings bundle lean.
This route is a good candidate for code-splitting.
Apply:
-import FFmpegSettings from './FFmpegSettings'
+const FFmpegSettings = React.lazy(() => import('./FFmpegSettings'))And wrap just this route element:
- <Route path="plugins" element={<FFmpegSettings />} />
+ <Route
+ path="plugins"
+ element={
+ <React.Suspense fallback={null}>
+ <FFmpegSettings />
+ </React.Suspense>
+ }
+ />📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Route path="plugins" element={<FFmpegSettings />} /> | |
| const FFmpegSettings = React.lazy(() => import('./FFmpegSettings')) | |
| <Route | |
| path="plugins" | |
| element={ | |
| <React.Suspense fallback={null}> | |
| <FFmpegSettings /> | |
| </React.Suspense> | |
| } | |
| /> |
🤖 Prompt for AI Agents
In src/renderer/src/pages/settings/SettingsPage.tsx around line 74, the
FFmpegSettings route is imported/used directly which prevents code-splitting;
change to lazy-load the component via React.lazy using a dynamic import (remove
the static import), and wrap this Route's element with a Suspense (or your app's
existing lazy wrapper) providing a small fallback so only this route is
code-split and the Settings bundle stays lean.
- 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.
- 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.
There was a problem hiding this comment.
Actionable comments posted: 9
♻️ Duplicate comments (1)
src/main/services/__tests__/FFmpegService.integration.test.ts (1)
135-153: Also assert download is NOT invoked when bundled exists.Strengthens the regression guard by verifying no side effects.
-const result = await ffmpegService.autoDetectAndDownload() +const ds = ffmpegService.getDownloadService() +const downloadSpy = vi.spyOn(ds, 'downloadFFmpeg') +const result = await ffmpegService.autoDetectAndDownload() @@ expect(result).toEqual({ available: true, needsDownload: false, downloadTriggered: false }) +expect(downloadSpy).not.toHaveBeenCalled()
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (2)
src/main/__tests__/ipc.database.test.ts(1 hunks)src/main/services/__tests__/FFmpegService.integration.test.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: 在组件/Hook 中避免硬编码尺寸和时长,优先使用 useTheme() 的 token(如 motionDurationMid、borderRadiusSM/MD 等)或集中定义的样式变量
定制 antd 组件样式时优先使用 styled-components(styled(Component) 包装),避免通过全局 SCSS 与全局 className 覆盖
项目使用 Zustand 结合 Immer 中间件与自定义中间件栈(持久化、DevTools、订阅选择器)进行状态管理
Files:
src/main/__tests__/ipc.database.test.tssrc/main/services/__tests__/FFmpegService.integration.test.ts
**/*.{tsx,ts}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{tsx,ts}: Zustand 必须在组件/Hook 顶层使用 selector(useStore(selector));禁止在 useMemo/useEffect 内部调用 store Hook
避免使用返回对象的 useStore 选择器(如 useStore(s => ({ a: s.a, b: s.b }))),应使用单字段选择器或配合 shallow 比较器
Files:
src/main/__tests__/ipc.database.test.tssrc/main/services/__tests__/FFmpegService.integration.test.ts
**/*.{test,spec}.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
测试使用 vitest 作为测试框架
Files:
src/main/__tests__/ipc.database.test.tssrc/main/services/__tests__/FFmpegService.integration.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx,js,jsx}: 统一使用 loggerService 记录日志,禁止使用 console
logger 使用示例:logger.error('Error in :', { error }); 第二个参数必须是对象字面量 {}
Files:
src/main/__tests__/ipc.database.test.tssrc/main/services/__tests__/FFmpegService.integration.test.ts
🧠 Learnings (1)
📚 Learning: 2025-09-07T16:43:49.564Z
Learnt from: CR
PR: mkdir700/EchoPlayer#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-07T16:43:49.564Z
Learning: Applies to **/*.{test,spec}.{ts,tsx,js,jsx} : 测试使用 vitest 作为测试框架
Applied to files:
src/main/services/__tests__/FFmpegService.integration.test.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: test (windows-latest, 20)
- GitHub Check: test (ubuntu-latest, 20)
- GitHub Check: test (macos-latest, 20)
🔇 Additional comments (1)
src/main/services/__tests__/FFmpegService.integration.test.ts (1)
33-45: Solid test harness setup.Uses vitest, isolates Electron paths, and resets mocks per test. LGTM.
| getFFmpegPath: vi.fn(), | ||
| getDownloadService: vi.fn(() => ({ | ||
| checkFFmpegExists: vi.fn(), | ||
| getFFmpegVersion: vi.fn(), | ||
| downloadFFmpeg: vi.fn(), | ||
| getDownloadProgress: vi.fn(), | ||
| cancelDownload: vi.fn(), | ||
| removeFFmpeg: vi.fn(), | ||
| getAllSupportedVersions: vi.fn(), | ||
| cleanupTempFiles: vi.fn() | ||
| })) |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
FFmpeg download service mock aligns; add contract verification to avoid drift.
Good addition; it unblocks IPC registration. To prevent silent breakage if IPC expects different shapes (async vs sync), verify callsites and consider pre-populating safe defaults if awaited.
Run to confirm the mocked API matches production usage:
Optionally, assert the full API shape during test setup to catch drift early.
🏁 Script executed:
#!/bin/bash
# Find usages of getDownloadService() and its methods
rg -nP -C2 --type=ts '(getDownloadService\(\))|(\b(ffmpegDownloadService|downloadService)\b\.)' src | sed -n '1,200p'Length of output: 5892
FFmpeg download service mock aligns with code usage — add a lightweight contract check.
rg output shows ipc handlers (src/main/ipc.ts) and FFmpegService (src/main/services/FFmpegService.ts) call: checkFFmpegExists, getFFmpegPath, getFFmpegVersion, downloadFFmpeg, getDownloadProgress, cancelDownload, removeFFmpeg, getAllSupportedVersions, cleanupTempFiles — all present in the test mock. Add a single test assertion that getDownloadService() returns these methods and stub async-returning methods to return Promises/expected shapes (e.g., getFFmpegVersion() -> { version: string }).
🤖 Prompt for AI Agents
In src/main/__tests__/ipc.database.test.ts around lines 169-179, the FFmpeg
download service mock lists all methods but the test lacks a lightweight
contract assertion and realistic async stubs; add a short assertion that
getDownloadService() returns an object with the named methods
(checkFFmpegExists, getFFmpegPath, getFFmpegVersion, downloadFFmpeg,
getDownloadProgress, cancelDownload, removeFFmpeg, getAllSupportedVersions,
cleanupTempFiles) and update the async-returning stubs to return
Promises/expected shapes (e.g., make getFFmpegVersion return Promise.resolve({
version: '0.0.0' }) and other async methods return resolved Promises or expected
objects) so the test verifies the contract used by ipc.ts and FFmpegService.
| vi.mock('path', () => ({ | ||
| join: vi.fn((...args) => args.join('/')), | ||
| dirname: vi.fn(), | ||
| basename: vi.fn() | ||
| })) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Avoid over-mocking path.join; use real path semantics to stay cross-platform.
Hardcoding POSIX join can mask Windows path issues. Prefer importing the real module and only spying if needed.
Apply:
-vi.mock('path', () => ({
- join: vi.fn((...args) => args.join('/')),
- dirname: vi.fn(),
- basename: vi.fn()
-}))
+// Use the real path module to preserve platform semantics
+const realPath = await vi.importActual<typeof import('path')>('path')
+vi.mock('path', () => realPath)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| vi.mock('path', () => ({ | |
| join: vi.fn((...args) => args.join('/')), | |
| dirname: vi.fn(), | |
| basename: vi.fn() | |
| })) | |
| // Use the real path module to preserve platform semantics | |
| const realPath = await vi.importActual<typeof import('path')>('path') | |
| vi.mock('path', () => realPath) |
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines 9
to 13, the test currently fully mocks the 'path' module and replaces path.join
with a POSIX-only implementation (args.join('/')), which hides Windows path
behavior; remove the full vi.mock of 'path' and instead import the real path
module and either stop mocking path.join entirely or use vi.spyOn(path, 'join')
if you need to assert calls, or explicitly use path.posix.join when POSIX
semantics are intended; ensure dirname/basename are not stubbed so real
cross-platform semantics are preserved and update assertions if they relied on
the mocked join output.
| vi.mock('electron', () => ({ | ||
| app: { | ||
| getPath: vi.fn(), | ||
| getAppPath: vi.fn(), | ||
| isPackaged: false | ||
| } | ||
| })) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Add packaged=true scenario to cover production paths.
Path resolution often differs in packaged apps; add a case toggling isPackaged.
Example:
it('should prefer bundled FFmpeg when available', () => {
@@
})
+it('should resolve paths correctly when app is packaged', () => {
+ vi.mocked(app.isPackaged as any) = true as any
+ vi.mocked(fs.existsSync).mockReturnValue(true)
+ vi.mocked(fs.statSync).mockReturnValue({ isFile: () => true } as any)
+ const path = ffmpegService.getFFmpegPath()
+ expect(path).toContain('ffmpeg')
+})Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines 14
to 20, the electron mock only covers the development path (isPackaged: false) so
production/path-resolution code isn't exercised; add a test scenario where
isPackaged is true by either creating a separate mock for electron with
isPackaged: true or parametrizing the mock per-test, and in that scenario stub
app.getPath and app.getAppPath to return production-like values and assert the
service resolves paths and behavior expected for packaged apps.
| vi.mock('child_process') | ||
| vi.mock('https') | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Remove unused mocks to reduce noise.
child_process and https aren’t used in this file.
-vi.mock('child_process')
-vi.mock('https')📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| vi.mock('child_process') | |
| vi.mock('https') |
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines 30
to 32, the test file contains vi.mock('child_process') and vi.mock('https')
which are unused and add noise; remove those two mock lines from the file so
only necessary mocks remain, run the tests to verify nothing else depends on
them, and commit the cleaned test file.
| it('should indicate download needed when no bundled FFmpeg', () => { | ||
| // Mock no bundled FFmpeg | ||
| vi.mocked(fs.existsSync).mockReturnValue(false) | ||
|
|
||
| const info = ffmpegService.getFFmpegInfo() | ||
|
|
||
| expect(info.isBundled).toBe(false) | ||
| expect(info.isSystemFFmpeg).toBe(true) | ||
| expect(info.needsDownload).toBe(true) | ||
| }) |
There was a problem hiding this comment.
Flaky: make getFFmpegInfo test deterministic wrt system FFmpeg.
If CI has ffmpeg on PATH, needsDownload may be false. Stub the system check.
-// Mock no bundled FFmpeg
-vi.mocked(fs.existsSync).mockReturnValue(false)
+// Mock no bundled FFmpeg and system ffmpeg not found
+vi.mocked(fs.existsSync).mockReturnValue(false)
+vi.spyOn(ffmpegService, 'checkFFmpegExists').mockResolvedValue(false)
@@
-expect(info.isSystemFFmpeg).toBe(true)
+expect(info.isSystemFFmpeg).toBe(false)
expect(info.needsDownload).toBe(true)Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines
87–96, the test assumes no system FFmpeg but doesn't stub the system-path check,
causing CI flakes when ffmpeg is on PATH; mock the helper the service uses to
detect system FFmpeg (the module/function that checks PATH or runs
`which/where`/`ffmpeg -version`) to return false for this test, and update the
assertions to expect isSystemFFmpeg to be false (and keep needsDownload true and
isBundled false) so the test is deterministic.
| const downloadService = ffmpegService.getDownloadService() | ||
| expect(downloadService).toBeDefined() | ||
| expect(typeof downloadService.checkFFmpegExists).toBe('function') | ||
| expect(typeof downloadService.downloadFFmpeg).toBe('function') | ||
| }) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Assert full download service surface to catch API drift.
Verify presence of all expected methods, not just two.
expect(downloadService).toBeDefined()
-expect(typeof downloadService.checkFFmpegExists).toBe('function')
-expect(typeof downloadService.downloadFFmpeg).toBe('function')
+;['checkFFmpegExists','getFFmpegVersion','downloadFFmpeg','getDownloadProgress',
+ 'cancelDownload','removeFFmpeg','getAllSupportedVersions','cleanupTempFiles'
+].forEach(k => expect(typeof (downloadService as any)[k]).toBe('function'))📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const downloadService = ffmpegService.getDownloadService() | |
| expect(downloadService).toBeDefined() | |
| expect(typeof downloadService.checkFFmpegExists).toBe('function') | |
| expect(typeof downloadService.downloadFFmpeg).toBe('function') | |
| }) | |
| const downloadService = ffmpegService.getDownloadService() | |
| expect(downloadService).toBeDefined() | |
| ;['checkFFmpegExists','getFFmpegVersion','downloadFFmpeg','getDownloadProgress', | |
| 'cancelDownload','removeFFmpeg','getAllSupportedVersions','cleanupTempFiles' | |
| ].forEach(k => expect(typeof (downloadService as any)[k]).toBe('function')) | |
| }) |
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines
171-175, the test only asserts two methods on downloadService; update it to
assert the full expected download service surface by defining an array of
expected method names (for example: "checkFFmpegExists", "downloadFFmpeg",
"getBinaryPath", "removeBinary", "cleanup") and iterating over that array to
assert each property is defined and typeof === 'function'; ensure the method
list matches the actual implementation/exported API and update the assertions
accordingly.
| it('should cleanup resources on destroy', async () => { | ||
| // Should not throw when destroying service | ||
| expect(async () => { | ||
| await ffmpegService.destroy() | ||
| }).not.toThrow() | ||
| }) |
There was a problem hiding this comment.
Fix async not.toThrow; current pattern can false-pass.
Use resolves to assert no rejection.
-expect(async () => {
- await ffmpegService.destroy()
-}).not.toThrow()
+await expect(ffmpegService.destroy()).resolves.toBeUndefined()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| it('should cleanup resources on destroy', async () => { | |
| // Should not throw when destroying service | |
| expect(async () => { | |
| await ffmpegService.destroy() | |
| }).not.toThrow() | |
| }) | |
| it('should cleanup resources on destroy', async () => { | |
| // Should not throw when destroying service | |
| await expect(ffmpegService.destroy()).resolves.toBeUndefined() | |
| }) |
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines
177-182, the test uses expect(async () => { await ffmpegService.destroy()
}).not.toThrow(), which can false-pass; replace this pattern by awaiting the
promise and asserting it resolves (e.g., await
expect(ffmpegService.destroy()).resolves.toBeUndefined()) so the test correctly
fails on rejection.
| describe('Error handling', () => { | ||
| it('should handle filesystem errors gracefully', () => { | ||
| vi.mocked(fs.existsSync).mockImplementation(() => { | ||
| throw new Error('Filesystem error') | ||
| }) | ||
|
|
||
| expect(() => { | ||
| const exists = ffmpegService.fastCheckFFmpegExists() | ||
| expect(exists).toBe(false) | ||
| }).not.toThrow() | ||
| }) | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Simplify error test; avoid expect inside not.toThrow.
Directly assert return value; any throw will fail the test.
-expect(() => {
- const exists = ffmpegService.fastCheckFFmpegExists()
- expect(exists).toBe(false)
-}).not.toThrow()
+expect(ffmpegService.fastCheckFFmpegExists()).toBe(false)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| describe('Error handling', () => { | |
| it('should handle filesystem errors gracefully', () => { | |
| vi.mocked(fs.existsSync).mockImplementation(() => { | |
| throw new Error('Filesystem error') | |
| }) | |
| expect(() => { | |
| const exists = ffmpegService.fastCheckFFmpegExists() | |
| expect(exists).toBe(false) | |
| }).not.toThrow() | |
| }) | |
| describe('Error handling', () => { | |
| it('should handle filesystem errors gracefully', () => { | |
| vi.mocked(fs.existsSync).mockImplementation(() => { | |
| throw new Error('Filesystem error') | |
| }) | |
| expect(ffmpegService.fastCheckFFmpegExists()).toBe(false) | |
| }) |
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines
215 to 226, the error-handling test wraps the assertion inside
expect(...).not.toThrow which is unnecessary and hides intent; replace the
wrapper with a direct call and assertion: keep the fs.existsSync mock that
throws, call ffmpegService.fastCheckFFmpegExists() directly, and assert that the
returned value is false (and remove the expect(() => { ... }).not.toThrow
wrapper).
| it('should handle missing download service gracefully', () => { | ||
| expect(() => { | ||
| const downloadService = ffmpegService.getDownloadService() | ||
| expect(downloadService).toBeDefined() | ||
| }).not.toThrow() | ||
| }) | ||
| }) |
There was a problem hiding this comment.
🧹 Nitpick (assertive)
Same here: remove unnecessary not.toThrow wrapper.
Keep it simple; call and assert.
-expect(() => {
- const downloadService = ffmpegService.getDownloadService()
- expect(downloadService).toBeDefined()
-}).not.toThrow()
+expect(ffmpegService.getDownloadService()).toBeDefined()📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| it('should handle missing download service gracefully', () => { | |
| expect(() => { | |
| const downloadService = ffmpegService.getDownloadService() | |
| expect(downloadService).toBeDefined() | |
| }).not.toThrow() | |
| }) | |
| }) | |
| it('should handle missing download service gracefully', () => { | |
| expect(ffmpegService.getDownloadService()).toBeDefined() | |
| }) | |
| }) |
🤖 Prompt for AI Agents
In src/main/services/__tests__/FFmpegService.integration.test.ts around lines
227 to 233, the test wraps calls in expect(() => { ... }).not.toThrow()
unnecessarily; simplify by invoking ffmpegService.getDownloadService() directly
and asserting the result is defined (e.g., const downloadService =
ffmpegService.getDownloadService(); expect(downloadService).toBeDefined())
without the not.toThrow wrapper.
…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.
…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.
# [1.0.0-alpha.10](v1.0.0-alpha.9...v1.0.0-alpha.10) (2025-09-13) ### Bug Fixes * **logger:** optimize logger memory management and reduce high-frequency logging ([#156](#156)) ([2462964](2462964)) * **subtitle:** resolve overlay pause/seek update delays with immediate state sync ([#153](#153)) ([cbd9432](cbd9432)) * **ui:** use system title bar for Windows and Linux platforms ([#158](#158)) ([0ddb189](0ddb189)) * **updater:** remove detailed release notes from system update dialog ([#152](#152)) ([9fea0be](9fea0be)) ### Features * add Windows ARM64 architecture support ([#157](#157)) ([4106908](4106908)) * **ffmpeg:** implement dynamic FFmpeg download system with runtime management ([#155](#155)) ([2c03521](2c03521))
…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.
…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.
…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.
# [1.0.0-beta.2](v1.0.0-beta.1...v1.0.0-beta.2) (2025-09-14) ### Bug Fixes * **logger:** optimize logger memory management and reduce high-frequency logging ([#156](#156)) ([64e36a2](64e36a2)) * **player:** persist relocated video file path to database ([#162](#162)) ([25bc32b](25bc32b)) * **subtitle:** resolve overlay pause/seek update delays with immediate state sync ([#153](#153)) ([582168f](582168f)) * **ui:** use system title bar for Windows and Linux platforms ([#158](#158)) ([ee435ce](ee435ce)) * **updater:** remove detailed release notes from system update dialog ([#152](#152)) ([996e76a](996e76a)) * **updater:** resolve pre-release version detection issue ([#161](#161)) ([3d90e67](3d90e67)) ### Features * add Windows ARM64 architecture support ([#157](#157)) ([30496b1](30496b1)) * **ffmpeg:** add China mirror support for FFmpeg downloads ([#164](#164)) ([61efdad](61efdad)) * **ffmpeg:** implement dynamic FFmpeg download system with runtime management ([#155](#155)) ([95dae5a](95dae5a)) ### BREAKING CHANGES * **ffmpeg:** 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
…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.
…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.
# 1.0.0 (2025-09-17) ### Bug Fixes * **build:** correct alpha channel update file naming ([#79](https://github.com/mkdir700/EchoPlayer/issues/79)) ([95e2ed2](https://github.com/mkdir700/EchoPlayer/commit/95e2ed262d6f29d2a645033089afe36a24afd56f)) * **build:** Fix FFmpeg cross-platform build on macOS for Windows targets ([#145](https://github.com/mkdir700/EchoPlayer/issues/145)) ([2a0b3a5](https://github.com/mkdir700/EchoPlayer/commit/2a0b3a5491a6906ce2714494dfd6f8954997d75e)) * **build:** 修复 Linux 构建产物架构命名转换问题 ([1f732ba](https://github.com/mkdir700/EchoPlayer/commit/1f732ba84ed69c803c6795c19ae7b5a2e11c3b70)) * **ci:** Failed to get next version ([a63caa3](https://github.com/mkdir700/EchoPlayer/commit/a63caa3acc7bbe2b31bedeaf58cb66ca9bbff009)) * **ci:** resolve duplicate GitHub releases issue ([#90](https://github.com/mkdir700/EchoPlayer/issues/90)) ([3e0117e](https://github.com/mkdir700/EchoPlayer/commit/3e0117eb2ad86af635915484090aafc4290422a5)) * **ci:** resolve GitHub Release creation issue with always publish strategy ([#85](https://github.com/mkdir700/EchoPlayer/issues/85)) ([712f0e8](https://github.com/mkdir700/EchoPlayer/commit/712f0e8cc8c11241678334c80e95f778055f57b2)) * **ci:** resolve semantic-release configuration issues ([#88](https://github.com/mkdir700/EchoPlayer/issues/88)) ([0a9e4a3](https://github.com/mkdir700/EchoPlayer/commit/0a9e4a3eb4501ade7aa25f377baab627de27b872)) * **ci:** resolve Windows build shell syntax compatibility issue ([#84](https://github.com/mkdir700/EchoPlayer/issues/84)) ([59b8460](https://github.com/mkdir700/EchoPlayer/commit/59b846044060a4c6ddd82c490c3c8706fe9daac7)) * **ci:** sync package.json version with manual trigger input ([#116](https://github.com/mkdir700/EchoPlayer/issues/116)) ([7008b6a](https://github.com/mkdir700/EchoPlayer/commit/7008b6a2f6a1369ab4ff1d547d517c4c537a82cb)) * **dictionary:** support pronunciation extraction without UK/US distinction ([#172](https://github.com/mkdir700/EchoPlayer/issues/172)) ([bfc6bb7](https://github.com/mkdir700/EchoPlayer/commit/bfc6bb754a1d9d840d67297d58c2d65799954cec)) * fix type check ([eae1e37](https://github.com/mkdir700/EchoPlayer/commit/eae1e378262d1f9162fd630cbb6dd867df933fb3)) * Fix TypeScript build errors and improve type safety ([#77](https://github.com/mkdir700/EchoPlayer/issues/77)) ([7861279](https://github.com/mkdir700/EchoPlayer/commit/7861279d8d5fd8c8e3bd5d5639f8e4b8f999b0ca)) * **homepage:** Fix UI desynchronization issue after deleting video records + i18n support ([#120](https://github.com/mkdir700/EchoPlayer/issues/120)) ([57b872d](https://github.com/mkdir700/EchoPlayer/commit/57b872dd7799d76ed8d0ff109663a9db4130f18b)) * improve release workflow and build configuration ([#91](https://github.com/mkdir700/EchoPlayer/issues/91)) ([2d9347f](https://github.com/mkdir700/EchoPlayer/commit/2d9347f6af5be076f439025e0468209df27770e0)) * **logger:** optimize logger memory management and reduce high-frequency logging ([#156](https://github.com/mkdir700/EchoPlayer/issues/156)) ([0a53c64](https://github.com/mkdir700/EchoPlayer/commit/0a53c641e34f1396576e8612bc0d249e6980e076)) * **player:** ensure video always starts paused and sync UI state correctly ([#102](https://github.com/mkdir700/EchoPlayer/issues/102)) ([83a0674](https://github.com/mkdir700/EchoPlayer/commit/83a067403e76f058e23a031cb5e96711441cf1d7)) * **player:** Fix subtitle navigation when activeCueIndex is -1 ([#119](https://github.com/mkdir700/EchoPlayer/issues/119)) ([05772a0](https://github.com/mkdir700/EchoPlayer/commit/05772a00010c9404291bf4e61b0a5e1b4617ccca)) * **player:** Fix subtitle overlay dragging to bottom and improve responsive design ([#122](https://github.com/mkdir700/EchoPlayer/issues/122)) ([a8a98db](https://github.com/mkdir700/EchoPlayer/commit/a8a98db1c355fa55dd8485f22b5e281cbd1c4069)) * **player:** improve play/pause button reliability ([#141](https://github.com/mkdir700/EchoPlayer/issues/141)) ([28f1156](https://github.com/mkdir700/EchoPlayer/commit/28f1156ff65798b73d4cfa57f9b65c33eb6996a5)) * **player:** improve subtitle overlay positioning and remove i18n dependencies ([#109](https://github.com/mkdir700/EchoPlayer/issues/109)) ([f7e8346](https://github.com/mkdir700/EchoPlayer/commit/f7e8346a8a7aa902eb6b5f9acfd0469888fd2ab5)) * **player:** integrate volume state in player engine context ([5ff32d9](https://github.com/mkdir700/EchoPlayer/commit/5ff32d91ce39d9499ae762ee433e61461e926c46)) * **player:** persist relocated video file path to database ([#162](https://github.com/mkdir700/EchoPlayer/issues/162)) ([bf76a18](https://github.com/mkdir700/EchoPlayer/commit/bf76a18faca7e80f74dd62d4d0e6c9f3369d3016)) * **player:** Prevent subtitle overlay interactions from triggering video play/pause ([#128](https://github.com/mkdir700/EchoPlayer/issues/128)) ([b1ae69c](https://github.com/mkdir700/EchoPlayer/commit/b1ae69cf934a8bff46ea4549fa6709896ac550a8)) * **player:** resolve focus loss after dictionary popup interaction ([#173](https://github.com/mkdir700/EchoPlayer/issues/173)) ([b2d577d](https://github.com/mkdir700/EchoPlayer/commit/b2d577d9b9787388e08c8bef98fa079120c35aae)) * **player:** resolve shortcut pause failure caused by state oscillation ([#174](https://github.com/mkdir700/EchoPlayer/issues/174)) ([6716c5b](https://github.com/mkdir700/EchoPlayer/commit/6716c5b6db4d558be1a4db70ad3e30f25ae2790d)), closes [#170](https://github.com/mkdir700/EchoPlayer/issues/170) * **player:** resolve spacebar shortcut not working after clicking to pause ([#182](https://github.com/mkdir700/EchoPlayer/issues/182)) ([3e46a69](https://github.com/mkdir700/EchoPlayer/commit/3e46a698ab08e9620c5c7dc4bff282658bc73e69)) * **release:** remove custom labels from GitHub release assets ([#92](https://github.com/mkdir700/EchoPlayer/issues/92)) ([848bace](https://github.com/mkdir700/EchoPlayer/commit/848bace4b659102a246a05518b8912c187fb730e)) * remove cheerio dependency to resolve Electron packaging issues - Remove cheerio and @types/cheerio from package.json dependencies - Replace cheerio-based HTML parsing with native regex implementation - Refactor parseEudicHtml() to parseEudicHtmlWithRegex() in dictionaryHandlers.ts - Support multiple HTML formats: list items, phonetics, examples, translations - Delete related test files that depend on cheerio - Fix TypeScript type errors for regex variables - Improve Electron runtime compatibility and reduce bundle size Fixes [#50](https://github.com/mkdir700/EchoPlayer/issues/50) ([b01fe4e](https://github.com/mkdir700/EchoPlayer/commit/b01fe4e33a0027d3c4fc6fdbb7e5577fb7f4165b)) * remove path unique constraint to allow duplicate video file addition ([#97](https://github.com/mkdir700/EchoPlayer/issues/97)) ([31c1486](https://github.com/mkdir700/EchoPlayer/commit/31c1486edd07fd34473f27b5e4110f42287cbf8a)) * **renderer:** resolve subsrt dynamic require issue in production build ([#78](https://github.com/mkdir700/EchoPlayer/issues/78)) ([028a8fb](https://github.com/mkdir700/EchoPlayer/commit/028a8fb9a9446ebb8dc7b25fb4a70fadc02fb085)) * resolve dead links in documentation and add missing pages ([fc36263](https://github.com/mkdir700/EchoPlayer/commit/fc3626305bdbf96c0efc70ae9d989ba02a0ededa)) * **subtitle:** improve ASS subtitle parsing for bilingual text ([#111](https://github.com/mkdir700/EchoPlayer/issues/111)) ([85b7f82](https://github.com/mkdir700/EchoPlayer/commit/85b7f82d40ce2008bfb91d6962f80eca51a22d55)) * **subtitle:** prevent overlay showing content during subtitle gaps ([#138](https://github.com/mkdir700/EchoPlayer/issues/138)) ([6f03bb8](https://github.com/mkdir700/EchoPlayer/commit/6f03bb849ecc0d9bc1de08502468ac6bc26694b4)) * **subtitle:** resolve overlay pause/seek update delays with immediate state sync ([#153](https://github.com/mkdir700/EchoPlayer/issues/153)) ([1672720](https://github.com/mkdir700/EchoPlayer/commit/1672720eb711f2d3741612915a6316016a6661cc)) * **test:** resolve SubtitleLibraryDAO schema validation and test framework improvements ([#80](https://github.com/mkdir700/EchoPlayer/issues/80)) ([4be2b8a](https://github.com/mkdir700/EchoPlayer/commit/4be2b8a390c454dc1b0287e352d15ceedb4ed67b)) * **titlebar:** keep title bar fixed at top during page scroll ([b3ff5c2](https://github.com/mkdir700/EchoPlayer/commit/b3ff5c2c6b5a8bea67da69b8e82c9200d5eb05fd)) * **ui:** Remove white border shadow from modal buttons in dark mode ([#124](https://github.com/mkdir700/EchoPlayer/issues/124)) ([eb22660](https://github.com/mkdir700/EchoPlayer/commit/eb22660417aa8a490be002a688f25890479a7915)) * **ui:** use system title bar for Windows and Linux platforms ([#158](https://github.com/mkdir700/EchoPlayer/issues/158)) ([4075b9c](https://github.com/mkdir700/EchoPlayer/commit/4075b9cfad7d33c203463f0a5ae473b55cb08041)) * **updater:** remove detailed release notes from system update dialog ([#152](https://github.com/mkdir700/EchoPlayer/issues/152)) ([f998d7b](https://github.com/mkdir700/EchoPlayer/commit/f998d7b4a48b14fe0b1c826226804ceba366f67e)) * **updater:** resolve auto-update channel handling and version-based test defaults ([#98](https://github.com/mkdir700/EchoPlayer/issues/98)) ([e92c7f0](https://github.com/mkdir700/EchoPlayer/commit/e92c7f07e946a1ddd0c257df9ca81868cd63d1b5)) * **updater:** resolve pre-release version detection issue ([#161](https://github.com/mkdir700/EchoPlayer/issues/161)) ([0afad9e](https://github.com/mkdir700/EchoPlayer/commit/0afad9ed9754ca500d84e9db6cf3670f578b9f75)) * **windows:** resolve file extension validation requiring double dots (.mp4 vs ..mp4) ([#126](https://github.com/mkdir700/EchoPlayer/issues/126)) ([91bab14](https://github.com/mkdir700/EchoPlayer/commit/91bab14afe7cc7aff0629f51e707995b01f98ce7)), closes [#118](https://github.com/mkdir700/EchoPlayer/issues/118) [#118](https://github.com/mkdir700/EchoPlayer/issues/118) * 优化文件路径处理逻辑以支持不同平台 ([dc4e1e3](https://github.com/mkdir700/EchoPlayer/commit/dc4e1e384588dac7e1aacc27eccf165fe2e43e4d)) * 修复 settings 相关组件找不到的问题 ([08f88ba](https://github.com/mkdir700/EchoPlayer/commit/08f88bad7099ac110a0bae109b3501a0348f0b78)) * 修复全屏模式下速度选择窗口溢出的问题 ([6309046](https://github.com/mkdir700/EchoPlayer/commit/63090466881d8df3e5dc062c0f235995dfe4134e)) * 修复在 Windows 上的 FFmpeg 文件下载和 ZIP 解压 ([6347b4e](https://github.com/mkdir700/EchoPlayer/commit/6347b4e62207dc104a1fa44f27af08667ff893a2)) * 修复在启用单句循环模式下,无法调整到下一句的问题 ([ec479be](https://github.com/mkdir700/EchoPlayer/commit/ec479beeff5c931821eed5aaffeaa054226b13c2)) * 修复文件路径处理逻辑以支持不同的 file URL 前缀 ([740015d](https://github.com/mkdir700/EchoPlayer/commit/740015d955f8266b96d2aa49bdc244d084937355)) * 修复方向键冲突检测问题 ([4a466c7](https://github.com/mkdir700/EchoPlayer/commit/4a466c7367860120d9a4ccc6f23ab5e79a2d8cae)) * 修复无法通过按钮退出全屏模式的问题 ([e69562b](https://github.com/mkdir700/EchoPlayer/commit/e69562b9ead8ea66c0933ad21b5cbeae3d88142f)) * 修复构建产物架构冲突问题 ([2398bd7](https://github.com/mkdir700/EchoPlayer/commit/2398bd78be4526a9f3f636c8f945df644bbc3d5b)) * 修复组件导出语句和优化字幕加载逻辑,移除未使用的状态 ([39708ce](https://github.com/mkdir700/EchoPlayer/commit/39708ce48bd6652488abce7d21752a2afe994d99)) * 删除上传到 cos 的步骤,因为网络波动问题上传失败 ([1cac918](https://github.com/mkdir700/EchoPlayer/commit/1cac918f21ad3198827138512ee61d770bd1367f)) * 在 UpdateNotification 组件中添加关闭对话框的逻辑,确保用户在操作后能够顺利关闭对话框 ([845a070](https://github.com/mkdir700/EchoPlayer/commit/845a070ac74b513ce5bda3cdc3d3e7a803a3b8d1)) * 始终在脚本直接执行时运行主函数,确保功能正常 ([a15378a](https://github.com/mkdir700/EchoPlayer/commit/a15378a914e54967f50642e04a111af184255344)) * 忽略依赖项警告 ([fc3f038](https://github.com/mkdir700/EchoPlayer/commit/fc3f038bb7d9b7e6962a5346bee00c858998ade0)) * 更新主题样式,使用 token 中的 zIndex 替代硬编码值 ([3940caf](https://github.com/mkdir700/EchoPlayer/commit/3940caf3b768efcba2043b3734bc7c7962f8c5a8)) * 更新测试文件中的 useTheme 和 useVideoPlaybackHooks 的路径 ([4fa9758](https://github.com/mkdir700/EchoPlayer/commit/4fa9758ae7bcb26789e8a458312ef23d577a34e6)) * 移除构建和发布工作流中的空选项,始终将草稿发布设置为 true,以确保发布过程的一致性 ([171028a](https://github.com/mkdir700/EchoPlayer/commit/171028adff214b3c696b7aaacb617c7c41b0302b)) ### Features * add API communication type definitions and unified export ([ea9f1c0](https://github.com/mkdir700/EchoPlayer/commit/ea9f1c0690d3b7fe5f6a2e2406b5fb88817aa8d1)) * add common base type definitions and interfaces for application ([73bd604](https://github.com/mkdir700/EchoPlayer/commit/73bd6046239341716eea727d95b316e9a3652ec8)) * add debounce hooks and corresponding tests ([7646088](https://github.com/mkdir700/EchoPlayer/commit/7646088b78106e40f00ff15a3cdd86b44aa541cc)) * add domain type definitions and constants for video, subtitle, playback, and UI ([a1c3209](https://github.com/mkdir700/EchoPlayer/commit/a1c3209271336891e0e9dbde444abc8c4e7d8e4b)) * add git hooks with lint-staged for automated code quality checks ([1311af9](https://github.com/mkdir700/EchoPlayer/commit/1311af96159b7e7b5d31f43f27f479cc9035d5a5)) * add handler to read directory contents ([6ce1d9e](https://github.com/mkdir700/EchoPlayer/commit/6ce1d9eff64968cef3a5673a67f8753de582d501)) * add IPC Client Service implementation with integration tests ([fe4400f](https://github.com/mkdir700/EchoPlayer/commit/fe4400ff63ff0640f32ca94f0b4d0d4c47b246ed)) * add performance optimization hooks and corresponding tests ([d7e1d0f](https://github.com/mkdir700/EchoPlayer/commit/d7e1d0f006dfe8c6c58a20bb0305621a657c9a65)) * add selectors for subtitle, UI, and video states with computed properties and hooks ([c64f41d](https://github.com/mkdir700/EchoPlayer/commit/c64f41dd27496bd311ff588474041e4ebacbd3a9)) * Add service layer type definitions for storage, video, subtitle, and dictionary services ([c658217](https://github.com/mkdir700/EchoPlayer/commit/c658217a5acc7e8a066004e6d7c1cd103be43a3b)) * add subtitle, UI, and video state actions for V2 ([1a4042a](https://github.com/mkdir700/EchoPlayer/commit/1a4042af3e1e917d6303a560c49e4aa8d52300ab)) * add unified export for V2 infrastructure layer type system ([ad94ea8](https://github.com/mkdir700/EchoPlayer/commit/ad94ea849bc17b5e569bd2296cf73c30ca06747d)) * add V2 state stores with type-safe validation and comprehensive documentation ([264cc66](https://github.com/mkdir700/EchoPlayer/commit/264cc661c2be83c9d886ba673d104b499ade0729)) * add Windows ARM64 architecture support ([#157](https://github.com/mkdir700/EchoPlayer/issues/157)) ([3d5152d](https://github.com/mkdir700/EchoPlayer/commit/3d5152dcfd11e59cdc81ebbd93d91cd11b056af6)) * **api:** add request and response type definitions for video, subtitle, file operations, and playback settings ([c0e9324](https://github.com/mkdir700/EchoPlayer/commit/c0e9324642d6920def8dcb79a97c92ab0f552397)) * **AutoResumeCountdown:** add auto-dismissal when playback manually resumed ([3852bca](https://github.com/mkdir700/EchoPlayer/commit/3852bca30af23c203698bc413e0b482a595c96d6)) * **ci:** add alpha and beta branch support to test workflow ([#94](https://github.com/mkdir700/EchoPlayer/issues/94)) ([f3cb1aa](https://github.com/mkdir700/EchoPlayer/commit/f3cb1aa1219f13721ad3169f8fd3ef45ba5b938d)) * **ci:** add dynamic workflow names to show release version in actions list ([#115](https://github.com/mkdir700/EchoPlayer/issues/115)) ([5742ac8](https://github.com/mkdir700/EchoPlayer/commit/5742ac893549dc148085fbb2c519013faeb5a1b2)) * **ci:** configure CodeRabbit for alpha, beta, and main branch PR reviews ([#108](https://github.com/mkdir700/EchoPlayer/issues/108)) ([074e94d](https://github.com/mkdir700/EchoPlayer/commit/074e94d23d9622adf588ffc659b60a6b24a15aac)) * **ci:** implement semantic-release with automatic version detection ([#117](https://github.com/mkdir700/EchoPlayer/issues/117)) ([39b69fd](https://github.com/mkdir700/EchoPlayer/commit/39b69fd6592c91c24440ad1affd49f82dcc40cf0)) * **ci:** implement semantic-release with three-branch strategy ([#89](https://github.com/mkdir700/EchoPlayer/issues/89)) ([5c6d4c5](https://github.com/mkdir700/EchoPlayer/commit/5c6d4c5a44b39e7b4b9199bb482547e225bc1994)) * **ci:** integrate semantic-release automation with GitHub workflow ([#87](https://github.com/mkdir700/EchoPlayer/issues/87)) ([874bd5a](https://github.com/mkdir700/EchoPlayer/commit/874bd5a0987c5944c14926230b32a49b4886158b)) * **ci:** migrate from action-gh-release to native electron-builder publishing ([#82](https://github.com/mkdir700/EchoPlayer/issues/82)) ([eab9ba1](https://github.com/mkdir700/EchoPlayer/commit/eab9ba1f1d8cc55d4cf6e7e6c3c8633b02938715)) * comprehensive auto-update system implementation ([#73](https://github.com/mkdir700/EchoPlayer/issues/73)) ([0dac065](https://github.com/mkdir700/EchoPlayer/commit/0dac065d54643bc761c741bae914057b9784e419)) * **ControllerPanel:** add disabled state for Loop and AutoPause controls when subtitles are empty ([a35f3e6](https://github.com/mkdir700/EchoPlayer/commit/a35f3e6cbf5c33ee4ebc6ca21dfb31a5b2b1b1a6)) * **ControllerPanel:** implement centralized menu management system for player controls ([1523758](https://github.com/mkdir700/EchoPlayer/commit/152375846dc6d5acf84d07a0d182160e29de4358)) * **db:** implement complete SQLite3 database layer with migrations and DAOs ([0a8a7dd](https://github.com/mkdir700/EchoPlayer/commit/0a8a7ddb5a240c6d6c145b4cfa0790e2292d3697)) * **db:** migrate from Dexie to Kysely with better-sqlite3 backend ([6b75cd8](https://github.com/mkdir700/EchoPlayer/commit/6b75cd877bd117b84d6205eb1c680450042b6eaa)) * define domain types for video, subtitle, and UI, and refactor RecentPlayItem interface imports ([f632beb](https://github.com/mkdir700/EchoPlayer/commit/f632beba5f9b20afb2ec6fc8e6df7dcba6fd29f0)) * **dictionary:** expose DictionaryService API in preload and add comprehensive tests ([#143](https://github.com/mkdir700/EchoPlayer/issues/143)) ([58fe719](https://github.com/mkdir700/EchoPlayer/commit/58fe7192dff218488b91258f974daa1430427710)) * enhance macOS build configuration with additional entitlements and notarization support ([d6e8ced](https://github.com/mkdir700/EchoPlayer/commit/d6e8ced7611b9f09743bc29344c6a0020ed0b19d)) * **ffmpeg:** add China mirror support for FFmpeg downloads ([#164](https://github.com/mkdir700/EchoPlayer/issues/164)) ([8a53634](https://github.com/mkdir700/EchoPlayer/commit/8a53634c59c602acdde9f60c7982e3a369a634a0)) * **ffmpeg:** implement dynamic FFmpeg download system with runtime management ([#155](https://github.com/mkdir700/EchoPlayer/issues/155)) ([161c8c7](https://github.com/mkdir700/EchoPlayer/commit/161c8c744e7ea0647f61e1c00021843d26d4c19a)) * **ffmpeg:** integrate bundled FFmpeg with automatic fallback mechanism ([#112](https://github.com/mkdir700/EchoPlayer/issues/112)) ([e826ad2](https://github.com/mkdir700/EchoPlayer/commit/e826ad2b0066c39b9599807b4ff830fb5646d93f)) * **home:** implement empty state with video file selection integration ([b6f6e40](https://github.com/mkdir700/EchoPlayer/commit/b6f6e401f622f1390926eb154f47fad812d5d0a7)) * implement Ctrl+C subtitle copy with lightweight toast notification ([#140](https://github.com/mkdir700/EchoPlayer/issues/140)) ([e497f86](https://github.com/mkdir700/EchoPlayer/commit/e497f86cf3049634b0e7338f46766d5a2f2bf824)), closes [#142](https://github.com/mkdir700/EchoPlayer/issues/142) * Implement dictionary engine framework ([0d74a83](https://github.com/mkdir700/EchoPlayer/commit/0d74a8315f86209c530ad2f306b6099e97328c1f)) * implement useThrottle hooks and corresponding tests ([da30344](https://github.com/mkdir700/EchoPlayer/commit/da303443b6847fe049be9c4592c98418aeea9785)) * implement version parsing and channel mapping logic ([8c95a2f](https://github.com/mkdir700/EchoPlayer/commit/8c95a2feeef1d066fb46f246724d8a94014fa627)) * **infrastructure:** add entry points for constants and shared modules, and refine video playback rate type ([94da255](https://github.com/mkdir700/EchoPlayer/commit/94da2556dd6909eec75d4edfe2b549e3858e2629)) * **logger:** export logger instance for easier access in modules ([5328152](https://github.com/mkdir700/EchoPlayer/commit/5328152999408cbec0515e501aea9f393032b933)) * **performance:** implement video import performance optimization with parallel processing and warmup strategies ([#121](https://github.com/mkdir700/EchoPlayer/issues/121)) ([e7fa955](https://github.com/mkdir700/EchoPlayer/commit/e7fa955d61fe42c7e4dd262a9ca47240d2871efc)) * **persistence:** add V2 state persistence manager and configuration files ([a545020](https://github.com/mkdir700/EchoPlayer/commit/a545020f3f676b526b3f3bf3ecff6d23c4c1a471)) * **playback:** update playback rate label for clarity and add storage type definitions ([5c40b98](https://github.com/mkdir700/EchoPlayer/commit/5c40b983ea22c1e57e5e678922c5d6492a39359c)) * player page ([aa79279](https://github.com/mkdir700/EchoPlayer/commit/aa792799580524ac65c8bf7e4d9bc7e13988a716)) * **player,logging,state:** orchestrated player engine with intent strategies and new controller panel ([73d7cfd](https://github.com/mkdir700/EchoPlayer/commit/73d7cfdc4b58f190afe8981eddadbca54c6763b0)) * **player:** add Ctrl+] shortcut for subtitle panel toggle ([#69](https://github.com/mkdir700/EchoPlayer/issues/69)) ([e1628f2](https://github.com/mkdir700/EchoPlayer/commit/e1628f2d04ea03cac20893960a3a9fec2dd9fdb2)) * **player:** comprehensive dictionary popover with pronunciation and theme support ([#171](https://github.com/mkdir700/EchoPlayer/issues/171)) ([1987f61](https://github.com/mkdir700/EchoPlayer/commit/1987f61128f2d6cdb23ac4741d6e64cf6dda1867)) * **player:** hide sidebar and optimize navbar for player page ([#70](https://github.com/mkdir700/EchoPlayer/issues/70)) ([5bb71e4](https://github.com/mkdir700/EchoPlayer/commit/5bb71e4465721c3b1f0dc326f9a92e879e1c048b)) * **player:** implement auto-resume countdown with UI notification ([5468f65](https://github.com/mkdir700/EchoPlayer/commit/5468f6531c3e2f3d8aaf94f631ec4f760d04241f)) * **player:** implement comprehensive video error recovery ([#113](https://github.com/mkdir700/EchoPlayer/issues/113)) ([1e27033](https://github.com/mkdir700/EchoPlayer/commit/1e27033a7306670dd12641d172cc85522ee8627f)) * **player:** implement favorite playback rates with hover menu system ([#100](https://github.com/mkdir700/EchoPlayer/issues/100)) ([c742fab](https://github.com/mkdir700/EchoPlayer/commit/c742fab019e9f34f0504866372fe4f55db091cce)) * **player:** Implement fullscreen toggle functionality with keyboard shortcuts ([#127](https://github.com/mkdir700/EchoPlayer/issues/127)) ([586b064](https://github.com/mkdir700/EchoPlayer/commit/586b06472aa6f2d085716800e883eb6ca9d5de86)) * **player:** implement hover menu system for control panel components ([#99](https://github.com/mkdir700/EchoPlayer/issues/99)) ([de2363a](https://github.com/mkdir700/EchoPlayer/commit/de2363a3269bacbe5159228399335fd037a2e060)) * **player:** implement volume wheel control with intelligent acceleration ([#105](https://github.com/mkdir700/EchoPlayer/issues/105)) ([351439b](https://github.com/mkdir700/EchoPlayer/commit/351439b3e3bb7b5e3f2b23bf287ca7190fc0570d)) * **player:** reposition progress bar between video and controls ([#71](https://github.com/mkdir700/EchoPlayer/issues/71)) ([248feed](https://github.com/mkdir700/EchoPlayer/commit/248feed534974b6c05ef2918a3758ae5fed1f42d)) * refine RecentPlayItem interface with detailed video info and playback metrics ([81679b6](https://github.com/mkdir700/EchoPlayer/commit/81679b6eb54f7a8f07a33065c743fa51d1eecc5d)) * replace FFmpeg with MediaInfo for video metadata extraction ([#95](https://github.com/mkdir700/EchoPlayer/issues/95)) ([6326c80](https://github.com/mkdir700/EchoPlayer/commit/6326c8031e8411a61e434dff7596d835b6c67656)) * **scripts:** optimize FFmpeg download progress display ([#125](https://github.com/mkdir700/EchoPlayer/issues/125)) ([992c233](https://github.com/mkdir700/EchoPlayer/commit/992c233722eba9c2f8f7a3fe785267c91c10edd3)) * **search:** implement video search engine with live results and highlighting ([#110](https://github.com/mkdir700/EchoPlayer/issues/110)) ([e459afa](https://github.com/mkdir700/EchoPlayer/commit/e459afa0319632b32e6b80405a16fe154c61e5cb)) * setup GitHub Pages deployment for documentation ([b8a42b9](https://github.com/mkdir700/EchoPlayer/commit/b8a42b974d7490ddddb4292608315a58df14a24b)) * **sidebar:** 禁用收藏按钮并添加开发中提示 ([#81](https://github.com/mkdir700/EchoPlayer/issues/81)) ([76e9b54](https://github.com/mkdir700/EchoPlayer/commit/76e9b5418ec5f07f4d3052d8130163d108965f47)) * **SplashScreen:** add animated splash screen with typewriter effect and smooth transitions ([31cfeca](https://github.com/mkdir700/EchoPlayer/commit/31cfeca9f0773db12b9a7b299820a32c309d9daf)) * **startup:** implement configurable startup intro with preloading optimization ([#104](https://github.com/mkdir700/EchoPlayer/issues/104)) ([7964b51](https://github.com/mkdir700/EchoPlayer/commit/7964b51dc3897690e6244df5f3270934bc24a758)) * **state.store:** 新增多个 store ([54e7ff5](https://github.com/mkdir700/EchoPlayer/commit/54e7ff5993631c6133e21948c2697bcd13919df6)) * **state:** implement V2 state management infrastructure with storage engine, middleware, and utility functions ([e225746](https://github.com/mkdir700/EchoPlayer/commit/e22574659d1ec63fbc622152fec2371323b4fe53)) * **storage:** implement application configuration storage service ([1209b56](https://github.com/mkdir700/EchoPlayer/commit/1209b56fae690a9876440faa679f072cb2ebc6da)) * **subtitle-library:** Add subtitle data caching for improved loading performance ([#86](https://github.com/mkdir700/EchoPlayer/issues/86)) ([40be325](https://github.com/mkdir700/EchoPlayer/commit/40be325f09f9f70e702260dfe29e354c6c7435b6)) * **SubtitleContent:** implement word-level tokenization and interactive text selection ([10c0cdf](https://github.com/mkdir700/EchoPlayer/commit/10c0cdf38fdbad53bfba4b82148b635e45657b11)) * **telemetry:** integrate Sentry error monitoring across main and renderer processes ([#175](https://github.com/mkdir700/EchoPlayer/issues/175)) ([f71c2da](https://github.com/mkdir700/EchoPlayer/commit/f71c2da5c140398f5d3e4bb17ff9cafddb846adf)) * **types:** add Serializable interface for flexible data structures ([32981df](https://github.com/mkdir700/EchoPlayer/commit/32981df183af23d9153ae65765b9d1c8a533540e)) * **ui:** enhance video selection clarity and simplify display ([#101](https://github.com/mkdir700/EchoPlayer/issues/101)) ([051ed71](https://github.com/mkdir700/EchoPlayer/commit/051ed7113d16d9b890a617d1e248d7cdd87525be)) * update macOS notarization configuration to enable automatic notarization ([6630e79](https://github.com/mkdir700/EchoPlayer/commit/6630e79975a5d39eea83bec44ef1ff0271c984da)) * **updater:** integrate China-specific feed URLs for better update experience ([#177](https://github.com/mkdir700/EchoPlayer/issues/177)) ([4111cfb](https://github.com/mkdir700/EchoPlayer/commit/4111cfb4bf0db355177e58e5bbe5dd1c64516ae7)) * **video.store:** add format property to CurrentVideoState and update video loading simulation ([0349a63](https://github.com/mkdir700/EchoPlayer/commit/0349a6351ba8fa2a1235a48b268825ad18ea37ff)) * **VolumeControl:** change volume popup from horizontal to vertical layout ([d4d435b](https://github.com/mkdir700/EchoPlayer/commit/d4d435b93a72b8bb8e1f9d4fe356fa41632d8993)) * **workflow:** auto-fetch GitHub release description when manual trigger without description ([#179](https://github.com/mkdir700/EchoPlayer/issues/179)) ([9a9d932](https://github.com/mkdir700/EchoPlayer/commit/9a9d932c7644a5be08619c709e2f67153aa01324)) * **wsl:** add WSL detection and hardware acceleration optimization ([c99403e](https://github.com/mkdir700/EchoPlayer/commit/c99403efa8af9fa9ebf106edcbdc4a0d21b31b2e)) * 为字幕组件新增右键菜单功能 ([62334d5](https://github.com/mkdir700/EchoPlayer/commit/62334d56bb0956b28582d5d70e7ea0a3c2f9e42d)) * 为音量控制组件添加音量调节快捷键 ([144d49c](https://github.com/mkdir700/EchoPlayer/commit/144d49c314688c6b7b0abbdd0c21f57c98f3084d)) * 优化 PlayPage 组件性能,减少不必要的重新渲染;重构播放状态管理逻辑,提升用户体验 ([24a2ebc](https://github.com/mkdir700/EchoPlayer/commit/24a2ebc6d7c040ffce5ffc1a404f338ad77a6791)) * 优化最近观看记录加载状态显示 ([e5f7e11](https://github.com/mkdir700/EchoPlayer/commit/e5f7e11498d52028cf20765ea2fe486cca49f3d1)) * 优化单词查询逻辑,增加超时处理和取消请求功能,提升用户体验和性能 ([c98dc4b](https://github.com/mkdir700/EchoPlayer/commit/c98dc4b5d65bdc7c68d82f6e0c1bcda248929503)) * 优化字幕列表滚动体验 ([63807c5](https://github.com/mkdir700/EchoPlayer/commit/63807c5a4a668d5000c7c920dcae5eb96623314e)) * 优化字幕控制功能,新增字幕模式选择器,提升用户交互体验;重构相关组件,移除不必要的代码,简化逻辑 ([559aada](https://github.com/mkdir700/EchoPlayer/commit/559aada0c7d224bdbc941b30aa9da71b08d84636)) * 优化字幕文本分段逻辑 ([33e591c](https://github.com/mkdir700/EchoPlayer/commit/33e591c08ac1d520886b20b2b0219e15eeea1d0d)) * 优化字幕模式选择器组件,增强用户体验和视觉一致性,添加响应式设计和毛玻璃效果 ([4b59a1b](https://github.com/mkdir700/EchoPlayer/commit/4b59a1b0ac1d3a66dfd0c129177f2820722f2416)) * 优化快捷键设置界面,增强输入状态反馈,更新样式以提升用户体验和一致性 ([64db31c](https://github.com/mkdir700/EchoPlayer/commit/64db31cd8112b08f509e16ef653f687381f5f636)) * 优化日志记录功能,新增组件渲染节流和数据简化处理,提升性能和可读性 ([a6e8480](https://github.com/mkdir700/EchoPlayer/commit/a6e8480ecb2458eefd899d0828af3955f3cbef6e)) * 优化标题栏平台信息处理 ([fb5a470](https://github.com/mkdir700/EchoPlayer/commit/fb5a470084ed46f6f662e060d4cbca89fca1736e)) * 优化视频卡片和视频网格组件的样式与布局 ([af59b44](https://github.com/mkdir700/EchoPlayer/commit/af59b44aa7cefeb06dfd87656532af3652013574)) * 优化词典查询逻辑,增加未找到释义时的警告提示,并调整相关代码结构 ([9f528bd](https://github.com/mkdir700/EchoPlayer/commit/9f528bd89e905af2490c9c1b2db3d9a00b19e1f8)) * 优化进度条handler显示和对齐 ([77d0496](https://github.com/mkdir700/EchoPlayer/commit/77d04965d4ac4aa2bfff965fe2852c82d9e4c91e)) * 在 FullscreenTestInfo 组件中新增折叠功能 ([b2eac46](https://github.com/mkdir700/EchoPlayer/commit/b2eac461e616b3da6be84ceabaffd08c583d1b59)) * 在 HomePage 组件中新增音频兼容性诊断功能,优化视频播放体验;更新视频兼容性报告以支持音频编解码器检测;重构相关逻辑以提升代码可读性和维护性 ([3cac307](https://github.com/mkdir700/EchoPlayer/commit/3cac307f50c791b2f4f76b3e0aec7571d4e30a98)) * 在 SubtitleListContent 组件中引入 rc-virtual-list 以优化字幕列表渲染性能,增强自动滚动功能 ([30165dc](https://github.com/mkdir700/EchoPlayer/commit/30165dcf42f2770be23392f6c6d07a8d1786f95f)) * 在 UpdatePromptDialog 组件中添加内容展开/折叠功能 ([96d9b1f](https://github.com/mkdir700/EchoPlayer/commit/96d9b1f32b15abea3661836a684e177e774b80e5)) * 在构建和发布工作流中添加Windows、Mac和Linux平台的上传步骤,优化版本变量设置和上传路径逻辑 ([3cfacb9](https://github.com/mkdir700/EchoPlayer/commit/3cfacb91cd3c60428af09bdb1b1ed74be1538e29)) * 在构建和发布工作流中添加更新 package.json 版本的步骤,确保版本号自动更新;优化草稿发布条件以支持预发布版本 ([a78fbc7](https://github.com/mkdir700/EchoPlayer/commit/a78fbc72166e08eeec641c0970eebf83763aba39)) * 在构建和发布工作流中添加测试构建选项,更新版本变量设置和上传路径逻辑 ([2848f92](https://github.com/mkdir700/EchoPlayer/commit/2848f92f7216dee720d84608ffce2840f5f67bcd)) * 在视频上传时重置字幕控制状态,新增重置状态功能;更新快捷键设置以支持单句循环功能,优化用户体验 ([688dcd6](https://github.com/mkdir700/EchoPlayer/commit/688dcd6e7ddfe43499035fd828bcf26f04e08d79)) * 增强全屏模式下的样式支持 ([94a77b1](https://github.com/mkdir700/EchoPlayer/commit/94a77b1166173b73789d14daaba12d0b7de2790a)) * 增强全屏模式的快捷键支持 ([218882c](https://github.com/mkdir700/EchoPlayer/commit/218882cdbdd597dff7cf41df3dac9e0587b43dd0)) * 增强字幕显示组件,新增中文字符检测和智能文本分割功能,优化用户交互体验 ([8cd50d9](https://github.com/mkdir700/EchoPlayer/commit/8cd50d9df0e2884f27187bb0df66a2f0f3c232b2)) * 增强字幕空状态组件,支持拖拽文件导入 ([db1f608](https://github.com/mkdir700/EchoPlayer/commit/db1f60833f27b75594790387c0382cc30abd28fe)) * 增强字幕组件交互功能 ([3e7e8c7](https://github.com/mkdir700/EchoPlayer/commit/3e7e8c74651da43cbcd5e525ba76324e6c403fd8)) * 增强字幕组件和文本选择功能 ([36c44aa](https://github.com/mkdir700/EchoPlayer/commit/36c44aae0884e22030aae37db7424ac92e3f2c60)) * 增强快捷键设置功能,新增快捷键冲突检查和平台特定符号显示,优化用户输入体验和界面样式 ([bde034b](https://github.com/mkdir700/EchoPlayer/commit/bde034bccab0dec6dbeb305fd5c4b7aca76caa91)) * 增强更新通知系统,添加红点提示和用户交互逻辑 ([fdf4c81](https://github.com/mkdir700/EchoPlayer/commit/fdf4c811e2cf2611319adc6b706e12b5510fe5c8)) * 增强版本比较逻辑,优化更新通知系统 ([f29a25f](https://github.com/mkdir700/EchoPlayer/commit/f29a25fc4d9859375654c8c3e1f532224e8e3049)) * 增强视频兼容性模态框功能,支持初始步骤和分析结果 ([3aba45c](https://github.com/mkdir700/EchoPlayer/commit/3aba45c3464151598c1b8400c8e14d2c612f53bf)) * 多平台构建和发布 ([cc521ea](https://github.com/mkdir700/EchoPlayer/commit/cc521ea8befde2b839810292e93475a806db4dd1)) * 实现动态 electron-updater 渠道配置 ([28d2836](https://github.com/mkdir700/EchoPlayer/commit/28d28360a4e5cee11603cd68f959098d4e40ca0b)), closes [#3](https://github.com/mkdir700/EchoPlayer/issues/3) * 将发布提供者从 generic 更改为 github,更新仓库和所有者信息,以支持自动更新功能 ([b6d4076](https://github.com/mkdir700/EchoPlayer/commit/b6d4076ff094f31d5f4eedf08e6b943f41f5fed6)) * 引入常量以支持视频容器格式检查 ([da68183](https://github.com/mkdir700/EchoPlayer/commit/da681831b60f4655b72731fd1ba34e5550149543)) * 新增 AimButton 组件以支持手动定位当前字幕并启用自动滚动;更新 SubtitleListContent 组件以集成 AimButton,优化用户滚动体验与字幕自动滚动逻辑 ([3c8a092](https://github.com/mkdir700/EchoPlayer/commit/3c8a09208d773f7a7e5d86bfb6a7ef26cfadf444)) * 新增 AppHeader 组件并更新样式,调整导航菜单布局以提升用户体验 ([94e35c3](https://github.com/mkdir700/EchoPlayer/commit/94e35c30ff96b534046190cbd654097f0b960095)) * 新增 cmd-reason.mdc 文件并更新 cmd-refactor-theme.mdc 规则 ([43d2222](https://github.com/mkdir700/EchoPlayer/commit/43d22225b7dd3546a90aec05ee5efb2dd158c8f6)) * 新增 E2E 测试用例和文件选择器助手 ([9928349](https://github.com/mkdir700/EchoPlayer/commit/99283494eddf4612fa0d9434473974337045b052)) * 新增 git commit 内容生成规则文件 ([6e0ee23](https://github.com/mkdir700/EchoPlayer/commit/6e0ee238be5d22aed2e23bf8cb4f51d5918d2a51)) * 新增主题系统 ([369d828](https://github.com/mkdir700/EchoPlayer/commit/369d828232f0e07d1212e750b961871fe8024a3f)) * 新增全屏模式支持 ([e8c9542](https://github.com/mkdir700/EchoPlayer/commit/e8c9542fef5766a048bd1fa65f11858cf1a44e7e)) * 新增全屏视频进度条组件并重构视频控制逻辑 ([7fc587f](https://github.com/mkdir700/EchoPlayer/commit/7fc587f93312c6d34869543ffab8153a20aa2975)) * 新增划词选中和快捷复制功能 ([9e22b44](https://github.com/mkdir700/EchoPlayer/commit/9e22b44a921ddea67f1ee95931c65116c619a9c2)) * 新增单词卡片组件,支持单词点击后显示详细信息和发音功能;优化字幕显示样式,提升用户交互体验 ([c6a4ab6](https://github.com/mkdir700/EchoPlayer/commit/c6a4ab6446e9ebc9e55d46b52d84e93987673706)) * 新增字幕列表上下文及相关钩子,重构播放页面以使用新的字幕管理逻辑,提升代码可读性与功能性 ([7766b74](https://github.com/mkdir700/EchoPlayer/commit/7766b74f5b7d472c94e78678f685ae1934e9c617)) * 新增字幕列表项样式并禁用焦点样式 ([654a0d1](https://github.com/mkdir700/EchoPlayer/commit/654a0d1d6581749a8c651d322444df60252dff38)) * 新增字幕布局锁定功能 ([82e75dc](https://github.com/mkdir700/EchoPlayer/commit/82e75dcb0741f6275fcf2863fccb6244383c75b2)) * 新增字幕模式覆盖层组件及相关逻辑 ([e75740c](https://github.com/mkdir700/EchoPlayer/commit/e75740cd20e588ae2542ece91acebd4f86206b51)) * 新增字幕空状态组件和外部链接打开功能 ([5bd4bd6](https://github.com/mkdir700/EchoPlayer/commit/5bd4bd6cb5f283114c83188c15301afe50b5d3c6)) * 新增字幕组件样式,重构相关组件以支持主题系统,提升视觉一致性和用户体验 ([822cb74](https://github.com/mkdir700/EchoPlayer/commit/822cb74a9348d89527f3871ba7d37f92952e3165)) * 新增字幕重置功能,优化字幕设置管理;重构相关组件以提升用户体验和代码可维护性 ([f4702a5](https://github.com/mkdir700/EchoPlayer/commit/f4702a5f59b77e36a8301c856c1ab81c3d8e26b5)) * 新增存储管理功能,添加最近播放项的增删改查接口,优化用户体验;重构相关组件,提升代码结构与可维护性 ([a746ed3](https://github.com/mkdir700/EchoPlayer/commit/a746ed388e2476c8a84f45ec13f7e5ab6af8ad82)) * 新增当前字幕显示上下文管理,优化字幕点击交互逻辑,确保用户体验流畅;重构相关组件以提升代码可维护性 ([91a215d](https://github.com/mkdir700/EchoPlayer/commit/91a215d0fa116f04c8f88403123574f0d6d7dd6f)) * 新增快捷键设置模态框和快捷键显示组件,优化用户输入体验 ([b605257](https://github.com/mkdir700/EchoPlayer/commit/b605257cd97fec50e58143eba479e39defe449b6)) * 新增控制弹窗样式并优化字幕模式选择器的交互体验;重构相关组件以提升代码可读性和用户体验 ([79eabdf](https://github.com/mkdir700/EchoPlayer/commit/79eabdfc684ba172425afc80dc61bb47ea95c78d)) * 新增播放设置上下文,重构相关组件以支持播放设置的管理;更新播放页面以使用新的播放设置上下文,提升代码可读性与功能性 ([6fe8b4f](https://github.com/mkdir700/EchoPlayer/commit/6fe8b4fed2d3ea0bf9b2487f48fe7bf98d293ba6)) * 新增播放速度覆盖层和相关功能 [#1](https://github.com/mkdir700/EchoPlayer/issues/1) ([d8637eb](https://github.com/mkdir700/EchoPlayer/commit/d8637eb6046ce8f24b0e4e08794681bf59a93ba9)) * 新增数据清理功能,优化日志记录中的数据序列化,确保记录的日志信息更为准确和安全 ([8ada21a](https://github.com/mkdir700/EchoPlayer/commit/8ada21a07acc9dcb06a59b205f9b42c326d6472f)) * 新增数据目录管理功能 ([2c93e19](https://github.com/mkdir700/EchoPlayer/commit/2c93e19e51efadcf0a91e55ae07b40c0589f2f2a)) * 新增日志系统,集成 electron-log 以支持主进程和渲染进程的日志记录;更新相关 API 以便于日志管理和调试 ([1f621d4](https://github.com/mkdir700/EchoPlayer/commit/1f621d42eaa8cce3ca13a1eec4c6fb5235a2d671)) * 新增智能分段功能及相关测试 ([f5b8f5c](https://github.com/mkdir700/EchoPlayer/commit/f5b8f5c96a00b64bc820335a3ed16083a7e44ce0)) * 新增视频UI配置管理功能 ([eaf7e41](https://github.com/mkdir700/EchoPlayer/commit/eaf7e418bf8d6ea7169f243e3afef5d2b8cb542a)) * 新增视频管理组件和确认模态框 ([4263c67](https://github.com/mkdir700/EchoPlayer/commit/4263c672a1bba108b83d80a1cfa78d71b6c6edb9)) * 新增视频转码功能及兼容性警告模态框 ([4fc86a2](https://github.com/mkdir700/EchoPlayer/commit/4fc86a28338e9814fb1b2c98780645cf23f35cda)) * 新增第三方服务配置组件,整合 OpenAI 和词典服务设置,优化用户界面和交互体验;引入模块化样式,提升整体一致性 ([3e45359](https://github.com/mkdir700/EchoPlayer/commit/3e45359efb188e7108ee4eb9663768b18b444678)) * 新增获取所有字幕的功能,优化字幕查找逻辑以支持根据当前时间查找上下句字幕,提升用户体验 ([04c5155](https://github.com/mkdir700/EchoPlayer/commit/04c5155f1276968967591acbaedb36200915a5cc)) * 新增词典服务相关的 IPC 处理器,支持有道和欧陆词典的 API 请求;实现 SHA256 哈希计算功能,增强应用的词典查询能力 ([707ee97](https://github.com/mkdir700/EchoPlayer/commit/707ee97b2680efcf9057acfd802e6113d4f89d8d)) * 新增边距验证逻辑,优化字幕拖拽和调整大小功能,确保字幕区域不超出容器边界 ([2294bcf](https://github.com/mkdir700/EchoPlayer/commit/2294bcffac6fc83e4d21e543c276cceaea0189ff)) * 更新 AppHeader 组件,增加背景装饰、应用图标和名称,优化导航按钮和辅助功能按钮的样式,提升用户体验 ([651c8d7](https://github.com/mkdir700/EchoPlayer/commit/651c8d79acf0649f24a30acc4a7a714f112ec85a)) * 更新 AppHeader 组件,调整文本样式和名称,提升视觉效果 ([f208d66](https://github.com/mkdir700/EchoPlayer/commit/f208d66199d33de47c8b3f885c6f95ca655081ac)) * 更新 GitHub Actions 工作流和文档,支持更多发布文件 ([c4bf6f7](https://github.com/mkdir700/EchoPlayer/commit/c4bf6f7a00d332a3e71f0796dbbdcf3c397ef175)) * 更新 index.html 文件,修改内容安全策略以支持新的脚本源,添加本地开发服务器的支持,优化页面加载逻辑 ([8c11edf](https://github.com/mkdir700/EchoPlayer/commit/8c11edfc841058448c24be872d641b98beda52ec)) * 更新 PlaybackRateSelector 组件样式和文本 ([034e758](https://github.com/mkdir700/EchoPlayer/commit/034e7581ec6facdffbd7cafc276449f7733c231b)) * 更新 SubtitleListContent 组件,替换 rc-virtual-list 为 react-virtualized,优化字幕列表渲染性能与用户体验;调整样式以适配虚拟列表,增强滚动效果与响应式设计 ([63d9ef4](https://github.com/mkdir700/EchoPlayer/commit/63d9ef4229b9e159b0da5ae272229d192cc27a25)) * 更新 SubtitleListContent 组件,添加激活字幕索引状态以优化渲染逻辑;重构字幕项组件以减少不必要的重渲染并提升性能;增强自动滚动逻辑,确保用户体验流畅 ([c997109](https://github.com/mkdir700/EchoPlayer/commit/c997109154faf0a92186bb94a8d2a019d85086e2)) * 更新E2E测试,移除冗余测试用例并优化测试ID使用 ([51fd721](https://github.com/mkdir700/EchoPlayer/commit/51fd721ecd84bf54472f18298e0541d20d0d1cb8)) * 更新E2E测试配置,添加Linux虚拟显示器支持并检查构建输出 ([ac1999f](https://github.com/mkdir700/EchoPlayer/commit/ac1999f8b30cf8cf48f9528b93b3fcb68b1c1b79)) * 更新主题系统,新增字体粗细、间距、圆角等设计令牌,优化组件样式一致性 ([62f87dd](https://github.com/mkdir700/EchoPlayer/commit/62f87dd4fc868eefaf7d26008204edde9e778bb4)) * 更新侧边栏导航功能和禁用状态提示 ([d41b25f](https://github.com/mkdir700/EchoPlayer/commit/d41b25f88d5a5b428b3a159db432fa951178a469)) * 更新最近播放项管理,使用文件ID替代原有ID,新增根据文件ID获取最近播放项的功能,优化播放设置管理,提升代码可维护性 ([920856c](https://github.com/mkdir700/EchoPlayer/commit/920856c095a8ac4d5d41dab635390493c13774ad)) * 更新图标文件,替换Mac和Windows平台的图标,优化SVG图标文件结构 ([bfe456f](https://github.com/mkdir700/EchoPlayer/commit/bfe456f9109fd99022796d8be8c533ba31c1fd9f)) * 更新图标资源,替换 PNG 格式图标并新增 SVG 格式图标,提升图标的可扩展性与清晰度 ([8eaf560](https://github.com/mkdir700/EchoPlayer/commit/8eaf5600cff468fceb1d36bca6416a52e43f9aa9)) * 更新字典引擎设置,默认选择为 'eudic-html',提升用户体验 ([ebaa5d2](https://github.com/mkdir700/EchoPlayer/commit/ebaa5d290cbbfcd1c2a5f5d7b8ed99ce9bbad449)) * 更新字幕上下文菜单,优化重置按钮状态和样式 ([cc542f2](https://github.com/mkdir700/EchoPlayer/commit/cc542f27e241c920e80272cc2c68d2aaa7ba00da)) * 更新字幕列表项组件,添加注释以说明仅展示学习语言,优化双语字幕显示逻辑 ([89e2b33](https://github.com/mkdir700/EchoPlayer/commit/89e2b33e65f7565ee4b89a329963c66b29a78df6)) * 更新字幕加载功能,新增对 ASS/SSA 格式的支持;优化字幕文件扩展名和解析逻辑,提升用户体验 ([9cab843](https://github.com/mkdir700/EchoPlayer/commit/9cab843eeb33c3429ce1c2a9e78f33eeee743191)) * 更新字幕加载模态框样式,新增加载状态提示与取消功能;重构相关逻辑以提升用户体验与代码可读性 ([1f8442a](https://github.com/mkdir700/EchoPlayer/commit/1f8442a0f6eec1afd4421f520774b4132528a3a2)) * 更新字幕展示组件样式,添加浮动控制按钮及其样式,优化响应式设计 ([ac586e2](https://github.com/mkdir700/EchoPlayer/commit/ac586e2cd1e7670855b0b92bc3dc887ec9586658)) * 更新字幕控制功能,添加自动暂停选项,修改快捷键设置,优化相关逻辑和组件交互 ([428e4cf](https://github.com/mkdir700/EchoPlayer/commit/428e4cfc1ba2f3856e604dd82614388c1e2d09a0)) * 更新字幕模式选择器,整合字幕显示模式的获取逻辑,优化状态管理,增强调试信息 ([c2d3c90](https://github.com/mkdir700/EchoPlayer/commit/c2d3c90cfa07c64fbd4a21ef0ee962cc389b121f)) * 更新循环播放设置,支持无限循环和自定义次数 ([e6c5d2e](https://github.com/mkdir700/EchoPlayer/commit/e6c5d2e3b291b3e5e4c562e43da278673c51ae23)) * 更新快捷键设置,修改单句循环和字幕导航的快捷键,优化用户体验 ([ce66e62](https://github.com/mkdir700/EchoPlayer/commit/ce66e6208e920bc6d75a1750c06de27c2958f7cd)) * 更新总结规则,启用始终应用选项;新增指令处理逻辑以提取项目开发指导内容并编写开发文档,确保文档规范性 ([d627e2e](https://github.com/mkdir700/EchoPlayer/commit/d627e2ec7676413f96950f580a6cddc73c9ff325)) * 更新构建产物处理逻辑,支持多架构文件重命名和 YAML 文件引用更新 ([e206e1d](https://github.com/mkdir700/EchoPlayer/commit/e206e1d5386855e5819ce6b74000487d51aa2d77)) * 更新构建配置,支持多架构构建和文件重命名 ([17b862d](https://github.com/mkdir700/EchoPlayer/commit/17b862d57bde74e4cff8c4f89ae423b183b1e9ed)) * 更新样式文件,优化警告框和卡片组件的视觉效果,增强响应式设计支持 ([ea6b4ab](https://github.com/mkdir700/EchoPlayer/commit/ea6b4ab9142e5cade134113e613c69b109b86889)) * 更新滚动条样式以支持 WebKit 规范 ([224f41d](https://github.com/mkdir700/EchoPlayer/commit/224f41d853a274324d5d1bbbf4ac7d07214cca96)) * 更新视频上传钩子,使用日志系统记录视频DAR信息和错误警告,提升调试能力 ([2392b38](https://github.com/mkdir700/EchoPlayer/commit/2392b3806dfdf8134555a6b006ea833065459a09)) * 更新视频兼容性模态框样式,提升用户体验 ([f5c1ba5](https://github.com/mkdir700/EchoPlayer/commit/f5c1ba5e42d44d65b5c0df55c70e9e2f44cbb855)) * 更新视频播放器和播放状态管理逻辑,重构字幕处理方式,统一使用 subtitleItems 以提升代码一致性与可读性;优化播放状态保存与恢复机制,确保更流畅的用户体验 ([0cbe11d](https://github.com/mkdir700/EchoPlayer/commit/0cbe11d4324806dbdab67dd181ac28acd5e45c06)) * 更新视频播放器的时间跳转逻辑,支持来源标记 ([f170ff1](https://github.com/mkdir700/EchoPlayer/commit/f170ff1b508c40bb122a20262ba436e4132c77da)) * 更新视频文件信息样式,添加文件名截断功能,优化头部布局以提升用户体验 ([a6639f1](https://github.com/mkdir700/EchoPlayer/commit/a6639f1494862620bc0fec6f7e140e6bd773335f)) * 更新窗口管理和标题栏组件,优化样式和功能 ([a1b50f6](https://github.com/mkdir700/EchoPlayer/commit/a1b50f6c52142a9cc2c2df12b98644e1e11ddfa6)) * 更新窗口管理器的窗口尺寸和最小尺寸,优化用户界面;移除不必要的响应式设计样式,简化 CSS 结构 ([dd561cf](https://github.com/mkdir700/EchoPlayer/commit/dd561cf35995ebd504553a26d2c83b73da06e3f1)) * 更新第三方服务配置组件,修改标签和提示文本为中文,增强用户友好性;新增申请应用ID和密钥的链接提示,提升信息获取便利性 ([5e68e85](https://github.com/mkdir700/EchoPlayer/commit/5e68e8507f1d5509cdcb2fb3459a570d92287aa9)) * 更新设置导航组件样式和功能 ([535f267](https://github.com/mkdir700/EchoPlayer/commit/535f267b140bc918672fdadaae6445b9eda0707f)) * 更新设置页面,移除视频转换相关功能 ([0d96fac](https://github.com/mkdir700/EchoPlayer/commit/0d96facf476cd73aa64fd023fb01c3a2442d0dbe)) * 更新设置页面,简化快捷键和数据管理部分的渲染逻辑,新增存储设置选项,优化用户界面和交互体验 ([9942740](https://github.com/mkdir700/EchoPlayer/commit/9942740d9bca7ba55cd4f730ed2214ed405ed867)) * 更新设置页面样式和主题支持 ([816ca6d](https://github.com/mkdir700/EchoPlayer/commit/816ca6d3d747ace1a18cf5f01523ee56ab8cb120)) * 更新设置页面的按钮样式和移除音频兼容性警告 ([f0be1e2](https://github.com/mkdir700/EchoPlayer/commit/f0be1e206fb69f3a75ad292dc8c3a90f02fced14)) * 更新通知系统优化,增强用户交互体验 ([6df4374](https://github.com/mkdir700/EchoPlayer/commit/6df4374ceb90b401799107c344211b164f7a0164)) * 更新页面渲染逻辑,添加页面冻结功能,确保首页始终挂载并优化其他页面的条件渲染,提升用户体验 ([7a4b2ba](https://github.com/mkdir700/EchoPlayer/commit/7a4b2ba5d72a83f3765b003384d09295e70403e5)) * 替换应用头部为侧边栏组件 ([0e621fc](https://github.com/mkdir700/EchoPlayer/commit/0e621fca1703f7461a101d2899ce7d85626156ff)) * 沉浸式标题栏 ([9c7c7d9](https://github.com/mkdir700/EchoPlayer/commit/9c7c7d9b91ba0c505d72cc3cf2d11b9049bd62a3)) * 添加 @ant-design/v5-patch-for-react-19 支持 React19 ([95d1019](https://github.com/mkdir700/EchoPlayer/commit/95d1019a02fb244e558f8819e4c52e3a7b0bc1bf)) * 添加 Stagewise 工具栏支持,仅在开发模式下初始化,更新 CSP 设置以允许外部样式源 ([ededb64](https://github.com/mkdir700/EchoPlayer/commit/ededb643573969a41ebc57a9666fbfd928e44e7c)) * 添加Codecov配置文件,更新测试配置以支持覆盖率报告上传 ([d9ec00d](https://github.com/mkdir700/EchoPlayer/commit/d9ec00d895792eca2c9ad6ea455f5b1eaadb2078)) * 添加E2E测试支持,更新Playwright配置和相关脚本 ([247b851](https://github.com/mkdir700/EchoPlayer/commit/247b85122ab88b05e789388e18b696769256e226)) * 添加全屏功能支持,优化视频播放器组件,更新样式以移除不必要的自定义样式,提升用户体验 ([a7d4b1c](https://github.com/mkdir700/EchoPlayer/commit/a7d4b1c1408ec6177ec07c60280993f23af8c605)) * 添加字幕控制组件,支持单句循环和自动循环功能,更新快捷键设置,优化样式和响应式设计 ([2902f2d](https://github.com/mkdir700/EchoPlayer/commit/2902f2d54e929b433ba7dfa2ed9ebe32dc8b2d58)) * 添加应用图标 ([b86e142](https://github.com/mkdir700/EchoPlayer/commit/b86e1420b4ca8701354d644b45653ac039845db2)) * 添加应用图标并优化代码中的事件监听和清理逻辑 ([c39da08](https://github.com/mkdir700/EchoPlayer/commit/c39da08c7ab5a17ed4fb718bcfc10df4a2b94cb9)) * 添加当前字幕展示组件,支持多种字幕显示模式及单词hover交互,优化视频控制区样式和响应式设计 ([df4b74a](https://github.com/mkdir700/EchoPlayer/commit/df4b74a98c5ae66e6c2d3be24e25c7e4261fc70e)) * 添加循环播放功能,支持自定义循环次数设置 ([1dbccfa](https://github.com/mkdir700/EchoPlayer/commit/1dbccfae97c22ac49a08e78287211f89ccf3aa46)) * 添加文件系统相关的 IPC 处理器,支持文件存在性检查、读取文件内容、获取文件 URL、文件信息获取及文件完整性验证;更新 preload 和 renderer 逻辑以支持视频和字幕文件的选择与恢复功能,优化用户体验 ([6d361eb](https://github.com/mkdir700/EchoPlayer/commit/6d361eb0ec1e8f8aa2eaca5167736bd1373d93bb)) * 添加更新通知和提示对话框组件 ([38df4d2](https://github.com/mkdir700/EchoPlayer/commit/38df4d2b55af83f3007f1b242da19eb02cca8a11)) * 添加更新通知跳过版本功能,优化用户体验 ([165adb6](https://github.com/mkdir700/EchoPlayer/commit/165adb69c7a4dae1d2749592b01f1561580c58ec)) * 添加本地更新测试环境脚本和相关功能 ([00aa019](https://github.com/mkdir700/EchoPlayer/commit/00aa01940583ec30e79034495fe804febe4479ab)) * 添加构建产物重命名和验证脚本 - 新增 rename-artifacts.ts 用于重命名构建产物以符合发布要求 - 新增 verify-build-artifacts.ts 用于验证构建产物的存在性和完整性 ([696cedc](https://github.com/mkdir700/EchoPlayer/commit/696cedc090caaa56b3f2c4921022d9e131d361ac)) * 添加构建和发布工作流,更新测试和发布脚本 ([2744005](https://github.com/mkdir700/EchoPlayer/commit/2744005aefb85874651d7e7937e5af1f9ead8b35)) * 添加欧陆词典HTML解析服务和单元测试框架 ([52ace3e](https://github.com/mkdir700/EchoPlayer/commit/52ace3ef0ba4aa0b58d000996d1f933365c093ce)) * 添加测试Electron CDP连接的脚本 ([9982514](https://github.com/mkdir700/EchoPlayer/commit/9982514f56ccbb6b048d0a4d961f8a5b7b29eea0)) * 添加版本管理脚本,支持版本类型检测和版本号递增功能;更新构建和发布工作流,优化版本变量设置和上传路径逻辑;新增发布指南文档,详细说明版本管理和发布流程 ([282bde8](https://github.com/mkdir700/EchoPlayer/commit/282bde883d4c8ae965963e555feb1cd4a011ab88)) * 添加视频播放器点击事件处理,优化用户交互体验 ([69c378f](https://github.com/mkdir700/EchoPlayer/commit/69c378fad8aa8c15b29833e668fd150775c477e3)) * 添加视频文件选择加载状态和清空确认模态框 ([ca95a7d](https://github.com/mkdir700/EchoPlayer/commit/ca95a7d5f2cae1e42423dbe7cfe3c7d09352e16c)) * 添加视频格式转换功能,新增视频兼容性检测与转换指南,优化视频播放器与文件上传逻辑,提升用户体验;重构相关组件,简化代码结构 ([5fd89fe](https://github.com/mkdir700/EchoPlayer/commit/5fd89fed2b346efbb4d0e5c0d029af51e60f07a1)) * 添加腾讯云COS上传功能,支持发布文件和自动更新文件的上传 ([e79e5a9](https://github.com/mkdir700/EchoPlayer/commit/e79e5a9c5b5e29f2092d50aa9af58dafa6297612)) * 添加自动更新功能,整合更新处理器,更新设置界面,支持版本检查和下载 ([5e5a03e](https://github.com/mkdir700/EchoPlayer/commit/5e5a03e5966e3978ba16d76ed202ce943903e3a1)) * 添加页面切换过渡效果,优化播放页面与性能监控功能;重构相关组件,提升用户交互体验与代码结构 ([e583ecc](https://github.com/mkdir700/EchoPlayer/commit/e583ecc78836dc241392039c76092833ca354695)) * 添加页面导航功能,重构 App 组件以支持多页面切换,新增关于、收藏、设置等页面,优化样式和用户体验 ([51f4263](https://github.com/mkdir700/EchoPlayer/commit/51f426365c12474091e8581211da3e7e36d29749)) * 添加高效测试标识符管理指南及相关工具函数,优化E2E测试中的测试ID使用 ([2dcfe5e](https://github.com/mkdir700/EchoPlayer/commit/2dcfe5e7443095890acc7034a5b919059dcad2bc)) * 现代化视频控制组件,优化样式和交互逻辑,增强用户体验;添加音量和设置控制,支持自动隐藏功能 ([dc45b83](https://github.com/mkdir700/EchoPlayer/commit/dc45b83bbaf02f90ccde2559f203520b172a0388)) * 移除 HomePage 组件中的 subtitleIndex 属性,优化视频播放状态管理逻辑;调整视频网格布局以提升用户界面的一致性与可读性 ([8f54e7f](https://github.com/mkdir700/EchoPlayer/commit/8f54e7fb54574552a308c7af5188f5f46d5a37ce)) * 移除 PlayPageHeader 的 CSS 模块,改为使用主题系统样式管理,提升组件的可维护性和一致性 ([52cedbc](https://github.com/mkdir700/EchoPlayer/commit/52cedbc09e95d3fe91308e1bdc70a38d1c988315)) * 移除 useSidebarResize 钩子及相关样式,改用 Ant Design 的 Splitter 组件实现侧边栏调整功能,优化播放页面布局与用户体验 ([bead645](https://github.com/mkdir700/EchoPlayer/commit/bead645f2680363621a7cc7dd6139aa990aa7750)) * 移除字幕位置控制相关组件及其逻辑,简化视频控制界面以提升用户体验 ([1edc857](https://github.com/mkdir700/EchoPlayer/commit/1edc857e3ef1f8ac87c35e6c62f1bdfcd4b545c6)) * 移除字幕设置相关功能和组件 ([32f0138](https://github.com/mkdir700/EchoPlayer/commit/32f0138c6285b6a5805720c9306dad2d4cfd7783)) * 移除推荐视频假数据,更新欢迎信息,优化首页布局和用户体验 ([78b000f](https://github.com/mkdir700/EchoPlayer/commit/78b000fcf2bd8511ef35e79f5a03114dfed297d4)) * 移除视频播放器和播放控制钩子,简化代码结构以提升可维护性 ([513ba3c](https://github.com/mkdir700/EchoPlayer/commit/513ba3c21f67fbc76fc3a61ac5b128506cca68db)) * 移除视频播放器的响应式设计中不必要的内边距,简化 CSS 结构 ([f8c8c28](https://github.com/mkdir700/EchoPlayer/commit/f8c8c2899d8545486a23421d882ecfd1c186446c)) * 调整 HomePage 组件的响应式布局,优化列宽设置以提升用户体验 ([3c435bf](https://github.com/mkdir700/EchoPlayer/commit/3c435bfee87ab529333a2dcf3fe51553b089cc45)) * 调整主题样式宽度 ([2fe9ff2](https://github.com/mkdir700/EchoPlayer/commit/2fe9ff24d2f35791712b3bf5b848fc7464b08fef)) * 调整全屏视频控制组件的进度条位置和样式 ([679521f](https://github.com/mkdir700/EchoPlayer/commit/679521f2f92c1c04646a89866944b20d22d6a917)) * 调整字幕覆盖层样式,修改底部位置为0%,移除移动端特定样式,简化 CSS 结构 ([515151d](https://github.com/mkdir700/EchoPlayer/commit/515151d022fc16d886471aad43aeda43f482214c)) * 重命名视频控制组件为 VideoControlsFullScreen,更新相关导入,提升代码可读性 ([0fe7954](https://github.com/mkdir700/EchoPlayer/commit/0fe795404702dd1a9b68c32a21fec5ad003dcf8d)) * 重构 SidebarSection 和 SubtitleListContent 组件,简化属性传递,增强字幕索引处理逻辑,优化自动滚动功能;新增获取指定时间点字幕索引的功能,提升用户体验与代码可读性 ([dabcbeb](https://github.com/mkdir700/EchoPlayer/commit/dabcbeb0718e2f8d6923a223d3c57e79453366a9)) * 重构字幕控制组件样式,使用主题系统优化按钮和图标样式,提升视觉一致性和用户体验 ([12e38f2](https://github.com/mkdir700/EchoPlayer/commit/12e38f2f260467e297ad11831ff1a44eea08c317)) * 重构字幕状态管理,新增视频特定字幕设置 ([ff5b5de](https://github.com/mkdir700/EchoPlayer/commit/ff5b5def52690c082eae9f26029f6d139d80cd47)) * 重构字幕组件,新增字幕覆盖层和文本组件,优化字幕显示逻辑和性能;移除旧版字幕组件,提升代码可维护性 ([4fbef84](https://github.com/mkdir700/EchoPlayer/commit/4fbef8419f703f398593043932f07a14a78e170c)) * 重构存储处理器模块,优化应用配置和通用存储功能 ([065c30d](https://github.com/mkdir700/EchoPlayer/commit/065c30d7cbc8fc5b01f3f3b59211e6548d679cdc)) * 重构存储管理功能,更新最近播放项的类型定义,优化播放设置管理,增强用户体验;新增播放设置的深度合并逻辑,提升代码可维护性 ([3f928d4](https://github.com/mkdir700/EchoPlayer/commit/3f928d4c84df465574fde222fcb1dccf72c3dfc6)) * 重构应用布局与样式,新增主页与播放页面组件,优化用户交互体验;整合最近文件管理功能,提升视频文件选择与加载逻辑 ([f3fefad](https://github.com/mkdir700/EchoPlayer/commit/f3fefadd3643f20e2935d2d72eeea1e56a65a1d1)) * 重构循环切换功能,简化状态管理和播放逻辑 ([fe11037](https://github.com/mkdir700/EchoPlayer/commit/fe11037cb82119f3ff3e74c825a44e80022158f7)) * 重构播放状态管理,替换为使用最近播放列表钩子,简化参数传递并优化代码逻辑;新增最近播放列表钩子以支持播放项的增删改查功能 ([1ec2cac](https://github.com/mkdir700/EchoPlayer/commit/1ec2cac7f2a84f11b1ff4ddd2d482a45c8eae1bd)) * 重构播放页面,整合视频播放器与字幕控制逻辑,新增 VideoPlayerProvider 以管理视频播放状态,优化组件结构与性能;移除不再使用的 SubtitleControls 组件,简化属性传递,提升代码可读性 ([e4111c9](https://github.com/mkdir700/EchoPlayer/commit/e4111c9274cb6b6dd112c5dd7f629b244450f802)) * 重构视频控制组件,新增全屏控制样式与逻辑,优化播放控制体验;更新相关类型定义,提升代码可读性与功能性 ([5c72a1b](https://github.com/mkdir700/EchoPlayer/commit/5c72a1b0ce481c63b0d9c03f048b527f612052e0)) * 重构视频播放上下文,新增视频文件上传和选择功能;更新相关组件以支持新的上下文逻辑,提升代码可读性与功能性 ([37e128e](https://github.com/mkdir700/EchoPlayer/commit/37e128eede0ad02f70ee7dc2aa2aab7d49a121df)) * 重构视频播放器组件,移除 CSS Modules,采用主题系统样式管理,提升代码可维护性和一致性 ([b3981bc](https://github.com/mkdir700/EchoPlayer/commit/b3981bc2d86a7ea7d343f1e068f404b46af509f0)) * 重构视频播放器逻辑,整合视频播放状态管理,优化组件结构;移除不再使用的 usePlayingVideoContext 钩子,新增多个视频控制钩子以提升性能与可读性 ([b1a6dc2](https://github.com/mkdir700/EchoPlayer/commit/b1a6dc29acb83fbdf4a167c9ded069f2e53d0491)) * 重构视频播放设置管理,整合字幕显示设置,优化状态管理逻辑,提升用户体验和代码可维护性 ([6c3d852](https://github.com/mkdir700/EchoPlayer/commit/6c3d852fbb8d66e5f07942fdf792b661327b3a4a)) * 重构设置页面,新增快捷键、数据管理和占位符组件,优化用户界面和交互体验;引入快捷键上下文管理,支持自定义快捷键功能 ([a498905](https://github.com/mkdir700/EchoPlayer/commit/a4989050d3a747b6a66d7deb2da21a1cf9a2a0be)) ### Reverts * Revert "build: 在构建和发布工作流中添加调试步骤,列出下载的文件并检查Windows、Mac和Linux平台的自动更新配置文件是否存在" ([d0f8fc4](https://github.com/mkdir700/EchoPlayer/commit/d0f8fc4be0f3b976df0752a57437eb3cd16321ef)) * Revert "chore: 更新 Linux 构建环境配置" ([cc179a0](https://github.com/mkdir700/EchoPlayer/commit/cc179a072721fd508662924073cf03bdfa684611)) * Revert "feat: 在构建和发布工作流中添加更新 package.json 版本的步骤,确保版本号自动更新;优化草稿发布条件以支持预发布版本" ([be1cf26](https://github.com/mkdir700/EchoPlayer/commit/be1cf2668cf7ad777739bdb40e5b75e145775386)) ### BREAKING CHANGES * **ffmpeg:** 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 * **player,logging,state:** - Removed TransportBar and deprecated hooks (usePlayerControls/useVideoEvents/useSubtitleSync). Migrate to ControllerPanel with usePlayerEngine/usePlayerCommandsOrchestrated. - Player store control actions are engine-only; components should send commands via the orchestrator instead of mutating store directly.
Summary
• 实现动态 FFmpeg 下载系统,支持运行时按需下载和管理 FFmpeg 二进制文件
• 新增 FFmpeg 设置界面,提供下载进度显示和管理功能
• 优化构建流程,移除静态 FFmpeg 依赖,减小应用体积
Test plan
Summary by CodeRabbit
New Features
UI/UX
Localization
Tests
Chores