Update error handling in makeVideoScreenshot
This commit is contained in:
parent
1480c3f13a
commit
d30da286dc
1 changed files with 51 additions and 30 deletions
|
@ -11,6 +11,7 @@ import { strictAssert } from '../util/assert';
|
||||||
import { canvasToBlob } from '../util/canvasToBlob';
|
import { canvasToBlob } from '../util/canvasToBlob';
|
||||||
import { KIBIBYTE } from './AttachmentSize';
|
import { KIBIBYTE } from './AttachmentSize';
|
||||||
import { explodePromise } from '../util/explodePromise';
|
import { explodePromise } from '../util/explodePromise';
|
||||||
|
import { SECOND } from '../util/durations';
|
||||||
|
|
||||||
export { blobToArrayBuffer };
|
export { blobToArrayBuffer };
|
||||||
|
|
||||||
|
@ -209,37 +210,12 @@ export type MakeVideoScreenshotOptionsType = Readonly<{
|
||||||
logger: Pick<LoggerType, 'error'>;
|
logger: Pick<LoggerType, 'error'>;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
async function loadVideo({
|
const MAKE_VIDEO_SCREENSHOT_TIMEOUT = 30 * SECOND;
|
||||||
objectUrl,
|
|
||||||
logger,
|
|
||||||
}: MakeVideoScreenshotOptionsType): Promise<HTMLVideoElement> {
|
|
||||||
const video = document.createElement('video');
|
|
||||||
const { promise, resolve, reject } = explodePromise();
|
|
||||||
video.addEventListener('loadeddata', resolve);
|
|
||||||
video.addEventListener('error', reject);
|
|
||||||
video.src = objectUrl;
|
|
||||||
try {
|
|
||||||
await promise;
|
|
||||||
} catch (error) {
|
|
||||||
logger.error('loadVideo error', toLogFormat(video.error));
|
|
||||||
throw error;
|
|
||||||
} finally {
|
|
||||||
video.removeEventListener('loadeddata', resolve);
|
|
||||||
video.removeEventListener('error', reject);
|
|
||||||
}
|
|
||||||
return video;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function makeVideoScreenshot({
|
function captureScreenshot(
|
||||||
objectUrl,
|
video: HTMLVideoElement,
|
||||||
contentType = IMAGE_PNG,
|
contentType: MIMEType
|
||||||
logger,
|
): Promise<Blob> {
|
||||||
}: MakeVideoScreenshotOptionsType): Promise<Blob> {
|
|
||||||
const video = await loadVideo({ objectUrl, logger });
|
|
||||||
await new Promise<unknown>(res => {
|
|
||||||
video.currentTime = 1.0;
|
|
||||||
video.addEventListener('seeked', res, { once: true });
|
|
||||||
});
|
|
||||||
const canvas = document.createElement('canvas');
|
const canvas = document.createElement('canvas');
|
||||||
canvas.width = video.videoWidth;
|
canvas.width = video.videoWidth;
|
||||||
canvas.height = video.videoHeight;
|
canvas.height = video.videoHeight;
|
||||||
|
@ -249,6 +225,51 @@ export async function makeVideoScreenshot({
|
||||||
return canvasToBlob(canvas, contentType);
|
return canvasToBlob(canvas, contentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function makeVideoScreenshot({
|
||||||
|
objectUrl,
|
||||||
|
contentType = IMAGE_PNG,
|
||||||
|
logger,
|
||||||
|
}: MakeVideoScreenshotOptionsType): Promise<Blob> {
|
||||||
|
const signal = AbortSignal.timeout(MAKE_VIDEO_SCREENSHOT_TIMEOUT);
|
||||||
|
const video = document.createElement('video');
|
||||||
|
|
||||||
|
const { promise: videoLoadedAndSeeked, resolve, reject } = explodePromise();
|
||||||
|
|
||||||
|
function onLoaded() {
|
||||||
|
if (signal.aborted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
video.addEventListener('seeked', resolve);
|
||||||
|
video.currentTime = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
function onAborted() {
|
||||||
|
reject(signal.reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
video.addEventListener('loadeddata', onLoaded);
|
||||||
|
video.addEventListener('error', reject);
|
||||||
|
signal.addEventListener('abort', onAborted);
|
||||||
|
|
||||||
|
try {
|
||||||
|
video.src = objectUrl;
|
||||||
|
await videoLoadedAndSeeked;
|
||||||
|
return await captureScreenshot(video, contentType);
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('makeVideoScreenshot error:', toLogFormat(error));
|
||||||
|
throw error;
|
||||||
|
} finally {
|
||||||
|
// hard reset the video element so it doesn't keep loading
|
||||||
|
video.src = '';
|
||||||
|
video.load();
|
||||||
|
|
||||||
|
video.removeEventListener('loadeddata', onLoaded);
|
||||||
|
video.removeEventListener('error', reject);
|
||||||
|
video.removeEventListener('seeked', resolve);
|
||||||
|
signal.removeEventListener('abort', onAborted);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function makeObjectUrl(
|
export function makeObjectUrl(
|
||||||
data: Uint8Array | ArrayBuffer,
|
data: Uint8Array | ArrayBuffer,
|
||||||
contentType: MIMEType
|
contentType: MIMEType
|
||||||
|
|
Loading…
Reference in a new issue