Use <standard> for code style, which removed lots of unused variables/requires

pull/64/merge
Romain 7 years ago
parent e71e5d4207
commit 59b9bdbbd2

@ -5,6 +5,7 @@
[![Travis CI](https://travis-ci.org/thumbsup/node-thumbsup.svg?branch=master)](https://travis-ci.org/thumbsup/node-thumbsup)
[![Dependencies](http://img.shields.io/david/thumbsup/node-thumbsup.svg?style=flat)](https://david-dm.org/thumbsup/node-thumbsup)
[![Dev dependencies](https://david-dm.org/thumbsup/node-thumbsup/dev-status.svg?style=flat)](https://david-dm.org/thumbsup/node-thumbsup?type=dev)
[![Standard - JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](http://standardjs.com/)
![banner](banner.jpg)

@ -1,10 +1,10 @@
#!/usr/bin/env node
var yargs = require('yargs');
var path = require('path');
var index = require('../src/index');
var yargs = require('yargs')
var path = require('path')
var index = require('../src/index')
console.log('');
console.log('')
var opts = yargs
.usage('Usages:\n' +
' thumbsup [required] [options]\n' +
@ -126,31 +126,30 @@ var opts = yargs
.epilogue('The optional JSON config should contain a single object with one key ' +
'per argument, not including the leading "--". For example:\n\n' +
'{ "sort-albums-by": "start-date" }')
.argv;
.argv
// Compatibility
if (opts['sort-folders'] == 'name') opts['sort-albums-by'] = 'title';
if (opts['sort-folders'] == 'date') opts['sort-albums-by'] = 'start-date';
if (opts['sort-folders'] === 'name') opts['sort-albums-by'] = 'title'
if (opts['sort-folders'] === 'date') opts['sort-albums-by'] = 'start-date'
index.build({
input: path.resolve(opts['input']),
output: path.resolve(opts['output']),
title: opts['title'],
thumbSize: opts['thumb-size'],
largeSize: opts['large-size'],
originalPhotos: opts['original-photos'],
originalVideos: opts['original-videos'],
albumsFrom: opts['albums-from'],
albumsDateFormat: opts['albums-date-format'],
sortAlbumsBy: opts['sort-albums-by'],
input: path.resolve(opts['input']),
output: path.resolve(opts['output']),
title: opts['title'],
thumbSize: opts['thumb-size'],
largeSize: opts['large-size'],
originalPhotos: opts['original-photos'],
originalVideos: opts['original-videos'],
albumsFrom: opts['albums-from'],
albumsDateFormat: opts['albums-date-format'],
sortAlbumsBy: opts['sort-albums-by'],
sortAlbumsDirection: opts['sort-albums-direction'],
sortMediaBy: opts['sort-media-by'],
sortMediaBy: opts['sort-media-by'],
sortMediaDirection: opts['sort-media-direction'],
theme: opts['theme'],
css: opts['css'],
googleAnalytics: opts['google-analytics'],
index: opts['index'],
footer: opts['footer'],
theme: opts['theme'],
css: opts['css'],
googleAnalytics: opts['google-analytics'],
index: opts['index'],
footer: opts['footer'],
albumsOutputFolder: opts['albums-output-folder']
});
})

@ -44,6 +44,19 @@
"markdown-toc": "^0.13.0",
"mocha": "^3.1.2",
"require-lint": "^1.1.2",
"should": "^11.1.1"
"should": "^11.1.1",
"standard": "^9.0.0"
},
"standard": {
"ignore": [
"public/**"
],
"globals": [
"afterEach",
"beforeEach",
"describe",
"it",
"xit"
]
}
}

@ -9,6 +9,9 @@ PATH=$(pwd)/node_modules/.bin:$PATH
echo "--- Check all dependencies in package.json"
require-lint --src bin/thumbsup.js --ignore-extra lightgallery
echo "--- Static code analysis"
standard
echo "--- Verify lightgallery dependency is built in"
grep \"lightgallery\" package.json 1>/dev/null

@ -1,6 +1,5 @@
const async = require('async')
const fs = require('fs-extra')
const pad = require('pad')
const path = require('path')
const database = require('./input/database')
const progress = require('./utils/progress')
@ -11,12 +10,10 @@ const resize = require('./output-media/resize')
const website = require('./output-website/website')
exports.build = function (opts) {
resize.sizes.thumb = opts.thumbSize
resize.sizes.large = opts.largeSize
fs.mkdirpSync(opts.output)
const media = path.join(opts.output, 'media')
const databaseFile = path.join(opts.output, 'metadata.json')
var album = null // root album with nested albums
@ -62,7 +59,6 @@ exports.build = function (opts) {
}
], finish)
}
function asyncProgress (bar) {

@ -1,10 +1,8 @@
const debug = require('debug')('thumbsup')
const exifdb = require('exiftool-json-db')
const pad = require('pad')
const progress = require('../utils/progress')
exports.update = function(media, databasePath, callback) {
exports.update = function (media, databasePath, callback) {
var updateBar = null
var emitter = null
@ -32,5 +30,4 @@ exports.update = function(media, databasePath, callback) {
})
emitter.on('error', callback)
}

@ -1,11 +1,12 @@
const debug = require('debug')('thumbsup')
exports.paths = function (filepath, mediaType, config) {
var originals = false
if (mediaType === 'image') {
var originals = config ? config.originalPhotos : false
originals = config ? config.originalPhotos : false
return imageOutput(filepath, originals)
} else if (mediaType === 'video') {
var originals = config ? config.originalVideos : false
originals = config ? config.originalVideos : false
return videoOutput(filepath, originals)
} else {
debug(`Unsupported file type: ${mediaType}`)
@ -58,9 +59,9 @@ function videoOutput (filepath, originals) {
} else {
output.download = output.video
}
return output;
return output
}
function ext(file, ext) {
function ext (file, ext) {
return file.replace(/\.[a-z0-9]+$/i, '.' + ext)
}

@ -1,141 +1,141 @@
var _ = require('lodash');
var path = require('path');
var url = require('url');
var index = 0;
var _ = require('lodash')
var path = require('path')
var url = require('url')
var index = 0
// number of images to show in the album preview grid
var PREVIEW_COUNT = 10;
var PREVIEW_COUNT = 10
var SORT_ALBUMS_BY = {
'title': function(album) { return album.title; },
'start-date': function(album) { return album.stats.fromDate; },
'end-date': function(album) { return album.stats.toDate; }
};
'title': function (album) { return album.title },
'start-date': function (album) { return album.stats.fromDate },
'end-date': function (album) { return album.stats.toDate }
}
var SORT_MEDIA_BY = {
'filename': function(file) { return file.filename; },
'date': function(file) { return file.date; }
};
'filename': function (file) { return file.filename },
'date': function (file) { return file.date }
}
var PREVIEW_MISSING = {
urls: {
thumbnail: 'public/missing.png'
}
};
}
function Album(opts) {
if (typeof opts === 'string') opts = { title: opts };
this.id = opts.id || ++index;
this.title = opts.title || ('Album ' + this.id);
this.basename = sanitise(this.title);
this.files = opts.files || [];
this.albums = opts.albums || [];
this.depth = 0;
this.home = false;
this.stats = null;
this.previews = null;
this.allFiles = [];
function Album (opts) {
if (typeof opts === 'string') opts = { title: opts }
this.id = opts.id || ++index
this.title = opts.title || ('Album ' + this.id)
this.basename = sanitise(this.title)
this.files = opts.files || []
this.albums = opts.albums || []
this.depth = 0
this.home = false
this.stats = null
this.previews = null
this.allFiles = []
}
Album.prototype.finalize = function(options, parent) {
options = options || {};
var albumsOutputFolder = options.albumsOutputFolder || '.';
Album.prototype.finalize = function (options, parent) {
options = options || {}
var albumsOutputFolder = options.albumsOutputFolder || '.'
// calculate final file paths and URLs
if (parent == null) {
this.path = options.index;
this.url = options.index;
this.depth = 0;
this.path = options.index
this.url = options.index
this.depth = 0
} else {
if (parent.depth > 0) {
this.basename = parent.basename + '-' + this.basename;
this.basename = parent.basename + '-' + this.basename
}
this.path = path.join(albumsOutputFolder, this.basename + '.html');
this.url = url.resolve(albumsOutputFolder + '/', this.basename + '.html');
this.depth = parent.depth + 1;
this.path = path.join(albumsOutputFolder, this.basename + '.html')
this.url = url.resolve(albumsOutputFolder + '/', this.basename + '.html')
this.depth = parent.depth + 1
}
// then finalize all nested albums (which uses the parent basename)
for (var i = 0; i < this.albums.length; ++i) {
this.albums[i].finalize(options, this);
this.albums[i].finalize(options, this)
}
// perform stats & other calculations
// once the nested albums have been finalized too
this.home = this.depth === 0;
this.calculateStats();
this.calculateSummary();
this.sort(options);
this.pickPreviews();
this.aggregateAllFiles();
};
this.home = this.depth === 0
this.calculateStats()
this.calculateSummary()
this.sort(options)
this.pickPreviews()
this.aggregateAllFiles()
}
Album.prototype.calculateStats = function() {
Album.prototype.calculateStats = function () {
// nested albums
var nestedPhotos = _.map(this.albums, 'stats.photos');
var nestedVideos = _.map(this.albums, 'stats.videos');
var nestedFromDates = _.map(this.albums, 'stats.fromDate');
var nestedToDates = _.map(this.albums, 'stats.toDate');
var nestedPhotos = _.map(this.albums, 'stats.photos')
var nestedVideos = _.map(this.albums, 'stats.videos')
var nestedFromDates = _.map(this.albums, 'stats.fromDate')
var nestedToDates = _.map(this.albums, 'stats.toDate')
// current level
var currentPhotos = _.filter(this.files, {isVideo: false}).length;
var currentVideos = _.filter(this.files, {isVideo: true}).length;
var currentFromDate = _.map(this.files, 'date');
var currentToDate = _.map(this.files, 'date');
var currentPhotos = _.filter(this.files, {isVideo: false}).length
var currentVideos = _.filter(this.files, {isVideo: true}).length
var currentFromDate = _.map(this.files, 'date')
var currentToDate = _.map(this.files, 'date')
// aggregate all stats
this.stats = {
albums: this.albums.length,
photos: _.sum(_.compact(_.concat(nestedPhotos, currentPhotos))) || 0,
videos: _.sum(_.compact(_.concat(nestedVideos, currentVideos))) || 0,
albums: this.albums.length,
photos: _.sum(_.compact(_.concat(nestedPhotos, currentPhotos))) || 0,
videos: _.sum(_.compact(_.concat(nestedVideos, currentVideos))) || 0,
fromDate: _.min(_.compact(_.concat(nestedFromDates, currentFromDate))),
toDate: _.max(_.compact(_.concat(nestedToDates, currentToDate)))
};
this.stats.total = this.stats.photos + this.stats.videos;
toDate: _.max(_.compact(_.concat(nestedToDates, currentToDate)))
}
this.stats.total = this.stats.photos + this.stats.videos
}
Album.prototype.calculateSummary = function() {
Album.prototype.calculateSummary = function () {
var items = [
itemCount(this.stats.albums, 'album'),
itemCount(this.stats.photos, 'photo'),
itemCount(this.stats.videos, 'video')
];
this.summary = _.compact(items).join(', ');
};
]
this.summary = _.compact(items).join(', ')
}
Album.prototype.sort = function(options) {
this.files = _.orderBy(this.files, SORT_MEDIA_BY[options.sortMediaBy], options.sortMediaDirection);
this.albums = _.orderBy(this.albums, SORT_ALBUMS_BY[options.sortAlbumsBy], options.sortAlbumsDirection);
};
Album.prototype.sort = function (options) {
this.files = _.orderBy(this.files, SORT_MEDIA_BY[options.sortMediaBy], options.sortMediaDirection)
this.albums = _.orderBy(this.albums, SORT_ALBUMS_BY[options.sortAlbumsBy], options.sortAlbumsDirection)
}
Album.prototype.pickPreviews = function() {
Album.prototype.pickPreviews = function () {
// also consider previews from nested albums
var nestedPicks = _.flatten(_.map(this.albums, 'previews')).filter(function(file) {
return file !== PREVIEW_MISSING;
});
var nestedPicks = _.flatten(_.map(this.albums, 'previews')).filter(function (file) {
return file !== PREVIEW_MISSING
})
// then pick the top ones
var potentialPicks = _.concat(this.files, nestedPicks);
this.previews = potentialPicks.slice(0, PREVIEW_COUNT);
var potentialPicks = _.concat(this.files, nestedPicks)
this.previews = potentialPicks.slice(0, PREVIEW_COUNT)
// and fill the gap with a placeholder
var missing = PREVIEW_COUNT - this.previews.length;
var missing = PREVIEW_COUNT - this.previews.length
for (var i = 0; i < missing; ++i) {
this.previews.push(PREVIEW_MISSING);
this.previews.push(PREVIEW_MISSING)
}
};
}
Album.prototype.aggregateAllFiles = function() {
Album.prototype.aggregateAllFiles = function () {
var nestedFiles = _.flatten(_.map(this.albums, 'allFiles'))
this.allFiles = _.concat(nestedFiles, this.files);
};
this.allFiles = _.concat(nestedFiles, this.files)
}
function sanitise(filename) {
return filename.replace(/[^a-z0-9-_]/ig, '');
function sanitise (filename) {
return filename.replace(/[^a-z0-9-_]/ig, '')
}
function itemCount(count, type) {
if (count === 0) return '';
var plural = (count > 1) ? 's' : '';
return '' + count + ' ' + type + plural;
function itemCount (count, type) {
if (count === 0) return ''
var plural = (count > 1) ? 's' : ''
return '' + count + ' ' + type + plural
}
// for testing purposes
Album.resetIds = function() {
index = 0;
};
Album.resetIds = function () {
index = 0
}
module.exports = Album;
module.exports = Album

@ -1,42 +1,42 @@
var _ = require('lodash');
var path = require('path');
var moment = require('moment');
var Album = require('./album');
var _ = require('lodash')
var path = require('path')
var moment = require('moment')
var Album = require('./album')
// creates nested albums based on the media date, e.g. "{year}/{month}"
// opts = {format}, where format is a valid <moment> format
// e.g. "YYYY-MM" or "YYYY/MMMM" for nested albums
exports.albums = function(collection, opts) {
exports.albums = function (collection, opts) {
opts = _.defaults(opts, {
grouping: opts.albumsDateFormat || 'YYYY-MMMM'
});
var groups = {};
})
var groups = {}
// put all files in the right albums
collection.forEach(function(media) {
var groupName = moment(media.date).format(opts.grouping);
createAlbumHierarchy(groups, groupName);
groups[groupName].files.push(media);
});
collection.forEach(function (media) {
var groupName = moment(media.date).format(opts.grouping)
createAlbumHierarchy(groups, groupName)
groups[groupName].files.push(media)
})
// only return top-level albums
var topLevel = _.keys(groups).filter(function(dir) {
return path.dirname(dir) === '.';
});
return _.values(_.pick(groups, topLevel));
};
var topLevel = _.keys(groups).filter(function (dir) {
return path.dirname(dir) === '.'
})
return _.values(_.pick(groups, topLevel))
}
function createAlbumHierarchy(albumsByFullDate, dateSegment) {
function createAlbumHierarchy (albumsByFullDate, dateSegment) {
if (!albumsByFullDate.hasOwnProperty(dateSegment)) {
// create parent albums first
var parentDate = path.dirname(dateSegment);
var parentDate = path.dirname(dateSegment)
if (parentDate !== '.') {
createAlbumHierarchy(albumsByFullDate, parentDate);
createAlbumHierarchy(albumsByFullDate, parentDate)
}
// then create album if it doesn't exist
var lastDateSegment = path.basename(dateSegment);
albumsByFullDate[dateSegment] = new Album({title: lastDateSegment});
var lastDateSegment = path.basename(dateSegment)
albumsByFullDate[dateSegment] = new Album({title: lastDateSegment})
// then attach to parent
if (parentDate !== '.') {
albumsByFullDate[parentDate].albums.push(albumsByFullDate[dateSegment]);
albumsByFullDate[parentDate].albums.push(albumsByFullDate[dateSegment])
}
}
}

@ -1,38 +1,38 @@
var _ = require('lodash');
var path = require('path');
var Album = require('./album');
var _ = require('lodash')
var path = require('path')
var Album = require('./album')
// for now only 1 level of folders,
// e.g. an album might be called "holidays/newyork" or "holidays/tokyo"n
// eventually we could return nested albums as an option
exports.albums = function(collection, opts) {
var albumsByFullPath = {};
exports.albums = function (collection, opts) {
var albumsByFullPath = {}
// put all files in the right album
collection.forEach(function(media) {
var fullDir = path.dirname(media.file.path);
createAlbumHierarchy(albumsByFullPath, fullDir);
albumsByFullPath[fullDir].files.push(media);
});
collection.forEach(function (media) {
var fullDir = path.dirname(media.file.path)
createAlbumHierarchy(albumsByFullPath, fullDir)
albumsByFullPath[fullDir].files.push(media)
})
// only return top-level albums
var topLevel = _.keys(albumsByFullPath).filter(function(dir) {
return path.dirname(dir) === '.';
});
return _.values(_.pick(albumsByFullPath, topLevel));
};
var topLevel = _.keys(albumsByFullPath).filter(function (dir) {
return path.dirname(dir) === '.'
})
return _.values(_.pick(albumsByFullPath, topLevel))
}
function createAlbumHierarchy(albumsByFullPath, fullDir) {
function createAlbumHierarchy (albumsByFullPath, fullDir) {
if (!albumsByFullPath.hasOwnProperty(fullDir)) {
// create parent albums first
var parentDir = path.dirname(fullDir);
var parentDir = path.dirname(fullDir)
if (parentDir !== '.') {
createAlbumHierarchy(albumsByFullPath, parentDir);
createAlbumHierarchy(albumsByFullPath, parentDir)
}
// then create album if it doesn't exist
var dirname = path.basename(fullDir);
albumsByFullPath[fullDir] = new Album({title: dirname});
var dirname = path.basename(fullDir)
albumsByFullPath[fullDir] = new Album({title: dirname})
// then attach to parent
if (parentDir !== '.') {
albumsByFullPath[parentDir].albums.push(albumsByFullPath[fullDir]);
albumsByFullPath[parentDir].albums.push(albumsByFullPath[fullDir])
}
}
}

@ -1,14 +1,8 @@
var _ = require('lodash')
var gm = require('gm')
var pad = require('pad')
var path = require('path')
var Album = require('./album')
var Media = require('./media')
var byFolder = require('./by-folder')
var byDate = require('./by-date')
exports.createAlbums = function (collection, opts) {
// top-level album for the home page
var home = new Album('Home')
home.filename = opts.index || 'index'
@ -19,7 +13,7 @@ exports.createAlbums = function (collection, opts) {
} else if (opts.albumsFrom === 'date') {
home.albums = byDate.albums(collection, opts)
} else {
throw 'Invalid <albumsFrom> option'
throw new Error('Invalid <albumsFrom> option')
}
// finalize all albums recursively (calculate stats, etc...)

@ -3,7 +3,7 @@ const moment = require('moment')
const path = require('path')
const EXIF_DATE_FORMAT = 'YYYY:MM:DD HH:mm:ssZ'
var index = 0;
var index = 0
/*
View model for album entries

@ -6,7 +6,7 @@ const path = require('path')
exports.sizes = {
thumb: 120,
large: 1000,
large: 1000
}
exports.copy = function (task, callback) {
@ -36,7 +36,7 @@ exports.photoLarge = function (task, callback) {
// Web-streaming friendly video
exports.videoWeb = function (task, callback) {
var ffmpeg = 'ffmpeg -i "' + task.src + '" -y "'+ task.dest +'" -f mp4 -vcodec libx264 -ab 96k'
var ffmpeg = 'ffmpeg -i "' + task.src + '" -y "' + task.dest + '" -f mp4 -vcodec libx264 -ab 96k'
// AVCHD/MTS videos need a full-frame export to avoid interlacing artefacts
if (path.extname(task.src).toLowerCase() === '.mts') {
ffmpeg += ' -vf yadif=1 -qscale:v 4'
@ -49,10 +49,10 @@ exports.videoWeb = function (task, callback) {
// Large video preview (before you click play)
exports.videoLarge = function (task, callback) {
async.series([
function(next) {
function (next) {
extractFrame(task, next)
},
function(next) {
function (next) {
exports.photoLarge({
src: task.dest,
dest: task.dest
@ -64,10 +64,10 @@ exports.videoLarge = function (task, callback) {
// Small square video preview
exports.videoSquare = function (task, callback) {
async.series([
function(next) {
function (next) {
extractFrame(task, next)
},
function(next) {
function (next) {
exports.photoSquare({
src: task.dest,
dest: task.dest

@ -1,64 +1,62 @@
var fs = require('fs');
var path = require('path');
var handlebars = require('handlebars');
var moment = require('moment');
var fs = require('fs')
var path = require('path')
var handlebars = require('handlebars')
var moment = require('moment')
exports.create = function(options) {
exports.create = function (options) {
var DIR_TEMPLATES = path.join(__dirname, '..', '..', 'templates')
var DIR_THEME = path.join(DIR_TEMPLATES, 'themes', options.theme)
var DIR_TEMPLATES = path.join(__dirname, '..', '..', 'templates');
var DIR_THEME = path.join(DIR_TEMPLATES, 'themes', options.theme);
function isTemplate(filepath) {
return path.extname(filepath) === '.hbs';
function isTemplate (filepath) {
return path.extname(filepath) === '.hbs'
}
function compileTemplate(hbsFile) {
var src = fs.readFileSync(hbsFile);
return handlebars.compile(src.toString());
function compileTemplate (hbsFile) {
var src = fs.readFileSync(hbsFile)
return handlebars.compile(src.toString())
}
// main entry points
var templates = {
'album': compileTemplate(path.join(DIR_TEMPLATES, 'album.hbs'))
};
}
// common partials
handlebars.registerPartial('analytics', compileTemplate(path.join(DIR_TEMPLATES, 'analytics.hbs')));
handlebars.registerPartial('analytics', compileTemplate(path.join(DIR_TEMPLATES, 'analytics.hbs')))
// theme partials
var files = fs.readdirSync(DIR_THEME);
files.filter(isTemplate).forEach(function(filename) {
var templateName = path.basename(filename, path.extname(filename));
handlebars.registerPartial(templateName, compileTemplate(path.join(DIR_THEME, filename)));
var files = fs.readdirSync(DIR_THEME)
files.filter(isTemplate).forEach(function (filename) {
var templateName = path.basename(filename, path.extname(filename))
handlebars.registerPartial(templateName, compileTemplate(path.join(DIR_THEME, filename)))
})
// utility helper
// render a date in a legible format
handlebars.registerHelper('date', function(date) {
return moment(date).format('DD MMM YYYY');
});
handlebars.registerHelper('date', function (date) {
return moment(date).format('DD MMM YYYY')
})
// utility helper
// render the first X items in an array
handlebars.registerHelper('slice', function(context, block) {
var ret = "";
var count = parseInt(block.hash.count) || 1;
var i = 0;
var j = (count < context.length) ? count : context.length;
for(i,j; i<j; i++) {
ret += block.fn(context[i]);
handlebars.registerHelper('slice', function (context, block) {
var ret = ''
var count = parseInt(block.hash.count) || 1
var i = 0
var j = (count < context.length) ? count : context.length
for (i, j; i < j; i++) {
ret += block.fn(context[i])
}
return ret;
});
return ret
})
// utility helper
// execute the child block N times
handlebars.registerHelper('times', function(n, block) {
var accum = '';
for(var i = 0; i < n; ++i)
accum += block.fn(i);
return accum;
});
handlebars.registerHelper('times', function (n, block) {
var accum = ''
for (var i = 0; i < n; ++i) { accum += block.fn(i) }
return accum
})
// utility helper
// execute a block if a condition matches
@ -66,48 +64,47 @@ exports.create = function(options) {
// however this lets theme authors be more creative without changing the core model
// THANKS TO http://doginthehat.com.au/2012/02/comparison-block-helper-for-handlebars-templates/#comment-44
handlebars.registerHelper('compare', function (lvalue, operator, rvalue, options) {
var operators, result;
if (arguments.length < 3) {
throw new Error("Handlerbars Helper 'compare' needs 2 parameters");
}
if (options === undefined) {
options = rvalue;
rvalue = operator;
operator = "===";
}
operators = {
'==': function (l, r) { return l == r; },
'===': function (l, r) { return l === r; },
'!=': function (l, r) { return l != r; },
'!==': function (l, r) { return l !== r; },
'<': function (l, r) { return l < r; },
'>': function (l, r) { return l > r; },
'<=': function (l, r) { return l <= r; },
'>=': function (l, r) { return l >= r; }
};
if (!operators[operator]) {
throw new Error("Handlerbars Helper 'compare' doesn't know the operator " + operator);
}
result = operators[operator](lvalue, rvalue);
if (result) {
return options.fn(this);
} else {
return options.inverse(this);
}
});
var operators, result
if (arguments.length < 3) {
throw new Error("Handlerbars Helper 'compare' needs 2 parameters")
}
if (options === undefined) {
options = rvalue
rvalue = operator
operator = '==='
}
operators = {
'==': function (l, r) { return l == r }, // eslint-disable-line eqeqeq
'===': function (l, r) { return l === r },
'!=': function (l, r) { return l != r }, // eslint-disable-line eqeqeq
'!==': function (l, r) { return l !== r },
'<': function (l, r) { return l < r },
'>': function (l, r) { return l > r },
'<=': function (l, r) { return l <= r },
'>=': function (l, r) { return l >= r }
}
if (!operators[operator]) {
throw new Error(`Handlerbars Helper 'compare' doesn't know the operator ${operator}`)
}
result = operators[operator](lvalue, rvalue)
if (result) {
return options.fn(this)
} else {
return options.inverse(this)
}
})
// utility helper
// return the relative path from the current folder to the argument
var currentFolder = '.';
handlebars.registerHelper('relative', function(target, options) {
return path.relative(currentFolder, target);
});
var currentFolder = '.'
handlebars.registerHelper('relative', function (target, options) {
return path.relative(currentFolder, target)
})
return {
render: function(template, data, folder) {
currentFolder = folder;
return templates[template](data);
render: function (template, data, folder) {
currentFolder = folder
return templates[template](data)
}
};
};
}
}

@ -1,23 +1,17 @@
var _ = require('lodash');
var fs = require('fs-extra');
var path = require('path');
var async = require('async');
var pad = require('pad');
var less = require('less');
var Album = require('../model/album');
var byFolder = require('../model//by-folder');
var byDate = require('../model//by-date');
var template = require('./template');
var fs = require('fs-extra')
var path = require('path')
var async = require('async')
var less = require('less')
var template = require('./template')
var DIR_PUBLIC = path.join(__dirname, '..', '..', 'public');
var DIR_TEMPLATES = path.join(__dirname, '..', '..', 'templates');
exports.build = function(rootAlbum, opts, callback) {
var DIR_PUBLIC = path.join(__dirname, '..', '..', 'public')
var DIR_TEMPLATES = path.join(__dirname, '..', '..', 'templates')
exports.build = function (rootAlbum, opts, callback) {
// create the right renderer (theme, download path, etc...)
var renderer = template.create(opts);
var renderer = template.create(opts)
function website(callback) {
function website (callback) {
// create top level gallery
var gallery = {
home: rootAlbum,
@ -28,71 +22,71 @@ exports.build = function(rootAlbum, opts, callback) {
thumbSize: opts.thumbSize,
largeSize: opts.largeSize,
googleAnalytics: opts.googleAnalytics
};
}
// render entire album hierarchy
var tasks = renderAlbum(gallery, [], rootAlbum);
async.parallel(tasks, callback);
var tasks = renderAlbum(gallery, [], rootAlbum)
async.parallel(tasks, callback)
}
function renderAlbum(gallery, breadcrumbs, album) {
function renderAlbum (gallery, breadcrumbs, album) {
// render this album
var thisAlbumTask = renderTemplate(album.path, 'album', {
gallery: gallery,
breadcrumbs: breadcrumbs,
album: album
});
var tasks = [thisAlbumTask];
})
var tasks = [thisAlbumTask]
// and all nested albums
album.albums.forEach(function(nested) {
var nestedAlbumsTasks = renderAlbum(gallery, breadcrumbs.concat([album]), nested);
Array.prototype.push.apply(tasks, nestedAlbumsTasks);
});
return tasks;
album.albums.forEach(function (nested) {
var nestedAlbumsTasks = renderAlbum(gallery, breadcrumbs.concat([album]), nested)
Array.prototype.push.apply(tasks, nestedAlbumsTasks)
})
return tasks
}
function renderTemplate(targetPath, templateName, data) {
function renderTemplate (targetPath, templateName, data) {
// render a given HBS template
var fullPath = path.join(opts.output, targetPath);
var targetFolder = path.dirname(targetPath);
var contents = renderer.render(templateName, data, targetFolder);
return function(next) {
var fullPath = path.join(opts.output, targetPath)
var targetFolder = path.dirname(targetPath)
var contents = renderer.render(templateName, data, targetFolder)
return function (next) {
fs.mkdirpSync(path.dirname(fullPath))
fs.writeFile(fullPath, contents, next);
};
fs.writeFile(fullPath, contents, next)
}
}
function support(callback) {
function support (callback) {
// copy all external JS/CSS
var dest = path.join(opts.output, 'public');
fs.copy(DIR_PUBLIC, dest, callback);
var dest = path.join(opts.output, 'public')
fs.copy(DIR_PUBLIC, dest, callback)
}
function lightGallery(callback) {
function lightGallery (callback) {
// note: this module might be deduped
// so we can't assume it's in the local node_modules
var lgPackage = require.resolve('lightgallery/package.json');
var src = path.join(path.dirname(lgPackage), 'dist');
var dest = path.join(opts.output, 'public', 'light-gallery');
fs.copy(src, dest, callback);
var lgPackage = require.resolve('lightgallery/package.json')
var src = path.join(path.dirname(lgPackage), 'dist')
var dest = path.join(opts.output, 'public', 'light-gallery')
fs.copy(src, dest, callback)
}
function videoJS (callback) {
// copy VideoJS fonts that need to be one level above in a folder called "f"
var dest = path.join(opts.output, 'f');
fs.copy(path.join(DIR_PUBLIC, 'f'), dest, callback);
var dest = path.join(opts.output, 'f')
fs.copy(path.join(DIR_PUBLIC, 'f'), dest, callback)
}
function renderStyles(callback) {
var themeFile = path.join(DIR_TEMPLATES, 'themes', opts.theme, 'theme.less');
var themeLess = fs.readFileSync(themeFile, 'utf-8');
function renderStyles (callback) {
var themeFile = path.join(DIR_TEMPLATES, 'themes', opts.theme, 'theme.less')
var themeLess = fs.readFileSync(themeFile, 'utf-8')
if (opts.css) {
themeLess += '\n' + fs.readFileSync(opts.css, 'utf-8');
themeLess += '\n' + fs.readFileSync(opts.css, 'utf-8')
}
less.render(themeLess, function (err, output) {
if (err) return callback(err);
var dest = path.join(opts.output, 'public', 'style.css');
fs.writeFile(dest, output.css, callback);
});
if (err) return callback(err)
var dest = path.join(opts.output, 'public', 'style.css')
fs.writeFile(dest, output.css, callback)
})
}
async.series([
@ -101,8 +95,7 @@ exports.build = function(rootAlbum, opts, callback) {
lightGallery,
videoJS,
renderStyles
], function(err) {
callback(err);
});
};
], function (err) {
callback(err)
})
}

@ -2,17 +2,18 @@ const pad = require('pad')
const ProgressBar = require('progress')
const util = require('util')
exports.create = function(message, count) {
exports.create = function (message, count) {
var format = ''
if (typeof count === 'undefined') {
var format = pad(message, 20) + '[:bar] :eta'
format = pad(message, 20) + '[:bar] :eta'
return new BetterProgressBar(format, 1)
}
if (Array.isArray(count)) count = count.length
if (count > 0) {
var format = pad(message, 20) + '[:bar] :current/:total :eta'
format = pad(message, 20) + '[:bar] :current/:total :eta'
return new BetterProgressBar(format, count)
} else {
var format = pad(message, 20) + '[:bar] up to date'
format = pad(message, 20) + '[:bar] up to date'
var bar = new BetterProgressBar(format, 1)
bar.tick(1)
return bar
@ -30,8 +31,8 @@ BetterProgressBar.prototype.eta = function () {
var ratio = this.curr / this.total
ratio = Math.min(Math.max(ratio, 0), 1)
var percent = ratio * 100
var elapsed = new Date - this.start
return (percent == 100) ? 0 : elapsed * (this.total / this.curr - 1)
var elapsed = new Date() - this.start
return (percent === 100) ? 0 : elapsed * ((this.total / this.curr) - 1)
}
BetterProgressBar.prototype.render = function (tokens) {
@ -44,15 +45,17 @@ BetterProgressBar.prototype.render = function (tokens) {
}
function formatEta (ms) {
var min = 0
var sec = 0
if (isNaN(ms) || !isFinite(ms)) return ''
if (ms > 60 * 1000) {
var min = Math.floor(ms / 60 / 1000)
min = Math.floor(ms / 60 / 1000)
return `(${min.toFixed(0)}min left)`
} else if (ms > 10 * 1000) {
var sec = Math.floor(ms / 10000) * 10
sec = Math.floor(ms / 10000) * 10
return `(${sec.toFixed(0)}s left)`
} else if (ms > 0) {
var sec = ms / 1000
sec = ms / 1000
return `(a few seconds left)`
} else {
return 'done'

@ -1,4 +1,3 @@
const File = require('../src/input/file')
const Media = require('../src/model/media')
exports.file = function (opts) {

@ -2,7 +2,6 @@ const should = require('should/as-function')
const File = require('../../src/input/file')
describe('Input file', function () {
it('reads the relative file path', function () {
var file = new File(dbFile({
SourceFile: 'holidays/beach.jpg'
@ -36,13 +35,12 @@ describe('Input file', function () {
}))
should(file.type).eql('video')
})
})
function dbFile (data) {
// some required data
if (!data.SourceFile) data.SourceFile = 'photo.jpg'
if (!data.File) data.File = {}
if (!data.File.FileModifyDate) data.File.FileModifyDate = '1999:12:31 23:59:59+00:00'
if (!data.File.FileModifyDate) data.File.FileModifyDate = '1999:12:31 23:59:59+00:00'
return data
}

@ -1,58 +1,53 @@
var should = require('should/as-function');
var Album = require('../../src/model/album');
var fixtures = require('../fixtures');
describe('Album', function() {
describe('stats', function() {
describe('single level stats', function() {
it('has no nested albums', function() {
var a = new Album({});
a.finalize();
should(a.stats.albums).eql(0);
var should = require('should/as-function')
var Album = require('../../src/model/album')
var fixtures = require('../fixtures')
describe('Album', function () {
describe('stats', function () {
describe('single level stats', function () {
it('has no nested albums', function () {
var a = new Album({})
a.finalize()
should(a.stats.albums).eql(0)
})
it('calculates counts for a single level', function() {
it('calculates counts for a single level', function () {
var a = new Album({
files: [
fixtures.photo(), fixtures.photo(),
fixtures.photo(), fixtures.photo(),
fixtures.video(), fixtures.video(),
fixtures.video(), fixtures.video()
]
});
a.finalize();
should(a.stats.photos).eql(4);
should(a.stats.videos).eql(2);
});
})
a.finalize()
should(a.stats.photos).eql(4)
should(a.stats.videos).eql(2)
})
it('calculates from/to dates', function() {
it('calculates from/to dates', function () {
var a = new Album({
files: [
fixtures.photo({date: '2016-09-14'}),
fixtures.photo({date: '2016-09-02'}),
fixtures.photo({date: '2016-10-21'}),
fixtures.photo({date: '2016-10-21'})
]
});
a.finalize();
should(a.stats.fromDate).eql(fixtures.date('2016-09-02').getTime());
should(a.stats.toDate).eql(fixtures.date('2016-10-21').getTime());
});
});
describe('nested albums stats', function() {
})
a.finalize()
should(a.stats.fromDate).eql(fixtures.date('2016-09-02').getTime())
should(a.stats.toDate).eql(fixtures.date('2016-10-21').getTime())
})
})
it('counts all nested albums', function() {
describe('nested albums stats', function () {
it('counts all nested albums', function () {
var root = new Album({
albums: [new Album('a'), new Album('b')]
});
root.finalize();
should(root.stats.albums).eql(2);
});
})
root.finalize()
should(root.stats.albums).eql(2)
})
it('counts all nested photos', function() {
it('counts all nested photos', function () {
var root = new Album({
files: [fixtures.photo()],
albums: [
@ -60,12 +55,12 @@ describe('Album', function() {
files: [fixtures.photo(), fixtures.photo()]
})
]
});
root.finalize();
should(root.stats.photos).eql(3);
});
})
root.finalize()
should(root.stats.photos).eql(3)
})
it('counts all nested photos', function() {
it('counts all nested photos', function () {
var root = new Album({
files: [fixtures.video()],
albums: [
@ -73,12 +68,12 @@ describe('Album', function() {
files: [fixtures.video(), fixtures.video()]
})
]
});
root.finalize();
should(root.stats.videos).eql(3);
});
})
root.finalize()
should(root.stats.videos).eql(3)
})
it('calculates from/to dates across all albums', function() {
it('calculates from/to dates across all albums', function () {
var a = new Album({
files: [fixtures.photo({date: '2016-09-14'})],
albums: [
@ -89,79 +84,74 @@ describe('Album', function() {
})]
})
]
});
a.finalize();
should(a.stats.fromDate).eql(fixtures.date('2016-09-02').getTime());
should(a.stats.toDate).eql(fixtures.date('2016-10-21').getTime());
});
});
});
describe('summary', function() {
})
a.finalize()
should(a.stats.fromDate).eql(fixtures.date('2016-09-02').getTime())
should(a.stats.toDate).eql(fixtures.date('2016-10-21').getTime())
})
})
})
it('creates a summary with a single photo', function() {
var a = new Album('single');
describe('summary', function () {
it('creates a summary with a single photo', function () {
var a = new Album('single')
a.files = [
fixtures.photo()
];
a.finalize();
]
a.finalize()
should(a.summary).eql('1 photo')
});
})
it('creates a summary with a single video', function() {
var a = new Album('single');
it('creates a summary with a single video', function () {
var a = new Album('single')
a.files = [
fixtures.video()
];
a.finalize();
]
a.finalize()
should(a.summary).eql('1 video')
});
})
it('creates a summary with a single album', function() {
var a = new Album('single');
a.albums = [new Album('nested')];
a.finalize();
it('creates a summary with a single album', function () {
var a = new Album('single')
a.albums = [new Album('nested')]
a.finalize()
should(a.summary).eql('1 album')
});
})
it('creates a summary with several photos', function() {
var a = new Album('single');
it('creates a summary with several photos', function () {
var a = new Album('single')
a.files = [
fixtures.photo(), fixtures.photo(),
];
a.finalize();
fixtures.photo(), fixtures.photo()
]
a.finalize()
should(a.summary).eql('2 photos')
});
})
it('creates a summary with several videos', function() {
var a = new Album('single');
it('creates a summary with several videos', function () {
var a = new Album('single')
a.files = [
fixtures.video(), fixtures.video(),
];
a.finalize();
fixtures.video(), fixtures.video()
]
a.finalize()
should(a.summary).eql('2 videos')
});
})
it('creates a summary with several albums', function() {
var a = new Album('single');
a.albums = [new Album('nested 1'), new Album('nested 2')];
a.finalize();
it('creates a summary with several albums', function () {
var a = new Album('single')
a.albums = [new Album('nested 1'), new Album('nested 2')]
a.finalize()
should(a.summary).eql('2 albums')
});
})
it('creates a summary with a mix of albums, photos and videos', function() {
var a = new Album('single');
a.albums = [new Album('nested')];
it('creates a summary with a mix of albums, photos and videos', function () {
var a = new Album('single')
a.albums = [new Album('nested')]
a.files = [
fixtures.photo(), fixtures.photo(),
fixtures.video(), fixtures.video(),
];
a.finalize();
fixtures.video(), fixtures.video()
]
a.finalize()
should(a.summary).eql('1 album, 2 photos, 2 videos')
});
});
});
})
})
})

@ -1,33 +1,29 @@
var should = require('should/as-function');
var Album = require('../../src/model/album');
var fixtures = require('../fixtures');
var path = require('path');
describe('Album', function() {
describe('options', function() {
it('can pass the title as a single argument', function() {
var a = new Album('Holidays');
should(a.title).eql('Holidays');
});
it('can pass a full hash of options', function() {
var a = new Album({id: 12, title: 'Holidays'});
should(a.id).eql(12);
should(a.title).eql('Holidays');
});
});
describe('output paths', function() {
it('sanitises album titles for the file name', function() {
var a = new Album('hello & world');
should(a.basename).eql('helloworld');
});
it('concatenates nested filenames for uniqueness', function() {
var should = require('should/as-function')
var Album = require('../../src/model/album')
var fixtures = require('../fixtures')
var path = require('path')
describe('Album', function () {
describe('options', function () {
it('can pass the title as a single argument', function () {
var a = new Album('Holidays')
should(a.title).eql('Holidays')
})
it('can pass a full hash of options', function () {
var a = new Album({id: 12, title: 'Holidays'})
should(a.id).eql(12)
should(a.title).eql('Holidays')
})
})
describe('output paths', function () {
it('sanitises album titles for the file name', function () {
var a = new Album('hello & world')
should(a.basename).eql('helloworld')
})
it('concatenates nested filenames for uniqueness', function () {
// to avoid having two nested albums called "October" overwrite each other
// note: doesn't use the root title to avoid "home-" or "index-"
var root = new Album({
@ -44,81 +40,79 @@ describe('Album', function() {
albums: [
new Album({title: 'October'})
]
}),
})
]
});
root.finalize();
should(root.basename).eql('home');
should(root.albums[0].basename).eql('2010');
should(root.albums[1].basename).eql('2011');
should(root.albums[0].albums[0].basename).eql('2010-October');
should(root.albums[1].albums[0].basename).eql('2011-October');
});
it('calculates the output file path', function() {
})
root.finalize()
should(root.basename).eql('home')
should(root.albums[0].basename).eql('2010')
should(root.albums[1].basename).eql('2011')
should(root.albums[0].albums[0].basename).eql('2010-October')
should(root.albums[1].albums[0].basename).eql('2011-October')
})
it('calculates the output file path', function () {
var root = new Album({
title: 'home',
albums: [new Album({title: '2010'})]
});
root.finalize({index: 'index.html'});
should(root.path).eql('index.html');
should(root.albums[0].path).eql('2010.html');
});
})
root.finalize({index: 'index.html'})
should(root.path).eql('index.html')
should(root.albums[0].path).eql('2010.html')
})
it('calculates the URL for the browser', function() {
it('calculates the URL for the browser', function () {
var root = new Album({
title: 'home',
albums: [new Album({title: '2010'})]
});
root.finalize({index: 'index.html'});
should(root.url).eql('index.html');
should(root.albums[0].url).eql('2010.html');
});
})
root.finalize({index: 'index.html'})
should(root.url).eql('index.html')
should(root.albums[0].url).eql('2010.html')
})
it('calculates the output path with a target folder (slashes match the OS)', function() {
it('calculates the output path with a target folder (slashes match the OS)', function () {
var root = new Album({
title: 'home',
albums: [new Album({title: '2010'})]
});
root.finalize({index: 'index.html', albumsOutputFolder: 'albums'});
should(root.path).eql('index.html');
should(root.albums[0].path).eql(path.join('albums', '2010.html'));
});
})
root.finalize({index: 'index.html', albumsOutputFolder: 'albums'})
should(root.path).eql('index.html')
should(root.albums[0].path).eql(path.join('albums', '2010.html'))
})
it('calculates the URL with a target folder (always forward slashes)', function() {
it('calculates the URL with a target folder (always forward slashes)', function () {
var root = new Album({
title: 'home',
albums: [new Album({title: '2010'})]
});
root.finalize({index: 'index.html', albumsOutputFolder: 'albums'});
should(root.path).eql('index.html');
should(root.albums[0].path).eql('albums/2010.html');
});
});
describe('previews', function() {
it('picks the first 10 files as previews', function() {
})
root.finalize({index: 'index.html', albumsOutputFolder: 'albums'})
should(root.path).eql('index.html')
should(root.albums[0].path).eql('albums/2010.html')
})
})
describe('previews', function () {
it('picks the first 10 files as previews', function () {
var a = new Album({files: [
fixtures.photo(), fixtures.photo(), fixtures.photo(), fixtures.photo(),
fixtures.photo(), fixtures.photo(), fixtures.photo(), fixtures.photo(),
fixtures.photo(), fixtures.photo(), fixtures.photo(), fixtures.photo(),
]});
a.finalize();
should(a.previews).have.length(10);
});
fixtures.photo(), fixtures.photo(), fixtures.photo(), fixtures.photo()
]})
a.finalize()
should(a.previews).have.length(10)
})
it('adds <missing> thumbnails to fill', function() {
it('adds <missing> thumbnails to fill', function () {
var a = new Album({files: [
fixtures.photo(), fixtures.photo(),
]});
a.finalize();
should(a.previews[2].urls.thumbnail).eql('public/missing.png');
should(a.previews[9].urls.thumbnail).eql('public/missing.png');
});
it('uses files from nested albums too', function() {
fixtures.photo(), fixtures.photo()
]})
a.finalize()
should(a.previews[2].urls.thumbnail).eql('public/missing.png')
should(a.previews[9].urls.thumbnail).eql('public/missing.png')
})
it('uses files from nested albums too', function () {
var a = new Album({
title: 'a',
albums: [
@ -131,125 +125,120 @@ describe('Album', function() {
files: [fixtures.photo(), fixtures.photo()]
})
]
});
a.finalize();
should(a.previews).have.length(10);
})
a.finalize()
should(a.previews).have.length(10)
for (var i = 0; i < 4; ++i) {
should(a.previews[i].urls.thumbnail).not.eql('public/missing.png');
should(a.previews[i].urls.thumbnail).not.eql('public/missing.png')
}
});
});
describe('sorting', function() {
it('can sort albums by title', function() {
var a = new Album('A');
var b = new Album('B');
var c = new Album('C');
var root = new Album({albums: [c, a, b]});
root.finalize({sortAlbumsBy: 'title'});
should(root.albums).eql([a, b, c]);
});
it('can sort albums by start date', function() {
var startJan = albumWithFileDates(['2010-01-01', '2010-05-01']);
var startFeb = albumWithFileDates(['2010-02-01', '2010-04-01']);
var startMar = albumWithFileDates(['2010-03-01', '2010-03-01']);
var root = new Album({albums: [startFeb, startMar, startJan]});
root.finalize({sortAlbumsBy: 'start-date'});
should(root.albums).eql([startJan, startFeb, startMar]);
});
it('can sort albums by end date', function() {
var endMay = albumWithFileDates(['2010-01-01', '2010-05-01']);
var endApr = albumWithFileDates(['2010-02-01', '2010-04-01']);
var endMar = albumWithFileDates(['2010-03-01', '2010-03-01']);
var root = new Album({albums: [endMay, endMar, endApr]});
root.finalize({sortAlbumsBy: 'end-date'});
should(root.albums).eql([endMar, endApr, endMay]);
});
it('can sort media by filename', function() {
var a = fixtures.photo({path: 'a'});
var b = fixtures.photo({path: 'b'});
var c = fixtures.photo({path: 'c'});
var album = new Album({files: [c, a, b]});
album.finalize({sortMediaBy: 'filename'});
should(album.files).eql([a, b, c]);
});
it('can sort media by reverse filename', function() {
var a = fixtures.photo({path: 'a'});
var b = fixtures.photo({path: 'b'});
var c = fixtures.photo({path: 'c'});
var album = new Album({files: [c, a, b]});
album.finalize({sortMediaBy: 'filename', sortMediaDirection: 'desc'});
should(album.files).eql([c, b, a]);
});
it('sorts nested albums too', function() {
var nested = new Album({title: 'nested', files: [
fixtures.photo({path: 'b'}),
fixtures.photo({path: 'a'}),
]});
var root = new Album({title: 'home', albums: [nested]});
root.finalize({sortMediaBy: 'filename'});
should(nested.files[0].file.path).eql('a');
should(nested.files[1].file.path).eql('b');
});
});
describe('nested albums basic logic', function() {
it('calculates the depth of every album', function() {
var a = new Album('single');
var b = new Album('single');
var c = new Album('single');
var d = new Album('single');
a.albums = [b, c];
c.albums = [d];
a.finalize();
should(a.depth).eql(0);
should(b.depth).eql(1);
should(c.depth).eql(1);
should(d.depth).eql(2);
});
it('sets the home flag on the top-level album', function() {
var a = new Album('single');
var b = new Album('single');
var c = new Album('single');
var d = new Album('single');
a.albums = [b, c];
c.albums = [d];
a.finalize();
should(a.home).eql(true);
should(b.home).eql(false);
should(c.home).eql(false);
should(d.home).eql(false);
});
it('passes finalising options to all nested albums (e.g. sorting)', function() {
var nested = new Album({title: 'nested', files: [
fixtures.photo({path: 'b'}),
fixtures.photo({path: 'a'}),
]});
var root = new Album({title: 'home', albums: [nested]});
root.finalize({sortMediaBy: 'filename'});
should(nested.files[0].file.path).eql('a');
should(nested.files[1].file.path).eql('b');
});
});
});
function albumWithFileDates(dates) {
var files = dates.map(function(d) {
return fixtures.photo({date: d});
});
return new Album({files: files});
})
})
describe('sorting', function () {
it('can sort albums by title', function () {
var a = new Album('A')
var b = new Album('B')
var c = new Album('C')
var root = new Album({albums: [c, a, b]})
root.finalize({sortAlbumsBy: 'title'})
should(root.albums).eql([a, b, c])
})
it('can sort albums by start date', function () {
var startJan = albumWithFileDates(['2010-01-01', '2010-05-01'])
var startFeb = albumWithFileDates(['2010-02-01', '2010-04-01'])
var startMar = albumWithFileDates(['2010-03-01', '2010-03-01'])
var root = new Album({albums: [startFeb, startMar, startJan]})
root.finalize({sortAlbumsBy: 'start-date'})
should(root.albums).eql([startJan, startFeb, startMar])
})
it('can sort albums by end date', function () {
var endMay = albumWithFileDates(['2010-01-01', '2010-05-01'])
var endApr = albumWithFileDates(['2010-02-01', '2010-04-01'])
var endMar = albumWithFileDates(['2010-03-01', '2010-03-01'])
var root = new Album({albums: [endMay, endMar, endApr]})
root.finalize({sortAlbumsBy: 'end-date'})
should(root.albums).eql([endMar, endApr, endMay])
})
it('can sort media by filename', function () {
var a = fixtures.photo({path: 'a'})
var b = fixtures.photo({path: 'b'})
var c = fixtures.photo({path: 'c'})
var album = new Album({files: [c, a, b]})
album.finalize({sortMediaBy: 'filename'})
should(album.files).eql([a, b, c])
})
it('can sort media by reverse filename', function () {
var a = fixtures.photo({path: 'a'})
var b = fixtures.photo({path: 'b'})
var c = fixtures.photo({path: 'c'})
var album = new Album({files: [c, a, b]})
album.finalize({sortMediaBy: 'filename', sortMediaDirection: 'desc'})
should(album.files).eql([c, b, a])
})
it('sorts nested albums too', function () {
var nested = new Album({title: 'nested',
files: [
fixtures.photo({path: 'b'}),
fixtures.photo({path: 'a'})
]})
var root = new Album({title: 'home', albums: [nested]})
root.finalize({sortMediaBy: 'filename'})
should(nested.files[0].file.path).eql('a')
should(nested.files[1].file.path).eql('b')
})
})
describe('nested albums basic logic', function () {
it('calculates the depth of every album', function () {
var a = new Album('single')
var b = new Album('single')
var c = new Album('single')
var d = new Album('single')
a.albums = [b, c]
c.albums = [d]
a.finalize()
should(a.depth).eql(0)
should(b.depth).eql(1)
should(c.depth).eql(1)
should(d.depth).eql(2)
})
it('sets the home flag on the top-level album', function () {
var a = new Album('single')
var b = new Album('single')
var c = new Album('single')
var d = new Album('single')
a.albums = [b, c]
c.albums = [d]
a.finalize()
should(a.home).eql(true)
should(b.home).eql(false)
should(c.home).eql(false)
should(d.home).eql(false)
})
it('passes finalising options to all nested albums (e.g. sorting)', function () {
var nested = new Album({title: 'nested',
files: [
fixtures.photo({path: 'b'}),
fixtures.photo({path: 'a'})
]})
var root = new Album({title: 'home', albums: [nested]})
root.finalize({sortMediaBy: 'filename'})
should(nested.files[0].file.path).eql('a')
should(nested.files[1].file.path).eql('b')
})
})
})
function albumWithFileDates (dates) {
var files = dates.map(function (d) {
return fixtures.photo({date: d})
})
return new Album({files: files})
}

@ -1,25 +1,26 @@
var should = require('should/as-function');
var Album = require('../../src/model/album.js');
var bydate = require('../../src/model/by-date.js');
var fixtures = require('../fixtures');
/* eslint-disable camelcase */
describe('ByDate', function() {
var should = require('should/as-function')
var Album = require('../../src/model/album.js')
var bydate = require('../../src/model/by-date.js')
var fixtures = require('../fixtures')
beforeEach(function() {
Album.resetIds();
});
describe('ByDate', function () {
beforeEach(function () {
Album.resetIds()
})
it('creates top-level albums grouped by month', function () {
// create files from different dates
var a_2016_06 = fixtures.photo({date: fixtures.date('2016-06-01')});
var b_2016_06 = fixtures.photo({date: fixtures.date('2016-06-10')});
var c_2016_07 = fixtures.photo({date: fixtures.date('2016-07-23')});
var d_2016_07 = fixtures.video({date: fixtures.date('2016-07-18')});
var a_2016_06 = fixtures.photo({date: fixtures.date('2016-06-01')})
var b_2016_06 = fixtures.photo({date: fixtures.date('2016-06-10')})
var c_2016_07 = fixtures.photo({date: fixtures.date('2016-07-23')})
var d_2016_07 = fixtures.video({date: fixtures.date('2016-07-18')})
// group them per month
var collection = [a_2016_06, b_2016_06, c_2016_07, d_2016_07]
var albums = bydate.albums(collection, {
grouping: 'YYYY-MM'
});
})
// assert on the result
should(albums).eql([
new Album({
@ -32,20 +33,20 @@ describe('ByDate', function() {
title: '2016-07',
files: [c_2016_07, d_2016_07]
})
]);
});
])
})
it('creates albums using a date hierarchy', function () {
// create files from different dates
var a_2015_06 = fixtures.photo({date: fixtures.date('2015-06-01')});
var b_2015_06 = fixtures.photo({date: fixtures.date('2015-06-10')});
var c_2016_07 = fixtures.photo({date: fixtures.date('2016-07-23')});
var d_2016_08 = fixtures.video({date: fixtures.date('2016-08-18')});
var a_2015_06 = fixtures.photo({date: fixtures.date('2015-06-01')})
var b_2015_06 = fixtures.photo({date: fixtures.date('2015-06-10')})
var c_2016_07 = fixtures.photo({date: fixtures.date('2016-07-23')})
var d_2016_08 = fixtures.video({date: fixtures.date('2016-08-18')})
// group them per year, and nested month
var collection = [a_2015_06, b_2015_06, c_2016_07, d_2016_08]
var albums = bydate.albums(collection, {
grouping: 'YYYY/MM'
});
})
// assert on the result
should(albums).eql([
new Album({
@ -77,7 +78,6 @@ describe('ByDate', function() {
})
]
})
]);
});
});
])
})
})

@ -1,23 +1,22 @@
var should = require('should/as-function');
var Album = require('../../src/model/album.js');
var byfolder = require('../../src/model/by-folder.js');
var fixtures = require('../fixtures');
var should = require('should/as-function')
var Album = require('../../src/model/album.js')
var byfolder = require('../../src/model/by-folder.js')
var fixtures = require('../fixtures')
describe('ByFolder', function() {
beforeEach(function() {
Album.resetIds();
});
describe('ByFolder', function () {
beforeEach(function () {
Album.resetIds()
})
it('creates albums by folders', function () {
// create files in different folders
var london1 = fixtures.photo({path: 'london/IMG_000001.jpg'});
var london2 = fixtures.photo({path: 'london/IMG_000002.jpg'});
var newyork1 = fixtures.photo({path: 'newyork/IMG_000003.jpg'});
var newyork2 = fixtures.video({path: 'newyork/IMG_000004.mp4'});
var london1 = fixtures.photo({path: 'london/IMG_000001.jpg'})
var london2 = fixtures.photo({path: 'london/IMG_000002.jpg'})
var newyork1 = fixtures.photo({path: 'newyork/IMG_000003.jpg'})
var newyork2 = fixtures.video({path: 'newyork/IMG_000004.mp4'})
// group them per folder
var collection = [london1, london2, newyork1, newyork2]
var albums = byfolder.albums(collection, {});
var albums = byfolder.albums(collection, {})
// assert on the result
should(albums).eql([
new Album({
@ -30,16 +29,16 @@ describe('ByFolder', function() {
title: 'newyork',
files: [newyork1, newyork2]
})
]);
});
])
})
it('creates nested albums for nested folders', function () {
// create files in nested folders
var photo1 = fixtures.photo({path: 'a/b/c/IMG_000001.jpg'});
var photo2 = fixtures.photo({path: 'a/d/IMG_000002.jpg'});
var photo1 = fixtures.photo({path: 'a/b/c/IMG_000001.jpg'})
var photo2 = fixtures.photo({path: 'a/d/IMG_000002.jpg'})
// group them per folder
var collection = [photo1, photo2]
var albums = byfolder.albums(collection, {});
var albums = byfolder.albums(collection, {})
// assert on the result
should(albums).eql([
new Album({
@ -66,7 +65,6 @@ describe('ByFolder', function() {
})
]
})
]);
});
});
])
})
})

@ -1,9 +1,8 @@
var should = require('should/as-function');
var Media = require('../../src/model/media');
var fixtures = require('../fixtures');
var should = require('should/as-function')
var Media = require('../../src/model/media')
var fixtures = require('../fixtures')
describe('Media', function () {
describe('date taken', function () {
it('reads the EXIF date if present', function () {
const file = fixtures.file()
@ -20,7 +19,7 @@ describe('Media', function () {
})
describe('photos and videos', function () {
it('can tell if a file is a regular photo', function() {
it('can tell if a file is a regular photo', function () {
const file = fixtures.file({type: 'image'})
file.meta.File.MIMEType = 'image/jpeg'
const media = new Media(file)
@ -28,7 +27,7 @@ describe('Media', function () {
should(media.isAnimated).eql(false)
})
it('can tell if a file is a non-animated gif', function() {
it('can tell if a file is a non-animated gif', function () {
const file = fixtures.file({type: 'image'})
file.meta.File.MIMEType = 'image/gif'
const media = new Media(file)
@ -36,7 +35,7 @@ describe('Media', function () {
should(media.isAnimated).eql(false)
})
it('can tell if a file is an animated gif', function() {
it('can tell if a file is an animated gif', function () {
const file = fixtures.file({type: 'image'})
file.meta.File.MIMEType = 'image/gif'
file.meta.GIF = {FrameCount: 10}
@ -45,7 +44,7 @@ describe('Media', function () {
should(media.isAnimated).eql(true)
})
it('can tell if a file is a video', function() {
it('can tell if a file is a video', function () {
const file = fixtures.file({type: 'video'})
const media = new Media(file)
should(media.isVideo).eql(true)
@ -53,7 +52,7 @@ describe('Media', function () {
})
})
describe('caption', function() {
describe('caption', function () {
it('uses the EXIF caption if present', function () {
const file = fixtures.file()
file.meta.EXIF['ImageDescription'] = 'some caption'
@ -76,5 +75,4 @@ describe('Media', function () {
should(media.caption).eql('exif caption')
})
})
})

Loading…
Cancel
Save