3

First thing first, I am trying to extract the video duration from the file and then display it without having to actually upload the file.

When a user selected a video - the information will be displayed below it includes file name, file size, file type. However much to my terrible skills - I cannot get the duration to display. I tried some code snippets i found from other sites as well as here but none of them seems to work. Just trying to find a simple code that would do the task.

I tried onloadedmetadata but I don't think that would even work.

Please note : I'm still learning javascript.

I also tried some sites tutorial & some code snippet I found via stackoverflow


           function uploadFunction(){
                //Variables
                var cVideo = document.getElementById("fileUp");
                var txtInfo = "";

               //function 
                if ('files' in cVideo){
                    if(cVideo.files.length == 0){
                    txtInfo = "Please select a video";
                } else {
                    for (var v = 0; v < cVideo.files.length; v++){
                        txtInfo += "<br><strong>#" + (v+1) + " File Information:</strong> <br>";         
                        var infoFile = cVideo.files[v];
                        if('name' in infoFile){
                            txtInfo += "File name: " +infoFile.name +"<br>";
                        }
                        if('size' in infoFile){
                           txtInfo += "File size: " +infoFile.size +" Bytes <br>"; 
                        }
                        if('type' in infoFile){
                            txtInfo += "File Type: "+infoFile.type +" <br>";
                        }
                        if('duration' in infoFile){
                            txtInfo += "Duration : "+infoFile.duration +"<br>";
                        }

                    }
                }

                }
                document.getElementById("information").innerHTML = txtInfo ;
 }

HTML


           <input type="file" id="fileUp" name="fileUpload" multiple size="50" onchange="uploadFunction()">
           <p id="information"></p>

Can't get the duration to appear at all.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Zyaan
  • 99
  • 2
  • 10
  • 1
    Its a bit convoluted to get this, but you _will_ have to read the. file with javascript, turn it into a blob, use it as a source for the video element, and await the `metadataloaded` event on the video to get the duration of a video file. I need to look up how this works again... – somethinghere Sep 23 '19 at 17:12
  • Possible duplicate of [Problem retrieving HTML5 video duration](https://stackoverflow.com/questions/2221029/problem-retrieving-html5-video-duration) – Peter Sep 23 '19 at 17:14
  • as @somethinghere noted, you cannot get the video duration from simply using a file picker element, you need to also create a video element and wait for it to load, THEN you have the duration. – Peter Sep 23 '19 at 17:16
  • Also, the `File` in your input is not actually aware that its a video - so all that video specific metadata does not exist. It just tells you what the size is, so you can do some fairly basic checks before doing anything else (like reading it). – somethinghere Sep 23 '19 at 17:25

1 Answers1

5

It's actually reasonably simple, but since this requires turning the file into a blob and then checking its duration with a video element, uploading a video longer than a couple of minutes will take a lot of processing and slow down your page immensly. I have added a filesize restriction (which is a reasonable start in my opinion). Here's a snippet (which will not work on Stack Overflow due to sandbox restrictions, but I did test it on a local server). I obviously also don't check MIME types or whether its a video at all, although loadedmetadata will not trigger if you upload anything that is not a video.

const fileInput = document.querySelector( 'input[type=file]' );
const fileDuration = document.getElementById( 'file-duration' )

// Listen for any change to the value of the file input

fileInput.addEventListener( 'change', event => {

    fileDuration.textContent = 'Fetching video duration...';

    // When the file selected by the user changes:
    // - create a fresh <video> element that has not yet fired any events
    // - create a file reader to safely retrieve and manipulate the file

    const file = event.target.files[0];
    const video = document.createElement( 'video' );
    const reader = new FileReader();

    // Cancel if the initial filesize just seems too large.
    // If the maximum allowed is 30 seconds, then a Gigabyte of file seems too much.

    if( file.size > 10000000 ){

        fileDuration.textContent = `File is too large (${file.size}). Refused to read duration.`;
        return;

    }

    // Before setting any source to the <video> element,
    // add a listener for `loadedmetadata` - the event that fires
    // when metadata such as duration is available.
    // As well as an error event is case something goes wrong.

    video.addEventListener( 'loadedmetadata', event => {

        // When the metadata is loaded, duration can be read.

        fileDuration.textContent = `Video is ${video.duration} seconds long.`;

    });

    video.addEventListener( 'error', event => {

        // If the file isn't a video or something went wrong, print out an error message.

        fileDuration.textContent = `Could not get duration of video, an error has occurred.`;

    });

    // Before reading any file, attach an event listener for
    // when the file is fully read by the reader.
    // After that we can use this read result as a source for the <video>

    reader.addEventListener( 'loadend', function(){

        // reader.result now contains a `blob:` url. This seems like a
        // nonsensical collection of characters, but the <video> element
        // should be able to play it.

        video.src = reader.result;

        // After we assigned it to the `src` of the <video>, it will be
        // act like any other video source, and will trigger the related
        // events such as `loadedmetadata`, `canplay`, etc...

    });

    // Instruct the reader to read the file as a url. When its done
    // it will trigger the `loadend` event handler above.

    reader.readAsDataURL( file );

});
<input type="file" />
<p id="file-duration">No video file</p>
somethinghere
  • 16,311
  • 2
  • 28
  • 42
  • Thank you! I just tested it and it works but I want to have a better understanding on what the code does. Is it possible if you can explain in step by step? That is if you don't mind. – Zyaan Sep 23 '19 at 17:46
  • Oh and one more thing.. how would I convert the console.log to display the result on **

    ** ? Thanks again!
    – Zyaan Sep 23 '19 at 18:06
  • 1
    @Zyaan I have updated my code to include comments and to output any data to a `p` tag instead of logging it, but that last step is nothing more than displaying information, so I also made it say that it is loading before doing anything else (this means that people at least get some feedback). Hope it helps, but in and of itself the code is pretty simple and self-explanatory. I honestly expected this to be more complicated than it was. Also, for the `p`, you might want to consider not using an `id`, that way you can reuse this widget multiple times if you want to. – somethinghere Sep 23 '19 at 18:14
  • Thank you so much for adding comments - it really helped! One last thing.. D: So I tried to run it so I can debug and understand the steps but I got an error stating that `Uncaught TypeError: Cannot read property 'addEventListener' of null` for the first EventListener. It's saying it's null but ????? i dont quite get it. – Zyaan Sep 23 '19 at 21:25
  • 1
    @Zyaan When you call `querySelector` or any of the native selecting functions, it either returns the element or `null` - and only elements have a method called `addEventListener` (since `null` is, well, nothing really, and definitely not something that can listen to events). It means that your `input` isn't found. Make sure that your selector actually matches the element you want to add the listener on. – somethinghere Sep 23 '19 at 21:35
  • Never mind, I had to put script below the HTML section. Is there anyway that I can still run it while script being at top of the page? Just saw your comment; I understood that part and everything was the same, didn't change anything. – Zyaan Sep 23 '19 at 21:36
  • 1
    Your script will be executed as soon as you add it to the page, so if your element gets created later in the HTML it simply doesn't exist yet. You can wrap the whole script in a function and listen for the `DOMContentLoaded` or the `pageshow` event on the `document` to only execute it after your entire HTML has been parsed. That should solve the issue and guarantee that your script only gets executed when every element on the page in instantiated. – somethinghere Sep 23 '19 at 21:47
  • Interesting @somethinghere thanks for clarifying that part. I also ran into another issue - It works fine with mp3/mp4 files but not other files? (I should probably stop extending the discussion in the comment section) – Zyaan Sep 23 '19 at 22:26
  • Thats what your browser supports. If your browser can play the file, it can read the duration. Can’t really help much more eith that! Good luck. – somethinghere Sep 23 '19 at 22:33