Skip to content

Instantly share code, notes, and snippets.

@jaames
Last active January 25, 2021 03:06
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jaames/e82576f84c86838d6768825a95842c1a to your computer and use it in GitHub Desktop.
Save jaames/e82576f84c86838d6768825a95842c1a to your computer and use it in GitHub Desktop.
Node mini-server that extracts thumbnail images from Flipnote Studio PPM or KWZ animation files
// requires promise-fs, gm and flipnote.js and imagemagick
// npm i promise-fs gm flipnote.js
// https://imagemagick.org/index.php
const http = require('http');
const path = require('path');
const url = require('url');
const fs = require('promise-fs');
const flipnote = require('flipnote.js/dist/node');
const gm = require('gm').subClass({imageMagick: true});
// may wanna change this or make it configurable from cli args or something
const PORT = 4000;
const USER_CONTENT_PATH = './';
const server = http.createServer();
server.on('request', (req, res) => {
const parts = url.parse(req.url, true);
const query = parts.query;
const filename = query['filename'];
const format = query['format'];
if (!filename) {
res.statusCode = 500;
res.end('No filename specified');
return;
}
// may wanna do extra santitisation but this should prevent path traversal bs
const filepath = path.normalize(path.join(USER_CONTENT_PATH, filename));
if (!fs.existsSync(filepath)) {
res.statusCode = 500;
res.end('File not found');
return;
}
fs.readFile(filepath)
.then(file => flipnote.parseSource(file.buffer))
.then(note => {
const gif = flipnote.gifEncoder.fromFlipnoteFrame(note, note.thumbFrameIndex);
const gifBuffer = Buffer.from(gif.getBuffer());
res.statusCode = 200;
switch (format) {
case 'png':
res.setHeader('Content-Type', 'image/png');
gm(gifBuffer, 'image.gif')
.stream('png')
.pipe(res);
break;
// gif is fastest but discord is shit at displaying them :(
case 'gif':
default:
res.setHeader('Content-Type', 'image/gif');
res.end(gifBuffer);
break;
}
})
.catch(err => {
console.error(err);
res.statusCode = 500;
res.end('Could not generate thumbnail');
});
})
server.listen(PORT, () => {
console.log(`Server running at http://localhost:${ PORT }/`)
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment