Skip to main content

Build a Netflix Clone with Vue 3, Vuetify, and SourceSync SDK

In this tutorial, we'll walk you through creating a Netflix-like video streaming application. We'll use Vue 3 (a popular JavaScript framework), Vuetify (a Material Design component library for Vue), and the SourceSync SDK (a toolkit for managing video content metadata and interactive overlays). By the end, you'll have a basic app with a homepage showing available videos, individual video detail pages, and a video player page with interactive overlays.

Building the App

Prerequisites

Before we start, make sure you have these tools installed on your computer:

  1. Node.js: This is a JavaScript runtime that allows you to run JavaScript on your computer, not just in a web browser. Download it from nodejs.org.

  2. npm (Node Package Manager): This comes automatically with Node.js. It helps you install and manage JavaScript packages.

You'll also need a SourceSync SDK app key. This is a unique identifier that allows you to use the SourceSync services. If you don't have one, you'll need to sign up at the SourceSync website (we're using a placeholder URL in this tutorial).

Step 1: Set up the Vue 3 project with Vuetify

First, we'll create a new Vue 3 project and add Vuetify to it. Vuetify will give us pre-made components to build our user interface quickly.

Open your command line and run:

npm create vuetify

This command prompts you with a few options before generating your scaffolded Vue / Vuetify 3 project.

✔ Project name: > netflix-clone-vuetify-overlays
✔ Which preset would you like to install? > Recommended (Everything from Default. Adds auto importing, layouts & pinia)
✔ Use TypeScript? > Yes
✔ Would you like to install dependencies with yarn, npm, pnpm, or bun? > npm
✔ Install Dependencies? … > Yes

After making your selections, create-vuetify will generate the structure for your new application.

Once the scaffold is complete, start the vite development server by running the following commands:

cd netflix-clone-vuetify-overlays

Step 2: Install dependencies & start application

Now we need to install the SourceSync SDK. This will allow us to manage video content and interactive overlays in our app.

In your project directory, run:

npm install sourcesync-sdk

This command tells npm to download and install the SourceSync SDK and add it to your project's dependencies.

npm run dev

This will start the app and provide the local address so you can see your changes

Step 3: Configure the SourceSync SDK

Now we'll set up the SourceSync SDK in our project. We'll create a new file that initializes the SDK, which we can then import and use throughout our app.

Create a new file src/plugins/sourcesync.ts and add the following code:

import { initializeApp } from '@sourcesync-sdk/app'
import { createActivationView, useSmartblockRenderer } from '@sourcesync-sdk/render-activation-web'
import type { Plugin } from 'vue'

// Initialize the SourceSync app
const app = await initializeApp({
appKey: import.meta.env.VITE_SOURCESYNC_APP_KEY,
env: import.meta.env.VITE_SOURCESYNC_MODE,
})

// Create and export the functions from render-activation-web
export const activationView = (activation: any, options: any) =>
createActivationView(app, activation, options)

export { useSmartblockRenderer }

// Define the plugin
const sourcesyncPlugin: Plugin = {
install: () => {
// The app is already initialized, so we don't need to do anything here
},
}

export default sourcesyncPlugin

Let's break this down:

  • We import necessary functions from the SourceSync SDK.
  • We initialize the SourceSync app with our app key and set the environment.
  • We export sopurcesync so we can use it in other parts of our app.

Now we need to make sourcesync available inside the application

/**
* plugins/index.ts
*
* Automatically included in `./src/main.ts`
*/

// Plugins
import vuetify from './vuetify'
import pinia from '../stores'
import router from '../router'
import sourcesync from './sourcesync'

// Types
import type { App } from 'vue'

export function registerPlugins (app: App) {
app
.use(vuetify)
.use(router)
.use(pinia)
.use(sourcesync)
}

Next, create a .env.local file in the root of your project and add your SourceSync app key and environment:

VITE_SOURCESYNC_APP_KEY=your_app_key_here
VITE_SOURCESYNC_MODE=the_environment_you_are_targeting

This file stores environment variables. The VITE_ prefix allows Vite (the build tool used by Vue) to expose this variable to your app.

Step 4: Create the App Layout

Now, let's create the basic layout for our app. We'll use Vuetify components to create a responsive design.

Update src/App.vue:

<template>
<v-app>
<v-app-bar app color="primary">
<v-app-bar-title>
<router-link class="text-h4 text-white text-decoration-none" to="/">
NetflixClone
</router-link>
</v-app-bar-title>
<v-spacer />
<v-btn to="/" type="text">Home</v-btn>
</v-app-bar>

<v-main>
<v-container fluid>
<router-view />
</v-container>
</v-main>
</v-app>
</template>

<script setup lang="ts">
// No additional setup needed
</script>

This creates an app bar at the top with a title that links to the home page, and a "Home" button. The <router-view> component is where the content of each page will be displayed.

Step 5: Create the Homepage

Now, let's create the homepage that will display a grid of available videos.

Create src/pages/index.vue:

<template>
<div>
<h1 class="text-h4 mb-6">Popular Videos</h1>
<v-row>
<v-col
v-for="video in videos"
:key="video.id"
cols="12"
lg="3"
md="4"
sm="6"
>
<v-card hover :to="{ name: '/VideoDetails/[id]', params: { id: video.id } }">
<v-img :aspect-ratio="16 / 9" cover :src="video.thumbnail" />
<v-card-title>{{ video.title }}</v-card-title>
</v-card>
</v-col>
</v-row>
</div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'

// Mock data - replace this with actual API calls to your backend
const videos = ref([
{ id: '1', title: 'Video 1', thumbnail: 'https://picsum.photos/300/200' },
{ id: '2', title: 'Video 2', thumbnail: 'https://picsum.photos/300/201' },
// Add more mock videos as needed
])

onMounted(async () => {
// In a real app, you would fetch videos from your backend here
// For example:
// const response = await fetch('https://your-api.com/videos');
// videos.value = await response.json();
})
</script>

This creates a responsive grid of video cards. Each card shows a thumbnail and title, and links to the details page for that video. We're using mock data here, but in a real app, you'd fetch this data from your backend.

Step 6: Create the Video Details Page

Next, let's create a page that shows more details about a selected video.

Create a folder src/pages/VideoDetails

Create a file inside your folder src/pages/VideoDetails/[id].vue

Now let's add the code to Video Details page

<template>
<div v-if="video">
<v-row>
<v-col cols="12" md="8">
<v-img :aspect-ratio="16/9" cover :src="video.thumbnail" />
</v-col>
<v-col cols="12" md="4">
<h1 class="text-h4 mb-4">{{ video.title }}</h1>
<p class="mb-4">{{ video.description }}</p>
<v-btn
color="primary"
:to="{ name: '/VideoPlayer/[id]', params: { id: video.id } }"
x-large
>
Watch Now
</v-btn>
</v-col>
</v-row>
</div>
</template>

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRoute } from 'vue-router'

const route = useRoute()
const video = ref({
id: null,
title: ``,
description: '',
thumbnail: ``,
})

onMounted(async () => {
const id = route.query.id as string
// In a real app, you would fetch video details from your backend here
// For example:
// const response = await fetch(`https://your-api.com/videos/${id}`);
// video.value = await response.json();
// For now, we'll use mock data:
video.value = {
id,
title: `Video ${id}`,
description: 'Video description',
thumbnail: `https://picsum.photos/300/200?random=${id}`,
}
})
</script>

This page displays a larger thumbnail, the video title, a description, and a "Watch Now" button. Again, we're using mock data, but in a real app, you'd fetch the details for the specific video from your backend.

Step 7: Create the Video Player Page

Finally, let's create the video player page. This is where we'll use the SourceSync SDK to handle video playback and interactive overlays.

Create src/views/VideoPlayer.vue:

<template>
<div v-if="video">
<div class="position-relative">
<video
ref="videoRef"
class="w-100"
:poster="video.thumbnail"
:src="video.videoUrl"
/>
<div
ref="overlayRef"
class="position-absolute top-0 start-0 w-100 h-100"
/>
<v-btn
class="m-4"
color="primary"
@click="handlePlayPause"
>
{{ isPlaying ? 'Pause' : 'Play' }}
</v-btn>
</div>
</div>
</template>

<script setup lang="ts">
import { onMounted, onUnmounted, ref } from 'vue'
import { useRoute } from 'vue-router'
import { activationView, useSmartblockRenderer } from '../../plugins/sourcesync'

const route = useRoute()

const video = ref({
id: null,
title: ``,
description: '',
thumbnail: ``,
videoUrl: '',
})
const videoRef = ref<HTMLVideoElement | null>(null)
const overlayRef = ref<HTMLDivElement | null>(null)
const isPlaying = ref(false)

const handlePlayPause = () => {
if (videoRef.value) {
if (isPlaying.value) {
videoRef.value.pause()
} else {
videoRef.value.play()
}
isPlaying.value = !isPlaying.value
}
}

onMounted(async () => {
const id = route.params.id as string
// In a real app, fetch video details from your backend here
video.value = {
id,
title: `Video ${id}`,
description: 'Video description',
thumbnail: `https://picsum.photos/300/200?random=${id}`,
videoUrl: 'https://storage.googleapis.com/cdn.sourcesync.io/videos/Frecon%20Farms%20Preview_1.mp4',
}

if (videoRef.value && overlayRef.value) {
const view = activationView(
{ distribution: { id: '56614' } },
{
el: overlayRef.value,
renderer: useSmartblockRenderer({}),
}
)

view.mount()

onUnmounted(() => {
view.unmount()
})
}
})
</script>

This page does several important things:

  1. It creates a video player using the HTML5 <video> element.
  2. It provides a play/pause button.
  3. Most importantly, it uses the SourceSync SDK to initialize the video player and manage overlays.

The activationView method sets up the overlay system. It needs:

  • A container for overlays el
  • A distribution ID (which you'll get from your SourceSync account)

In a real app, you'd replace the mock data with actual video data and handle the overlay activations to display interactive content.

Conclusion

Congratulations! You've now created a basic Netflix-like streaming application using Vue 3, Vuetify, and the SourceSync SDK. Your application has:

  1. A homepage displaying a grid of available videos
  2. A video details page showing more information about each video
  3. A video player page for watching videos, with support for interactive overlays
  4. Basic navigation between these pages

Key things to remember:

  • The SourceSync SDK's renderer-activation-web module handles overlay management.
  • Use activationView() to manage overlays.
  • In a real application, you'd replace the mock data with actual API calls to your backend.
  • You'll need to use a real distribution ID from your SourceSync account.

To further improve your application, consider adding:

  1. User authentication
  2. A search function
  3. Video categories or genres
  4. A "Continue Watching" feature to save user progress
  5. More complex interactions with the overlays provided by the SDK

Remember to consult the SourceSync SDK documentation for more advanced features and best practices for working with video content and interactivity.

Happy coding!