Skip to content

📺 This repository is a Netflix clone project that was built using cutting-edge technologies such as TypeScript, Next.js, React, Hasura, Supabase, GraphQL, Magic, and more.

Cwarcup/netflix-clone

Repository files navigation

Netflix Clone

Netflix Clone

Live Website

In order to view the live website, you will need to sign in with your email. You can use any email address, no password is required. Once you sign in, you will be able to view the videos, like/dislike videos, and view your favourites list.

Link: https://netflixclonedemo.vercel.app/

Preview and Demo Clips

Check out a few video examples!

Login Process with Magic

Discover videos, like/dislike

View and like a video

Homepage image

More Images

Dynamic Pages Image

My-List of favourited videos

User Stories

Users should ba able to:

  • login to their account with email, no password needed
  • see a list of videos
  • play a video
  • be responsive on mobile
  • like/dislike a video
  • view favourited videos (liked videos)
  • view videos they have already watched
  • discover new videos by topic/category

Tech Stack

Component Architecture

The real Netflix app has a pretty complex UI, but to break it down into simple components it looks something like this:

  • Header/Navbar
    • Logo
    • Favourites List
    • Profile
  • Banner
    • Large image
    • Title, Description
    • Play button
  • Categories List
    • Title
    • List of videos (Card)
      • On hover...
        • Title, Description, Play button, Like/Dislike button
  • Feature Section
    • Tall images list

I used these as the basis for my component architecture.

Sign In

The user can sign in with their email. I used Magic to send a link to the user's email and once they click the link, they are signed in.

Instead of storing passwords, I used Magic to generate a public and private key on the client side. Instead of creating and storing passwords in a database I control, Magic generates a DID (Decentralized Identifier) for the user, which is a unique identifier for the user. I used the DID to identify the user and store their watch data in a Supabase database.

Playing Videos

Videos are displayed using the YouTube Player API to embed videos within an iframe. This allows us to control the video using JavaScript, however it created some challenges.

One struggle was displaying a gradient over the iframe YouTube element. Because the gradient sits on top of the video, the native play and pause buttons could not be clicked. To get around this, I updated the player attribute to auto-play when the user clicks the video. This also causes the gradient to be hidden, so the user can click the native play and pause buttons. I don't love this solution, but it works for now.

Fetching Data

As we know, Next.js provides multiple methods for fetching data. We can use getStaticProps to fetch data at build time (SSG), or getServerSideProps to fetch data at request time. We can also use getInitialProps to fetch data on the client side.

For the specific video page ('/video/:id'), I decided to use incremental site regeneration using getStaticProps with the revalidate option. This means that the page will be regenerated at a specific time interval.

Some of the pages I could create statically at build time, and some of the pages I could create at request time. For example, the banner video will always be the same, so I could create that page statically at build time. However, the video page will change depending on the video, so I could create that page at request time.

GraphQL and Database

I used Hasura to create a GraphQL API. Hasura is a GraphQL engine that connects to a Postgres database.

For my database, I used a Postgres database hosted by Supabase. Supabase is an open source Firebase alternative. It provides a Postgres database, and a GUI to create tables, and to query the database.

Architecture

Users
column issuer (PK) publicAddress email id
type text text text int
did:ethr:0x92bc... 0x92bc... info@cwarcup.com 1

I used the Decentralized ID from Magic to identify the user and is the primary key for the users table. The getMetadata method returns an object with the user's public address, email, and DID.

Stats
column id (PK) userId (FK) videoId favourited watched
type int text text boolean or Null boolean
1 did:ethr:0x92bc... Lcd0df7jwpM true true

The stats table stores information about the user's interactions with a video. The userId is the user's DID, and the videoId is the YouTube video ID. The favourited column is a boolean that indicates whether the user has liked/disliked the video. The watched column is a boolean that indicates whether the user has watched the video.

I created a user role to ensure that only that user has access to their data. I used a JSON Web Token (JWT) token to authenticate the user.

Authentication api/auth

Created an API route (/api/auth) to handle authentication. The API route uses the Magic Admin SDK NodeJS implementation to authenticate the user. The API route returns a JWT token to the client. The client then stores the JWT token in a cookie.

Middleware

Next.js provides a middleware feature. Middleware is a function that is executed before a request is sent to the API route. I used the middleware to verify the JWT token from the browsers cookie.

I initially used JSON Web Token to handle the signing and verification of the JWT token. However, because the middleware was being run on Next.js' Edge Runtime, I didn't have access to the Native NodeJS modules, and therefore some of the methods in the jsonwebtoken package were not available. I decided to use jose instead.

Authentication Flow

The JWT token contains information about the user, such as their email, public address, and DID. When a user logs in, a new JWT token is generated, GraphQL queries Hasura to see if the user exists in the database by using the newly created JWT token (remember, this has 3 parts). If the user exists, user is logged in and the JWT token is stored in a cookie. If the user doesn't exist, GraphQL mutation occurs to create a new user in the database. The user is then logged in and the JWT token is stored in a cookie.

The database is setup to only allow a user to access their own data unless they have X-Hasura-Role set to admin and have the x-hasura-admin-secret. This ensures that a user can only access their own data.

User Stats api/stats

The stats API is used to read the token from the cookie created during the authentication process. The JWT token if verified using the Magic SDK and then queried against the database. If the stats for that user do not exist, they are created. If the stats do exist, they are returned to the client.

The API's purpose is to allow a user to like/dislike a video, as well as view previously watched videos.

About

📺 This repository is a Netflix clone project that was built using cutting-edge technologies such as TypeScript, Next.js, React, Hasura, Supabase, GraphQL, Magic, and more.

Topics

Resources

Stars

Watchers

Forks