2
0
mirror of https://github.com/thumbsup/thumbsup synced 2024-11-03 15:40:14 +00:00

Fix #61: new options to avoid copying original photos to the output folder

This commit is contained in:
Romain 2017-05-25 21:43:03 +10:00 committed by Romain
parent 92706276a0
commit 80f7a88c35
8 changed files with 315 additions and 49 deletions

View File

@ -60,11 +60,12 @@ Required:
--output Output path for the static website [string] [required]
Output options:
--thumb-size Pixel size of the square thumbnails [number] [default: 120]
--large-size Pixel height of the fullscreen photos [number] [default: 1000]
--original-photos Copy and allow download of full-size photos [boolean] [default: false]
--original-videos Copy and allow download of full-size videos [boolean] [default: false]
--cleanup Remove any output file that's no longer needed [boolean] [default: false]
--thumb-size Pixel size of the square thumbnails [number] [default: 120]
--large-size Pixel height of the fullscreen photos [number] [default: 1000]
--download-photos Target of the photo download links [choices: "large", "copy", "symlink", "link"] [default: "large"]
--download-videos Target of the video download links [choices: "large", "copy", "symlink", "link"] [default: "large"]
--download-link-prefix Path or URL prefix for linked downloads [string]
--cleanup Remove any output file that's no longer needed [boolean] [default: false]
Album options:
--albums-from How to group media into albums [choices: "folders", "date"] [default: "folders"]
@ -83,6 +84,10 @@ Website options:
--css Path to a custom provided CSS/LESS file for styling [string]
--google-analytics Code for Google Analytics tracking [string]
Deprecated:
--original-photos Copy and allow download of full-size photos [boolean] [default: false]
--original-videos Copy and allow download of full-size videos [boolean] [default: false]
Options:
--help Show help [boolean]
--config Path to JSON config file [string]

View File

@ -46,17 +46,22 @@ var opts = yargs
type: 'number',
'default': 1000
},
'original-photos': {
'download-photos': {
group: 'Output options:',
description: 'Copy and allow download of full-size photos',
type: 'boolean',
'default': false
description: 'Target of the photo download links',
choices: ['large', 'copy', 'symlink', 'link'],
'default': 'large'
},
'original-videos': {
'download-videos': {
group: 'Output options:',
description: 'Copy and allow download of full-size videos',
type: 'boolean',
'default': false
description: 'Target of the video download links',
choices: ['large', 'copy', 'symlink', 'link'],
'default': 'large'
},
'download-link-prefix': {
group: 'Output options:',
description: 'Path or URL prefix for linked downloads',
type: 'string'
},
'cleanup': {
group: 'Output options:',
@ -153,6 +158,23 @@ var opts = yargs
'config': {
description: 'JSON config file (one key per argument)',
normalize: true
},
// ------------------------------------
// Deprecated options
// ------------------------------------
'original-photos': {
group: 'Deprecated:',
description: 'Copy and allow download of full-size photos',
type: 'boolean',
'default': false
},
'original-videos': {
group: 'Deprecated:',
description: 'Copy and allow download of full-size videos',
type: 'boolean',
'default': false
}
})
@ -162,15 +184,27 @@ var opts = yargs
'{ "sort-albums-by": "start-date" }')
.argv
// Post-processing and smart defaults
opts['input'] = path.resolve(opts['input'])
opts['output'] = path.resolve(opts['output'])
if (!opts['download-link-prefix']) {
opts['download-link-prefix'] = path.relative(opts['output'], opts['input'])
}
// Convert deprecated options to the new replacement
if (opts['original-photos']) opts['download-photos'] = 'copy'
if (opts['original-videos']) opts['download-videos'] = 'copy'
index.build({
input: path.resolve(opts['input']),
output: path.resolve(opts['output']),
input: opts['input'],
output: opts['output'],
cleanup: opts['cleanup'],
title: opts['title'],
thumbSize: opts['thumb-size'],
largeSize: opts['large-size'],
originalPhotos: opts['original-photos'],
originalVideos: opts['original-videos'],
downloadPhotos: opts['download-photos'],
downloadVideos: opts['download-videos'],
downloadLinkPrefix: opts['download-link-prefix'],
albumsFrom: opts['albums-from'],
albumsDateFormat: opts['albums-date-format'],
sortAlbumsBy: opts['sort-albums-by'],

View File

@ -39,6 +39,7 @@
"moment": "^2.16.0",
"pad": "^1.0.2",
"progress": "~1.1.8",
"url-join": "^2.0.2",
"video.js": "^5.17.0",
"yargs": "^6.3.0"
},

View File

@ -13,7 +13,7 @@ function File (dbEntry, opts) {
this.path = dbEntry.SourceFile
this.date = fileDate(dbEntry)
this.type = mediaType(dbEntry)
this.output = output.paths(this.path, this.type, opts)
this.output = output.paths(this.path, this.type, opts || {})
}
function fileDate (dbEntry) {

View File

@ -1,20 +1,21 @@
const debug = require('debug')('thumbsup')
const path = require('path')
const urljoin = require('url-join')
exports.paths = function (filepath, mediaType, config) {
var originals = false
if (mediaType === 'image') {
originals = config ? config.originalPhotos : false
return imageOutput(filepath, originals)
// originals = config ? config.originalPhotos : false
return imageOutput(filepath, config)
} else if (mediaType === 'video') {
originals = config ? config.originalVideos : false
return videoOutput(filepath, originals)
// originals = config ? config.originalVideos : false
return videoOutput(filepath, config)
} else {
debug(`Unsupported file type: ${mediaType}`)
return {}
}
}
function imageOutput (filepath, originals) {
function imageOutput (filepath, config) {
const output = {
thumbnail: {
path: 'media/thumbs/' + filepath,
@ -25,18 +26,11 @@ function imageOutput (filepath, originals) {
rel: 'photo:large'
}
}
if (originals) {
output.download = {
path: 'media/original/' + filepath,
rel: 'original'
}
} else {
output.download = output.large
}
setDownload(filepath, config, 'image', output)
return output
}
function videoOutput (filepath, originals) {
function videoOutput (filepath, config) {
var output = {
thumbnail: {
path: 'media/thumbs/' + ext(filepath, 'jpg'),
@ -51,17 +45,46 @@ function videoOutput (filepath, originals) {
rel: 'video:resized'
}
}
if (originals) {
output.download = {
path: 'media/original/' + filepath,
rel: 'original'
}
} else {
output.download = output.video
}
setDownload(filepath, config, 'video', output)
return output
}
function setDownload (filepath, config, type, output) {
const configKey = (type === 'image' ? 'downloadPhotos' : 'downloadVideos')
const largeVersion = (type === 'image' ? output.large : output.video)
switch (config[configKey]) {
case 'large':
output.download = largeVersion
break
case 'copy':
output.download = {
path: path.join('media', 'original', filepath),
rel: 'fs:copy'
}
break
case 'symlink':
output.download = {
path: path.join('media', 'original', filepath),
rel: 'fs:symlink'
}
break
case 'link':
output.download = {
path: join(config.downloadLinkPrefix, filepath),
rel: 'fs:link'
}
break
}
}
function ext (file, ext) {
return file.replace(/\.[a-z0-9]+$/i, '.' + ext)
}
function join (prefix, filepath) {
if (prefix.match(/^https?:\/\//)) {
return urljoin(prefix, filepath)
} else {
return path.join(prefix, filepath)
}
}

View File

@ -1,6 +1,5 @@
const async = require('async')
const childProcess = require('child_process')
const fs = require('fs-extra')
const gm = require('gm')
const path = require('path')
@ -9,10 +8,6 @@ exports.sizes = {
large: 1000
}
exports.copy = function (task, callback) {
fs.copy(task.src, task.dest, callback)
}
// Small square photo thumbnail
exports.photoSquare = function (task, callback) {
gm(task.src)

View File

@ -3,8 +3,17 @@ const fs = require('fs-extra')
const path = require('path')
const resize = require('./resize')
function copy (task, callback) {
fs.copy(task.src, task.dest, callback)
}
function symlink (task, callback) {
fs.symlink(task.src, task.dest, callback)
}
const ACTION_MAP = {
'original': resize.copy,
'fs:copy': copy,
'fs:symlink': symlink,
'photo:thumbnail': resize.photoSquare,
'photo:large': resize.photoLarge,
'video:thumbnail': resize.videoSquare,
@ -26,8 +35,9 @@ exports.create = function (opts, files, filterType) {
var src = path.join(opts.input, f.path)
var dest = path.join(opts.output, f.output[out].path)
var destDate = modifiedDate(dest)
if (f.date > destDate) {
var action = ACTION_MAP[f.output[out].rel]
var action = ACTION_MAP[f.output[out].rel]
// ignore output files that don't have an action (e.g. existing links)
if (action && f.date > destDate) {
tasks[dest] = (done) => {
fs.mkdirsSync(path.dirname(dest))
debug(`${f.output[out].rel} from ${src} to ${dest}`)

198
test/input/output.spec.js Normal file
View File

@ -0,0 +1,198 @@
const should = require('should/as-function')
const output = require('../../src/input/output')
describe('Output paths', function () {
describe('Images', function () {
it('generates a thumbnail', function () {
var o = output.paths('holidays/beach.jpg', 'image', {})
should(o.thumbnail).eql({
path: 'media/thumbs/holidays/beach.jpg',
rel: 'photo:thumbnail'
})
})
it('generates a large "web" version', function () {
var o = output.paths('holidays/beach.jpg', 'image', {})
should(o.large).eql({
path: 'media/large/holidays/beach.jpg',
rel: 'photo:large'
})
})
it('can point downloads to the large version', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'large'
})
should(o.download).eql({
path: 'media/large/holidays/beach.jpg',
rel: 'photo:large'
})
})
it('can point downloads to a copy in the output folder', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'copy'
})
should(o.download).eql({
path: 'media/original/holidays/beach.jpg',
rel: 'fs:copy'
})
})
it('can point downloads to a symlink to the originals', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'symlink'
})
should(o.download).eql({
path: 'media/original/holidays/beach.jpg',
rel: 'fs:symlink'
})
})
it('can point downloads to an existing link', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'link',
downloadLinkPrefix: '../myphotos'
})
should(o.download).eql({
path: '../myphotos/holidays/beach.jpg',
rel: 'fs:link'
})
})
})
describe('Videos', function () {
it('generates a thumbnail', function () {
var o = output.paths('holidays/seagull.mp4', 'video', {})
should(o.thumbnail).eql({
path: 'media/thumbs/holidays/seagull.jpg',
rel: 'video:thumbnail'
})
})
it('generates a poster image', function () {
var o = output.paths('holidays/seagull.mp4', 'video', {})
should(o.large).eql({
path: 'media/large/holidays/seagull.jpg',
rel: 'video:poster'
})
})
it('generates a resized "web" video', function () {
var o = output.paths('holidays/seagull.mp4', 'video', {})
should(o.video).eql({
path: 'media/large/holidays/seagull.mp4',
rel: 'video:resized'
})
})
it('can point downloads to the large version', function () {
var o = output.paths('holidays/seagull.mp4', 'video', {
downloadVideos: 'large'
})
should(o.download).eql({
path: 'media/large/holidays/seagull.mp4',
rel: 'video:resized'
})
})
it('can point downloads to a copy in the output folder', function () {
var o = output.paths('holidays/seagull.mp4', 'video', {
downloadVideos: 'copy'
})
should(o.download).eql({
path: 'media/original/holidays/seagull.mp4',
rel: 'fs:copy'
})
})
it('can point downloads to a symlink to the originals', function () {
var o = output.paths('holidays/seagull.mp4', 'video', {
downloadVideos: 'symlink'
})
should(o.download).eql({
path: 'media/original/holidays/seagull.mp4',
rel: 'fs:symlink'
})
})
it('can point downloads to an existing link', function () {
var o = output.paths('holidays/seagull.mp4', 'video', {
downloadVideos: 'link',
downloadLinkPrefix: '../myphotos'
})
should(o.download).eql({
path: '../myphotos/holidays/seagull.mp4',
rel: 'fs:link'
})
})
})
describe('Download links', function () {
it('can use a relative link prefix', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'link',
downloadLinkPrefix: '../myphotos'
})
should(o.download).eql({
path: '../myphotos/holidays/beach.jpg',
rel: 'fs:link'
})
})
it('can use a relative link prefix ending with a slash', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'link',
downloadLinkPrefix: '../myphotos/'
})
should(o.download).eql({
path: '../myphotos/holidays/beach.jpg',
rel: 'fs:link'
})
})
it('can use an absolute link prefix', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'link',
downloadLinkPrefix: '/Photos'
})
should(o.download).eql({
path: '/Photos/holidays/beach.jpg',
rel: 'fs:link'
})
})
it('can use an absolute link prefix ending with a slash', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'link',
downloadLinkPrefix: '/Photos/'
})
should(o.download).eql({
path: '/Photos/holidays/beach.jpg',
rel: 'fs:link'
})
})
it('can use a URL prefix', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'link',
downloadLinkPrefix: 'http://mygallery.com/photos'
})
should(o.download).eql({
path: 'http://mygallery.com/photos/holidays/beach.jpg',
rel: 'fs:link'
})
})
it('can use a URL prefix ending with a slash', function () {
var o = output.paths('holidays/beach.jpg', 'image', {
downloadPhotos: 'link',
downloadLinkPrefix: 'http://mygallery.com/photos/'
})
should(o.download).eql({
path: 'http://mygallery.com/photos/holidays/beach.jpg',
rel: 'fs:link'
})
})
})
})