diff --git a/src/main.ts b/src/main.ts index c6a2e9f..8c55c75 100644 --- a/src/main.ts +++ b/src/main.ts @@ -920,7 +920,7 @@ if (supportedAltDomain(location.host)) { document.addEventListener('4chanThreadUpdated', ((e: CustomEvent<{ count: number }>) => { document.dispatchEvent(new CustomEvent("ThreadUpdate", { detail: { - newPosts: [...document.querySelector(".thread")!.children].slice(-e.detail.count).map(e => 'b.' + e.id.slice(2)) + newPosts: [...(document.querySelector(".thread")! as any).children].slice(-e.detail.count).map(e => 'b.' + e.id.slice(2)) } })); }) as any); diff --git a/src/utils.ts b/src/utils.ts index 91e8cbe..4f0ee50 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -16,7 +16,63 @@ settings.subscribe(b => { csettings = b; }); +const generateUglyThumbnail = async (f: File): Promise => { + const can = document.createElement("canvas"); + + const [sw, sh] = [125, 125]; + const url = URL.createObjectURL(f); + + let source: CanvasImageSource; + let iw: number, ih: number; + + if (f.type.startsWith("image")) { + const imgElem = document.createElement('img'); + imgElem.src = url; + await new Promise(_ => imgElem.onload = _); + [iw, ih] = [imgElem.naturalWidth, imgElem.naturalHeight]; + source = imgElem; + } else if (f.type.startsWith("video")) { + const vidElem = document.createElement('video'); + vidElem.src = url; + await new Promise(_ => vidElem.onloadedmetadata = _); + vidElem.currentTime = 0; + await new Promise(_ => vidElem.onloadeddata = _); + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + await new Promise(requestAnimationFrame); + [iw, ih] = [vidElem.videoWidth, vidElem.videoHeight]; + source = vidElem; + } else + return Buffer.alloc(0); + + const scale = Math.min(1, sw / iw, sh / ih); + const dims = [~~(iw * scale), ~~(ih * scale)] as [number, number]; + + can.width = dims[0]; + can.height = dims[1]; + + const ctx = can.getContext("2d"); + + if (!ctx) + return Buffer.alloc(0); + + ctx.drawImage(source, 0, 0, dims[0], dims[1]); + + const blob = await new Promise(_ => can.toBlob(_)); + if (!blob) + return Buffer.alloc(0); + return Buffer.from(await blob.arrayBuffer()); +}; + const generateThumbnail = async (f: File): Promise => { + try { + return await generateProperThumbnail(f); + } catch { + return await generateUglyThumbnail(f); + } +}; + +const generateProperThumbnail = async (f: File): Promise => { const can = document.createElement("canvas"); const [sw, sh] = [125, 125]; diff --git a/tsconfig.json b/tsconfig.json index 71c89bb..6eaf404 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,9 @@ */ "importsNotUsedAsValues": "error", "isolatedModules": true, + "lib": [ + "dom" + ], /** To have warnings/errors of the Svelte compiler at the correct position, enable source maps by default.