Cloudinary provides various tools for creating, managing, and optimizing visual experiences, including a javascript-based HTML5 video player. In this article, we’ll build a responsive and optimized video playlist application using Next.js and Cloudinary.
We’ll go through getting our video assets from Cloudinary using the Node.js SDK and embedding the Cloudinary video player on a web page. Let’s get started!
Here is a link to the demo on CodeSandbox.
It is assumed you have a basic knowledge of using React and an understanding of how serverless functions.
Run this command in your terminal to create a Next.js application:
npx create-next-app cloudinary-video-playlist
Run this command to install the required dependencies:
npm install --save cloudinary axios
We will use the Cloudinary node SDK to get our video assets from the Cloudinary storage, and axios is the HTTP client we will use to communicate with the serverless function endpoint.
Click here to create an account with Cloudinary or login if you already have one. After a successful onboarding, you should see your dashboard page containing your Cloudinary credentials.
We will be using the Cloud name, API key, and API secret. The API key and API secret are private credentials, so we need to add them to a .env
file.
Create a .env
file at the root of your project and add the following to it:
CLOUDINARY_API_KEY = ***Your API key***
CLOUDINARY_API_SECRET = ***Your API secret***
Now we need to upload some videos to Cloudinary. See this documentation on uploading assets to Cloudinary.
Let’s create a serverless function for fetching our video assets from our Cloudinary media library. In the api
folder in your pages
directory, create a file named getVideosData.js
and add the following to it:
import cloudinary from 'cloudinary';
cloudinary.v2.config({
cloud_name: 'ifeomaimoh',
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
secure: true
});
export default async function getData(req,res) {
try {
const cloudRes = await cloudinary.v2.api.resources({ resource_type: 'video' });
return res.json(cloudRes.resources)
} catch (error) {
return res.json({message:error.message})
}
}
Code language: JavaScript (javascript)
In the code shown above, we started by importing an instance of Cloudinary. Then we configure it by passing in an object consisting of the basic Cloudinary credentials.
We create our serverless function, which sends an HTTP request to retrieve all video assets in our Cloudinary media library. The object { resource_type: 'video'}
passed as an argument to the resources
method tells Cloudinary to return the resources of type video. To see other options that are available for requesting assets, click here.
After successfully creating our serverless function and using it to fetch the video assets, we need to create a way to get our data to the frontend to feed it to the player. To do this, we send an HTTP request to the endpoint /api/getVideosData
and then pass the response data to the Player
component.
Add the following to your index.js
file:
import React, { useEffect, useState } from "react";
import styles from "../styles/Home.module.css";
import axios from "axios";
import Player from "../components/Player";
export default function Home() {
const [videosData, setVideosData] = useState([]);
useEffect(() => {
getVideos();
}, []);
async function getVideos() {
try {
const response = await axios.get("/api/getVideosData");
setVideosData(response.data);
} catch (error) {
console.error(error);
}
}
return (
<div className={styles.container}>
{videosData.length > 0 ? <Player videosData={videosData} /> : ""}
</div>
);
}
Code language: JavaScript (javascript)
We start by setting up a state, videoData
, to store our video data. After the component is rendered to the page, we call getVideos()
inside the useEffect
hook. The function sends an HTTP request to the endpoint created by the serverless function, stores the result in a response variable that is then used to update the state if successful otherwise, it sends an error to the console.
The Home
component returns a component called Player
, which receives the videosData
as props.
At the root of your project, create a folder called components
, and inside it, create another file named Player.js
and add the following to it:
import React, { useEffect } from "react";
import styles from "../styles/Home.module.css";
export default function Player({ videosData }) {
const formattedData = videosData.map((x) => x.public_id);
useEffect(() => {
const cld = window.cloudinary.Cloudinary.new({
cloud_name: "ifeomaimoh",
});
if (videosData) {
const player = cld.videoPlayer("example-player", {
playlistWidget: {
direction: "horizontal",
total: formattedData?.length,
},
});
player.playlist(formattedData, {
autoAdvance: true,
repeat: true,
presentUpcoming: 3,
});
}
}, [videosData, formattedData]);
return (
<div className={styles.player}>
<video
id="example-player"
controls
className="cld-video-player cld-video-player-skin-dark"
></video>
</div>
);
}
Code language: JavaScript (javascript)
We instantiate a Cloudinary instance with our Cloudinary configuration, and then we instantiate the Cloudinary videoPlayer
method and assign it to the variable player
. Because the window object does not exist when Next.js renders on the server, we’re referencing the window object in a useEffect hook
. The videoPlayer
method takes in the video element id and a playlist widget object.
The playlist
method, which takes the source data and other parameters object as an argument, is called on the player
object. We specified an autoAdvance
key in the parameter object, which indicates whether to auto-advance to the next video and the delay between them. We also set a presetUpcoming
key which displays a thumbnail link of the next video on the playlist, 3seconds before the end of the current video.
To embed the video player, we return a video
tag that includes the standard HTML5 video player attributes, an id
, and a class that adds a dark skin theme. The Player
component receives the videos’ data as props from the Home
component.
To implement the video player, we can either reference the necessary video player package files directly from UNPKG CDN or install the complete video player package locally and then reference the relevant local files. In this project, we will go with the first option.
Add the following to your _app.js
file:
import "../styles/globals.css";
import Script from "next/script";
import Head from "next/head";
function MyApp({ Component, pageProps }) {
return (
<>
<Head>
<link
href="https://unpkg.com/cloudinary-video-player@1.5.9/dist/cld-video-player.min.css"
rel="stylesheet"
/>
</Head>
<Script
src="https://unpkg.com/cloudinary-core@latest/cloudinary-core-shrinkwrap.min.js"
type="text/javascript"
crossOrigin="anonymous"
strategy="beforeInteractive"
/>
);
}
export default MyApp;
Code language: JavaScript (javascript)
We used the built-in Next.js Head
and Script
tags to load the video player resources. We specified a link
tag in the Head
component, which points to the stylesheet provided by Cloudinary. We specify a strategy
prop for the scripts that help load the scripts before the page becomes interactive. See here for more on the Script
Component provided by Next.js.
Now replace what’s in your Home.module.css
file with the following to give the application a decent look and make it responsive:
.container {
width: 1024px;
max-width: 100%;
margin: 1.5rem auto;
}
.player {
border: 1px solid rgba(0, 0, 0, 0.1);
display: flex;
justify-content: center;
align-items: center;
}
.player > div {
width: 100%;
height: 100%;
}
.player > div > div:first-of-type > div {
width: 100%;
height: 15rem;
}
.span {
text-align: center;
font-weight: 500;
}
Code language: CSS (css)
Run this command to start up your development server:
npm run dev
Head over to your browser; you should have a video player with a playlist of videos from your Cloudinary media library.
Find the complete project here on GitHub.
Resources you may find useful: