mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-17 10:01:20 -08:00
133 lines
3.1 KiB
TypeScript
133 lines
3.1 KiB
TypeScript
import type { Cleanup, ExtractionJob, ThumbnailSheet } from './types'
|
|
|
|
export function cleanupAll(actions: Cleanup[]) {
|
|
let failure: unknown
|
|
let failed = false
|
|
for (const action of actions) {
|
|
try {
|
|
action()
|
|
}
|
|
catch (error) {
|
|
if (!failed) {
|
|
failed = true
|
|
failure = error
|
|
}
|
|
}
|
|
}
|
|
return { failed, failure }
|
|
}
|
|
|
|
export default function createSession(publish: (sheet: ThumbnailSheet) => void, report: (error: unknown) => void) {
|
|
let closed = false
|
|
let current: ExtractionJob | undefined
|
|
let lastUrl: string | undefined
|
|
const urls = new Set<string>()
|
|
|
|
function release(url: string | undefined) {
|
|
if (url !== undefined && urls.delete(url))
|
|
URL.revokeObjectURL(url)
|
|
}
|
|
|
|
function cancel() {
|
|
const previous = current
|
|
current = undefined
|
|
previous?.dispose()
|
|
}
|
|
|
|
function destroy() {
|
|
if (closed)
|
|
return
|
|
closed = true
|
|
const result = cleanupAll([cancel, ...[...urls].map(url => () => release(url))])
|
|
lastUrl = undefined
|
|
if (result.failed)
|
|
report(result.failure)
|
|
}
|
|
|
|
function start() {
|
|
if (closed)
|
|
return
|
|
// Install the replacement before cleanup, which can reenter through host APIs.
|
|
const previous = current
|
|
const actions: Cleanup[] = []
|
|
let disposed = false
|
|
const job: ExtractionJob = {
|
|
active: () => !closed && !disposed && current === job,
|
|
own(action) {
|
|
if (disposed) {
|
|
const result = cleanupAll([action])
|
|
if (result.failed)
|
|
report(result.failure)
|
|
}
|
|
else {
|
|
actions.push(action)
|
|
}
|
|
},
|
|
dispose() {
|
|
if (disposed)
|
|
return
|
|
disposed = true
|
|
if (current === job)
|
|
current = undefined
|
|
const result = cleanupAll(actions.splice(0).reverse())
|
|
if (result.failed)
|
|
report(result.failure)
|
|
},
|
|
fail(error) {
|
|
if (!job.active())
|
|
return
|
|
job.dispose()
|
|
report(error)
|
|
},
|
|
guard(callback) {
|
|
return (...args) => {
|
|
if (!job.active())
|
|
return
|
|
try {
|
|
return callback(...args)
|
|
}
|
|
catch (error) {
|
|
job.fail(error)
|
|
}
|
|
}
|
|
},
|
|
publish(blob, config) {
|
|
if (!job.active())
|
|
return
|
|
if (!blob)
|
|
throw new Error('Auto-thumbnail encoding returned no Blob')
|
|
const url = URL.createObjectURL(blob)
|
|
urls.add(url)
|
|
if (!job.active()) {
|
|
release(url)
|
|
return
|
|
}
|
|
const previousUrl = lastUrl
|
|
lastUrl = url
|
|
try {
|
|
publish({ url, ...config })
|
|
}
|
|
catch (error) {
|
|
if (lastUrl === url)
|
|
lastUrl = previousUrl !== undefined && urls.has(previousUrl) ? previousUrl : undefined
|
|
const result = cleanupAll([() => release(url)])
|
|
if (result.failed)
|
|
report(result.failure)
|
|
throw error
|
|
}
|
|
release(previousUrl)
|
|
},
|
|
}
|
|
current = job
|
|
previous?.dispose()
|
|
return job
|
|
}
|
|
|
|
return {
|
|
start,
|
|
cancel,
|
|
destroy,
|
|
get closed() { return closed },
|
|
}
|
|
}
|