- Reorder onEnd callback before play() in Engine.goToScene to prevent missed ended event if video ends synchronously - Wait for loadedmetadata event in VideoManager.play() before seeking to ensure currentTime reset works correctly on new video sources
72 lines
1.8 KiB
TypeScript
72 lines
1.8 KiB
TypeScript
type VideoEndCallback = () => void
|
|
type TimeUpdateCallback = (time: number) => void
|
|
|
|
export class VideoManager {
|
|
private videoEl: HTMLVideoElement | null = null
|
|
private onEndCallback: VideoEndCallback | null = null
|
|
private onTimeCallback: TimeUpdateCallback | null = null
|
|
private lastSrc: string = ''
|
|
|
|
attach(videoEl: HTMLVideoElement) {
|
|
this.videoEl = videoEl
|
|
videoEl.addEventListener('ended', this.handleEnded)
|
|
videoEl.addEventListener('timeupdate', this.handleTimeUpdate)
|
|
}
|
|
|
|
detach() {
|
|
if (!this.videoEl) return
|
|
this.videoEl.removeEventListener('ended', this.handleEnded)
|
|
this.videoEl.removeEventListener('timeupdate', this.handleTimeUpdate)
|
|
this.videoEl = null
|
|
}
|
|
|
|
play(src: string) {
|
|
if (!this.videoEl) return
|
|
if (this.lastSrc !== src) {
|
|
this.videoEl.src = src
|
|
this.lastSrc = src
|
|
if (this.videoEl.readyState >= 1) {
|
|
this.videoEl.currentTime = 0
|
|
this.videoEl.play().catch(() => {})
|
|
} else {
|
|
const onReady = () => {
|
|
if (this.videoEl) {
|
|
this.videoEl.currentTime = 0
|
|
this.videoEl.play().catch(() => {})
|
|
}
|
|
}
|
|
this.videoEl.addEventListener('loadedmetadata', onReady, { once: true })
|
|
}
|
|
} else {
|
|
this.videoEl.currentTime = 0
|
|
this.videoEl.play().catch(() => {})
|
|
}
|
|
}
|
|
|
|
pause() {
|
|
this.videoEl?.pause()
|
|
}
|
|
|
|
getCurrentTime(): number {
|
|
return this.videoEl?.currentTime ?? 0
|
|
}
|
|
|
|
onEnd(cb: VideoEndCallback) {
|
|
this.onEndCallback = cb
|
|
}
|
|
|
|
onTimeUpdate(cb: TimeUpdateCallback) {
|
|
this.onTimeCallback = cb
|
|
}
|
|
|
|
private handleEnded = () => {
|
|
this.onEndCallback?.()
|
|
}
|
|
|
|
private handleTimeUpdate = () => {
|
|
if (this.videoEl) {
|
|
this.onTimeCallback?.(this.videoEl.currentTime)
|
|
}
|
|
}
|
|
}
|