File size: 2,545 Bytes
4f01dd5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// Browser-side preprocessing adapted from the Valen website's media.ts.
function once(target, event, signal) {
  return new Promise((resolve, reject) => {
    const finish = error => {
      clearTimeout(timer);target.removeEventListener(event, success);target.removeEventListener('error', failure);
      signal.removeEventListener('abort', abort);error ? reject(error) : resolve();
    };
    const success = () => finish();
    const failure = () => finish(new Error('image'));
    const abort = () => finish(new DOMException('Aborted','AbortError'));
    const timer = setTimeout(failure,20000);
    target.addEventListener(event,success,{once:true});target.addEventListener('error',failure,{once:true});
    signal.addEventListener('abort',abort,{once:true});if(signal.aborted)abort();
  });
}
function jpeg(source, width, height) {
  if(!width||!height)throw new Error('image');
  const scale=Math.min(1,1536/Math.max(width,height));
  const canvas=document.createElement('canvas');canvas.width=Math.max(1,Math.round(width*scale));canvas.height=Math.max(1,Math.round(height*scale));
  const ctx=canvas.getContext('2d');if(!ctx)throw new Error('image');
  ctx.fillStyle='#fff';ctx.fillRect(0,0,canvas.width,canvas.height);ctx.drawImage(source,0,0,canvas.width,canvas.height);
  return canvas.toDataURL('image/jpeg',.85);
}
export async function readMedia(file, signal) {
  const videoType=['video/mp4','video/webm'].includes(file.type);
  if(!videoType&&!['image/jpeg','image/png','image/webp'].includes(file.type))throw new Error('image');
  if(file.size>(videoType?20:3)*1000000)throw new Error('size');
  const url=URL.createObjectURL(file);
  try {
    if(!videoType) {
      const image=new Image();const loaded=once(image,'load',signal);image.src=url;await loaded;
      return {kind:'image',name:file.name,image:jpeg(image,image.naturalWidth,image.naturalHeight),objectUrl:url};
    }
    const video=document.createElement('video');video.muted=true;video.playsInline=true;video.preload='auto';
    try {
      const loaded=once(video,'loadeddata',signal);video.src=url;await loaded;
      if(!Number.isFinite(video.duration)||video.duration<=0)throw new Error('image');
      if(video.duration/2>.01){const seeked=once(video,'seeked',signal);video.currentTime=video.duration/2;await seeked;}
      return {kind:'video',name:file.name,image:jpeg(video,video.videoWidth,video.videoHeight),video:url,objectUrl:url};
    } finally {video.removeAttribute('src');video.load();}
  } catch(error) {URL.revokeObjectURL(url);throw error;}
}