Files
ArtPlayer/packages/artplayer/src/subtitle/track.ts
T

84 lines
2.3 KiB
TypeScript

import type { SubtitleView } from './types'
import { releaseSubtitleURL, subtitleState } from './state'
export function replaceSubtitleTrack(subtitle: SubtitleView, kind: string, url: string): void {
const state = subtitleState(subtitle)
if (state.scope.closed)
return
const revision = ++state.trackRevision
const { art } = subtitle
const { template } = art
const previous = template.$track
const parent = previous.parentNode
const next = previous.nextSibling
const track = document.createElement('track')
const scope = state.scope.child()
scope.add(() => {
track.onload = null
track.onerror = null
})
let committed = false
try {
track.default = true
track.kind = kind
track.src = url
track.label = art.option.subtitle.name || 'Artplayer'
track.track.mode = 'hidden'
track.onload = () => {
if (!scope.closed && template.$track === track)
art.emit('subtitleLoad', subtitle.cues, subtitle.option)
}
track.onerror = () => {
if (!scope.closed && template.$track === track)
art.notice.show = new Error('Failed to load subtitle track')
}
if (scope.closed || state.trackRevision !== revision) {
scope.dispose()
return
}
previous.remove()
template.$video.appendChild(track)
template.$track = track
const textTrack = subtitle.textTrack
const cleanup = textTrack
? art.proxy(textTrack, 'cuechange', () => {
if (!scope.closed && template.$track === track)
subtitle.update()
})
: () => {}
scope.add(() => {
art.events.remove(cleanup)
})
if (scope.closed || state.trackRevision !== revision) {
scope.dispose()
track.remove()
return
}
const previousScope = state.track
state.track = scope
subtitle.destroyEvent = cleanup
previous.onload = null
previous.onerror = null
committed = true
try {
previousScope?.dispose()
}
finally {
if (state.ownedURL && state.ownedURL !== url)
releaseSubtitleURL(state)
}
}
catch (error) {
if (committed)
throw error
scope.dispose()
track.remove()
if (state.scope.closed || state.trackRevision !== revision)
throw error
template.$track = previous
if (parent)
parent.insertBefore(previous, next?.parentNode === parent ? next : null)
throw error
}
}