mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-19 19:51:20 -08:00
116 lines
3.4 KiB
TypeScript
116 lines
3.4 KiB
TypeScript
import type ArtplayerToolThumbnail from './index'
|
|
import type { Cleanup } from './types'
|
|
import { cleanupAll, revoke, stateFor } from './lifecycle'
|
|
|
|
export function loadSource(tool: ArtplayerToolThumbnail, file?: File | null) {
|
|
const state = stateFor(tool)
|
|
if (!file || state.closed)
|
|
return
|
|
const initialEpoch = state.epoch
|
|
const video = tool.video
|
|
const support = video.canPlayType(file.type)
|
|
tool.errorHandle(support === 'maybe' || support === 'probably', `Playback of this file format is not supported: ${file.type}`)
|
|
if (state.closed || state.epoch !== initialEpoch)
|
|
return
|
|
const url = URL.createObjectURL(file)
|
|
state.sourceUrls.add(url)
|
|
if (state.closed || state.epoch !== initialEpoch) {
|
|
revoke(state.sourceUrls, url)
|
|
return
|
|
}
|
|
const epoch = ++state.epoch
|
|
const initialWait = !state.sourceUrl && !tool.file && state.job?.adopt(epoch)
|
|
if (!initialWait)
|
|
state.job?.cancel('source changed')
|
|
state.loading = true
|
|
const current = () => !state.closed && state.epoch === epoch
|
|
const previousListeners = state.sourceListeners
|
|
const listeners: Cleanup[] = []
|
|
state.sourceListeners = listeners
|
|
let pendingCleanup = () => {}
|
|
let reported = false
|
|
const error = () => {
|
|
if (!current() || reported || (video.currentSrc && video.currentSrc !== url))
|
|
return
|
|
reported = true
|
|
state.loading = false
|
|
const failure = new Error(`Unable to load video: media error ${video.error?.code || 0}`)
|
|
if (state.job)
|
|
state.job.fail(failure)
|
|
else
|
|
tool.emit('error', failure.message)
|
|
}
|
|
const ready = () => {
|
|
if (current() && (!video.currentSrc || video.currentSrc === url)) {
|
|
state.loading = false
|
|
state.job?.ready()
|
|
}
|
|
}
|
|
try {
|
|
cleanupAll(previousListeners.splice(0))
|
|
if (!current()) {
|
|
revoke(state.sourceUrls, url)
|
|
return
|
|
}
|
|
for (const [name, callback] of [['error', error], ['loadedmetadata', ready]] as const) {
|
|
pendingCleanup = () => video.removeEventListener(name, callback)
|
|
listeners.push(pendingCleanup)
|
|
video.addEventListener(name, callback)
|
|
if (!current()) {
|
|
cleanupAll([pendingCleanup, ...listeners.splice(0)])
|
|
revoke(state.sourceUrls, url)
|
|
return
|
|
}
|
|
}
|
|
tool.videoUrl = url
|
|
tool.file = file
|
|
tool.emit('file', file)
|
|
if (!current()) {
|
|
revoke(state.sourceUrls, url)
|
|
return
|
|
}
|
|
video.src = url
|
|
if (!current()) {
|
|
revoke(state.sourceUrls, url)
|
|
return
|
|
}
|
|
state.sourceUrl = url
|
|
for (const previous of [...state.sourceUrls]) {
|
|
if (previous !== url)
|
|
revoke(state.sourceUrls, previous)
|
|
}
|
|
if (current())
|
|
tool.emit('video', video)
|
|
}
|
|
catch (error) {
|
|
if (current()) {
|
|
state.loading = false
|
|
state.job?.cancel('source setup failed')
|
|
}
|
|
try {
|
|
cleanupAll([pendingCleanup, ...listeners.splice(0)])
|
|
}
|
|
catch {}
|
|
revoke(state.sourceUrls, url)
|
|
throw error
|
|
}
|
|
}
|
|
|
|
export function replaceThumbnail(tool: ArtplayerToolThumbnail, blob: Blob, live: () => boolean) {
|
|
const state = stateFor(tool)
|
|
const url = URL.createObjectURL(blob)
|
|
state.thumbnailUrls.add(url)
|
|
if (!live()) {
|
|
revoke(state.thumbnailUrls, url)
|
|
return null
|
|
}
|
|
const previous = new Set([...state.thumbnailUrls, tool.thumbnailUrl])
|
|
state.thumbnailUrl = url
|
|
tool.thumbnailUrl = url
|
|
for (const old of previous) {
|
|
if (old && old !== url)
|
|
revoke(state.thumbnailUrls, old)
|
|
}
|
|
return live() ? url : null
|
|
}
|