Initial commit
This commit is contained in:
parent
9a1d04b6d6
commit
3d2130a17e
7 changed files with 4245 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
node_modules
|
4023
package-lock.json
generated
Normal file
4023
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
21
package.json
Normal file
21
package.json
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
{
|
||||||
|
"name": "zoom-clone",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"devStart": "nodemon server.js"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"ejs": "^3.1.6",
|
||||||
|
"express": "^4.17.2",
|
||||||
|
"socket.io": "^2.4.1",
|
||||||
|
"uuid": "^8.3.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"nodemon": "^2.0.15"
|
||||||
|
}
|
||||||
|
}
|
53
public/script.js
Normal file
53
public/script.js
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
const socket = io("/")
|
||||||
|
const videos = document.getElementById("videos")
|
||||||
|
const myPeer = new Peer()
|
||||||
|
const myVideo = document.createElement("video")
|
||||||
|
|
||||||
|
myVideo.muted = true
|
||||||
|
|
||||||
|
const connectToNewUser = (userId, stream) => {
|
||||||
|
const call = myPeer.call(userId, stream)
|
||||||
|
const video = document.createElement("video")
|
||||||
|
|
||||||
|
call.on("stream", (userVideoStream) =>
|
||||||
|
addVideoStream(video, userVideoStream)
|
||||||
|
)
|
||||||
|
|
||||||
|
call.on("close", () => video.remove())
|
||||||
|
}
|
||||||
|
|
||||||
|
const addVideoStream = (video, stream) => {
|
||||||
|
video.srcObject = stream
|
||||||
|
video.addEventListener("loadedmetadata", () => video.play())
|
||||||
|
videos.append(video)
|
||||||
|
}
|
||||||
|
|
||||||
|
navigator.mediaDevices
|
||||||
|
.getUserMedia({
|
||||||
|
video: true,
|
||||||
|
audio: true,
|
||||||
|
})
|
||||||
|
.then((stream) => {
|
||||||
|
addVideoStream(myVideo, stream)
|
||||||
|
myPeer.on("call", (call) => {
|
||||||
|
call.answer(stream)
|
||||||
|
const video = document.createElement("video")
|
||||||
|
// const fullscreen = document.createElement("button")
|
||||||
|
// fullscreen.dataset.id =
|
||||||
|
call.on("close", () => video.remove())
|
||||||
|
call.on("stream", (userVideoStream) =>
|
||||||
|
addVideoStream(video, userVideoStream)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on("user-connected", (userId) =>
|
||||||
|
connectToNewUser(userId, stream)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
socket.on("user-disconnected", (userId) => {
|
||||||
|
const call = myPeer.connections[userId]
|
||||||
|
if (call) call[0].close()
|
||||||
|
})
|
||||||
|
|
||||||
|
myPeer.on("open", (id) => socket.emit("join-room", ROOM_ID, id))
|
98
public/style.css
Normal file
98
public/style.css
Normal file
|
@ -0,0 +1,98 @@
|
||||||
|
:root {
|
||||||
|
--primary: #14bbaa;
|
||||||
|
--secondary: #2c3c4c;
|
||||||
|
}
|
||||||
|
|
||||||
|
*,
|
||||||
|
*::before,
|
||||||
|
*::after {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
font-family: "Lato", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
||||||
|
"Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji",
|
||||||
|
"Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
|
||||||
|
font-size: 1.2em;
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
grid-auto-rows: 10vh 74vh 16vh;
|
||||||
|
display: grid;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav,
|
||||||
|
footer {
|
||||||
|
background-color: var(--secondary);
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 100vw;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
nav a {
|
||||||
|
font-size: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
margin: 0 0.5em;
|
||||||
|
text-decoration: none;
|
||||||
|
width: fit-content;
|
||||||
|
color: white;
|
||||||
|
grid-template-columns: 1fr 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#videos {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(33%, 1fr));
|
||||||
|
grid-template-rows: repeat(auto-fit, minmax(33%, 1fr));
|
||||||
|
background-color: var(--primary);
|
||||||
|
color: white;
|
||||||
|
padding: 4px 0 4px 0;
|
||||||
|
gap: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
border: none;
|
||||||
|
border-radius: 2em;
|
||||||
|
color: #f5f0f0;
|
||||||
|
background-color: transparent;
|
||||||
|
font-size: 1em;
|
||||||
|
padding: 0.7rem 1.6rem;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-primary {
|
||||||
|
background-color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.medium-header {
|
||||||
|
font-size: 2.5rem;
|
||||||
|
font-weight: 200;
|
||||||
|
line-height: 1.2;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-secondary {
|
||||||
|
background-color: var(--secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
button:not(:disabled) {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:is(:disabled, :hover) {
|
||||||
|
filter: brightness(0.9);
|
||||||
|
}
|
||||||
|
|
||||||
|
video.your-video {
|
||||||
|
display: none;
|
||||||
|
}
|
25
server.js
Normal file
25
server.js
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
const express = require("express")
|
||||||
|
const app = express()
|
||||||
|
const server = require("http").Server(app)
|
||||||
|
const io = require("socket.io")(server)
|
||||||
|
const { v4: uuidV4 } = require("uuid")
|
||||||
|
|
||||||
|
app.set("view engine", "ejs")
|
||||||
|
app.use(express.static("public"))
|
||||||
|
|
||||||
|
app.get("/", (_, res) => res.redirect(`/${uuidV4()}`))
|
||||||
|
|
||||||
|
app.get("/:room", (req, res) => res.render("room", { roomId: req.params.room }))
|
||||||
|
|
||||||
|
io.on("connection", (socket) =>
|
||||||
|
socket.on("join-room", (roomId, userId) => {
|
||||||
|
socket.join(roomId)
|
||||||
|
socket.to(roomId).emit("user-connected", userId)
|
||||||
|
|
||||||
|
socket.on("disconnect", () => {
|
||||||
|
socket.to(roomId).broadcast.emit("user-disconnected", userId)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
server.listen(3000)
|
24
views/room.ejs
Normal file
24
views/room.ejs
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
|
||||||
|
<script>
|
||||||
|
const ROOM_ID = "<%= roomId %>"
|
||||||
|
</script>
|
||||||
|
<script
|
||||||
|
src="https://unpkg.com/peerjs@1.3.1/dist/peerjs.min.js"
|
||||||
|
defer
|
||||||
|
></script>
|
||||||
|
<script src="/socket.io/socket.io.js" defer></script>
|
||||||
|
<script src="script.js" defer></script>
|
||||||
|
<link rel="stylesheet" href="style.css" />
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav><a href="#">Home</a></nav>
|
||||||
|
<div id="videos"></div>
|
||||||
|
<footer></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
Reference in a new issue