b u g
This commit is contained in:
truewhile
2026-08-25 19:41:02 +08:00
parent b61c51e064
commit 10770b2b77
+24 -27
View File
@@ -115,12 +115,6 @@ export function PlayerVideoStage({
return return
} }
const timers = new Set<ReturnType<typeof setTimeout>>()
const delay = (fn: () => void, ms: number) => {
const id = setTimeout(fn, ms)
timers.add(id)
}
const updateCue = () => { const updateCue = () => {
const trackEls = Array.from(video.querySelectorAll('track')) const trackEls = Array.from(video.querySelectorAll('track'))
const selectedEl = trackEls[subtitleIndex] const selectedEl = trackEls[subtitleIndex]
@@ -130,16 +124,24 @@ export function PlayerVideoStage({
return return
} }
// 优先从浏览器 activeCues 中取当前文本;若浏览器在 hidden 模式下延迟触发 cuechange,
// 则从 tt.cues 中根据 video.currentTime 实时匹配当前字幕,确保初次加载无感立即可见。
const texts: string[] = []
if (tt.activeCues && tt.activeCues.length > 0) { if (tt.activeCues && tt.activeCues.length > 0) {
const texts: string[] = []
for (let i = 0; i < tt.activeCues.length; i++) { for (let i = 0; i < tt.activeCues.length; i++) {
const cue = tt.activeCues[i] as VTTCue const cue = tt.activeCues[i] as VTTCue
if (cue && cue.text) texts.push(cue.text) if (cue && cue.text) texts.push(cue.text)
} }
setActiveCueText(texts.join('\n')) } else if (tt.cues && tt.cues.length > 0) {
} else { const cur = video.currentTime
setActiveCueText('') for (let i = 0; i < tt.cues.length; i++) {
const cue = tt.cues[i] as VTTCue
if (cue && cur >= cue.startTime && cur <= cue.endTime && cue.text) {
texts.push(cue.text)
}
}
} }
setActiveCueText(texts.join('\n'))
} }
const apply = () => { const apply = () => {
@@ -162,18 +164,8 @@ export function PlayerVideoStage({
tt.addEventListener('cuechange', updateCue) tt.addEventListener('cuechange', updateCue)
} }
// 竞态兜底重载检测 selected.removeEventListener('load', updateCue)
delay(() => { selected.addEventListener('load', updateCue)
const curTt = selected.track
if (curTt && curTt.mode === 'hidden' && (!curTt.cues || curTt.cues.length === 0)) {
const src = selected.getAttribute('src')
if (src) {
selected.setAttribute('src', '')
selected.setAttribute('src', src)
curTt.mode = 'hidden'
}
}
}, 1200)
updateCue() updateCue()
} }
@@ -183,20 +175,24 @@ export function PlayerVideoStage({
video.addEventListener('timeupdate', updateCue) video.addEventListener('timeupdate', updateCue)
video.addEventListener('seeking', updateCue) video.addEventListener('seeking', updateCue)
video.addEventListener('seeked', updateCue) video.addEventListener('seeked', updateCue)
video.addEventListener('playing', updateCue)
return () => { return () => {
video.removeEventListener('loadedmetadata', apply) video.removeEventListener('loadedmetadata', apply)
video.removeEventListener('timeupdate', updateCue) video.removeEventListener('timeupdate', updateCue)
video.removeEventListener('seeking', updateCue) video.removeEventListener('seeking', updateCue)
video.removeEventListener('seeked', updateCue) video.removeEventListener('seeked', updateCue)
timers.forEach(clearTimeout) video.removeEventListener('playing', updateCue)
const trackEls = Array.from(video.querySelectorAll('track')) const trackEls = Array.from(video.querySelectorAll('track'))
const selected = trackEls[subtitleIndex] const selected = trackEls[subtitleIndex]
if (selected?.track) { if (selected) {
selected.track.removeEventListener('cuechange', updateCue) selected.removeEventListener('load', updateCue)
if (selected.track) {
selected.track.removeEventListener('cuechange', updateCue)
}
} }
} }
}, [subtitleIndex, subs, videoRef]) }, [subtitleIndex, subs, videoRef, media])
// 根据视频画面宽高比与舞台宽高比,确定视频在哪个轴向撑满 100% // 根据视频画面宽高比与舞台宽高比,确定视频在哪个轴向撑满 100%
const isWiderThanStage = const isWiderThanStage =
@@ -238,13 +234,14 @@ export function PlayerVideoStage({
className="h-full w-full object-contain bg-black" className="h-full w-full object-contain bg-black"
onError={onVideoError} onError={onVideoError}
> >
{subs.map((track) => ( {subs.map((track, index) => (
<track <track
key={track.path} key={track.path}
kind="subtitles" kind="subtitles"
src={subtitlesAPI.url(media.id, track.path)} src={subtitlesAPI.url(media.id, track.path)}
srcLang={track.lang} srcLang={track.lang}
label={track.label || track.lang} label={track.label || track.lang}
default={index === subtitleIndex}
/> />
))} ))}
</video> </video>