Skip to content

Instantly share code, notes, and snippets.

@ezirmusitua
Last active January 17, 2019 15:19
Show Gist options
  • Save ezirmusitua/e9565d96245a370f212bfd401e2e2e81 to your computer and use it in GitHub Desktop.
Save ezirmusitua/e9565d96245a370f212bfd401e2e2e81 to your computer and use it in GitHub Desktop.
[Local video server] Simplest node video player running in localhost #node #javascript #tools #video
const fs = require('fs');
const path = require('path');
const http = require('http');
function createServer(videoRepoPath) {
return http.createServer((req, res) => {
if (/video\/.*\/view/gi.test(req.url)) {
console.log(req.url, req.url.split('/'));
const [, , video] = req.url.split('/');
const ext = path.extname(video);
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.write(`<html>
<body>
<video controls width="100%">
<source src="/video/${video}" type="video/${ext.slice(1)}" >
</video>
</body>
</html>`);
return res.end();
}
if (/video\/.*/gi.test(req.url)) {
const [, , video] = req.url.split('/');
const ext = path.extname(video);
const abspath = decodeURIComponent(path.join(videoRepoPath, video));
const stat = fs.statSync(abspath);
const videoSize = stat.size;
const range = req.headers.range;
if (range) {
const parts = range.replace(/bytes=/, '').split('-');
const start = parseInt(parts[0], 10);
const end = parts[1] ? parseInt(parts[1], 10) : videoSize - 1;
const chunkSize = (end - start) + 1
const fileChunk = fs.createReadStream(abspath, {start, end})
const headers = {
'Content-Range': `bytes ${start}-${end}/${videoSize}`,
'Accept-Range': 'bytes',
'Content-Length': chunkSize,
'Content-Type': `video/${ext.slice(1)}`
};
res.writeHead(206, headers);
fileChunk.pipe(res);
} else {
const headers = {
'Content-Length': videoSize,
'Content-Type': `video/${ext.slice(1)}`
};
fs.createReadStream(abspath).pipe(res);
}
} else {
const videos = fs.readdirSync(videoRepoPath);
const videosStr = videos.filter((video) => fs.statSync(path.join(videoRepoPath, video)).isFile())
.map((v) => `<a style="font-size: 16px; margin-bottom: 12px;" href="/video/${v}/view" style="font-size: 20px; color: rgba(2, 3, 44, 0.87); margin-bottom: 16px;">
${v}
</a>`)
.join('\n');
res.setHeader('Content-Type', 'text/html; charset=utf-8');
res.write(`<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>${videoRepoPath}</title>
</head>
<body style="margin: 0">
<article style="padding: 64px 40px; display: flex; flex-direction: column;">
<h2>${videoRepoPath}</h2>
${videosStr}
</article>
</body>
</html>`);
return res.end();
}
});
}
function getRepoPath() {
const repoPath = process.argv[2];
if (!repoPath) return __dirname;
return repoPath;
}
function main() {
const imageViewer = createServer(getRepoPath());
console.info('Server listening on: 0.0.0.0:8080');
imageViewer.listen({ host: '0.0.0.0', port: 8080 });
}
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment