An Interest In:
Web News this Week
- April 2, 2024
- April 1, 2024
- March 31, 2024
- March 30, 2024
- March 29, 2024
- March 28, 2024
- March 27, 2024
Video thumbnails generate with vanilla JS, ReactJS. Like YouTube
Have you ever needed where the user uploads the video and has the option to select a thumbnail? if yes keep reading.
Recently I needed to create a service in one of my projects where users will upload a video and can select a thumbnail of that video, and I needed to generate multiple thumbnails from the different timeframes of video. So the user can select one of the thumbnail from the given
something like this [can't upload the original screen]
I search for JS libraries which can do this for me but ended up creating my own NPM
package.
video-thumbnails-generator
Contributions are more than welcome, I have already added a roadmap in the Readme.md
.
But first lets see how its working behind the scene.
Index.js
The Driver
// convert image to object part instead of base64 for better performance// https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURLexport const importFileandPreview = (file, revoke) => { return new Promise((resolve, reject) => { window.URL = window.URL || window.webkitURL; let preview = window.URL.createObjectURL(file); // remove reference if (revoke) { window.URL.revokeObjectURL(preview); } setTimeout(() => { resolve(preview); }, 100); });}/** * * @param videoFile {FIle} // the video file * @param numberOfThumbnails {number} //number of thumbnails you want to generate * @returns {string[]} // an array of base64 thumbnails images * * @abstract * Idea taken from - https://codepen.io/aertmann/pen/mrVaPx * The original functionality of getVideoThumbnail() function is customized as per working code * If it didn't work in future then replace it with about links working example */export const generateVideoThumbnails = async (videoFile, numberOfThumbnails) => { let thumbnail = []; let fractions = []; return new Promise(async (resolve, reject) => { if (!videoFile.type?.includes("video")) reject("not a valid video file"); await getVideoDuration(videoFile).then(async (duration) => { // divide the video timing into particular timestamps in respective to number of thumbnails // ex if time is 10 and numOfthumbnails is 4 then result will be -> 0, 2.5, 5, 7.5 ,10 // we will use this timestamp to take snapshots for (let i = 0; i <= duration; i += duration / numberOfThumbnails) { fractions.push(Math.floor(i)); } // the array of promises let promiseArray = fractions.map((time) => { return getVideoThumbnail(videoFile, time) }) // console.log('promiseArray', promiseArray) // console.log('duration', duration) // console.log('fractions', fractions) await Promise.all(promiseArray).then((res) => { res.forEach((res) => { // console.log('res', res.slice(0,8)) thumbnail.push(res); }); // console.log('thumbnail', thumbnail) resolve(thumbnail); }).catch((err) => { console.error(err) }).finally((res) => { console.log(res); resolve(thumbnail); }) }); reject("something went wront"); });};const getVideoThumbnail = (file, videoTimeInSeconds) => { return new Promise((resolve, reject) => { if (file.type.match("video")) { importFileandPreview(file).then((urlOfFIle) => { var video = document.createElement("video"); var timeupdate = function () { if (snapImage()) { video.removeEventListener("timeupdate", timeupdate); video.pause(); } }; video.addEventListener("loadeddata", function () { if (snapImage()) { video.removeEventListener("timeupdate", timeupdate); } }); var snapImage = function () { var canvas = document.createElement("canvas"); canvas.width = video.videoWidth; canvas.height = video.videoHeight; canvas.getContext("2d").drawImage(video, 0, 0, canvas.width, canvas.height); var image = canvas.toDataURL(); var success = image.length > 100000; if (success) { URL.revokeObjectURL(urlOfFIle); resolve(image); } return success; }; video.addEventListener("timeupdate", timeupdate); video.preload = "metadata"; video.src = urlOfFIle; // Load video in Safari / IE11 video.muted = true; video.playsInline = true; video.currentTime = videoTimeInSeconds; video.play(); }); } else { reject("file not valid"); } });};/** * * @param videoFile {File} * @returns {number} the duration of video in seconds */export const getVideoDuration = (videoFile)=> { return new Promise((resolve, reject) => { if (videoFile) { if (videoFile.type.match("video")) { importFileandPreview(videoFile).then((url) => { let video = document.createElement("video"); video.addEventListener("loadeddata", function () { resolve(video.duration); }); video.preload = "metadata"; video.src = url; // Load video in Safari / IE11 video.muted = true; video.playsInline = true; video.play(); // window.URL.revokeObjectURL(url); }); } } else { reject(0); } });};
Explanations
importFileandPreview()
/*** This function will take an File object and will convert it* into windowObjectURI which look something like this - * blob:http://localhost/2d7b2c97-02f3-4e7d-a6c1-d04746c27730*/export const importFileandPreview = (file, revoke) => { return new Promise((resolve, reject) => { //@todo - your logic here });}
getVideoDuration()
/** * @abbrivation This function takes a video File object as an * input and returns the duration of that video. * * @param videoFile {File} * @returns {number} the duration of video in seconds */export const getVideoDuration = (videoFile)=> { return new Promise((resolve, reject) => { if (videoFile) { resolve(duration); } else { reject(0); } });};
getVideoThumbnail()
/*** @abbrivation * This function takes a video File Object and the time where we* need a snapshot of video screen.* It will return a snapshot of the video at the given time* in `base64` format.** @param {File} file * @param {number} videoTimeInSeconds * @returns string // base64Image */const getVideoThumbnail = (file, videoTimeInSeconds) => { return new Promise((resolve, reject) => { if (file.type.match("video")) { resolve(thumbnail); //base64 image } else { reject("file not valid"); } });};
generateVideoThumbnails()
/** * This functin will take two input video File and Number * And It will generate that many thumbnails. * * @param videoFile {FIle} // the video file * @param numberOfThumbnails {number} //number of thumbnails you want to generate * @returns {string[]} // an array of base64 thumbnails images * * @abstract * Idea taken from - https://codepen.io/aertmann/pen/mrVaPx * The original functionality of getVideoThumbnail() function is customized as per working code * If it didn't work in future then replace it with about links working example */export const generateVideoThumbnails = async (videoFile, numberOfThumbnails) => { let thumbnail = []; let fractions = []; return new Promise(async (resolve, reject) => { if (!videoFile.type?.includes("video")) reject("not a valid video file"); // first we get video duration // then we calculate how many thumbnails to generate // we cann generateThumbnail() function that many times // then we resolve all those promises and return result. await Promise.all(promiseArray).then((res) => { res.forEach((res) => { thumbnail.push(res); }); resolve(thumbnail); }).catch((err) => { console.error(err) }).finally((res) => { resolve(thumbnail); }) }); reject("something went wrong"); });};
See it in action - Live Demo.
Hope you enjoyed it reading. Do not forget share of hit that heart icon see you soon with new material .
Original Link: https://dev.to/rajeshroyal/video-thumbnails-generate-with-vanilla-js-reactjs-like-youtube-3ok8
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To