feat: cancel thumbnailer if the render request is long-running
Some checks failed
Check / check (push) Has been cancelled

This commit is contained in:
ThaUnknown 2025-07-09 17:01:52 +02:00
parent a0cbacd6c6
commit 303a138107
No known key found for this signature in database
5 changed files with 39 additions and 14 deletions

View file

@ -1,6 +1,6 @@
{
"name": "ui",
"version": "6.4.27",
"version": "6.4.28",
"license": "BUSL-1.1",
"private": true,
"packageManager": "pnpm@9.14.4",

View file

@ -791,7 +791,9 @@
{/if}
{#if seeking}
{#await thumbnailer.getThumbnail(seekIndex) then src}
<img {src} alt='thumbnail' class='w-full h-full bg-black absolute top-0 right-0 object-contain' loading='lazy' decoding='async' class:!object-cover={fitWidth} />
{#if src}
<img {src} alt='thumbnail' class='w-full h-full bg-black absolute top-0 right-0 object-contain' loading='lazy' decoding='async' class:!object-cover={fitWidth} />
{/if}
{/await}
{/if}
{#if stats}

View file

@ -160,11 +160,18 @@
{/if}
<div>{toTS(seekTime)}</div>
{:then src}
<img {src} alt='thumbnail' class='w-40 rounded-lg min-h-10' loading='lazy' decoding='async' />
{#if title}
<div class='max-w-24 text-ellipsis overflow-clip absolute top-0 bg-white py-1 px-2 rounded-b-lg'>{title}</div>
{#if src}
<img {src} alt='thumbnail' class='w-40 rounded-lg min-h-10' loading='lazy' decoding='async' />
{#if title}
<div class='max-w-24 text-ellipsis overflow-clip absolute top-0 bg-white py-1 px-2 rounded-b-lg'>{title}</div>
{/if}
<div class='absolute bottom-0 bg-white py-1 px-2 rounded-t-lg'>{toTS(seekTime)}</div>
{:else}
{#if title}
<div class='max-w-24 text-ellipsis overflow-clip'>{title}</div>
{/if}
<div>{toTS(seekTime)}</div>
{/if}
<div class='absolute bottom-0 bg-white py-1 px-2 rounded-t-lg'>{toTS(seekTime)}</div>
{/await}
</div>
</div>

View file

@ -16,7 +16,7 @@ export default class Thumbnailer {
src
constructor (src?: string) {
this.video.preload = 'none'
this.video.preload = 'metadata'
this.video.playbackRate = 0
this.video.muted = true
this.video.crossOrigin = 'anonymous'
@ -38,19 +38,31 @@ export default class Thumbnailer {
}, { signal: this.timeUpdateCtrl.signal })
}
_nextTask () {
this.currentTask = undefined
if (this.nextTask) {
this.currentTask = this.nextTask
this.nextTask = undefined
this.currentTask.run()
}
}
_createTask (index: number): RenderItem {
const { promise, resolve } = Promise.withResolvers<string | undefined>()
const run = () => {
this.video.requestVideoFrameCallback(async (_now, meta) => {
const vfc = this.video.requestVideoFrameCallback(async (_now, meta) => {
clearTimeout(timeout)
resolve(await this._paintThumbnail(this.video, index, meta.width, meta.height))
this.currentTask = undefined
if (this.nextTask) {
this.currentTask = this.nextTask
this.nextTask = undefined
this.currentTask.run()
}
this._nextTask()
})
const timeout = setTimeout(() => {
this.video.cancelVideoFrameCallback(vfc)
// this cancels the current load request, in case something bad is happening like long loads or mass seeking
this.video.load()
resolve(undefined)
this._nextTask()
}, 3000)
this.video.currentTime = index * this.interval
}

View file

@ -304,3 +304,7 @@ export const safefetch = async <T> (_fetch: typeof fetch, ...args: Parameters<ty
export function arrayEqual <T> (a: T[], b: T[]) {
return a.length === b.length && a.every((v, i) => v === b[i])
}
export function nextTick () {
return new Promise<void>(resolve => queueMicrotask(resolve))
}