How to Build A Video Player with timeline comments using Appwrite & Cloudinary in Next.js
Chidi Eze
Posted on May 4, 2023
Timeline comments allow viewers to add comments or notes to specific points in a video, providing additional context or information about what is happening on screen. This feature enhances the viewer's experience, facilitates collaboration and engagement, improves accessibility, and provides valuable data insights for creators.
This article discusses building a video player with timeline comments using Appwrite storage, the Cloudinary video player, and Next.js.
Appwrite is an open-source backend server that provides a range of APIs and SDKs to help developers build web and mobile applications. It offers user authentication, database management, file storage, and more features.
Cloudinary is a cloud-based image and video management platform that provides developers with tools for storing, manipulating, optimizing, and delivering images and videos on their websites or applications.
Next.js is a popular open-source React-based framework for building web applications. It provides a range of features, such as server-side rendering, static site generation, and automatic code splitting.
Check out the GitHub repository to quickly get started:
https://github.com/Kizmelvin/nextjs-video-comments
Prerequisites
To fully grasp the concepts presented in this tutorial, the following are required:
- Basic understanding of JavaScript and React
- Cloudinary account and at least one video uploaded to the media library (Create a free account here)
Getting started
Log in to Cloudinary, navigate to the “Dashboard” page, and copy the cloud name
.
Next, navigate to the Media Library tab, select a video, or click the Upload button to upload a video. Grab the video's id and keep it safe; we need it later.
Creating a Next.js application
First, let’s run the following command in the terminal to create a new Next.js application:
npx create-next-app with-tailwindcss video-comments
The command above creates a starter Next.js application and adds tailwind CSS to the application with the with-tailwindcss flag in the video-comments folder.
Next, navigate to the project directory and start the application with the following commands:
cd video-comments #navigate into the project directory
npm run dev #start the dev server
Building the video player and the comments section
First, clean up the index.js
file in the pages folder and update it with the following snippet:
//pages/index.js
import { useEffect, useState, useRef } from "react";
const Home = () => {
const videoRef = useRef();
const cloudinaryRef = useRef();
const playerRef = useRef();
useEffect(() => {
if (cloudinaryRef.current) return;
cloudinaryRef.current = window.cloudinary;
playerRef.current = cloudinaryRef.current.videoPlayer(videoRef.current, {
cloud_name: "kizmelvin",
secure: true,
});
});
return (
<div className=" flex min-h-screen justify-around py-2">
{/* Video player */}
<section className="flex w-8/12 flex-col items-center justify-center px-10 text-center">
<div className="w-full">
<video
ref={videoRef}
id="demo-player"
className="cld-video-player cld-fluid "
controls
data-cld-public-id="video-demo"
/>
</div>
</section>
</div>
);
};
export default Home;
In the snippet above:
- We created some references, instantiated a Cloudinary instance in the
useEffect()
function, and passed our cloud name. - In the return function, we returned a video tag, passed
ref
andid
properties, and set thedata-cld-public-id
property to the video ID we obtained from Cloudinary.
In the browser, the application should like the image below:
Creating the comments section
Let’s create an input to collect user comments and buttons to submit and cancel the process.
Next, let’s update the index.js
with the following snippet:
In the snippet above, we:
- Created state constants using the useState hook.
- Created the
openComment()
function to pause the video and grab the current playing time. - In the return function, we rendered a
Comment
button, an input field for the comment, aSubmit
button to save the comment to Appwrite, and aCancel
button to terminate the process.
Integrating Appwrite for comments storage
Now it’s time to integrate Appwrite into our application to handle the video timeline comments.
First, log in to the Appwrite cloud or create an account. Check out this article on how to set up an Appwrite instance locally.
After successfully signing in, click on the + Create project button, choose a name for the project, and click the Create button.
After creating the project, navigate to the database tab, click the +Create database button, name the database, and click the create button to continue.
Next, grab the database ID and keep it handy. Click the +Create collection button, name the collection, and click the Create button to continue.
On the next screen, grab the collection ID and save it. Navigate to the attributes tab, click the +Create collection” button and the prompts, and create a name
, comment
, and videoTime
attribute.
Finally, click the Settings button in the bottom-left corner and grab the project ID and the API Endpoint; we’ll need them to set up the Appwrite instance.
Back in the code editor, run the following command to install Appwrite, uuid, and dotenv npm packages:
npm install appwrite uuidv4 dotenv #install the packages
Next, create a .env.local
file in the root directory of the project and save the Appwrite credentials like the below:
/.env.local
NEXT_PUBLIC_PROJECT_ID = "YOUR PROJECT ID"
NEXT_PUBLIC_DATABASE_ID = "YOUR DATABASE ID"
NEXT_PUBLIC_COLLECTION_ID = "YOUR COLLECTION ID"
Let’s create a helper folder in the root directory and create a Utils.js
file with the following snippet:
//helper/Utils.js
import { Client, Databases } from "appwrite";
import { v4 as uuidv4 } from "uuid";
//Initializing Appwrite
export const client = new Client();
client.setEndpoint("https://cloud.appwrite.io/v1").setProject(process.env.PROJECT_ID);
const dataB = new Databases(client);
//Saving Comments to Appwrite Database
export const saveComments = async (details) => {
try {
await dataB.createDocument(
process.env.DATABASE_ID,
process.env.COLLECTION_ID,
uuidv4(),
{
comment: `${details.comment}`,
videoTime: `${details.videoTime}`,
name: `${details.name}`,
}
);
} catch (error) {
console.log(error);
}
};
//Fetching comments from Appwrite Database
export const listComments = ({ setComments }) => {
const promise = dataB.listDocuments(
process.env.DATABASE_ID,
process.env.COLLECTION_ID
);
promise.then(
(response) => setComments(response.documents),
(error) => console.log(error)
);
};
In the snippet above, we did the following:
- Created a new Client and two Database instances and passed the
project_id
to the client. - Created the
saveComment
function to save the video time and the user comment to the Appwrite database. - Created the
listComments
function to get the list of comments from Appwrite and update our comment state.
Now in the index.js
file, let’s grab the details from our user; update the index.js
file with the following snippet:
In the above snippet, we:
- Imported
saveComments
andlistComments
functions from theUtils.js
file and created thedetails
object. - Called the
saveComments()
in thehandleSubmit()
function and passed the details object to it. - Created a button to view and hide the comments, looped through the comment state, and displayed the comments.
The complete code of the index.js
file can be found in this Github Gist.
Now, we have a functional video player with timeline commenting functionality in the browser.
Conclusion
Building a video player with timeline comments is a great way to enhance user experience and engagement. By leveraging the power of these technologies, we created a seamless and interactive video playback experience that allows users to leave comments and feedback at specific points in the video timeline. So, to take your website to the next level, consider implementing a video player with timeline comments using Appwrite and Cloudinary in Next.js.
Resources
These resources might be helpful:
Posted on May 4, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.