anistream/index.js
ShakedAp bfdd897a20 Added settings file and removed videos from repo
Created settings.json that contains the settings
Created .gitignore that ignores the videos folder
Modified index.js to take the settings settings.json
Modified client.js to take the WebSocket settings from the window
2023-06-25 09:07:52 +03:00

121 lines
3.6 KiB
JavaScript

// https://www.npmjs.com/package/ws#api-docs
// https://developer.mozilla.org/en-US/docs/Web/API/WebSocket
const fs = require("fs");
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const WebSocket = require('ws');
const wss = new WebSocket.Server({ server:server });
const settings = JSON.parse(fs.readFileSync("settings.json"));
const THRESH_IGNORANCE = 250;
let users_amount = 0;
let unique_id = 0;
let state = {
video_timestamp: 0,
last_updated: get_time(),
playing: false,
global_timestamp: 0,
client_uid: null
};
wss.on('connection', function connection(ws) {
users_amount += 1;
console.log('A new client Connected. Amount of users: ', users_amount);
state.client_uid = unique_id;
unique_id +=1 ;
ws.send(`state_update_from_server ${JSON.stringify(state)}`);
ws.on('error', console.error);
ws.on('message', function message(data) {
data = data.toString();
if(data.startsWith("time_sync_request_backward"))
{
ws.send(`time_sync_response_backward ${get_time()}`);
}
if(data.startsWith("time_sync_request_forward"))
{
let client_time = Number(data.slice("time_sync_request_forward".length + 1));
ws.send(`time_sync_response_forward ${get_time() - client_time}`);
}
if(data.startsWith("state_update_from_client"))
{
let new_state = JSON.parse(data.slice("state_update_from_client".length + 1));
let too_soon = (get_time() - state.last_updated) < THRESH_IGNORANCE;
let other_ip = (new_state.client_uid != state.client_uid);
let stale = (new_state.last_updated < state.last_updated)
if (!stale && !(too_soon && other_ip))
{
state = new_state;
wss.clients.forEach(function each(client) {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(`state_update_from_server ${JSON.stringify(state)}`);
}
});
}
}
});
ws.on('close', function close() {
users_amount -= 1;
console.log('Client diconnected. Amount of users: ', users_amount);
});
});
app.use(express.static(__dirname));
app.get("/", function (req, res) {
res.sendFile(__dirname + "/index.html");
});
app.get("/video", function (req, res) {
// Ensure there is a range given for the video
const range = req.headers.range;
if (!range) {
res.status(400).send("Requires Range header");
}
// get video stats (about 61MB)
const videoPath = settings.video_path;
const videoSize = fs.statSync(videoPath).size;
// Parse Range
// Example: "bytes=32324-"
const CHUNK_SIZE = 10 ** 6; // 1MB
const start = Number(range.replace(/\D/g, ""));
const end = Math.min(start + CHUNK_SIZE, videoSize - 1);
// Create headers
const contentLength = end - start + 1;
const headers = {
"Content-Range": `bytes ${start}-${end}/${videoSize}`,
"Accept-Ranges": "bytes",
"Content-Length": contentLength,
"Content-Type": "video/mp4",
};
// HTTP Status 206 for Partial Content
res.writeHead(206, headers);
// create video read stream for this particular chunk
const videoStream = fs.createReadStream(videoPath, { start, end });
// Stream the video chunk to the client
videoStream.pipe(res);
});
server.listen(settings.server_port, settings.server_ip, () => console.log(`Listening on port: 3000`));
function get_time(){
let d = new Date();
return d.getTime();
}