{"id":27823,"date":"2021-07-01T23:58:38","date_gmt":"2021-07-01T23:58:38","guid":{"rendered":"http:\/\/Making-User-Generated-Video-Slideshows-in-Redwood-with-Cloudinary"},"modified":"2021-07-01T23:58:38","modified_gmt":"2021-07-01T23:58:38","slug":"making-user-generated-video-slideshows-in-redwood-with-cloudinary","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/","title":{"rendered":"Making User Generated Video Slideshows in Redwood with Cloudinary"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Videos are one of the most popular forms of content online. They help people start new professions and they keep us endlessly entertained. That\u2019s why you have to make sure any video-based apps you work on give users a good experience.<\/p>\n<p>Users like it when they can customize videos to display what they need. In this tutorial, you\u2019ll learn how to let your users make custom video slideshows with Redwood and Cloudinary.<\/p>\n<h2>Setting up media<\/h2>\n<p>We\u2019re going to be working with Cloudinary to handle our media because they make it easy to work with. To start, make sure you have a <a href=\"https:\/\/cloudinary.com\/users\/register\/free\">Cloudinary account<\/a>. Then go to the Media Library and upload any images and videos you want users to be able to select from.<\/p>\n<p>You\u2019ll also need to upload the template for a slideshow to your Media Library. Right now, you have to <a href=\"https:\/\/res.cloudinary.com\/demo\/video\/upload\/slideshow.clt\">download this slideshow template<\/a> because it\u2019s the only one supported by the slideshow generation functionality.<\/p>\n<p>Before we jump into the code, it\u2019ll help to take a look at the URL we\u2019ll be working with to generate these custom slideshows. You can also find an <a href=\"https:\/\/cloudinary.com\/documentation\/video_slideshow_generation\">explanation of this URL in the docs<\/a>.<\/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\">https:<span class=\"hljs-comment\">\/\/res.cloudinary.com\/`cloudname`\/video\/upload\/fn_render:`global-settings`;vars_(`slide-settings`(`individual-slide`))\/`global-transformations`\/`template`.`ext`<\/span>\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>You can find the <code>cloudname<\/code> in your Cloudinary console.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624820952\/e-603fc55d218a650069f5228b\/pprlbwwdzotci6tpddpf.png\" alt=\"cloud name in Cloudinary console\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"634\" height=\"310\"\/><\/p>\n<ul>\n<li>\n<code>global-settings<\/code>: general settings applied to your video, like the height and width that Cloudinary should return as well as the duration that the video should be.<\/li>\n<li>\n<code>slide-settings<\/code>: settings that apply to each slide. This will include things like how long the image is shown before switching to the next one, what kind of transition is applied between slides, and how long the transition lasts.<\/li>\n<li>\n<code>individual-slide<\/code>: how you add images or videos based on their <code>public_id<\/code> to your slideshow. We\u2019ll use this to add the specific images we want a little later.<\/li>\n<li>\n<code>global-transformations<\/code>: how you can use the regular transformations Cloudinary has available, like automatically adjusting the quality of the video so that it\u2019s optimized for your users.<\/li>\n<li>\n<code>template<\/code>: how we let Cloudinary know we\u2019re going to create a video slideshow. This is the <a href=\"https:\/\/res.cloudinary.com\/demo\/video\/upload\/slideshow.clt\">template we downloaded earlier<\/a>.<\/li>\n<\/ul>\n<p>This is what all of our work is leading up to: letting the user control their own slideshow.<\/p>\n<h2>Creating the customizations<\/h2>\n<p>We\u2019re going to let users define which videos are in the slideshow, the duration of the slideshow, the width of the video, the duration of each slide, the height of the video, and the duration of each transition. Let\u2019s set up the Redwood app with the following command.<\/p>\n<p><code>yarn create redwood-app .\/user-generated-slideshows<\/code><\/p>\n<p>This will make a fresh Redwood project for you. We\u2019ll be working in the <code>api<\/code> directory to handle the database and back-end and the <code>web<\/code> directory to handle the front-end.<\/p>\n<p>We\u2019ll start by making a new schema for our Postgres database.<\/p>\n<p><em>If you want to follow along with the database set up, you\u2019ll need to <a href=\"https:\/\/www.postgresql.org\/download\/\">have Postgres installed locally<\/a>.<\/em><\/p>\n<p>In the <code>api &gt; db<\/code> directory, open the <code>schema.prisma<\/code> file. The first thing we\u2019ll do in here is update the database provider. Right now it\u2019s set to <code>sqlite<\/code>. We need to update this value to <code>postgresql<\/code>.<\/p>\n<p>You\u2019ll also see an example of a schema model here and we\u2019ll be replacing that with the following.<\/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\">model Property {\n  id                 Int      @id @<span class=\"hljs-keyword\">default<\/span>(autoincrement())\n  width              Int\n  height             Int\n  videoDuration      Int\n  slideDuration      Int\n  transitionDuration Int\n  videos             <span class=\"hljs-built_in\">String<\/span>&#91;]\n}\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 defines all of the properties of the slideshow a user can set. There are a few more things we need to do to make sure our database gets set up correctly. In the root of the project, open the <code>.env<\/code> file. There\u2019s a line assigning a value to <code>DATABASE_URL<\/code> and it\u2019s commented out.<\/p>\n<p>Uncomment that line and update the URL to the connection string for your local Postgres database instance. It might look something like this.<\/p>\n<p><code>DATABASE_URL=postgres:\/\/postgres:admin@localhost:5432\/slideshows<\/code><\/p>\n<p>Now you have everything in place to run a database migration! To do that, run the following command.<\/p>\n<p><code>yarn rw prisma migrate dev<\/code><\/p>\n<p>This will get Prisma to generate your migration and update the database according to your schema definition. We can move on to the back-end and front-end now.<\/p>\n<h2>Making the back-end<\/h2>\n<p>Now it\u2019s time to create a few things to get the back-end working. First, we\u2019ll generate a GraphQL schema and a resolver with the following command.<\/p>\n<p><code>yarn rw g sdl property<\/code><\/p>\n<p>Going to the <code>api &gt; src &gt; graphql<\/code> folder will show you a new sdl file. This holds all of the GraphQL types you need to get started. Since we\u2019re already in this file, let\u2019s add a new mutation type. This mutation will create a new set of properties when the user submits the form we\u2019ll create on the front-end later.<\/p>\n<p>Below the <code>UpdatePropertyInput<\/code> type, add the following mutation type.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">type Mutation {\n  createProperty(input: CreatePropertyInput): Property\n}\n<\/code><\/span><\/pre>\n<p>This adds the create mutation to our GraphQL definitions. Now we need to add the actual functionality that will update the database.<\/p>\n<p>Go to <code>api &gt; src &gt; services<\/code> and you\u2019ll see a <code>properties<\/code> folder. The files inside this folder were generated when we ran that <code>yarn rw g sdl property<\/code> command earlier. It has a resolver for fetching all of the properties from the database. Now we need to add a resolver that will handle the creation of a property.<\/p>\n<p>At the bottom of the <code>properties.js<\/code> file, add the following code for the create resolver.<\/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\">export<\/span> <span class=\"hljs-keyword\">const<\/span> createProperty = <span class=\"hljs-function\">(<span class=\"hljs-params\">{ input }<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> db.property.create({ <span class=\"hljs-attr\">data<\/span>: input })\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>That\u2019s it for the back-end! So far we have the database created and connected the GraphQL resolvers to it. All that\u2019s left is for us to make a front-end for users to interact with.<\/p>\n<h2>Building the front-end<\/h2>\n<p>Let\u2019s make a home page that displays the video slideshow and the form with the options they choose. We can let Redwood generate a new page and add the new routing with this command.<\/p>\n<p><code>yarn rw g page home \/<\/code><\/p>\n<p>If you go to <code>web &gt; src &gt; pages<\/code>, you\u2019ll see the <code>HomePage<\/code> folder. The files inside were created with the command we just ran. If you take a look at <code>Routes.js<\/code>, you\u2019ll see the new route for the home page is already there.<\/p>\n<p>Then we\u2019ll update the <code>HomePage<\/code> component to display the form users will use to make their custom slideshow.<\/p>\n<h3>Adding the form<\/h3>\n<p>We\u2019ll need a form to get the info we need to make these custom slideshows. Redwood has its own form helpers to make them easier to work with. In the <code>HomePage<\/code> component, we\u2019ll import a few things at the top of the file.<\/p>\n<p><em>You can delete the existing imports because we won\u2019t be using them.<\/em><\/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> { Form, Label, TextField, Submit } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@redwoodjs\/forms'<\/span>\n<span class=\"hljs-keyword\">import<\/span> { useMutation } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@redwoodjs\/web'<\/span>\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>We\u2019ll use these imports to make our form and send the new property to the database through the GraphQL server. Let\u2019s add the form first.<\/p>\n<p><em>You can delete everything inside the <code>HomePage<\/code> component. We\u2019ll be adding completely new elements.<\/em><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" 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> HomePage = <span class=\"hljs-function\"><span class=\"hljs-params\">()<\/span> =&gt;<\/span> {\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Form<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{onSubmit}<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"video1\"<\/span>&gt;<\/span>First video<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TextField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"video1\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"video2\"<\/span>&gt;<\/span>Second video<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TextField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"video2\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"video3\"<\/span>&gt;<\/span>Third video<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">TextField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"video3\"<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"width\"<\/span>&gt;<\/span>Video width (px)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NumberField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"width\"<\/span> <span class=\"hljs-attr\">max<\/span>=<span class=\"hljs-string\">{500}<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"height\"<\/span>&gt;<\/span>Video height (px)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NumberField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"height\"<\/span> <span class=\"hljs-attr\">max<\/span>=<span class=\"hljs-string\">{500}<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"videoDuration\"<\/span>&gt;<\/span>Video duration (ms)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NumberField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"videoDuration\"<\/span> <span class=\"hljs-attr\">max<\/span>=<span class=\"hljs-string\">{11500}<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"slideDuration\"<\/span>&gt;<\/span>Slide duration (ms)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NumberField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"slideDuration\"<\/span> <span class=\"hljs-attr\">max<\/span>=<span class=\"hljs-string\">{5500}<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Label<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"transitionDuration\"<\/span>&gt;<\/span>Transition duration (ms)<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Label<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">NumberField<\/span> <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"transitionDuration\"<\/span> <span class=\"hljs-attr\">max<\/span>=<span class=\"hljs-string\">{5000}<\/span> \/&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Submit<\/span>&gt;<\/span>Save<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Submit<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Form<\/span>&gt;<\/span><\/span>\n  )\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><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>We\u2019ve made all of the fields to match the data we need to store in the database. That means it\u2019s time to bring in the GraphQL so that we send these values correctly. This is how we\u2019ll create a new property. Inside of the <code>HomePage<\/code> component, add this code above the <code>return<\/code> statement.<\/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\">const<\/span> &#91;createProperty] = useMutation(CREATE_PROPERTY)\n\n<span class=\"hljs-keyword\">const<\/span> onSubmit = <span class=\"hljs-function\">(<span class=\"hljs-params\">data<\/span>) =&gt;<\/span> {\n  <span class=\"hljs-keyword\">const<\/span> videos = &#91;data.video1, data.video2, data.video3]\n  createProperty({\n    <span class=\"hljs-attr\">variables<\/span>: {\n      <span class=\"hljs-attr\">width<\/span>: data.width,\n      <span class=\"hljs-attr\">height<\/span>: data.height,\n      <span class=\"hljs-attr\">videoDuration<\/span>: data.videoDuration,\n      <span class=\"hljs-attr\">slideDuration<\/span>: data.slideDuration,\n      <span class=\"hljs-attr\">transitionDuration<\/span>: data.transitionDuration,\n      <span class=\"hljs-attr\">videos<\/span>: videos,\n    },\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>Here, we make a mutation out of <code>CREATE_PROPERTY<\/code> which we\u2019ll be making right after this and we make the <code>onSubmit<\/code> for the form to handle the GraphQL call. At the bottom of the file, above the <code>export<\/code> statement add this code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-keyword\">const<\/span> CREATE_PROPERTY = gql`\n  mutation CreateProperty(\n    $width: Int!\n    $height: Int!\n    $videoDuration: Int!\n    $slideDuration: Int!\n    $transitionDuration: Int!\n    $videos: &#91;String]!\n  ) {\n    createProperty(\n      input: {\n        width: $width\n        height: $height\n        videoDuration: $videoDuration\n        slideDuration: $slideDuration\n        transitionDuration: $transitionDuration\n        videos: $videos\n      }\n    ) {\n      id\n      width\n      height\n      videoDuration\n      slideDuration\n      transitionDuration\n      videos\n    }\n  }\n`\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><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>This GraphQL mutation is what we use in the <code>useMutation<\/code> method to create a property. It passes all of the data to the resolver.<\/p>\n<p>If you run the app with <code>yarn rw dev<\/code>, you should see something like this in your browser.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624821014\/e-603fc55d218a650069f5228b\/ydl3lf9e9scsgsu13jty.png\" alt=\"form on home page\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"579\"\/><\/p>\n<p>Go ahead and create a new property and save it. This will help us later in the tutorial.<\/p>\n<h3>Adding the video<\/h3>\n<p>We can finally add the video to the page! Earlier we looked at the slideshow generation URL, now we\u2019re going to use it with a few placeholder values. First, we\u2019ll create a new variable under the mutation definition.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" 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> properties = {\n  <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">500<\/span>,\n  <span class=\"hljs-attr\">height<\/span>: <span class=\"hljs-number\">500<\/span>,\n  <span class=\"hljs-attr\">videoDuration<\/span>: <span class=\"hljs-number\">15<\/span>,\n  <span class=\"hljs-attr\">slideDuration<\/span>: <span class=\"hljs-number\">3000<\/span>,\n  <span class=\"hljs-attr\">transitionDuration<\/span>: <span class=\"hljs-number\">1000<\/span>,\n  <span class=\"hljs-attr\">videos<\/span>: &#91;<span class=\"hljs-string\">'beach-boat'<\/span>, <span class=\"hljs-string\">'3dogs'<\/span>, <span class=\"hljs-string\">'reindeer'<\/span>],\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><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 gives us some default values to start with so that our video will load. Now we\u2019ll actually add the video. Below the form, add the following code.<\/p>\n<p><em>You\u2019ll need to wrap the form and the video in a fragment so that React stays happy.<\/em><\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">video<\/span> <span class=\"hljs-attr\">controls<\/span>&gt;<\/span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">source<\/span>\n    <span class=\"hljs-attr\">src<\/span>=<span class=\"hljs-string\">{<\/span>`<span class=\"hljs-attr\">https:<\/span>\/\/<span class=\"hljs-attr\">res.cloudinary.com<\/span>\/<span class=\"hljs-attr\">milecia<\/span>\/<span class=\"hljs-attr\">video<\/span>\/<span class=\"hljs-attr\">upload<\/span>\/<span class=\"hljs-attr\">fn_render:w_<\/span>${\n      <span class=\"hljs-attr\">properties.width<\/span>\n    };<span class=\"hljs-attr\">h_<\/span>${<span class=\"hljs-attr\">properties.height<\/span>};<span class=\"hljs-attr\">du_<\/span>${<span class=\"hljs-attr\">properties.videoDuration<\/span>};<span class=\"hljs-attr\">vars_<\/span>(<span class=\"hljs-attr\">sdur_<\/span>${\n      <span class=\"hljs-attr\">properties.slideDuration<\/span>\n    };<span class=\"hljs-attr\">tdur_<\/span>${\n      <span class=\"hljs-attr\">properties.transitionDuration<\/span>\n    };<span class=\"hljs-attr\">transition_s:circlecrop<\/span>;<span class=\"hljs-attr\">slides_<\/span>(${<span class=\"hljs-attr\">properties.videos<\/span>\n      <span class=\"hljs-attr\">.map<\/span>((<span class=\"hljs-attr\">mediaDoc<\/span>) =&gt;<\/span> `(media_i:${mediaDoc})`)\n      .join(';')}))\/f_auto,q_auto\/slideshow_hlhpzw.mp4`}\n    type=\"video\/mp4\"\n  \/&gt;\n  Your browser does not support the video tag.\n<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">video<\/span>&gt;<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This URL looks pretty crazy since we\u2019ve added a bunch of extra parentheses and curly braces, but it\u2019s just loading the values into the placeholders we described earlier.<\/p>\n<p>If you run your app again, your home page should look similar to this.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/jesse-thisdot\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1624821081\/e-603fc55d218a650069f5228b\/knffook2no6ssyx8fudx.png\" alt=\"home page with form and video\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1002\"\/><\/p>\n<p>So you have the form in place and the video displaying on the page. The only thing left is to load in a property so that the user sees their custom slideshow.<\/p>\n<h3>Loading the saved properties<\/h3>\n<p>We\u2019ll need to add one more GraphQL query to the front-end and we\u2019ll be able to set our initial video state. First, we\u2019ll add a new method to an existing import.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" 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> { useMutation, useQuery } <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">'@redwoodjs\/web'<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><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>Then we\u2019ll create a query inside of the <code>HomePage<\/code> component, just above the mutation.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-11\" 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> { loading, data } = useQuery(PROPERTIES)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-11\"><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>Next we\u2019ll add <code>PROPERTIES<\/code> just above our <code>CREATE_PROPERTY<\/code> mutation at the bottom of the file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-12\" 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> PROPERTIES = gql<span class=\"hljs-string\">`\n  query Properties {\n    properties {\n      id\n      width\n      height\n      videoDuration\n      slideDuration\n      transitionDuration\n      videos\n    }\n  }\n`<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-12\"><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>The generates the GraphQL query that we need to fetch all of the properties from the database. Now let\u2019s update our default variable to read the latest property that was added.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-13\" 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> properties = data.properties&#91;data.properties.length - <span class=\"hljs-number\">1<\/span>]\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-13\"><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>To make sure we have data to read, we\u2019re going to use the <code>loading<\/code> variable we received from <code>useQuery<\/code>. Right above the last line of code we wrote, add this.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-14\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-keyword\">if<\/span> (loading) {\n  <span class=\"hljs-keyword\">return<\/span> <span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>Loading..<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span><\/span>\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-14\"><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 is going to prevent the app from crashing while the data is loading. Now if you refresh your app, you should see a slideshow generated with the values you saved earlier! You can try it out with a new value if you want and then reload the page.<\/p>\n<p><em>Keep in mind that video slideshow generation is still a beta feature so it might be a little buggy sometimes.<\/em><\/p>\n<h2>Finished code<\/h2>\n<p>You can check out the finished code in <a href=\"https:\/\/codesandbox.io\/s\/trusting-wilson-ecfsh\">this Code Sandbox<\/a> or in <a href=\"https:\/\/github.com\/flippedcoder\/blog-examples\">this GitHub repo in the \u2019user-gen-vids` folder<\/a>.<\/p>\n<h2>Conclusion<\/h2>\n<p>Adding customizations can make it easier for people to learn and interact with your site. Video content is not slowing down so giving your users more control can be something that gives your site an edge over the others. Plus, working with Redwood will hopefully make it easier for you to keep things up to date!<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":27824,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[134,177,246,371,303],"class_list":["post-27823","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-guest-post","tag-javascript","tag-react","tag-under-review","tag-video"],"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>Making User Generated Video Slideshows in Redwood with Cloudinary<\/title>\n<meta name=\"description\" content=\"Users like it when they have access to customization for their videos so it&#039;s important that we give them things that make their experience better.\" \/>\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\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Making User Generated Video Slideshows in Redwood with Cloudinary\" \/>\n<meta property=\"og:description\" content=\"Users like it when they have access to customization for their videos so it&#039;s important that we give them things that make their experience better.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2021-07-01T23:58:38+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"420\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\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\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Making User Generated Video Slideshows in Redwood with Cloudinary\",\"datePublished\":\"2021-07-01T23:58:38+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/\"},\"wordCount\":9,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA\",\"keywords\":[\"Guest Post\",\"Javascript\",\"React\",\"Under Review\",\"Video\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2021\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/\",\"name\":\"Making User Generated Video Slideshows in Redwood with Cloudinary\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA\",\"datePublished\":\"2021-07-01T23:58:38+00:00\",\"description\":\"Users like it when they have access to customization for their videos so it's important that we give them things that make their experience better.\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA\",\"width\":1000,\"height\":420},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Making User Generated Video Slideshows in Redwood with Cloudinary\"}]},{\"@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":"Making User Generated Video Slideshows in Redwood with Cloudinary","description":"Users like it when they have access to customization for their videos so it's important that we give them things that make their experience better.","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\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/","og_locale":"en_US","og_type":"article","og_title":"Making User Generated Video Slideshows in Redwood with Cloudinary","og_description":"Users like it when they have access to customization for their videos so it's important that we give them things that make their experience better.","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/","og_site_name":"Cloudinary Blog","article_published_time":"2021-07-01T23:58:38+00:00","og_image":[{"width":1000,"height":420,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA","type":"image\/png"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/"},"author":{"name":"","@id":""},"headline":"Making User Generated Video Slideshows in Redwood with Cloudinary","datePublished":"2021-07-01T23:58:38+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/"},"wordCount":9,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA","keywords":["Guest Post","Javascript","React","Under Review","Video"],"inLanguage":"en-US","copyrightYear":"2021","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/","name":"Making User Generated Video Slideshows in Redwood with Cloudinary","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA","datePublished":"2021-07-01T23:58:38+00:00","description":"Users like it when they have access to customization for their videos so it's important that we give them things that make their experience better.","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA","width":1000,"height":420},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/making-user-generated-video-slideshows-in-redwood-with-cloudinary\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Making User Generated Video Slideshows in Redwood with Cloudinary"}]},{"@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\/v1681926169\/Web_Assets\/blog\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84\/c5ee96bfde457afabcf0fbbb0fa59724cfde0c20-1000x420-1_2782471d84.png?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27823","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=27823"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27823\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/27824"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27823"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27823"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27823"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}