javascripthtml5-videozod

Zod > video file duration check (Javascript mastery required)


I'm trying to use Zod and validate video file input duration. The issue is that to load metadata, there needs to be async / await and this is where I've reach my Javascript mastery limit. This is what I'm trying to do, I think I'm on the right track but I cant figure out how to await it.

How do I make sure this code will await onloadedmetadata before returning a response ?

video: z
    .custom<File>()
    .refine(
      (file) => file instanceof File && file.type.includes('video'),
      'Must select a video file'
    )
    .refine(async (file): Promise<boolean> => {
      const video = document.createElement('video');
      video.preload = 'metadata';

      video.onloadedmetadata = () => {
        window.URL.revokeObjectURL(video.src);
        console.log(video.duration);
        if (video.duration < 303) return true;
      };

      video.src = URL.createObjectURL(file);

      return new Promise((resolve) => {
        
      });
    }, 'video duration limit reached!'),

EDIT:

I worked out an alternative path. I changed zod check to number. And I do the metadata loading on the input field, and trigger zod validation when metadata is loaded

Zod:

 video: z
    .number()
    .refine((duration) => duration < 303, 'Video duration limit reached!'),

Input:

 onChange={(event) => {
                  const files = event.target.files;
                  if (!files) return;

                  const video = document.createElement('video');
                  video.preload = 'metadata';

                  video.onloadedmetadata = () => {
                    window.URL.revokeObjectURL(video.src);
                    console.log(video.duration);
                    onChange(video.duration);
                    form.trigger('video');
                  };

                  video.src = URL.createObjectURL(files[0]);

Solution

  • This is how I managed to do it as I originally intended

        video: z.instanceof(File).refine(async (file) => {
        return new Promise<boolean>((resolve) => {
          try {
            const video = document.createElement('video');
            video.preload = 'metadata';
            video.src = URL.createObjectURL(file);
            video.onloadedmetadata = () => {
              window.URL.revokeObjectURL(video.src);
              const durationCheck = video.duration <= 303 ? true : false;
              return resolve(durationCheck);
            };
          } catch (error) {
            return resolve(false);
          }
        });
      }, 'Video duration limit exceeded (5 min max)'),
    

    New Javascript Skill unlocked -> 'Promisification'