Building a Real-Time Watch-Party Application with Node.js and Socket.IO

I'm a Student, Developer, Writer and a Tech Geek
Watch-party applications have gained popularity for enabling synchronized viewing experiences among users separated by distance. Leveraging Node.js for server-side logic and Socket.IO for real-time communication, we can construct a robust platform for hosting virtual movie nights with seamless synchronization and interactive features. In this technical guide, we'll walk through the process of creating a watch-party application from scratch, complete with code snippets for implementation.
Setting Up the Development Environment
Ensure you have Node.js and npm installed on your machine. Initialize a new Node.js project and install the required dependencies:
mkdir watch-party-app
cd watch-party-app
npm init -y
npm install express socket.io
Server-Side Implementation (server.js)
First, let's set up our Node.js server using Express.js and Socket.IO:
const express = require("express");
const http = require("http");
const socketIO = require("socket.io");
const app = express();
const server = http.createServer(app);
const io = socketIO(server);
app.use(express.static("public"));
app.get("/", (req, res) => {
res.sendFile(__dirname + "/public/index.html");
});
const users = {};
let videoState = { playing: false, currentTime: 0 };
io.on("connection", (socket) => {
// User joins the room
socket.on("join", (username) => {
users[socket.id] = username;
io.emit("updateUsers", Object.values(users));
socket.broadcast.emit("message", `${username} has joined the room`);
socket.emit("videoSync", videoState);
});
// User sends a chat message
socket.on("chatMessage", (message) => {
io.emit("message", `${users[socket.id]}: ${message}`);
});
// User plays, pauses, or seeks the video
socket.on('videoControl', (data) => {
videoState = data;
io.emit('videoControl', data);
});
// User leaves the room
socket.on("disconnect", () => {
io.emit("message", `${users[socket.id]} has left the room`);
delete users[socket.id];
io.emit("updateUsers", Object.values(users));
});
});
const PORT = process.env.PORT || 3000;
server.listen(PORT,'127.0.0.1', () => {
console.log(`Server is running on port ${PORT}`);
});
Client-Side Implementation (index.html)
Now, let's create the client-side interface for our watch-party application. Create a new folder and name it "public". In the public folder create a new file and name it "index.html":
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Watch Party App</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: auto;
background-color: #f0f0f0;
}
#container {
display: flex;
flex-direction: column;
align-items: center;
padding: 20px;
background-color: #fff;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
}
#chat {
display: flex;
flex-direction: column;
align-items: center;
margin-bottom: 20px;
}
#messages {
list-style-type: none;
padding: 0;
margin: 0;
max-height: 300px;
overflow-y: auto;
border: 1px solid #ddd;
border-radius: 4px;
padding: 10px;
background-color: #f9f9f9;
}
input {
margin-top: 10px;
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
overflow-y: auto;
}
button {
margin-top: 10px;
padding: 8px;
background-color: #4caf50;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
}
#users {
font-style: italic;
color: #555;
}
</style>
</head>
<body>
<div id="container">
<h1>Watch Party</h1>
<div>
<video id="videoPlayer" width="640" height="360" controls>
<source src="./vtest1.mp4" type="video/mp4">
Your browser does not support the video tag.
</video>
</div>
<div id="chat">
<ul id="messages"></ul>
<input id="m" placeholder="Type your message..." autocomplete="off"/>
<button onclick="sendMessage()" >Send</button>
</div>
<div id="users">Users: </div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="script.js"></script>
</body>
</html>
Connection between Client-Server (script.js)
Now, let's create a new file in the public folder and name it "script.js".
document.addEventListener("DOMContentLoaded", () => {
const socket = io();
const video = document.getElementById("videoPlayer");
// Prompt for username and join the room
const username = prompt("Enter your username:");
socket.emit("join", username);
// Update users list
socket.on("updateUsers", (users) => {
document.getElementById("users").innerHTML = `Users: ${users.join(", ")}`;
});
// Receive and display chat messages
socket.on("message", (data) => {
const messages = document.getElementById("messages");
const item = document.createElement("li");
// item.textContent = `${data.username}: ${data.message}`;
item.textContent = data;
messages.appendChild(item);
});
// Receive and handle video control events
socket.on("videoControl", (data) => {
if (data.playing) {
video.play();
} else {
video.pause();
}
video.currentTime = data.currentTime;
});
// Send chat message
window.sendMessage = () => {
const input = document.getElementById("m");
const message = input.value.trim();
if (message !== "") {
socket.emit("chatMessage", message);
input.value = "";
}
};
// Update video state when playing, pausing, or seeking
video.addEventListener("play", () => {
const currentTime = video.currentTime;
socket.emit("videoControl", { playing: true, currentTime });
});
video.addEventListener("pause", () => {
const currentTime = video.currentTime;
socket.emit("videoControl", { playing: false, currentTime });
});
// Handle file select and emit the video to the server
window.handleFileSelect = () => {
const file = videoInput.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
const videoData = {
name: file.name,
type: file.type,
data: event.target.result,
};
socket.emit("uploadVideo", videoData);
};
reader.readAsDataURL(file);
}
};
});
Deploying the Application
Once you've completed development and testing locally, deploy your application to a server or cloud platform for public access. Utilize platforms like Render or AWS for hosting your Node.js application. I would recommend render.com which has free plans.
Conclusion
By following this guide and implementing the provided code snippets, you've created a real-time watch-party application using Node.js and Socket.IO. Users can now enjoy synchronized video playback and engage in real-time chat during movie nights, regardless of their physical location. Experiment with additional features and enhancements to tailor the application to your specific requirements. Happy coding!
GitHub Link: https://github.com/manoj-narasimha/watch-party-app
Follow me for more articles like this ☝️


