feat(player): HLS session progress polling with media server integration#209
feat(player): HLS session progress polling with media server integration#209
Conversation
Walkthrough该变更引入转码会话就绪轮询:新增 SessionService.getSessionProgress 与相关类型;在 PlayerPage 中轮询会话进度并在就绪后切换至 HLS 播放源,展示确定性进度条;移除 SubtitleOverlay 的调试日志;更新 backend 子模块引用。 Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User as 用户
participant Player as PlayerPage
participant Sess as SessionService
participant Media as 媒体服务
participant HLS as HLS 播放器
User->>Player: 打开视频 / 请求播放
Player->>Sess: 创建/使用会话(现有流程)
note right of Player: 设置 waitingForSessionReady=true\n初始化 sessionProgress
loop 轮询直到就绪或失败
Player->>Sess: getSessionProgress(sessionId)
Sess->>Media: GET /{sessionId}/progress
Media-->>Sess: 200 {progress, is_ready, playlist_url} 或 425 Too Early
alt 425 Too Early
Sess-->>Player: 返回可重试(非就绪)
note over Player: 等待后继续轮询
else 返回进度
Sess-->>Player: {progress_percent, progress_stage, is_ready, playlist_url}
Player->>Player: 更新确定性进度条与阶段文本
end
end
alt is_ready = true
Player->>Player: 选择最终 HLS 播放列表 URL
Player->>HLS: 切换至 HLS 源并开始播放
else 错误或超时
Player->>Player: 记录错误,回退到原始文件 URL(若适用)
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (4)src/renderer/src/**/*.{ts,tsx,scss,css}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
src/renderer/src/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/player/**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
🧠 Learnings (3)📚 Learning: 2025-09-17T14:59:36.985ZApplied to files:
📚 Learning: 2025-09-17T14:59:36.985ZApplied to files:
📚 Learning: 2025-09-17T14:59:36.985ZApplied to files:
🧬 Code graph analysis (1)src/renderer/src/pages/player/PlayerPage.tsx (2)
⏰ 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)
🔇 Additional comments (3)
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 |
…back - Add waitForSessionReady to poll session creation progress before playback - Integrate useSessionProgress hook for reusable progress tracking logic - Display deterministic progress bar with percentage and stage information during session initialization - Add SessionService.getSessionProgress API with HTTP 425 handling for in-progress state - Update backend submodule to v64aaf0b with HLS session progress support - Remove excessive debug logging in SubtitleOverlay to reduce console noise Changes: PlayerPage: - Add waitForSessionReady state and sessionProgress state for UI rendering - Implement polling loop with 2s interval to fetch session progress until ready - Display progress bar with stage text and percentage during session creation - Handle HTTP 425 (session not ready) gracefully in progress polling - Fallback to default playlist URL if progress response URL parsing fails useSessionProgress Hook: - Provide reusable session progress polling with configurable interval (default 2s) - Auto-stop polling when session is ready or error occurs - Expose startPolling, stopPolling, reset methods for lifecycle control - Implement progress threshold (5%) to reduce log noise SessionService: - Add getSessionProgress(sessionId) API to fetch session creation progress - Define SessionProgressResponse and AudioProgressInfo interfaces - Treat HTTP 425 as normal in-progress state (not error) This enhancement provides real-time visual feedback during HLS session initialization, improving user experience by showing progress instead of generic "loading..." spinner. The polling mechanism ensures playback starts only after the session is fully ready, preventing premature playlist access.
b167306 to
87d67f6
Compare
There was a problem hiding this comment.
Actionable comments posted: 8
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
backend(1 hunks)src/renderer/src/pages/player/PlayerPage.tsx(7 hunks)src/renderer/src/pages/player/components/SubtitleOverlay.tsx(0 hunks)src/renderer/src/services/SessionService.ts(2 hunks)
💤 Files with no reviewable changes (1)
- src/renderer/src/pages/player/components/SubtitleOverlay.tsx
🧰 Additional context used
📓 Path-based instructions (4)
src/renderer/src/**/*.{ts,tsx,scss,css}
📄 CodeRabbit inference engine (CLAUDE.md)
优先使用 CSS 变量,避免硬编码样式值(颜色等)
Files:
src/renderer/src/services/SessionService.tssrc/renderer/src/pages/player/PlayerPage.tsx
src/renderer/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
尺寸与时长等不要硬编码,优先使用 useTheme() 的 token 或集中样式变量(如 motionDurationMid、borderRadiusSM/MD)
Files:
src/renderer/src/services/SessionService.tssrc/renderer/src/pages/player/PlayerPage.tsx
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: 定制 antd 组件样式优先使用 styled-components 包装 styled(Component),避免全局 classNames
项目的图标统一使用 lucide-react,不使用 emoji 作为图标
组件/Hook 顶层必须通过 useStore(selector) 使用 Zustand,禁止在 useMemo/useEffect 内部调用 store Hook
避免使用返回对象的 Zustand 选择器(如 useStore(s => ({ a: s.a, b: s.b })));应使用单字段选择器或配合 shallow 比较器
遵循 React「副作用与状态更新」规范:渲染纯函数、Effect 三分法、幂等更新、稳定引用、严格清理、禁止写回自身依赖、Provider 值 memo、外部状态 selector 稳定等
统一使用 loggerService 记录日志而不是 console
logger 使用示例中第二个参数必须为对象字面量(如 logger.error('msg', { error }))
任何组件或页面都不要写入 media 元素的 currentTime,播放器控制由编排器统一负责
在 styled-components 中:主题相关属性使用 AntD CSS 变量(如 var(--ant-color-bg-elevated));
在 styled-components 中:设计系统常量(尺寸、动画、层级、字体、毛玻璃等)使用 JS 常量(如 SPACING、BORDER_RADIUS、Z_INDEX、FONT_SIZES 等)
Files:
src/renderer/src/services/SessionService.tssrc/renderer/src/pages/player/PlayerPage.tsx
**/player/**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
Player 页面:统一在组件顶层使用 Zustand selector,禁止在 useMemo/useEffect 内调用 store Hook;useSubtitleEngine 通过参数传入 subtitles 等防御处理
Files:
src/renderer/src/pages/player/PlayerPage.tsx
🧬 Code graph analysis (2)
src/renderer/src/services/SessionService.ts (1)
src/renderer/src/services/Logger.ts (1)
error(422-424)
src/renderer/src/pages/player/PlayerPage.tsx (1)
src/renderer/src/services/SessionService.ts (2)
SessionService(154-600)SessionError(138-147)
⏰ 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 (macos-latest, 20)
- GitHub Check: test (windows-latest, 20)
- GitHub Check: test (ubuntu-latest, 20)
🔇 Additional comments (3)
src/renderer/src/pages/player/PlayerPage.tsx (3)
7-7: 引入 SessionError 以识别 425 语义 — LGTM用于区分“未就绪”与真实错误,符合预期。
169-171: 初始化等待/进度状态 — LGTM开始前清空状态,避免脏数据。
380-383: 在 finally 中复位等待与加载状态 — LGTM确保非取消场景下正确收尾。
| const [waitingForSessionReady, setWaitingForSessionReady] = useState(false) | ||
| const [sessionProgress, setSessionProgress] = useState<{ | ||
| percent: number | ||
| stage: string | ||
| status: string | ||
| } | null>(null) | ||
| // const { pokeInteraction } = usePlayerUI() |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
进度本地状态定义 OK;可提取为类型别名以增强可读性
将 { percent, stage, status } 提为 SessionProgressViewState,便于复用。
🤖 Prompt for AI Agents
In src/renderer/src/pages/player/PlayerPage.tsx around lines 99 to 105, extract
the anonymous object type used for sessionProgress into a named type alias (e.g.
SessionProgressViewState) and replace the inline generic with that alias; add
the type alias near the top of the file (or next to related types), update the
useState declaration to use useState<SessionProgressViewState | null>(null), and
export the alias if it will be reused elsewhere.
| // 加载视频数据 | ||
| useEffect(() => { | ||
| let cancelled = false | ||
| const pollIntervalMs = 2000 |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
避免硬编码轮询间隔,提取为常量/配置
将 2000ms 提取到常量(或主题 token/配置),便于统一调整与测试。
- const pollIntervalMs = 2000
+ const pollIntervalMs = POLL_INTERVAL_MS // 顶部或模块常量,例如 2000可在文件顶部新增:
const POLL_INTERVAL_MS = 2000As per coding guidelines
🤖 Prompt for AI Agents
In src/renderer/src/pages/player/PlayerPage.tsx around line 113, the poll
interval is hardcoded as 2000ms; extract this magic number into a named constant
(e.g., POLL_INTERVAL_MS) declared at the top of the file or moved to a shared
config/constants file, then replace the inline 2000 value with that constant so
the interval is configurable and easier to test.
| const waitForSessionReady = async (sessionId: string) => { | ||
| while (!cancelled) { | ||
| try { | ||
| const progress = await SessionService.getSessionProgress(sessionId) | ||
| if (cancelled) { | ||
| break | ||
| } | ||
|
|
||
| setSessionProgress((prev) => { | ||
| const stage = progress.progress_stage?.trim() || prev?.stage || '处理中...' | ||
| const rawPercent = | ||
| typeof progress.progress_percent === 'number' | ||
| ? progress.progress_percent | ||
| : Number(progress.progress_percent) | ||
| const percent = Number.isFinite(rawPercent) ? rawPercent : (prev?.percent ?? 0) | ||
| return { | ||
| percent, | ||
| stage, | ||
| status: progress.status | ||
| } | ||
| }) | ||
|
|
||
| if (progress.is_ready) { | ||
| setSessionProgress((prev) => ({ | ||
| percent: 100, | ||
| stage: progress.progress_stage?.trim() || prev?.stage || '就绪', | ||
| status: progress.status | ||
| })) | ||
| return progress | ||
| } | ||
| } catch (progressError) { | ||
| if ( | ||
| progressError instanceof SessionError && | ||
| progressError.statusCode && | ||
| progressError.statusCode === 425 | ||
| ) { | ||
| // 会话尚未返回进度,等待下一轮 | ||
| } else { | ||
| throw progressError | ||
| } | ||
| } | ||
|
|
||
| if (cancelled) { | ||
| break | ||
| } | ||
|
|
||
| await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)) | ||
| } | ||
|
|
||
| throw new Error('会话进度轮询已取消') | ||
| } |
There was a problem hiding this comment.
轮询缺少失败/超时退出条件,存在无限等待风险
- 未处理 progress.error_message 或 status=error/failed 等错误态,可能无限等待。
- 无总超时上限,后端异常时用户会一直卡在“处理中”。
建议:
- 检测错误态并立即中止。
- 增加总超时(如 120s,可配置)。
- 保持已有的 425 继续轮询语义。
示例修改(核心片段):
- const waitForSessionReady = async (sessionId: string) => {
+ const waitForSessionReady = async (sessionId: string) => {
+ const MAX_WAIT_MS = 120_000 // 可提取到常量
+ const startTs = Date.now()
while (!cancelled) {
try {
const progress = await SessionService.getSessionProgress(sessionId)
if (cancelled) {
break
}
+ // 错误态快速失败
+ if (
+ progress.error_message ||
+ progress.status === 'error' ||
+ progress.status === 'failed'
+ ) {
+ throw new Error(progress.error_message || '会话进度报告错误状态')
+ }
setSessionProgress((prev) => {
const stage = progress.progress_stage?.trim() || prev?.stage || '处理中...'
const rawPercent =
typeof progress.progress_percent === 'number'
? progress.progress_percent
: Number(progress.progress_percent)
const percent = Number.isFinite(rawPercent) ? rawPercent : (prev?.percent ?? 0)
return {
percent,
stage,
status: progress.status
}
})
if (progress.is_ready) {
setSessionProgress((prev) => ({
percent: 100,
stage: progress.progress_stage?.trim() || prev?.stage || '就绪',
status: progress.status
}))
return progress
}
} catch (progressError) {
if (
progressError instanceof SessionError &&
progressError.statusCode &&
progressError.statusCode === 425
) {
// 会话尚未返回进度,等待下一轮
} else {
throw progressError
}
}
+ // 超时保护
+ if (Date.now() - startTs > MAX_WAIT_MS) {
+ throw new Error('会话准备超时')
+ }
if (cancelled) {
break
}
await new Promise((resolve) => setTimeout(resolve, pollIntervalMs))
}
throw new Error('会话进度轮询已取消')
}As per coding guidelines
📝 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 waitForSessionReady = async (sessionId: string) => { | |
| while (!cancelled) { | |
| try { | |
| const progress = await SessionService.getSessionProgress(sessionId) | |
| if (cancelled) { | |
| break | |
| } | |
| setSessionProgress((prev) => { | |
| const stage = progress.progress_stage?.trim() || prev?.stage || '处理中...' | |
| const rawPercent = | |
| typeof progress.progress_percent === 'number' | |
| ? progress.progress_percent | |
| : Number(progress.progress_percent) | |
| const percent = Number.isFinite(rawPercent) ? rawPercent : (prev?.percent ?? 0) | |
| return { | |
| percent, | |
| stage, | |
| status: progress.status | |
| } | |
| }) | |
| if (progress.is_ready) { | |
| setSessionProgress((prev) => ({ | |
| percent: 100, | |
| stage: progress.progress_stage?.trim() || prev?.stage || '就绪', | |
| status: progress.status | |
| })) | |
| return progress | |
| } | |
| } catch (progressError) { | |
| if ( | |
| progressError instanceof SessionError && | |
| progressError.statusCode && | |
| progressError.statusCode === 425 | |
| ) { | |
| // 会话尚未返回进度,等待下一轮 | |
| } else { | |
| throw progressError | |
| } | |
| } | |
| if (cancelled) { | |
| break | |
| } | |
| await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)) | |
| } | |
| throw new Error('会话进度轮询已取消') | |
| } | |
| const waitForSessionReady = async (sessionId: string) => { | |
| const MAX_WAIT_MS = 120_000 // 可提取到常量 | |
| const startTs = Date.now() | |
| while (!cancelled) { | |
| try { | |
| const progress = await SessionService.getSessionProgress(sessionId) | |
| if (cancelled) { | |
| break | |
| } | |
| // 错误态快速失败 | |
| if ( | |
| progress.error_message || | |
| progress.status === 'error' || | |
| progress.status === 'failed' | |
| ) { | |
| throw new Error(progress.error_message || '会话进度报告错误状态') | |
| } | |
| setSessionProgress((prev) => { | |
| const stage = progress.progress_stage?.trim() || prev?.stage || '处理中...' | |
| const rawPercent = | |
| typeof progress.progress_percent === 'number' | |
| ? progress.progress_percent | |
| : Number(progress.progress_percent) | |
| const percent = Number.isFinite(rawPercent) ? rawPercent : (prev?.percent ?? 0) | |
| return { | |
| percent, | |
| stage, | |
| status: progress.status | |
| } | |
| }) | |
| if (progress.is_ready) { | |
| setSessionProgress((prev) => ({ | |
| percent: 100, | |
| stage: progress.progress_stage?.trim() || prev?.stage || '就绪', | |
| status: progress.status | |
| })) | |
| return progress | |
| } | |
| } catch (progressError) { | |
| if ( | |
| progressError instanceof SessionError && | |
| progressError.statusCode === 425 | |
| ) { | |
| // 会话尚未返回进度,等待下一轮 | |
| } else { | |
| throw progressError | |
| } | |
| } | |
| // 超时保护 | |
| if (Date.now() - startTs > MAX_WAIT_MS) { | |
| throw new Error('会话准备超时') | |
| } | |
| if (cancelled) { | |
| break | |
| } | |
| await new Promise((resolve) => setTimeout(resolve, pollIntervalMs)) | |
| } | |
| throw new Error('会话进度轮询已取消') | |
| } |
🤖 Prompt for AI Agents
In src/renderer/src/pages/player/PlayerPage.tsx around lines 115-165, the
session polling loop lacks failure/status and total-timeout handling which can
cause infinite waits; modify waitForSessionReady to (1) accept/configure a total
timeout (e.g. default 120000 ms) and record a startTime, (2) on each loop check
elapsed time and immediately throw a timeout Error when exceeded, (3) inspect
the returned progress for explicit error conditions (e.g. progress.status ===
'error' || progress.status === 'failed' || progress.error_message) and throw a
descriptive Error to abort polling (but preserve the existing special-case
handling for SessionError with statusCode === 425 so it continues polling), and
(4) ensure any thrown errors clear/stop the loop and propagate to caller so the
UI can show failure instead of hanging.
| const progressPercent = Math.max(0, Math.min(100, Math.round(sessionProgress?.percent ?? 0))) | ||
|
|
||
| return ( | ||
| <Container> | ||
| <LoadingContainer> | ||
| <LoadingText>加载中...</LoadingText> | ||
| <LoadingBarContainer> | ||
| <LoadingBarProgress /> | ||
| </LoadingBarContainer> | ||
| {waitingForSessionReady ? ( | ||
| <> | ||
| <ProgressStageText> | ||
| {sessionProgress?.stage || '正在创建转码会话...'} | ||
| </ProgressStageText> | ||
| <DeterminateBarTrack> | ||
| <DeterminateBarFill $percent={progressPercent} /> | ||
| </DeterminateBarTrack> | ||
| <ProgressPercentText>{progressPercent}%</ProgressPercentText> | ||
| </> | ||
| ) : ( | ||
| <> | ||
| <LoadingText>加载中...</LoadingText> | ||
| <LoadingBarContainer> | ||
| <LoadingBarProgress /> | ||
| </LoadingBarContainer> | ||
| </> | ||
| )} |
There was a problem hiding this comment.
新文案需接入 i18n;无障碍可读性可加 aria 标签
- '正在创建转码会话...'、'处理中...'、'就绪' 均为新文案,建议使用 t()。
- 进度条可添加 aria-valuenow/aria-valuemin/aria-valuemax 增强可访问性。
示例:
- {sessionProgress?.stage || '正在创建转码会话...'}
+ {sessionProgress?.stage || t('player.transcode.creatingSession')}Determinate 容器:
- <DeterminateBarFill $percent={progressPercent} />
+ <DeterminateBarFill
+ $percent={progressPercent}
+ role="progressbar"
+ aria-valuemin={0}
+ aria-valuemax={100}
+ aria-valuenow={progressPercent}
/>As per coding guidelines
📝 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 progressPercent = Math.max(0, Math.min(100, Math.round(sessionProgress?.percent ?? 0))) | |
| return ( | |
| <Container> | |
| <LoadingContainer> | |
| <LoadingText>加载中...</LoadingText> | |
| <LoadingBarContainer> | |
| <LoadingBarProgress /> | |
| </LoadingBarContainer> | |
| {waitingForSessionReady ? ( | |
| <> | |
| <ProgressStageText> | |
| {sessionProgress?.stage || '正在创建转码会话...'} | |
| </ProgressStageText> | |
| <DeterminateBarTrack> | |
| <DeterminateBarFill $percent={progressPercent} /> | |
| </DeterminateBarTrack> | |
| <ProgressPercentText>{progressPercent}%</ProgressPercentText> | |
| </> | |
| ) : ( | |
| <> | |
| <LoadingText>加载中...</LoadingText> | |
| <LoadingBarContainer> | |
| <LoadingBarProgress /> | |
| </LoadingBarContainer> | |
| </> | |
| )} | |
| const progressPercent = Math.max(0, Math.min(100, Math.round(sessionProgress?.percent ?? 0))) | |
| return ( | |
| <Container> | |
| <LoadingContainer> | |
| {waitingForSessionReady ? ( | |
| <> | |
| <ProgressStageText> | |
| {sessionProgress?.stage || t('player.transcode.creatingSession')} | |
| </ProgressStageText> | |
| <DeterminateBarTrack> | |
| <DeterminateBarFill | |
| $percent={progressPercent} | |
| role="progressbar" | |
| aria-valuemin={0} | |
| aria-valuemax={100} | |
| aria-valuenow={progressPercent} | |
| /> | |
| </DeterminateBarTrack> | |
| <ProgressPercentText>{progressPercent}%</ProgressPercentText> | |
| </> | |
| ) : ( | |
| <> | |
| <LoadingText>加载中...</LoadingText> | |
| <LoadingBarContainer> | |
| <LoadingBarProgress /> | |
| </LoadingBarContainer> | |
| </> | |
| )} |
| /** | ||
| * 音频进度信息 | ||
| */ | ||
| export interface AudioProgressInfo { | ||
| status: string | ||
| progress_percent: number | ||
| processed_time: number | ||
| total_duration: number | ||
| transcode_speed: number | ||
| eta_seconds: number | ||
| error_message: string | null | ||
| } | ||
|
|
||
| /** | ||
| * 会话进度响应 | ||
| */ | ||
| export interface SessionProgressResponse { | ||
| session_id: string | ||
| status: string | ||
| progress_percent: number | ||
| progress_stage: string | ||
| error_message: string | null | ||
| is_ready: boolean | ||
| playlist_url: string | null | ||
| audio_progress: AudioProgressInfo | null | ||
| } | ||
|
|
There was a problem hiding this comment.
进度类型与实际使用不一致,建议放宽为联合类型并将 stage 设为可选
PlayerPage 中对 progress_percent 做了 number/string 的兼容处理,且对 progress_stage 使用了可选链。为避免类型与后端/实际返回不一致导致的隐患,请将类型调整为联合并将 stage 设为可选。
export interface AudioProgressInfo {
status: string
- progress_percent: number
+ progress_percent: number | string
processed_time: number
total_duration: number
transcode_speed: number
eta_seconds: number
error_message: string | null
}
export interface SessionProgressResponse {
session_id: string
status: string
- progress_percent: number
- progress_stage: string
+ progress_percent: number | string
+ progress_stage?: string
error_message: string | null
is_ready: boolean
playlist_url: string | null
audio_progress: AudioProgressInfo | null
}请同时确认后端返回是否存在其它可能为 string 的数值字段(如 transcode_speed、eta_seconds),必要时一并放宽类型。As per coding guidelines
📝 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 AudioProgressInfo { | |
| status: string | |
| progress_percent: number | |
| processed_time: number | |
| total_duration: number | |
| transcode_speed: number | |
| eta_seconds: number | |
| error_message: string | null | |
| } | |
| /** | |
| * 会话进度响应 | |
| */ | |
| export interface SessionProgressResponse { | |
| session_id: string | |
| status: string | |
| progress_percent: number | |
| progress_stage: string | |
| error_message: string | null | |
| is_ready: boolean | |
| playlist_url: string | null | |
| audio_progress: AudioProgressInfo | null | |
| } | |
| /** | |
| * 音频进度信息 | |
| */ | |
| export interface AudioProgressInfo { | |
| status: string | |
| progress_percent: number | string | |
| processed_time: number | |
| total_duration: number | |
| transcode_speed: number | |
| eta_seconds: number | |
| error_message: string | null | |
| } | |
| /** | |
| * 会话进度响应 | |
| */ | |
| export interface SessionProgressResponse { | |
| session_id: string | |
| status: string | |
| progress_percent: number | string | |
| progress_stage?: string | |
| error_message: string | null | |
| is_ready: boolean | |
| playlist_url: string | null | |
| audio_progress: AudioProgressInfo | null | |
| } |
🤖 Prompt for AI Agents
In src/renderer/src/services/SessionService.ts around lines 108 to 134, the
defined interfaces are too strict compared to actual usage: make numeric fields
that are treated as string or number (at least progress_percent and any
backend-returned numeric-like fields such as transcode_speed, eta_seconds,
processed_time, total_duration) into union types number | string, and mark
progress_stage as optional (progress_stage?: string). Update AudioProgressInfo
and SessionProgressResponse accordingly and audit other numeric fields returned
by the backend to relax types where needed.
…e tokens
- Import theme constants (SPACING, FONT_SIZES, ANIMATION_DURATION, etc.)
- Replace hardcoded width (240px) with SPACING.XXL * 5
- Replace hardcoded heights (4px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_HEIGHT_HOVER
- Replace hardcoded border-radius (2px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_BORDER_RADIUS
- Replace hardcoded font-sizes (16px, 14px) with FONT_SIZES.BASE and FONT_SIZES.SM
- Replace hardcoded transition timing with ANIMATION_DURATION.SLOW and EASING.STANDARD
- Fix: Add setTranscodeStatus('completed') call after HLS session completes
Changes ensure theme consistency, maintainability, and proper status tracking
across components. Progress bar now respects design system tokens for
cross-theme compatibility.
…ion (#209) * feat(player): implement HLS session progress polling with visual feedback - Add waitForSessionReady to poll session creation progress before playback - Integrate useSessionProgress hook for reusable progress tracking logic - Display deterministic progress bar with percentage and stage information during session initialization - Add SessionService.getSessionProgress API with HTTP 425 handling for in-progress state - Update backend submodule to v64aaf0b with HLS session progress support - Remove excessive debug logging in SubtitleOverlay to reduce console noise Changes: PlayerPage: - Add waitForSessionReady state and sessionProgress state for UI rendering - Implement polling loop with 2s interval to fetch session progress until ready - Display progress bar with stage text and percentage during session creation - Handle HTTP 425 (session not ready) gracefully in progress polling - Fallback to default playlist URL if progress response URL parsing fails useSessionProgress Hook: - Provide reusable session progress polling with configurable interval (default 2s) - Auto-stop polling when session is ready or error occurs - Expose startPolling, stopPolling, reset methods for lifecycle control - Implement progress threshold (5%) to reduce log noise SessionService: - Add getSessionProgress(sessionId) API to fetch session creation progress - Define SessionProgressResponse and AudioProgressInfo interfaces - Treat HTTP 425 as normal in-progress state (not error) This enhancement provides real-time visual feedback during HLS session initialization, improving user experience by showing progress instead of generic "loading..." spinner. The polling mechanism ensures playback starts only after the session is fully ready, preventing premature playlist access. * refactor(PlayerPage): replace progress bar hardcoded values with theme tokens - Import theme constants (SPACING, FONT_SIZES, ANIMATION_DURATION, etc.) - Replace hardcoded width (240px) with SPACING.XXL * 5 - Replace hardcoded heights (4px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_HEIGHT_HOVER - Replace hardcoded border-radius (2px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_BORDER_RADIUS - Replace hardcoded font-sizes (16px, 14px) with FONT_SIZES.BASE and FONT_SIZES.SM - Replace hardcoded transition timing with ANIMATION_DURATION.SLOW and EASING.STANDARD - Fix: Add setTranscodeStatus('completed') call after HLS session completes Changes ensure theme consistency, maintainability, and proper status tracking across components. Progress bar now respects design system tokens for cross-theme compatibility.
…ion (#209) * feat(player): implement HLS session progress polling with visual feedback - Add waitForSessionReady to poll session creation progress before playback - Integrate useSessionProgress hook for reusable progress tracking logic - Display deterministic progress bar with percentage and stage information during session initialization - Add SessionService.getSessionProgress API with HTTP 425 handling for in-progress state - Update backend submodule to v64aaf0b with HLS session progress support - Remove excessive debug logging in SubtitleOverlay to reduce console noise Changes: PlayerPage: - Add waitForSessionReady state and sessionProgress state for UI rendering - Implement polling loop with 2s interval to fetch session progress until ready - Display progress bar with stage text and percentage during session creation - Handle HTTP 425 (session not ready) gracefully in progress polling - Fallback to default playlist URL if progress response URL parsing fails useSessionProgress Hook: - Provide reusable session progress polling with configurable interval (default 2s) - Auto-stop polling when session is ready or error occurs - Expose startPolling, stopPolling, reset methods for lifecycle control - Implement progress threshold (5%) to reduce log noise SessionService: - Add getSessionProgress(sessionId) API to fetch session creation progress - Define SessionProgressResponse and AudioProgressInfo interfaces - Treat HTTP 425 as normal in-progress state (not error) This enhancement provides real-time visual feedback during HLS session initialization, improving user experience by showing progress instead of generic "loading..." spinner. The polling mechanism ensures playback starts only after the session is fully ready, preventing premature playlist access. * refactor(PlayerPage): replace progress bar hardcoded values with theme tokens - Import theme constants (SPACING, FONT_SIZES, ANIMATION_DURATION, etc.) - Replace hardcoded width (240px) with SPACING.XXL * 5 - Replace hardcoded heights (4px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_HEIGHT_HOVER - Replace hardcoded border-radius (2px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_BORDER_RADIUS - Replace hardcoded font-sizes (16px, 14px) with FONT_SIZES.BASE and FONT_SIZES.SM - Replace hardcoded transition timing with ANIMATION_DURATION.SLOW and EASING.STANDARD - Fix: Add setTranscodeStatus('completed') call after HLS session completes Changes ensure theme consistency, maintainability, and proper status tracking across components. Progress bar now respects design system tokens for cross-theme compatibility.
# [1.1.0-alpha.3](v1.1.0-alpha.2...v1.1.0-alpha.3) (2025-10-13) ### Bug Fixes * **codec-compatibility:** handle missing codec information gracefully ([46ed61a](46ed61a)) * **FFmpegSection:** manage completion timeout for download process ([99018a0](99018a0)) * **FFprobeSection:** add return statement to download progress polling function ([d99231f](d99231f)) * **FFprobeSection:** ensure timeout cleanup after download success ([75d8429](75d8429)) * **FFprobeSection:** manage success timeout for download completion ([f4332d0](f4332d0)) * **FFprobeSection:** standardize font size using theme constants ([4665620](4665620)) * **FFprobeSection:** standardize spacing in styled components ([ef89ef6](ef89ef6)) * **MediaServerService:** enhance error handling for file existence check ([fe552e3](fe552e3)) * **MediaServerService:** replace fs.existsSync with async stat for file existence check ([566af29](566af29)) * **player:** apply playback rate change through orchestrator when cycling speeds ([#210](#210)) ([d69cc52](d69cc52)) * **player:** remove HLS player missing error handling ([5c2aa64](5c2aa64)) * **TranscodeLoadingIndicator:** remove logging for loading indicator display ([fe69cd0](fe69cd0)) * **UvBootstrapperService:** enhance UV download logic with cached path checks ([e39cb7d](e39cb7d)) * **UvBootstrapperService:** ensure temp directory cleanup after download ([811b597](811b597)) * **UvBootstrapperService:** prevent concurrent downloads by checking download controllers ([17be090](17be090)) * **VolumeIndicator:** skip indicator display on initial render ([d0cfb23](d0cfb23)) ### Features * **media-server:** add transcode cache cleanup for deleted videos ([b5b9601](b5b9601)) * **player:** HLS session progress polling with media server integration ([#209](#209)) ([0135646](0135646))
…ion (#209) * feat(player): implement HLS session progress polling with visual feedback - Add waitForSessionReady to poll session creation progress before playback - Integrate useSessionProgress hook for reusable progress tracking logic - Display deterministic progress bar with percentage and stage information during session initialization - Add SessionService.getSessionProgress API with HTTP 425 handling for in-progress state - Update backend submodule to v64aaf0b with HLS session progress support - Remove excessive debug logging in SubtitleOverlay to reduce console noise Changes: PlayerPage: - Add waitForSessionReady state and sessionProgress state for UI rendering - Implement polling loop with 2s interval to fetch session progress until ready - Display progress bar with stage text and percentage during session creation - Handle HTTP 425 (session not ready) gracefully in progress polling - Fallback to default playlist URL if progress response URL parsing fails useSessionProgress Hook: - Provide reusable session progress polling with configurable interval (default 2s) - Auto-stop polling when session is ready or error occurs - Expose startPolling, stopPolling, reset methods for lifecycle control - Implement progress threshold (5%) to reduce log noise SessionService: - Add getSessionProgress(sessionId) API to fetch session creation progress - Define SessionProgressResponse and AudioProgressInfo interfaces - Treat HTTP 425 as normal in-progress state (not error) This enhancement provides real-time visual feedback during HLS session initialization, improving user experience by showing progress instead of generic "loading..." spinner. The polling mechanism ensures playback starts only after the session is fully ready, preventing premature playlist access. * refactor(PlayerPage): replace progress bar hardcoded values with theme tokens - Import theme constants (SPACING, FONT_SIZES, ANIMATION_DURATION, etc.) - Replace hardcoded width (240px) with SPACING.XXL * 5 - Replace hardcoded heights (4px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_HEIGHT_HOVER - Replace hardcoded border-radius (2px) with COMPONENT_TOKENS.PROGRESS_BAR.TRACK_BORDER_RADIUS - Replace hardcoded font-sizes (16px, 14px) with FONT_SIZES.BASE and FONT_SIZES.SM - Replace hardcoded transition timing with ANIMATION_DURATION.SLOW and EASING.STANDARD - Fix: Add setTranscodeStatus('completed') call after HLS session completes Changes ensure theme consistency, maintainability, and proper status tracking across components. Progress bar now respects design system tokens for cross-theme compatibility.
# [1.1.0-beta.1](v1.0.0...v1.1.0-beta.1) (2025-10-15) ### Bug Fixes * **AppUpdater, FFmpegDownloadService:** update default mirror source to global ([83194b3](83194b3)) * **build:** adjust resource handling for media-server in packaging ([086bd1b](086bd1b)) * **codec-compatibility:** handle missing codec information gracefully ([ea29f21](ea29f21)) * **FFmpegSection:** manage completion timeout for download process ([39b43c0](39b43c0)) * **FFprobeSection:** add return statement to download progress polling function ([49636cf](49636cf)) * **FFprobeSection:** ensure timeout cleanup after download success ([81a1431](81a1431)) * **FFprobeSection:** manage success timeout for download completion ([ce55d49](ce55d49)) * **FFprobeSection:** standardize font size using theme constants ([6387445](6387445)) * **FFprobeSection:** standardize spacing in styled components ([ba3c3d4](ba3c3d4)) * **homepage:** improve bottom spacing for card grid ([#194](#194)) ([801b6cd](801b6cd)) * make subtitle overlay container semantic ([2d6ae60](2d6ae60)) * **MediaServerService:** enhance error handling for file existence check ([11b74ef](11b74ef)) * **MediaServerService:** replace fs.existsSync with async stat for file existence check ([c9c98da](c9c98da)) * **player:** apply playback rate change through orchestrator when cycling speeds ([#210](#210)) ([fa9aa09](fa9aa09)) * **player:** remove HLS player missing error handling ([c7b593e](c7b593e)) * remove green glow effect from progress bar ([#196](#196)) ([abc6f3e](abc6f3e)), closes [#e50914](https://github.com/mkdir700/EchoPlayer/issues/e50914) [#00b96](https://github.com/mkdir700/EchoPlayer/issues/00b96) * **semantic-release:** enhance version increment rules for prerelease branches ([#199](#199)) ([5d1e533](5d1e533)) * **theme:** resolve theme color not updating immediately for Switch components and progress bars ([#197](#197)) ([eed9ea2](eed9ea2)) * **TranscodeLoadingIndicator:** remove logging for loading indicator display ([085db44](085db44)) * **useSubtitleScrollStateMachine:** start auto-return timer on user interactions ([8496ae0](8496ae0)) * **UvBootstrapperService:** enhance UV download logic with cached path checks ([fc0791a](fc0791a)) * **UvBootstrapperService:** ensure temp directory cleanup after download ([02c7b16](02c7b16)) * **UvBootstrapperService:** prevent concurrent downloads by checking download controllers ([19d31e7](19d31e7)) * **VolumeIndicator:** skip indicator display on initial render ([82d2281](82d2281)) * **workflow:** update artifact listing command for better compatibility ([dfb6ee4](dfb6ee4)) ### Features * integrate session-backed HLS playback flow ([#200](#200)) ([ee972d1](ee972d1)) * intro backend for hls player ([2d34e7b](2d34e7b)) * **media-server:** add transcode cache cleanup for deleted videos ([e2de9ad](e2de9ad)) * **media-server:** implement runtime runtime management system ([#204](#204)) ([f5f68b0](f5f68b0)) * optimize media-server build output to resources directory ([#201](#201)) ([1b8c28e](1b8c28e)) * **player:** add animated loading progress bar to PlayerPage ([#206](#206)) ([8ba6f7f](8ba6f7f)) * **player:** add media server recommendation prompt for incompatible videos ([#205](#205)) ([63221a2](63221a2)) * **player:** add subtitle search functionality ([c3228c3](c3228c3)) * **player:** add toggle auto-pause functionality ([98b59ef](98b59ef)) * **player:** HLS session progress polling with media server integration ([#209](#209)) ([a76e8c2](a76e8c2)) * **PlayerSettingsLoader:** add mask mode to subtitle overlay ([56e4f65](56e4f65)) * **player:** update seek button icons from rewind/fastforward to undo/redo ([#193](#193)) ([1612c43](1612c43)) * **RegionDetection:** integrate region detection service for IP-based country identification ([dbeb077](dbeb077)) * **subtitle:** introduce mask mode for subtitle overlay ([e1fb3eb](e1fb3eb)) * **SubtitleOverlay:** enhance positioning and collision handling ([92b061a](92b061a)) * **UvBootstrapperService:** enhance download management with concurrency control ([20522e9](20522e9)) ### Reverts * "fix(build): adjust resource handling for media-server in packaging" ([2133401](2133401))
# [1.1.0](v1.0.0...v1.1.0) (2025-10-16) ### Bug Fixes * **AppUpdater, FFmpegDownloadService:** update default mirror source to global ([83194b3](83194b3)) * **build:** adjust resource handling for media-server in packaging ([086bd1b](086bd1b)) * **codec-compatibility:** handle missing codec information gracefully ([ea29f21](ea29f21)) * **FFmpegSection:** manage completion timeout for download process ([39b43c0](39b43c0)) * **FFprobeSection:** add return statement to download progress polling function ([49636cf](49636cf)) * **FFprobeSection:** ensure timeout cleanup after download success ([81a1431](81a1431)) * **FFprobeSection:** manage success timeout for download completion ([ce55d49](ce55d49)) * **FFprobeSection:** standardize font size using theme constants ([6387445](6387445)) * **FFprobeSection:** standardize spacing in styled components ([ba3c3d4](ba3c3d4)) * **homepage:** improve bottom spacing for card grid ([#194](#194)) ([801b6cd](801b6cd)) * make subtitle overlay container semantic ([2d6ae60](2d6ae60)) * **MediaServerService:** enhance error handling for file existence check ([11b74ef](11b74ef)) * **MediaServerService:** replace fs.existsSync with async stat for file existence check ([c9c98da](c9c98da)) * **player:** apply playback rate change through orchestrator when cycling speeds ([#210](#210)) ([fa9aa09](fa9aa09)) * **player:** remove HLS player missing error handling ([c7b593e](c7b593e)) * **player:** restore muted state when re-entering player page ([1ec5c56](1ec5c56)) * remove green glow effect from progress bar ([#196](#196)) ([abc6f3e](abc6f3e)), closes [#e50914](https://github.com/mkdir700/EchoPlayer/issues/e50914) [#00b96](https://github.com/mkdir700/EchoPlayer/issues/00b96) * **semantic-release:** enhance version increment rules for prerelease branches ([#199](#199)) ([5d1e533](5d1e533)) * **theme:** resolve theme color not updating immediately for Switch components and progress bars ([#197](#197)) ([eed9ea2](eed9ea2)) * **TranscodeLoadingIndicator:** remove logging for loading indicator display ([085db44](085db44)) * **useSubtitleScrollStateMachine:** start auto-return timer on user interactions ([8496ae0](8496ae0)) * **UvBootstrapperService:** enhance UV download logic with cached path checks ([fc0791a](fc0791a)) * **UvBootstrapperService:** ensure temp directory cleanup after download ([02c7b16](02c7b16)) * **UvBootstrapperService:** prevent concurrent downloads by checking download controllers ([19d31e7](19d31e7)) * **VolumeIndicator:** skip indicator display on initial render ([82d2281](82d2281)) * **workflow:** update artifact listing command for better compatibility ([dfb6ee4](dfb6ee4)) ### Features * integrate session-backed HLS playback flow ([#200](#200)) ([ee972d1](ee972d1)) * intro backend for hls player ([2d34e7b](2d34e7b)) * **media-server:** add transcode cache cleanup for deleted videos ([e2de9ad](e2de9ad)) * **media-server:** implement runtime runtime management system ([#204](#204)) ([f5f68b0](f5f68b0)) * optimize media-server build output to resources directory ([#201](#201)) ([1b8c28e](1b8c28e)) * **player:** add animated loading progress bar to PlayerPage ([#206](#206)) ([8ba6f7f](8ba6f7f)) * **player:** add media server recommendation prompt for incompatible videos ([#205](#205)) ([63221a2](63221a2)) * **player:** add subtitle search functionality ([c3228c3](c3228c3)) * **player:** add toggle auto-pause functionality ([98b59ef](98b59ef)) * **player:** HLS session progress polling with media server integration ([#209](#209)) ([a76e8c2](a76e8c2)) * **PlayerSettingsLoader:** add mask mode to subtitle overlay ([56e4f65](56e4f65)) * **player:** update seek button icons from rewind/fastforward to undo/redo ([#193](#193)) ([1612c43](1612c43)) * **RegionDetection:** integrate region detection service for IP-based country identification ([dbeb077](dbeb077)) * **subtitle:** introduce mask mode for subtitle overlay ([e1fb3eb](e1fb3eb)) * **SubtitleOverlay:** enhance positioning and collision handling ([92b061a](92b061a)) * **UvBootstrapperService:** enhance download management with concurrency control ([20522e9](20522e9)) ### Reverts * "fix(build): adjust resource handling for media-server in packaging" ([2133401](2133401))
Summary by CodeRabbit
Summary by CodeRabbit
新功能
性能与稳定性
杂项