fix: filter stale timeupdate events by tracking sceneVideo element

This commit is contained in:
2026-06-08 21:09:10 +08:00
parent 6c0deea0e2
commit 972738572f

View File

@@ -11,6 +11,7 @@ export class VideoManager {
private currentSrc = '' private currentSrc = ''
private preloaded: Map<'A' | 'B', string> = new Map() private preloaded: Map<'A' | 'B', string> = new Map()
private switching = false private switching = false
private sceneVideo: HTMLVideoElement | null = null
private get active(): HTMLVideoElement { private get active(): HTMLVideoElement {
return this.activeSlot === 'A' ? this.elA! : this.elB! return this.activeSlot === 'A' ? this.elA! : this.elB!
@@ -27,6 +28,7 @@ export class VideoManager {
attach(elA: HTMLVideoElement, elB: HTMLVideoElement) { attach(elA: HTMLVideoElement, elB: HTMLVideoElement) {
this.elA = elA this.elA = elA
this.elB = elB this.elB = elB
this.sceneVideo = elA
for (const el of [elA, elB]) { for (const el of [elA, elB]) {
el.addEventListener('ended', this.handleEnded) el.addEventListener('ended', this.handleEnded)
el.addEventListener('timeupdate', this.handleTimeUpdate) el.addEventListener('timeupdate', this.handleTimeUpdate)
@@ -41,6 +43,7 @@ export class VideoManager {
} }
detach() { detach() {
this.sceneVideo = null
for (const el of [this.elA, this.elB]) { for (const el of [this.elA, this.elB]) {
if (!el) continue if (!el) continue
el.removeEventListener('ended', this.handleEnded) el.removeEventListener('ended', this.handleEnded)
@@ -55,6 +58,7 @@ export class VideoManager {
playInitial(src: string, preloadUrls: string[]) { playInitial(src: string, preloadUrls: string[]) {
if (!this.elA) return if (!this.elA) return
this.sceneVideo = this.elA
this.currentSrc = src this.currentSrc = src
this.activeSlot = 'A' this.activeSlot = 'A'
this.preloaded.set('A', src) this.preloaded.set('A', src)
@@ -88,10 +92,12 @@ export class VideoManager {
const alreadyPreloaded = this.preloaded.get(inKey) const alreadyPreloaded = this.preloaded.get(inKey)
if (alreadyPreloaded === src) { if (alreadyPreloaded === src) {
this.sceneVideo = this.inactive
this.doCrossFade(src, preloadUrls) this.doCrossFade(src, preloadUrls)
} else { } else {
this.preloaded.set(inKey, src) this.preloaded.set(inKey, src)
this.inactive.src = src this.inactive.src = src
this.sceneVideo = this.inactive
this.waitReady(this.inactive).then(() => { this.waitReady(this.inactive).then(() => {
this.doCrossFade(src, preloadUrls) this.doCrossFade(src, preloadUrls)
}) })
@@ -169,10 +175,9 @@ export class VideoManager {
this.onEndCallback?.() this.onEndCallback?.()
} }
private handleTimeUpdate = () => { private handleTimeUpdate = (e: Event) => {
if (this.active) { const el = e.target as HTMLVideoElement
const t = this.active.currentTime if (!this.sceneVideo || el !== this.sceneVideo) return
this.onTimeCallbacks.forEach((cb) => cb(t)) this.onTimeCallbacks.forEach((cb) => cb(el.currentTime))
}
} }
} }