refactor(auto-thumbnail): [PKG-AUTO-THUMB-10] own JPEG encoding cancellation and deadlines

This commit is contained in:
Harvey Zhao committed 2026-09-14 11:55:05 +08:00
1 parent afb632d16f
commit 4acf85ea69
21 files changed
+652 -35

No files matched your search

@@ -0,0 +1,41 @@
import type { ExtractionJob } from './types'
interface PendingEncoding {
timer: ReturnType<typeof setTimeout> | null
}
export default function createEncoder(job: ExtractionJob, canvas: HTMLCanvasElement) {
let pending: PendingEncoding | undefined
function clear() {
const previous = pending
pending = undefined
if (previous && previous.timer !== null)
clearTimeout(previous.timer)
}
job.own(clear)
return (publish: (blob: Blob | null) => void) => {
if (!job.active())
return
if (pending)
throw new Error('Auto-thumbnail encoding is already pending')
const current: PendingEncoding = { timer: null }
pending = current
const active = () => job.active() && pending === current
current.timer = setTimeout(job.guard(() => {
if (active())
throw new Error('Auto-thumbnail encoding timed out')
}), 30000)
if (!active()) {
clearTimeout(current.timer)
return
}
canvas.toBlob(job.guard((blob) => {
if (!active())
return
clear()
if (job.active())
publish(blob)
}), 'image/jpeg')
}
}
@@ -1,4 +1,5 @@
import type { ExtractionConfig, ExtractionJob } from './types'
import createEncoder from './encoding'
import createFrameReader from './frames'
import { sheetSize } from './options'
import createVideo from './video'
@@ -47,6 +48,7 @@ export default function extract(job: ExtractionJob, config: ExtractionConfig) {
if (!job.active())
return
const readFrame = createFrameReader(job, video)
const encode = createEncoder(job, canvas)
let index = 0
const seek = job.guard(() => {
if (index >= config.number) {
@@ -57,17 +59,13 @@ export default function extract(job: ExtractionJob, config: ExtractionConfig) {
ctx.drawImage(video, (index % 10) * config.width, Math.floor(index / 10) * height, config.width, height)
if (!job.active())
return
let delivered = false
canvas.toBlob(job.guard((blob) => {
if (delivered)
return
delivered = true
encode((blob) => {
job.publish(blob, { height, column: 10, number: config.number, width: config.width, scale: config.scale })
if (job.active()) {
index += 1
seek()
}
}), 'image/jpeg')
})
}))
})
seek()