Skip to content

Instantly share code, notes, and snippets.

@ezirmusitua
Last active January 17, 2019 15:26
Show Gist options
  • Save ezirmusitua/d0a3306900e3e5eace1d7b27526d94d4 to your computer and use it in GitHub Desktop.
Save ezirmusitua/d0a3306900e3e5eace1d7b27526d94d4 to your computer and use it in GitHub Desktop.
[Local image server] Simplest node image viewer with pagination in localhost #node #javascript #tools #image
// usage: node image-viewer <Gallery Root>
const fs = require('fs');
const path = require('path');
const http = require('http');
// yarn add global gm & apt install graphicmagic
let gm;
try {
const gm = require('gm');
catch (err) {
console.warn('gm not found, run `$npm install gm` in script directory to install');
}
const PRESET_IMAGE_WIDTH = 960;
const PAGE_SIZE = 50;
function createServer(imageRepoPath) {
return http.createServer((req, res) => {
if (/directory\/.*\/file\/.*/gi.test(req.url)) {
const [, , dir, , file] = req.url.split('/');
const ext = path.extname(file);
res.setHeader('Content-Type', `image/${ext.slice(1)}`);
const abspath = decodeURIComponent(path.join(imageRepoPath, dir, file));
if (gm) return gm(abspath)
.resize(PRESET_IMAGE_WIDTH, PRESET_IMAGE_WIDTH)
.toBuffer((err, buffer) => {
res.write(buffer);
res.end();
});
res.write(fs.readFileSync(abspath));
return res.end();
}
if (/directory\/.*\/?page=.*/gi.test(req.url)) {
const [, , dir, query] = req.url.split('/');
const page = parseInt((query || 'page=1').split('=')[1], 10);
const files = fs.readdirSync(path.join(imageRepoPath, decodeURIComponent(dir)));
const total = parseInt((files.length / PAGE_SIZE), 10) + 1;
const filesStr = files
.slice((page - 1) * PAGE_SIZE, page * PAGE_SIZE)
.map((f) => `<img src="/directory/${dir}/file/${f}" style="max-width: 100vw;"/>`)
.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>${dir}</title>
</head>
<body style="margin: 0">
<article>
<nav style="width: 100%; background-color: yellow; padding: 8px 12px; display: flex;">
<a style="font-size: 20px" href="/">Home</a>
<a style="font-size: 20px; max-width: 50%; display: block; white-space: nowrap; text-overflow: ellipsis; overflow-x: hidden" href="/directory/${dir}/?page=1">&gt;${decodeURIComponent(dir)}</a>
<a style="font-size: 20px;">&gt;page: ${page}/${total}</a>
</nav>
${filesStr}
<div style="display: flex; justify-content: space-between; padding: 16px 24px;">
<a href="/directory/${dir}/?page=${(page - 1 || 1)}">< Previous</a>
<a href="/">Home</a>
<a href="/directory/${dir}/?page=${(page + 1) > total ? total : page + 1}">Next ></a>
</div>
</article>
</body>
</html>
`);
return res.end();
}
const dirs = fs.readdirSync(imageRepoPath);
const dirsStr = dirs.filter((d) => fs.statSync(path.join(imageRepoPath, d)).isDirectory())
.map((d) => `<a style="font-size: 16px; margin-bottom: 12px;" href="/directory/${d}/?page=1" style="font-size: 20px; color: rgba(2, 3, 44, 0.87); margin-bottom: 16px;">
${d}
</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>${imageRepoPath}</title>
</head>
<body style="margin: 0">
<article style="padding: 64px 40px; display: flex; flex-direction: column;">
<h2>${imageRepoPath}</h2>
${dirsStr}
</article>
</body>
</html>`);
return res.end();
});
}
function getImageReopPath() {
const repoPath = process.argv[2];
if (!repoPath) return __dirname;
return repoPath;
}
function main() {
const imageViewer = createServer(getImageReopPath());
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