Skip to content

Commit

Permalink
Checksum support for bin/generate
Browse files Browse the repository at this point in the history
  • Loading branch information
florentsolt committed Aug 23, 2017
1 parent 97fd1b1 commit 18a190d
Show file tree
Hide file tree
Showing 4 changed files with 186 additions and 126 deletions.
32 changes: 32 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Photos

Photos (yay, awesome name) is a node web application to show beautilful and neat photos gallery.
But not only, it has been super optimized to do it fast!
It scores 100/100 on Google PageSpeed Insights https://developers.google.com/speed/pagespeed/insights/.

# Demo

It's up and running here http://photos.solt.biz/potd.
Just check by yourself: https://developers.google.com/speed/pagespeed/insights/?url=http%3A%2F%2Fphotos.solt.biz%2Fpotd&tab=mobile.

# How to install

$> git clone https://github.com/florentsolt/photos.git

Then, create a folder in the "uploads" folder, for example "uploads/1stgallery".
Finally run:

$> ./bin/generate 1stgallery

If you are as lazy as me, you can also use the autcomplete of your shell and type "up" then <Tab> key, then type "1st" and <Tab>:

$> ./bin/generate uploads/1stgallery

You gallery is ready!

Edit the config file (copy the config-dist.js file).
And run the web app:

$> ./bin/www

Enjoy!
88 changes: 60 additions & 28 deletions bin/generate
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,27 @@ var config = require('../config'),
fs = require('fs'),
fsx = require('fs.extra'),
Log = require('console-log-level'),
hasha = require('hasha'),
which = require('which'),
log,
util = require('util'),
exif = require('fast-exif'),
execFile = util.promisify(require('child_process').execFile),
leftPad = require('left-pad'),
sizeOf = util.promisify(require('image-size'));

['vipsthumbnail', 'jpegtran', 'zip', 'montage'].forEach(binary => {
if (!which.sync(binary, {nothrow: true})) {
program.help(() => "The mandorty binary \"" + binary + "\" is not present or not in the $PATH.\n");
}
});

Promise.promisifyAll(fs);

program
.option('-d, --debug', 'output debug information')
.option('-t, --title [text]', 'specify a title')
.option('-e, --description [text]', 'specify a description')
.option('-e, --desc [text]', 'specify a description')
.option('-f, --font [name]', 'specify google font name (https://fonts.google.com)')
.option('-r, --reverse', 'reverse order')
.arguments('<album>')
Expand All @@ -31,8 +39,6 @@ if (!program.album) {
program.help(txt => "You must specify an album name.\n" + txt);
}

// FIXME: check for all programs in the path

if (program.debug) {
log = Log({
level: 'debug',
Expand All @@ -45,7 +51,7 @@ if (program.debug) {
}

log.debug('title is', program.title);
log.debug('description is', program.description);
log.debug('description is', program.desc);
log.debug('font is', program.font);
log.debug('reverse is', program.reverse);

Expand All @@ -66,8 +72,7 @@ if (!fs.existsSync(folders.album)) fs.mkdirSync(folders.album);

['originals', 'previews', 'thumbs'].forEach(folder => {
folders[folder] = path.join(folders.album, folder);
if (fs.existsSync(folders[folder])) fsx.rmrfSync(folders[folder]);
fsx.mkdirpSync(folders[folder]);
if (!fs.existsSync(folders[folder])) fsx.mkdirpSync(folders[folder]);
});

/*
Expand All @@ -88,6 +93,7 @@ if (!fs.existsSync(folders.album)) fs.mkdirSync(folders.album);
* {
* id: 0,
* idStr: "00000",
* hash: "",
* filename: "",
* preview: {width: 0, height: 0},
* thumb: {width: 0, height: 0},
Expand All @@ -96,36 +102,62 @@ if (!fs.existsSync(folders.album)) fs.mkdirSync(folders.album);
* }
*/

var album = {
reverse: program.reverse || false,
dates: {},
pictures: []
};
var album;

if (fs.existsSync(path.join(folders.album, 'album.json'))) {
album = JSON.parse(fs.readFileSync(path.join(folders.album, 'album.json')));
} else {
album = {
reverse: false,
dates: {},
pictures: []
};
}

if (program.reverse) album.reverse = true;
if (program.title) album.title = program.title;
if (program.description) album.description = program.description;
if (program.desc) album.description = program.desc;
if (program.font) album.font = program.font;

/*
* Find all picture files and link them into ./originals/
*/
var i = 1;
fs.readdirAsync(folders.upload).each(filename => {
fs.readdirAsync(folders.upload).map(filename => {
return hasha.fromFile(path.join(folders.upload, filename), {algorithm: 'md5'})
.then(hash => [filename, hash])
.catch(() => [filename, false]);
})
// FIXME remove extra items from .pictures regarding nb of items in this array ^^
// Also remove unused files (previews & thumbs & originals)
.each(filenameAndHash => {
var filename = filenameAndHash[0];
var hash = filenameAndHash[1];

if (path.extname(filename) === '.jpg') {
log.debug('found', filename);
var idStr = leftPad(i, 5, 0);
var target = program.album.replace(/[ _\+\(\)]/g, '-').replace(/-+/, '-') + '-' + idStr + '.jpg';
album.pictures.push({filename: target, id: i, idStr: idStr});
log.info('symlink', filename, 'to', target);
fs.symlinkSync(path.join(folders.upload, filename), path.join(folders.originals, target));
log.debug('found', filename, hash);
if (album.pictures[i - 1] && hash !== false && album.pictures[i - 1].hash === hash) {
log.debug('skip (same hash)', filename, hash);
album.pictures[i - 1].skip = true;
} else {
var idStr = leftPad(i, 5, 0);
var target = program.album.replace(/[ _\+\(\)]/g, '-').replace(/-+/, '-') + '-' + idStr + '.jpg';
album.pictures[i - 1] = {filename: target, id: i, idStr: idStr, hash: hash};
log.info('symlink', filename, 'to', target);
if (fs.existsSync(path.join(folders.originals, target))) fs.unlinkSync(path.join(folders.originals, target));
fs.symlinkSync(path.join(folders.upload, filename), path.join(folders.originals, target));
}
i++;
} else {
log.debug('skip', filename);
log.debug('skip (not a jpg)', filename);
return false;
}
})
.then(() => album.pictures)
.then(() => album.pictures.filter(picture => picture.skip !== true))
.each((picture) => {
/*
* Extract dates from EXIF metadata
*/
return exif.read(path.join(folders.originals, picture.filename)).then(data => {
var date;
if (data && data.exif) {
Expand All @@ -140,8 +172,8 @@ fs.readdirAsync(folders.upload).each(filename => {
}
});
})
.then(() => album.pictures)
.each((picture, index) => {
.then(() => album.pictures.filter(picture => picture.skip !== true))
.each(picture => {
/*
* Resize all originals a save them into ./previews/
*/
Expand All @@ -157,11 +189,11 @@ fs.readdirAsync(folders.upload).each(filename => {
.then(() => sizeOf(output))
.then(dimensions => {
delete(dimensions.type);
album.pictures[index].preview = dimensions;
picture.preview = dimensions;
});
})
.then(() => album.pictures)
.each((picture, index) => {
.then(() => album.pictures.filter(picture => picture.skip !== true))
.each(picture => {
/*
* Resize all originals a save them into ./thumbs/
*/
Expand All @@ -177,8 +209,8 @@ fs.readdirAsync(folders.upload).each(filename => {
.then(() => sizeOf(output))
.then(dimensions => {
delete(dimensions.type);
album.pictures[index].thumb = dimensions;
album.pictures[index].flex = {
picture.thumb = dimensions;
picture.flex = {
width: Math.floor(dimensions.width * 200 / dimensions.height),
padding: dimensions.height / dimensions.width * 100
};
Expand Down
Loading

0 comments on commit 18a190d

Please sign in to comment.