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 { KIBIBYTE } from './AttachmentSize';
|
||||
import { explodePromise } from '../util/explodePromise';
|
||||
import { SECOND } from '../util/durations';
|
||||
|
||||
export { blobToArrayBuffer };
|
||||
|
||||
|
@ -209,37 +210,12 @@ export type MakeVideoScreenshotOptionsType = Readonly<{
|
|||
logger: Pick<LoggerType, 'error'>;
|
||||
}>;
|
||||
|
||||
async function loadVideo({
|
||||
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;
|
||||
}
|
||||
const MAKE_VIDEO_SCREENSHOT_TIMEOUT = 30 * SECOND;
|
||||
|
||||
export async function makeVideoScreenshot({
|
||||
objectUrl,
|
||||
contentType = IMAGE_PNG,
|
||||
logger,
|
||||
}: MakeVideoScreenshotOptionsType): Promise<Blob> {
|
||||
const video = await loadVideo({ objectUrl, logger });
|
||||
await new Promise<unknown>(res => {
|
||||
video.currentTime = 1.0;
|
||||
video.addEventListener('seeked', res, { once: true });
|
||||
});
|
||||
function captureScreenshot(
|
||||
video: HTMLVideoElement,
|
||||
contentType: MIMEType
|
||||
): Promise<Blob> {
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
|
@ -249,6 +225,51 @@ export async function makeVideoScreenshot({
|
|||
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(
|
||||
data: Uint8Array | ArrayBuffer,
|
||||
contentType: MIMEType
|
||||
|
|
Loading…
Reference in a new issue