mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-26 08:51:20 -08:00
78 lines
2.4 KiB
TypeScript
78 lines
2.4 KiB
TypeScript
import type { ControlHost } from '../types'
|
|
import type ResourceScope from '../../lifecycle/scope'
|
|
import { keyboardSlider } from '../../accessibility/slider'
|
|
import { entryScope } from '../../component/resources'
|
|
import { isClosing } from '../../lifecycle/instance'
|
|
import { captureSource, getSourceScope } from '../../source/operation'
|
|
import { positionRestoration } from '../../source/restore-position'
|
|
import { secondToTime } from '../../utils'
|
|
import { controlEvents } from '../resources'
|
|
|
|
export function installProgressKeyboard(art: ControlHost, element: HTMLDivElement): void {
|
|
const scope = entryScope(element)
|
|
const { on } = controlEvents(art, element)
|
|
let revision = 0
|
|
let pending: ResourceScope | undefined
|
|
const update = keyboardSlider(scope, element, art.i18n.get('Progress'), () => ({
|
|
min: 0,
|
|
max: art.duration,
|
|
value: art.currentTime,
|
|
step: art.constructor.SEEK_STEP,
|
|
text: value => `${secondToTime(value)} / ${secondToTime(Number.isFinite(art.duration) && art.duration > 0 ? art.duration : 0)}`,
|
|
}), (value) => {
|
|
const action = ++revision
|
|
pending?.dispose()
|
|
const operation = scope.child()
|
|
pending = operation
|
|
const releaseSource = getSourceScope(art).add(() => {
|
|
operation.dispose()
|
|
})
|
|
operation.add(() => {
|
|
releaseSource()
|
|
})
|
|
operation.add(() => {
|
|
if (pending === operation)
|
|
pending = undefined
|
|
})
|
|
const sourceActive = captureSource(art)
|
|
const active = () => action === revision && !operation.closed && !isClosing(art) && sourceActive()
|
|
const position = positionRestoration(art, value, active)
|
|
const settle = () => {
|
|
if (!active()) {
|
|
operation.dispose()
|
|
return
|
|
}
|
|
if (position.ready()) {
|
|
operation.dispose()
|
|
update()
|
|
}
|
|
}
|
|
for (const name of ['video:seeked', 'video:ended'] as const) {
|
|
art.on(name, settle)
|
|
operation.add(() => {
|
|
art.off(name, settle)
|
|
})
|
|
}
|
|
try {
|
|
art.emit('setBar', 'played', value / art.duration)
|
|
if (active()) {
|
|
position.restore(() => {
|
|
art.seek = value
|
|
})
|
|
}
|
|
settle()
|
|
}
|
|
catch (error) {
|
|
operation.dispose()
|
|
throw error
|
|
}
|
|
})
|
|
on('video:loadedmetadata', update)
|
|
on('video:durationchange', update)
|
|
on('video:emptied', update)
|
|
on('video:timeupdate', update)
|
|
on('video:seeking', update)
|
|
on('video:seeked', update)
|
|
on('video:ended', update)
|
|
}
|