How to Build A Video Player with timeline comments using Appwrite & Cloudinary in Next.js
Tags: webdev, appwritehack, nextjs, cloudstorage
Published: 2023-05-04 13:41:02

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](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) 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](https://cloudinary.com/?utm_source=hackmamba&utm_medium=hackmamba-blog) 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](https://nextjs.org/) 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](https://cloudinary.com/users/register_free#gsc.tab=0?utm_source=hackmamba&utm_medium=hackmamba-blog))


## Getting started

[Log](https://cloudinary.com/users/login) [](https://cloudinary.com/users/login)[in](https://cloudinary.com/users/login) to Cloudinary, navigate to the “Dashboard” page, and copy the `cloud name`.

![](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679312541307_Screenshot+2023-03-20+at+12.37.05.png)


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.


![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679312902477_Screenshot+2023-03-20+at+12.46.37.png)



## Creating a Next.js application

First, let’s run the following command in the terminal to create a new Next.js application:

```js
    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:

```js
    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:

```js
    //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` and `id` properties, and set the `data-cld-public-id` property to the video ID we obtained from Cloudinary.

In the browser, the application should like the image below:

![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679340292484_Screenshot+2023-03-20+at+20.24.44.png)

## 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:

{% embed https://gist.github.com/Kizmelvin/7491bb71ee0943c7558d3e370d6a0043 %}

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, a `Submit` button to save the comment to Appwrite, and a `Cancel` button to terminate the process.
![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679399145771_vcgif.gif)

## Integrating Appwrite for comments storage

Now it’s time to integrate [Appwrite](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) into our application to handle the video timeline comments.

First, [log in](https://cloud.appwrite.io/login) to the Appwrite cloud or create an account. Check out this [article](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba) 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.


![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679341849719_Screenshot+2023-03-20+at+20.50.43.png)


After creating the project, navigate to the **database** tab, click the **+Create database** button, name the database, and click the **create** button to continue.


![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679342355036_Screenshot+2023-03-20+at+20.59.09.png)


Next, grab the **database ID** and keep it handy. Click the **+Create collection** button, name the collection, and click the **Create** button to continue.

![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679342947808_Screenshot+2023-03-20+at+21.07.19.png)


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.


![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679343597835_Screenshot+2023-03-20+at+21.15.08.png)


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](https://appwrite.io/?utm_source=hackmamba&utm_medium=hackmamba-blog) instance.

![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679398585961_Screenshot+2023-03-21+at+12.30.51.png)


Back in the code editor, run the following command to install [A](https://www.npmjs.com/package/appwrite)[ppwrite](https://www.npmjs.com/package/appwrite), [uuid](https://www.npmjs.com/package/uuidv4), and [dotenv](https://www.npmjs.com/package/dotenv) npm packages:

```js
    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:

```js
    /.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:
 
```js
    //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:


{% embed https://gist.github.com/Kizmelvin/fded5b73cdad0ff69667f7402285c903 %}

In the above snippet, we:

- Imported `saveComments` and `listComments` functions from the `Utils.js` file and created the `details` object.
- Called the `saveComments()` in the `handleSubmit()` 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](https://gist.github.com/Kizmelvin/f07ad809b3fd6697e16499143b96521e).

Now, we have a functional video player with timeline commenting functionality in the browser.

![image-demo](https://paper-attachments.dropboxusercontent.com/s_7E4AED48E4FABB34AE53D515B21BE4CABBC46B580BC6988A0BE6ECD6F8A2691A_1679400941707_vcgif2.gif)

## 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:

- [Setting up Appwrite instance locally](https://dev.to/hackmamba/create-a-local-appwrite-instance-in-3-steps-19n9?utm_source=hackmamba&utm_medium=hackmamba)
- [Getting started with Appwrite](https://appwrite.io/docs/getting-started-for-web?utm_source=hackmamba&utm_medium=hackmamba-blog)