{"id":28199,"date":"2022-02-16T17:20:51","date_gmt":"2022-02-16T17:20:51","guid":{"rendered":"http:\/\/Auto-generate-Video-Slideshows-with-Cloudinary"},"modified":"2022-02-16T17:20:51","modified_gmt":"2022-02-16T17:20:51","slug":"auto-generate-video-slideshows-with-cloudinary","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/","title":{"rendered":"Auto-generate Video Slideshows"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><h1>Build a Personal Image Slideshow<\/h1>\n<p>In this article, we will take advantage of a new feature provided by <a href=\"https:\/\/cloudinary.com\">Cloudinary<\/a>, which is video slideshow generation. We will build an application that uses a webcam to capture images and generate a slideshow video with them.<\/p>\n<p>Here is a <a href=\"https:\/\/codesandbox.io\/s\/video-slideshow-with-cloudinary-gxxgp\">link<\/a> to the demo on CodeSandbox.<\/p>\n<\/div>\n  \n  <div class=\"wp-block-cloudinary-code-sandbox \">\n    <iframe\n      src=\"https:\/\/codesandbox.io\/embed\/video-slideshow-with-cloudinary-gxxgp?theme=dark&amp;codemirror=1&amp;highlights=&amp;editorsize=50&amp;fontsize=14&amp;expanddevtools=0&amp;hidedevtools=0&amp;eslint=0&amp;forcerefresh=0&amp;hidenavigation=0&amp;initialpath=%2F&amp;module=&amp;moduleview=0&amp;previewwindow=&amp;view=&amp;runonclick=1\"\n      height=\"500\"\n      style=\"width: 100%;\"\n      title=\"video-slideshow-with-cloudinary-gxxgp\"\n      loading=\"lazy\"\n      allow=\"accelerometer; ambient-light-sensor; camera; encrypted-media; geolocation; gyroscope; hid; microphone; midi; payment; usb; vr; xr-spatial-tracking\"\n      sandbox=\"allow-forms allow-modals allow-popups allow-presentation allow-same-origin allow-scripts\"\n    ><\/iframe>\n  <\/div>\n\n  <div class=\"wp-block-cloudinary-markdown \"><h2>Cloudinary Setup<\/h2>\n<p>To store and manage media using the Cloudinary platform, we need to <a href=\"https:\/\/cloudinary.com\/signup\">create an account<\/a>. In the account details section on your dashboard, you should see your Credentials, as shown below. In our case, we only need the <strong>Cloud name<\/strong>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_187DC717030F34CF7C9DCCACAD7FB2DD31484BC3F303833182C225163C8EC863_1641318733342_CleanShot+2022-01-04+at+21.51.212x.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"577\"\/><\/p>\n<p>Since all our uploads will be done on our client application, we need to create an unsigned upload preset. See <a href=\"https:\/\/cloudinary.com\/documentation\/upload_presets\">here<\/a> for how to create an unsigned upload preset.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_187DC717030F34CF7C9DCCACAD7FB2DD31484BC3F303833182C225163C8EC863_1641318658702_CleanShot+2022-01-04+at+21.48.192x.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1171\"\/><\/p>\n<p>Take note of your preset name because we will need it later. As seen in the image above, I created an unsigned upload preset called <code>testpreset<\/code>, but you can use any name you like.<\/p>\n<p>Cloudinary provides us with two ways to generate slideshows. In our case, we will be using the delivery URL method, and this requires a CLT template file provided by Cloudinary. This template file will be used to generate our slideshows. We need to <a href=\"https:\/\/res.cloudinary.com\/demo\/video\/upload\/slideshow.clt\">download the template file<\/a> and upload it to our Cloudinary account. See <a href=\"https:\/\/cloudinary.com\/documentation\/media_library_upload_tutorial\">here<\/a> for how to upload an asset to Cloudinary using the media library.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_187DC717030F34CF7C9DCCACAD7FB2DD31484BC3F303833182C225163C8EC863_1640082047660_CleanShot+2021-12-21+at+14.19.562x.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1646\" height=\"1402\"\/><\/p>\n<p>After a successful upload, you should see the template file appear in the list of your media files. Take note of the template file\u2019s publicID as seen above. We\u2019ll need it later when generating URLs for our slideshows.<\/p>\n<h2>Project Setup<\/h2>\n<p>Run this command in your terminal to create a simple React application:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npx create-react-app my-slideshow-app\n<\/code><\/span><\/pre>\n<p>Next, run the following command in your terminal to install the dependencies we\u2019ll need for this project:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npm i axios react-webcam\n<\/code><\/span><\/pre>\n<p>The <strong>axios<\/strong> module will be the HTTP client, while <strong>react-webcam<\/strong> will be used to access the user\u2019s camera to capture images.<\/p>\n<h2>Breaking Down Our Application<\/h2>\n<p>The essence of our application is to display a slideshow containing some images. These are the pieces that make up our app, along with their fundamental roles:<\/p>\n<ul>\n<li>\n<strong>Camera: T<\/strong>his represents our image source.<\/li>\n<li>\n<strong>Image Previewer: U<\/strong>sed to display and delete images.<\/li>\n<li>\n<strong>SlideShow Previewer:<\/strong>  Used to display the slideshow, which is just a regular video.<\/li>\n<\/ul>\n<h2>Capturing and Displaying  Images<\/h2>\n<p>Create a folder called <code>components<\/code> in your <code>src<\/code> directory. Create a file called <code>WebCamera.js<\/code> inside the <code>components<\/code> folder and add the following to it:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> Webcam <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react-webcam\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> { useRef } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n    \n    <span class=\"hljs-keyword\">const<\/span> WebCamera = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ onCapture, loading }<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> capture = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n        <span class=\"hljs-comment\">\/\/ get screenshot<\/span>\n        <span class=\"hljs-keyword\">const<\/span> image = webCamRef.current.getScreenshot();\n        onCapture(image);\n      };\n      <span class=\"hljs-keyword\">const<\/span> webCamRef = useRef();\n      <span class=\"hljs-keyword\">const<\/span> videoConstraints = {\n        <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">500<\/span>,\n        <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-number\">400<\/span>,\n        <span class=\"hljs-attr\">facingMode<\/span>: <span class=\"hljs-string\">\"user\"<\/span>,\n      };\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"media_box\"<\/span>&gt;<\/span>\n          {\/* web cam *\/}\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Webcam<\/span>\n            <span class=\"hljs-attr\">audio<\/span>=<span class=\"hljs-string\">{false}<\/span>\n            <span class=\"hljs-attr\">height<\/span>=<span class=\"hljs-string\">{400}<\/span>\n            <span class=\"hljs-attr\">ref<\/span>=<span class=\"hljs-string\">{webCamRef}<\/span>\n            <span class=\"hljs-attr\">screenshotFormat<\/span>=<span class=\"hljs-string\">\"image\/jpeg\"<\/span>\n            <span class=\"hljs-attr\">width<\/span>=<span class=\"hljs-string\">{600}<\/span>\n            <span class=\"hljs-attr\">videoConstraints<\/span>=<span class=\"hljs-string\">{videoConstraints}<\/span>\n          \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span>\n            <span class=\"hljs-attr\">disabled<\/span>=<span class=\"hljs-string\">{loading}<\/span>\n            <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{capture}<\/span>\n            <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">{<\/span>\"<span class=\"hljs-attr\">capture_btn<\/span>\"}\n          &gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">article<\/span>&gt;<\/span><\/span>\n      );\n    };\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> WebCamera\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the code above, the <code>Webcamera<\/code> component expects two props. The <code>onCapure<\/code> prop will be used to return a captured image to the parent component that renders it, and the <code>loading<\/code> prop will be used to toggle the loading states of some sort internally. The component starts by creating a function called <code>capture<\/code> accompanied by a reference variable and an object that defines the specifications we want on the video track. Here, we specified that the video should have a resolution of 600 by 400 and that it should be streamed from the front camera.<\/p>\n<p>Its return statement renders the <code>Webcam<\/code> component, which accepts the reference variable, the video constraints, and the format for the captured image as props.<\/p>\n<p>A notification will be displayed requesting permission to access the front camera. If the user accepts, it binds some methods to the reference variable passed, one of which is the <code>getScreenshot()<\/code> function used to take a picture and then feed the resulting base64 encoded string representing the image to the <code>onCapture<\/code> prop. The <code>capture<\/code> function is triggered by a button that is disabled when loading to prevent the user from taking more pictures.<\/p>\n<p>Next, we need to create a component that will be used to display captured images. In your <code>components<\/code> folder, create a file named <code>ImagePreviewer.js<\/code> and add the following to it:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">const<\/span> ImagePreviewer = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ url, del }<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">figure<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"single_img\"<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">img<\/span> <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{url}<\/span> <span class=\"hljs-attr\">alt<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">captures<\/span>`} \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"btn_red\"<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{del}<\/span>&gt;<\/span>\n            Delete\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">figure<\/span>&gt;<\/span><\/span>\n      );\n    };\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> ImagePreviewer;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This component renders an image using the URL it accepts as props and a button that deletes the image when clicked. Now that we have our <code>WebCamera<\/code> and <code>ImagePreviewer<\/code> components set up, we can use them in our <code>App.js<\/code> file. Replace the code in your <code>App.js<\/code> file with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> WebCamera <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/WebCamera\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> ImagePreviewer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/ImagePreviewer\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">\".\/App.css\"<\/span>;\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n      <span class=\"hljs-keyword\">const<\/span> &#91;loading, setLoading] = useState(<span class=\"hljs-literal\">false<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> &#91;images, setImages] = useState(&#91;]);\n      <span class=\"hljs-keyword\">const<\/span> onCapture = <span class=\"hljs-function\">(<span class=\"hljs-params\">newImage<\/span>) =&gt;<\/span>\n        setImages(<span class=\"hljs-function\">(<span class=\"hljs-params\">prevImages<\/span>) =&gt;<\/span> &#91;...prevImages, newImage]);\n      <span class=\"hljs-keyword\">const<\/span> deleteImage = <span class=\"hljs-function\">(<span class=\"hljs-params\">ind<\/span>) =&gt;<\/span>\n        setImages(<span class=\"hljs-function\">(<span class=\"hljs-params\">prevImages<\/span>) =&gt;<\/span> images.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">_, index<\/span>) =&gt;<\/span> index !== ind));\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"main con\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">WebCamera<\/span> <span class=\"hljs-attr\">onCapture<\/span>=<span class=\"hljs-string\">{onCapture}<\/span> <span class=\"hljs-attr\">loading<\/span>=<span class=\"hljs-string\">{loading}<\/span> \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span><span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"captured_imags_con con\"<\/span>&gt;<\/span>\n            {images.map((imgURL, index) =&gt; (\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ImagePreviewer<\/span>\n                <span class=\"hljs-attr\">url<\/span>=<span class=\"hljs-string\">{imgURL}<\/span>\n                <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span>\n                <span class=\"hljs-attr\">del<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> deleteImage(index)}\n              \/&gt;\n            ))}\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span><\/span>\n      );\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This Component starts by creating two state variables, one to manage the loading state, and the other is an array to store the captured images. We also have two functions that update and delete images from the array.<\/p>\n<p>It then returns the <code>WebCam<\/code> component, which receives the required props. We also iterate over the array of images and display them on the screen.<\/p>\n<p>Start your development server and head over to your browser to see how our application currently looks.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">    npm start\n<\/code><\/span><\/pre>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_187DC717030F34CF7C9DCCACAD7FB2DD31484BC3F303833182C225163C8EC863_1643189948653_CleanShot+2022-01-26+at+13.38.44.gif\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"800\" height=\"271\"\/><\/p>\n<h2>Requesting for the Slideshow<\/h2>\n<p>Our app currently allows us to capture, view, and delete images. Next, we need to combine these images and generate a slideshow. Irrespective of the method chosen to generate slideShows, every Slideshow created using Cloudinary consists of the following components:<\/p>\n<ul>\n<li>Template: this is the template file provided by Cloudinary that we uploaded earlier.<\/li>\n<li>Manifest transformation: refers to the global Slideshow settings, global slide Settings, and ****individual slide settings(the images or videos you want to include in the slideshow and their settings).<\/li>\n<li>Global transformations: the visual enhancements, filters, and effects you wish to apply to the resulting slideshow.<\/li>\n<\/ul>\n<p>In this post, we will create our slideshows using the Delivery URL syntax, which combines the components mentioned above to give the following syntax.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/cloudinary-marketing-res.cloudinary.com\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/media_jams\/s_6305DC17043B931E4D10EFC59CB09D1DB63EBC8CD4A6D2B68986D4612F7CE8B9_1640001904912_syntax+for+del+URL.png\" alt=\"\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"1821\" height=\"794\"\/><\/p>\n<p>From the diagram above, we can see the part of the URL where the settings would live, but most importantly, we see where our captured images will live. We cannot directly embed the <strong>base64<\/strong> encoded version of our captured images in this URL. We need to upload them first, get their publicIDs, and embed them in the URL.<\/p>\n<p>Let\u2019s create a file that will hold some utility functions. Create a file named <code>helpers.js<\/code> inside your <code>src<\/code> folder and add the following to it:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"axios\"<\/span>;\n    \n    <span class=\"hljs-keyword\">const<\/span> cloudName = <span class=\"hljs-string\">\"ifeomaimoh\"<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> upload = <span class=\"hljs-keyword\">async<\/span> (imgFileB64) =&gt; {\n      <span class=\"hljs-keyword\">const<\/span> imageData = <span class=\"hljs-keyword\">new<\/span> FormData();\n      imageData.append(<span class=\"hljs-string\">\"file\"<\/span>, imgFileB64);\n      imageData.append(<span class=\"hljs-string\">\"upload_preset\"<\/span>, <span class=\"hljs-string\">\"testpreset\"<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> res = <span class=\"hljs-keyword\">await<\/span> axios.post(\n        <span class=\"hljs-string\">` https:\/\/api.cloudinary.com\/v1_1\/<span class=\"hljs-subst\">${cloudName}<\/span>\/image\/upload`<\/span>,\n        imageData\n      );\n      <span class=\"hljs-keyword\">const<\/span> imageDetails = res.data;\n      <span class=\"hljs-keyword\">return<\/span> imageDetails.public_id;\n    };\n    \n    <span class=\"hljs-keyword\">const<\/span> genDeliveryURL = <span class=\"hljs-function\">(<span class=\"hljs-params\">arrOfAsetIds<\/span>) =&gt;<\/span> {\n      <span class=\"hljs-keyword\">const<\/span> templateID = <span class=\"hljs-string\">\"slideshow_i2o0w9_a1hyoq\"<\/span>;\n      <span class=\"hljs-keyword\">const<\/span> globalSettings = <span class=\"hljs-string\">`w_500;h_500;du_10`<\/span>;\n      <span class=\"hljs-keyword\">const<\/span> slideSettings = <span class=\"hljs-string\">`tdur_1500;transition_s:InvertedPageCurl`<\/span>;\n      <span class=\"hljs-keyword\">const<\/span> individualSlides = arrOfAsetIds\n        .map(<span class=\"hljs-function\">(<span class=\"hljs-params\">id<\/span>) =&gt;<\/span> <span class=\"hljs-string\">\"(media_i:\"<\/span> + id + <span class=\"hljs-string\">\")\"<\/span>)\n        .join(<span class=\"hljs-string\">\";\"<\/span>);\n      <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">`https:\/\/res.cloudinary.com\/<span class=\"hljs-subst\">${cloudName}<\/span>\/video\/upload\/fn_render:<span class=\"hljs-subst\">${globalSettings}<\/span>;vars_(<span class=\"hljs-subst\">${slideSettings}<\/span>;slides_(<span class=\"hljs-subst\">${individualSlides}<\/span>))\/<span class=\"hljs-subst\">${templateID}<\/span>.mp4`<\/span>;\n    };\n    <span class=\"hljs-keyword\">export<\/span> { upload, genDeliveryURL };\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the code above, we start by importing the <a href=\"https:\/\/www.npmjs.com\/package\/axios\">axios<\/a> module, and then we define a variable that holds our Cloud name. The <code>upload<\/code> function accepts a base64 encoded string representing an image as an input. It uses the input file and the upload preset we created earlier to create the request body. It then makes a request to the API to upload the image. If the request is successful, it returns the public ID of the uploaded image.<\/p>\n<p>The <code>genDeliveryURL<\/code> function returns a URL for the slideshow. It accepts an array containing the public IDs of images. It creates several variables that match the components of the slideshow. Most of the settings specified are based on preferences.<\/p>\n<p>First, we stored the publicID of our CLT template. For global settings, we specified the dimensions of the video to be 500 by 500, and it should last for a duration that is twice the number of images provided (i.e., two images would take 4s). We specified 1500ms as the duration for each slide transition for the global slide settings.<\/p>\n<p>Finally, we created a string that contains the media assets that would be included in the slideshow. Click <a href=\"https:\/\/cloudinary.com\/documentation\/video_slideshow_generation#slide_settings\">here<\/a> to see a list of the available settings that can be applied to a slideshow.<\/p>\n<p>Create a file called <code>SlideShowPreviewer.js<\/code> inside your <code>components<\/code> directory and add the following to it.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\">    import { useRef, useState, useEffect } from <span class=\"hljs-string\">\"react\"<\/span>;\n    import axios from <span class=\"hljs-string\">\"axios\"<\/span>;\n    <span class=\"hljs-keyword\">const<\/span> SlideShowPreviewer = ({ url }) =&gt; {\n      <span class=\"hljs-keyword\">const<\/span> ref = useRef();\n      <span class=\"hljs-keyword\">const<\/span> &#91;retry, SetRetry] = useState(<span class=\"hljs-number\">1<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> &#91;canView, setCanView] = useState(<span class=\"hljs-keyword\">false<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> &#91;URL, setURL] = useState(<span class=\"hljs-string\">\"\"<\/span>);\n      let loadingText = (\n        &lt;p&gt;\n          Requesting slideshow please wait...{retry}{<span class=\"hljs-string\">\" \"<\/span>}\n          {retry &gt; <span class=\"hljs-number\">1<\/span> ? <span class=\"hljs-string\">\"retries\"<\/span> : <span class=\"hljs-string\">\"retry\"<\/span>} so far\n        &lt;\/p&gt;\n      );\n      async <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">tryToGetSlideShow<\/span><span class=\"hljs-params\">(URL)<\/span> <\/span>{\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">new<\/span> Promise(async (res, rej) =&gt; {\n          <span class=\"hljs-keyword\">try<\/span> {\n            <span class=\"hljs-keyword\">const<\/span> response = await axios(URL);\n            console.log({ response });\n            setURL(URL);\n            setCanView(<span class=\"hljs-keyword\">true<\/span>);\n          } <span class=\"hljs-keyword\">catch<\/span> (error) {\n            SetRetry(retry + <span class=\"hljs-number\">1<\/span>);\n          }\n        });\n      }\n      useEffect(() =&gt; setCanView(<span class=\"hljs-keyword\">false<\/span>), &#91;url]);\n      useEffect(() =&gt; {\n        <span class=\"hljs-keyword\">if<\/span> (!canView) ref.current = setTimeout(() =&gt; tryToGetSlideShow(url), <span class=\"hljs-number\">7000<\/span>);\n        <span class=\"hljs-keyword\">return<\/span> () =&gt; clearTimeout(ref.current);\n      }, &#91;retry, canView, url]);\n      <span class=\"hljs-keyword\">return<\/span> (\n        &lt;article className=<span class=\"hljs-string\">\"slide_box\"<\/span>&gt;\n          {canView || URL ? (\n            &lt;&gt;\n              &lt;video src={URL} autoPlay muted loop controls \/&gt;\n              {!canView &amp;&amp; loadingText}\n            &lt;\/&gt;\n          ) : (\n            loadingText\n          )}\n        &lt;\/article&gt;\n      );\n    };\n    export <span class=\"hljs-keyword\">default<\/span> SlideShowPreviewer;\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>As you can see, the slideshows are generated asynchronously. This means that even if we generate the delivery URL for the slideshows and make a request for it, it won\u2019t be available immediately. The generation of the slideshow may take some time depending on the number of media assets, the transformations used, etc.<\/p>\n<p>In the code above, the component expects the delivery URL as props. We defined some state variables to track if the slideshow can be viewed or not and the number of unsuccessful attempts to get the slideshow. In the effect hook, the component repeatedly requests the slideshow every 7 seconds. If the request is successful, it toggles the state to indicate that the slideshow is ready and feeds the delivery URL to an HTML <code>video<\/code> element, but if it fails, it retries.<\/p>\n<p>Let\u2019s import and use the helper functions and <code>SlideShowPreviewer<\/code> component in our <code>App<\/code> component. Update your <code>App.js<\/code> file with the following:<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">    <span class=\"hljs-keyword\">import<\/span> { useState } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> WebCamera <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/WebCamera\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> ImagePreviewer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/ImagePreviewer\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> SlideShowPreviewer <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/components\/SlideShowPreviewer\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> { upload, genDeliveryURL } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\".\/helpers\"<\/span>;\n    <span class=\"hljs-keyword\">import<\/span> <span class=\"hljs-string\">\".\/App.css\"<\/span>;\n    <span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span>(<span class=\"hljs-params\"><\/span>) <\/span>{\n      <span class=\"hljs-keyword\">const<\/span> &#91;loading, setLoading] = useState(<span class=\"hljs-literal\">false<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> &#91;deliveryURL, setDeliveryURL] = useState(<span class=\"hljs-string\">\"\"<\/span>);\n      <span class=\"hljs-keyword\">const<\/span> &#91;images, setImages] = useState(&#91;]);\n      <span class=\"hljs-keyword\">const<\/span> onCapture = <span class=\"hljs-function\">(<span class=\"hljs-params\">newImage<\/span>) =&gt;<\/span>\n        setImages(<span class=\"hljs-function\">(<span class=\"hljs-params\">prevImages<\/span>) =&gt;<\/span> &#91;...prevImages, newImage]);\n      <span class=\"hljs-keyword\">const<\/span> deleteImage = <span class=\"hljs-function\">(<span class=\"hljs-params\">ind<\/span>) =&gt;<\/span>\n        setImages(<span class=\"hljs-function\">(<span class=\"hljs-params\">prevImages<\/span>) =&gt;<\/span> images.filter(<span class=\"hljs-function\">(<span class=\"hljs-params\">_, index<\/span>) =&gt;<\/span> index !== ind));\n      <span class=\"hljs-keyword\">const<\/span> uploadMultipleImages = <span class=\"hljs-keyword\">async<\/span> (images) =&gt; {\n        <span class=\"hljs-keyword\">let<\/span> arrOfImageIds = &#91;];\n        <span class=\"hljs-keyword\">for<\/span> (<span class=\"hljs-keyword\">const<\/span> image <span class=\"hljs-keyword\">of<\/span> images) {\n          arrOfImageIds.push(<span class=\"hljs-keyword\">await<\/span> upload(image));\n        }\n        <span class=\"hljs-keyword\">return<\/span> arrOfImageIds;\n      };\n      <span class=\"hljs-keyword\">const<\/span> buildSlideShow = <span class=\"hljs-keyword\">async<\/span> () =&gt; {\n        <span class=\"hljs-keyword\">try<\/span> {\n          setLoading(<span class=\"hljs-literal\">true<\/span>);\n          <span class=\"hljs-keyword\">const<\/span> uploadedImgsPublicIds = <span class=\"hljs-keyword\">await<\/span> uploadMultipleImages(images);\n          <span class=\"hljs-keyword\">const<\/span> deliveryURL = genDeliveryURL(uploadedImgsPublicIds);\n          setDeliveryURL(deliveryURL);\n          setImages(&#91;]);\n        } <span class=\"hljs-keyword\">catch<\/span> (error) {\n          <span class=\"hljs-built_in\">console<\/span>.log(error);\n        } <span class=\"hljs-keyword\">finally<\/span> {\n          setLoading(<span class=\"hljs-literal\">false<\/span>);\n        }\n      };\n      <span class=\"hljs-keyword\">return<\/span> (\n        <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">main<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"main con\"<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">WebCamera<\/span> <span class=\"hljs-attr\">onCapture<\/span>=<span class=\"hljs-string\">{onCapture}<\/span> <span class=\"hljs-attr\">loading<\/span>=<span class=\"hljs-string\">{loading}<\/span> \/&gt;<\/span>\n            {deliveryURL &amp;&amp; <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">SlideShowPreviewer<\/span> <span class=\"hljs-attr\">url<\/span>=<span class=\"hljs-string\">{deliveryURL}<\/span> \/&gt;<\/span>}\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n          {images.length &gt;= 2 &amp;&amp; (\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{buildSlideShow}<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"create_slide_btn\"<\/span>&gt;<\/span>\n                {loading ? \"processing\" : \"generate slideshow\"}\n              <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          )}\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">section<\/span> <span class=\"hljs-attr\">className<\/span>=<span class=\"hljs-string\">\"captured_imags_con con\"<\/span>&gt;<\/span>\n            {images.map((imgURL, index) =&gt; (\n              <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ImagePreviewer<\/span>\n                <span class=\"hljs-attr\">url<\/span>=<span class=\"hljs-string\">{imgURL}<\/span>\n                <span class=\"hljs-attr\">key<\/span>=<span class=\"hljs-string\">{index}<\/span>\n                <span class=\"hljs-attr\">del<\/span>=<span class=\"hljs-string\">{()<\/span> =&gt;<\/span> deleteImage(index)}\n              \/&gt;\n            ))}\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">section<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">main<\/span>&gt;<\/span><\/span>\n      );\n    }\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>In the return statement for this component, we added a button that will only be displayed when we have captured at least three images. This button triggers a function called <code>buildSlideShow<\/code>. This function first attempts to upload the captured images. Then it generates the URL for the slideshow using the publicIDs returned from the <code>uploadMultipleImages<\/code> function and stores it in the state. We also passed the URL to the <code>SlideShowPreviewer<\/code> as props. If we run our app now, we should see the resulting slideshow as expected.<\/p>\n<p>You can find the complete project <a href=\"https:\/\/github.com\/ifeoma-imoh\/slideshows-with-cloudinary\">here<\/a> on Github.<\/p>\n<h2>Conclusion<\/h2>\n<p>Today, there are several use-cases for slideshows, and with solutions like Cloudinary, we can easily combine assets to create auto-generated slideshows that match the needs of our projects.<\/p>\n<p>Resources you may find useful:<\/p>\n<ul>\n<li>\n<a href=\"https:\/\/cloudinary.com\/documentation\/video_slideshow_generation\">Cloudinary video slideshow generation<\/a>\n<\/li>\n<li>\n<a href=\"https:\/\/www.npmjs.com\/package\/react-webcam\">React Webcam<\/a>\n<\/li>\n<\/ul>\n<!--  Hello, thank you for your content! Your project was a great read, instructions were easy to follow. The additional resources of git and code sandbox worked well for me when double verifying snippets. The explanations and comments for code snippets were well and plentiful. The outlining for the project was perfect. Did not experience any issues during the build - NO NOTES! Thank you for the great build, as always!\n -->\n<!--- Thanks a lot Nina!!\n -->\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":28200,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,370,246,371],"class_list":["post-28199","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-image","tag-react","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Auto-generate Video Slideshows<\/title>\n<meta name=\"description\" content=\"This post describes how to use Cloudinary&#039;s video slideshow feature to create auto-generated slideshows from images captured using a webcam.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Auto-generate Video Slideshows\" \/>\n<meta property=\"og:description\" content=\"This post describes how to use Cloudinary&#039;s video slideshow feature to create auto-generated slideshows from images captured using a webcam.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-02-16T17:20:51+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"5833\" \/>\n\t<meta property=\"og:image:height\" content=\"3376\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Auto-generate Video Slideshows\",\"datePublished\":\"2022-02-16T17:20:51+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/\"},\"wordCount\":3,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA\",\"keywords\":[\"Guest Post\",\"Image\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/\",\"name\":\"Auto-generate Video Slideshows\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA\",\"datePublished\":\"2022-02-16T17:20:51+00:00\",\"description\":\"This post describes how to use Cloudinary's video slideshow feature to create auto-generated slideshows from images captured using a webcam.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA\",\"width\":5833,\"height\":3376},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Auto-generate Video Slideshows\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Auto-generate Video Slideshows","description":"This post describes how to use Cloudinary's video slideshow feature to create auto-generated slideshows from images captured using a webcam.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/","og_locale":"en_US","og_type":"article","og_title":"Auto-generate Video Slideshows","og_description":"This post describes how to use Cloudinary's video slideshow feature to create auto-generated slideshows from images captured using a webcam.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-02-16T17:20:51+00:00","og_image":[{"width":5833,"height":3376,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/"},"author":{"name":"","@id":""},"headline":"Auto-generate Video Slideshows","datePublished":"2022-02-16T17:20:51+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/"},"wordCount":3,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA","keywords":["Guest Post","Image","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/","name":"Auto-generate Video Slideshows","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA","datePublished":"2022-02-16T17:20:51+00:00","description":"This post describes how to use Cloudinary's video slideshow feature to create auto-generated slideshows from images captured using a webcam.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA","width":5833,"height":3376},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/auto-generate-video-slideshows-with-cloudinary\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Auto-generate Video Slideshows"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925128\/Web_Assets\/blog\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6\/c87dfae7df10a76653204256e505eb7c4dc90df7-5833x3376-1_28200a5da6.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28199","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=28199"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/28199\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/28200"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=28199"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=28199"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=28199"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}