mirror of
https://github.com/thumbsup/thumbsup
synced 2024-11-11 07:10:26 +00:00
feat(albums): --albums-from can be a list of patterns with special keywords
- %path expands to the path of the photo/video - %keywords expands to the IPTC keywords of the photo - {format} expands to the photo's EXIF date, e.g. {YYYY MM}
This commit is contained in:
parent
23f19566d0
commit
286dc8d15f
@ -67,14 +67,9 @@ const OPTIONS = {
|
|||||||
|
|
||||||
'albums-from': {
|
'albums-from': {
|
||||||
group: 'Album options:',
|
group: 'Album options:',
|
||||||
description: 'How to group media into albums',
|
description: 'How files are grouped into albums',
|
||||||
choices: ['folders', 'date'],
|
type: 'array',
|
||||||
'default': 'folders'
|
'default': ['%path']
|
||||||
},
|
|
||||||
'albums-date-format': {
|
|
||||||
group: 'Album options:',
|
|
||||||
description: 'How albums are named in <date> mode [moment.js pattern]',
|
|
||||||
'default': 'YYYY-MM'
|
|
||||||
},
|
},
|
||||||
'sort-albums-by': {
|
'sort-albums-by': {
|
||||||
group: 'Album options:',
|
group: 'Album options:',
|
||||||
@ -178,6 +173,11 @@ const OPTIONS = {
|
|||||||
description: 'Copy and allow download of full-size videos',
|
description: 'Copy and allow download of full-size videos',
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
'default': false
|
'default': false
|
||||||
|
},
|
||||||
|
'albums-date-format': {
|
||||||
|
group: 'Album options:',
|
||||||
|
description: 'How albums are named in <date> mode [moment.js pattern]',
|
||||||
|
'default': 'YYYY-MM'
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
41
src/input/album-mapper.js
Normal file
41
src/input/album-mapper.js
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Returns all albums that a file should belong to,
|
||||||
|
based on the --albums-from array of patterns provided
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
const _ = require('lodash')
|
||||||
|
const albumPattern = require('./album-pattern')
|
||||||
|
|
||||||
|
class AlbumMapper {
|
||||||
|
constructor (opts) {
|
||||||
|
const patterns = opts.albumsFrom || '%path'
|
||||||
|
this.patterns = patterns.map(pattern => load(pattern, opts.albumsDateFormat))
|
||||||
|
}
|
||||||
|
getAlbums (file) {
|
||||||
|
return _.flatMap(this.patterns, pattern => pattern(file))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function load (pattern, dateFormat) {
|
||||||
|
// legacy short-hand names (deprecated)
|
||||||
|
if (pattern === 'folders') {
|
||||||
|
return albumPattern.create('%path')
|
||||||
|
}
|
||||||
|
if (pattern === 'date') {
|
||||||
|
return albumPattern.create(`{${dateFormat}}`)
|
||||||
|
}
|
||||||
|
// custom mapper file
|
||||||
|
if (typeof pattern === 'string' && pattern.startsWith('file://')) {
|
||||||
|
const filepath = pattern.slice('file://'.length)
|
||||||
|
return require(filepath)
|
||||||
|
}
|
||||||
|
if (typeof pattern === 'string') {
|
||||||
|
return albumPattern.create(pattern)
|
||||||
|
}
|
||||||
|
// already a function
|
||||||
|
return pattern
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = AlbumMapper
|
51
src/input/album-pattern.js
Normal file
51
src/input/album-pattern.js
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
Returns a list of album names for every file.
|
||||||
|
Can be based on anything, e.g. directory name, date, metadata keywords...
|
||||||
|
e.g. `Holidays/London/IMG_00001.jpg` -> `Holidays/London`
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
const moment = require('moment')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
const TOKEN_REGEX = /%[a-z]+/g
|
||||||
|
const DATE_REGEX = /{[^}]+}/g
|
||||||
|
|
||||||
|
const TOKEN_FUNC = {
|
||||||
|
'%path': file => path.dirname(file.path)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.create = pattern => {
|
||||||
|
const cache = {
|
||||||
|
usesTokens: TOKEN_REGEX.test(pattern),
|
||||||
|
usesDates: DATE_REGEX.test(pattern),
|
||||||
|
usesKeywords: pattern.indexOf('%keywords') > -1
|
||||||
|
}
|
||||||
|
// return a standard mapper function (file => album names)
|
||||||
|
return file => {
|
||||||
|
var album = pattern
|
||||||
|
// replace known tokens
|
||||||
|
if (cache.usesTokens) {
|
||||||
|
album = album.replace(TOKEN_REGEX, token => replaceToken(file, token))
|
||||||
|
}
|
||||||
|
if (cache.usesDates) {
|
||||||
|
album = album.replace(DATE_REGEX, format => replaceDate(file, format))
|
||||||
|
}
|
||||||
|
// create one album per keyword if required
|
||||||
|
if (cache.usesKeywords) {
|
||||||
|
return file.meta.keywords.map(k => album.replace('%keywords', k))
|
||||||
|
} else {
|
||||||
|
return [album]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceToken (file, token) {
|
||||||
|
const fn = TOKEN_FUNC[token]
|
||||||
|
return fn ? fn(file) : token
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceDate (file, format) {
|
||||||
|
const fmt = format.slice(1, -1)
|
||||||
|
return moment(file.meta.date).format(fmt)
|
||||||
|
}
|
@ -19,13 +19,16 @@ function group (collection, mapper) {
|
|||||||
'.': new Album('Home')
|
'.': new Album('Home')
|
||||||
}
|
}
|
||||||
// put all files in the right albums
|
// put all files in the right albums
|
||||||
|
// a file can be in multiple albums
|
||||||
collection.forEach(function (file) {
|
collection.forEach(function (file) {
|
||||||
var groupName = mapper(file)
|
const albums = mapper.getAlbums(file)
|
||||||
if (!groupName || groupName === '/') {
|
albums.forEach(albumPath => {
|
||||||
groupName = '.'
|
if (!albumPath || albumPath === '/') {
|
||||||
}
|
albumPath = '.'
|
||||||
createAlbumHierarchy(groups, groupName)
|
}
|
||||||
groups[groupName].files.push(file)
|
createAlbumHierarchy(groups, albumPath)
|
||||||
|
groups[albumPath].files.push(file)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
// return the top-level album
|
// return the top-level album
|
||||||
return groups['.']
|
return groups['.']
|
||||||
|
@ -1,23 +0,0 @@
|
|||||||
/*
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
Returns the target album path for a single file.
|
|
||||||
Can be based on anything, e.g. directory name, date, metadata keywords...
|
|
||||||
e.g. `Holidays/London/IMG_00001.jpg` -> `Holidays/London`
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
const moment = require('moment')
|
|
||||||
const path = require('path')
|
|
||||||
|
|
||||||
exports.create = function (opts) {
|
|
||||||
var mapper = null
|
|
||||||
if (opts.albumsFrom === 'folders') {
|
|
||||||
mapper = (file) => path.dirname(file.path)
|
|
||||||
} else if (opts.albumsFrom === 'date') {
|
|
||||||
var dateFormat = opts.albumsDateFormat || 'YYYY MMMM'
|
|
||||||
mapper = (file) => moment(file.meta.date).format(dateFormat)
|
|
||||||
} else {
|
|
||||||
throw new Error('Invalid <albumsFrom> option')
|
|
||||||
}
|
|
||||||
return mapper
|
|
||||||
}
|
|
@ -8,7 +8,7 @@ Caches the results in <thumbsup.db> for faster re-runs
|
|||||||
const hierarchy = require('../input/hierarchy.js')
|
const hierarchy = require('../input/hierarchy.js')
|
||||||
const Index = require('../components/index/index')
|
const Index = require('../components/index/index')
|
||||||
const info = require('debug')('thumbsup:info')
|
const info = require('debug')('thumbsup:info')
|
||||||
const mapper = require('../input/mapper')
|
const AlbumMapper = require('../input/album-mapper')
|
||||||
const Metadata = require('../model/metadata')
|
const Metadata = require('../model/metadata')
|
||||||
const File = require('../model/file')
|
const File = require('../model/file')
|
||||||
const Observable = require('zen-observable')
|
const Observable = require('zen-observable')
|
||||||
@ -49,8 +49,8 @@ exports.run = function (opts, callback) {
|
|||||||
|
|
||||||
// finished, we can create the albums
|
// finished, we can create the albums
|
||||||
emitter.on('done', stats => {
|
emitter.on('done', stats => {
|
||||||
const albumMapper = mapper.create(opts)
|
const mapper = new AlbumMapper(opts)
|
||||||
const album = hierarchy.createAlbums(files, albumMapper, opts)
|
const album = hierarchy.createAlbums(files, mapper, opts)
|
||||||
callback(null, files, album)
|
callback(null, files, album)
|
||||||
observer.complete()
|
observer.complete()
|
||||||
})
|
})
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
const Picasa = require('../input/picasa')
|
|
||||||
const mapper = require('../input/mapper')
|
|
||||||
const hierarchy = require('../input/hierarchy.js')
|
|
||||||
const File = require('../model/file')
|
|
||||||
const Metadata = require('../model/metadata')
|
|
||||||
|
|
||||||
exports.run = function (database, opts, callback) {
|
|
||||||
const picasaReader = new Picasa()
|
|
||||||
// create a flat array of files
|
|
||||||
const files = database.map(entry => {
|
|
||||||
// create standarised metadata model
|
|
||||||
const picasa = picasaReader.file(entry.SourceFile)
|
|
||||||
const meta = new Metadata(entry, picasa || {})
|
|
||||||
// create a file entry for the albums
|
|
||||||
return new File(entry, meta, opts)
|
|
||||||
})
|
|
||||||
// create the full album hierarchy
|
|
||||||
const albumMapper = mapper.create(opts)
|
|
||||||
const album = hierarchy.createAlbums(files, albumMapper, opts)
|
|
||||||
// return the results
|
|
||||||
return {files, album}
|
|
||||||
}
|
|
@ -5,14 +5,21 @@ const options = require('../../bin/options.js')
|
|||||||
const BASE_ARGS = ['--input', 'photos', '--output', 'website']
|
const BASE_ARGS = ['--input', 'photos', '--output', 'website']
|
||||||
|
|
||||||
describe('options', function () {
|
describe('options', function () {
|
||||||
it('--input is converted to an absolute path', function () {
|
it('--input is converted to an absolute path', () => {
|
||||||
const opts = options.get(BASE_ARGS)
|
const opts = options.get(BASE_ARGS)
|
||||||
should(opts.input).eql(path.join(process.cwd(), 'photos'))
|
should(opts.input).eql(path.join(process.cwd(), 'photos'))
|
||||||
})
|
})
|
||||||
it('--output is converted to an absolute path', function () {
|
it('--output is converted to an absolute path', () => {
|
||||||
const opts = options.get(BASE_ARGS)
|
const opts = options.get(BASE_ARGS)
|
||||||
should(opts.output).eql(path.join(process.cwd(), 'website'))
|
should(opts.output).eql(path.join(process.cwd(), 'website'))
|
||||||
})
|
})
|
||||||
|
describe('--albums-from', () => {
|
||||||
|
it('can be a single pattern value', () => {
|
||||||
|
const args = BASE_ARGS.concat(['--albums-from "%path"'])
|
||||||
|
const opts = options.get(args)
|
||||||
|
should(opts.albumsFrom).eql(['%path'])
|
||||||
|
})
|
||||||
|
})
|
||||||
describe('deprecated', () => {
|
describe('deprecated', () => {
|
||||||
it('--original-photos false', () => {
|
it('--original-photos false', () => {
|
||||||
const args = BASE_ARGS.concat(['--original-photos false'])
|
const args = BASE_ARGS.concat(['--original-photos false'])
|
||||||
|
@ -11,7 +11,9 @@ exports.exiftool = function (opts) {
|
|||||||
MIMEType: opts.mimeType || 'image/jpg'
|
MIMEType: opts.mimeType || 'image/jpg'
|
||||||
},
|
},
|
||||||
EXIF: {},
|
EXIF: {},
|
||||||
IPTC: {},
|
IPTC: {
|
||||||
|
Keywords: opts.keywords
|
||||||
|
},
|
||||||
XMP: {},
|
XMP: {},
|
||||||
H264: {},
|
H264: {},
|
||||||
QuickTime: {}
|
QuickTime: {}
|
||||||
|
53
test/input/album-mapper.spec.js
Normal file
53
test/input/album-mapper.spec.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
const should = require('should/as-function')
|
||||||
|
const AlbumMapper = require('../../src/input/album-mapper.js')
|
||||||
|
const fixtures = require('../fixtures.js')
|
||||||
|
|
||||||
|
const TEST_FILE = fixtures.photo({
|
||||||
|
path: 'Holidays/IMG_0001.jpg',
|
||||||
|
date: '2016:07:14 12:07:41'
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('Album mapper', function () {
|
||||||
|
it('can use a single string pattern', function () {
|
||||||
|
const mapper = new AlbumMapper({
|
||||||
|
albumsFrom: ['%path']
|
||||||
|
})
|
||||||
|
should(mapper.getAlbums(TEST_FILE)).eql(['Holidays'])
|
||||||
|
})
|
||||||
|
it('can use a single function (for testing)', function () {
|
||||||
|
const custom = file => 'hello'
|
||||||
|
const mapper = new AlbumMapper({
|
||||||
|
albumsFrom: [custom]
|
||||||
|
})
|
||||||
|
should(mapper.getAlbums(TEST_FILE)).eql(['hello'])
|
||||||
|
})
|
||||||
|
it('can provide multiple string patterns', function () {
|
||||||
|
const mapper = new AlbumMapper({
|
||||||
|
albumsFrom: ['%path', '{YYYY}']
|
||||||
|
})
|
||||||
|
should(mapper.getAlbums(TEST_FILE)).eql(['Holidays', '2016'])
|
||||||
|
})
|
||||||
|
it('merges all albums into a single array', function () {
|
||||||
|
const custom1 = file => ['one']
|
||||||
|
const custom2 = file => ['two', 'three']
|
||||||
|
const mapper = new AlbumMapper({
|
||||||
|
albumsFrom: [custom1, custom2]
|
||||||
|
})
|
||||||
|
should(mapper.getAlbums(TEST_FILE)).eql(['one', 'two', 'three'])
|
||||||
|
})
|
||||||
|
describe('deprecated options', () => {
|
||||||
|
it('can use <folders> to mean %path', () => {
|
||||||
|
const mapper = new AlbumMapper({
|
||||||
|
albumsFrom: ['folders']
|
||||||
|
})
|
||||||
|
should(mapper.getAlbums(TEST_FILE)).eql(['Holidays'])
|
||||||
|
})
|
||||||
|
it('can use <date> to mean {date}', () => {
|
||||||
|
const mapper = new AlbumMapper({
|
||||||
|
albumsFrom: ['date'],
|
||||||
|
albumsDateFormat: 'YYYY MM'
|
||||||
|
})
|
||||||
|
should(mapper.getAlbums(TEST_FILE)).eql(['2016 07'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
98
test/input/album-pattern.spec.js
Normal file
98
test/input/album-pattern.spec.js
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
const should = require('should/as-function')
|
||||||
|
const pattern = require('../../src/input/album-pattern.js')
|
||||||
|
const fixtures = require('../fixtures.js')
|
||||||
|
|
||||||
|
describe('AlbumPattern', function () {
|
||||||
|
describe('text', () => {
|
||||||
|
it('can return a plain text album name', function () {
|
||||||
|
const func = pattern.create('Holidays/Canada')
|
||||||
|
const file = fixtures.photo()
|
||||||
|
should(func(file)).eql(['Holidays/Canada'])
|
||||||
|
})
|
||||||
|
it('can have extra text around keywords', function () {
|
||||||
|
const func = pattern.create('Holidays/%path')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
path: 'Canada/IMG_0001.jpg'
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['Holidays/Canada'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('path', () => {
|
||||||
|
it('%path returns the relative path of the photo', function () {
|
||||||
|
const func = pattern.create('%path')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
path: 'Holidays/IMG_0001.jpg'
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['Holidays'])
|
||||||
|
})
|
||||||
|
it('%path includes all subfolders', function () {
|
||||||
|
const func = pattern.create('%path')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
path: 'Holidays/Canada/IMG_0001.jpg'
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['Holidays/Canada'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('creation date', () => {
|
||||||
|
it('can use a moment.js format: {YYYY MM}', function () {
|
||||||
|
const func = pattern.create('{YYYY MM}')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
date: '2016:07:14 12:07:41'
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['2016 07'])
|
||||||
|
})
|
||||||
|
it('can include slashes in the format: {YYYY/MM}', function () {
|
||||||
|
const func = pattern.create('{YYYY/MM}')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
date: '2016:07:14 12:07:41'
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['2016/07'])
|
||||||
|
})
|
||||||
|
it('can have multiple dates in the same pattern: {YYYY}/{MM}', function () {
|
||||||
|
const func = pattern.create('{YYYY}/{MM}')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
date: '2016:07:14 12:07:41'
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['2016/07'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('keywords', () => {
|
||||||
|
it('can return a single keyword', () => {
|
||||||
|
const func = pattern.create('%keywords')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
keywords: ['beach']
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['beach'])
|
||||||
|
})
|
||||||
|
it('can return multiple keyword', () => {
|
||||||
|
const func = pattern.create('%keywords')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
keywords: ['beach', 'sunset']
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['beach', 'sunset'])
|
||||||
|
})
|
||||||
|
it('can use plain text around the keywords', () => {
|
||||||
|
const func = pattern.create('Tags/%keywords')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
keywords: ['beach', 'sunset']
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['Tags/beach', 'Tags/sunset'])
|
||||||
|
})
|
||||||
|
it('does not return any albums if the photo does not have keywords', () => {
|
||||||
|
const func = pattern.create('{YYYY}/tags/%keywords')
|
||||||
|
const file = fixtures.photo()
|
||||||
|
should(func(file)).eql([])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
describe('Complex patterns', () => {
|
||||||
|
it('can mix several tokens inside a complex pattern', () => {
|
||||||
|
const func = pattern.create('{YYYY}/%path/%keywords')
|
||||||
|
const file = fixtures.photo({
|
||||||
|
path: 'Holidays/IMG_0001.jpg',
|
||||||
|
date: '2016:07:14 12:07:41',
|
||||||
|
keywords: ['beach', 'sunset']
|
||||||
|
})
|
||||||
|
should(func(file)).eql(['2016/Holidays/beach', '2016/Holidays/sunset'])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -11,20 +11,20 @@ describe('hierarchy', function () {
|
|||||||
|
|
||||||
describe('root album', function () {
|
describe('root album', function () {
|
||||||
it('creates a root album (homepage) to put all sub-albums', function () {
|
it('creates a root album (homepage) to put all sub-albums', function () {
|
||||||
const mapper = (file) => 'all'
|
const mapper = mockMapper(file => ['all'])
|
||||||
const home = hierarchy.createAlbums([], mapper, {})
|
const home = hierarchy.createAlbums([], mapper, {})
|
||||||
should(home.title).eql('Home')
|
should(home.title).eql('Home')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('defaults the homepage to index.html', function () {
|
it('defaults the homepage to index.html', function () {
|
||||||
const mapper = (file) => 'all'
|
const mapper = mockMapper(file => ['all'])
|
||||||
const home = hierarchy.createAlbums([], mapper, {})
|
const home = hierarchy.createAlbums([], mapper, {})
|
||||||
should(home.path).eql('index.html')
|
should(home.path).eql('index.html')
|
||||||
should(home.url).eql('index.html')
|
should(home.url).eql('index.html')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can configure the homepage path', function () {
|
it('can configure the homepage path', function () {
|
||||||
const mapper = (file) => 'all'
|
const mapper = mockMapper(file => ['all'])
|
||||||
const home = hierarchy.createAlbums([], mapper, {index: 'default.html'})
|
const home = hierarchy.createAlbums([], mapper, {index: 'default.html'})
|
||||||
should(home.path).eql('default.html')
|
should(home.path).eql('default.html')
|
||||||
should(home.url).eql('default.html')
|
should(home.url).eql('default.html')
|
||||||
@ -39,7 +39,7 @@ describe('hierarchy', function () {
|
|||||||
fixtures.photo({path: 'IMG_000001.jpg'}),
|
fixtures.photo({path: 'IMG_000001.jpg'}),
|
||||||
fixtures.photo({path: 'IMG_000002.jpg'})
|
fixtures.photo({path: 'IMG_000002.jpg'})
|
||||||
]
|
]
|
||||||
const mapper = file => value
|
const mapper = mockMapper(file => [value])
|
||||||
const home = hierarchy.createAlbums(files, mapper)
|
const home = hierarchy.createAlbums(files, mapper)
|
||||||
should(home.albums.length).eql(0)
|
should(home.albums.length).eql(0)
|
||||||
should(home.files.length).eql(2)
|
should(home.files.length).eql(2)
|
||||||
@ -55,7 +55,7 @@ describe('hierarchy', function () {
|
|||||||
fixtures.photo({path: 'IMG_000001.jpg'}),
|
fixtures.photo({path: 'IMG_000001.jpg'}),
|
||||||
fixtures.photo({path: 'IMG_000002.jpg'})
|
fixtures.photo({path: 'IMG_000002.jpg'})
|
||||||
]
|
]
|
||||||
const mapper = (file) => 'all'
|
const mapper = mockMapper(file => ['all'])
|
||||||
const home = hierarchy.createAlbums(files, mapper)
|
const home = hierarchy.createAlbums(files, mapper)
|
||||||
should(home.albums.length).eql(1)
|
should(home.albums.length).eql(1)
|
||||||
should(home.albums[0].title).eql('all')
|
should(home.albums[0].title).eql('all')
|
||||||
@ -67,7 +67,7 @@ describe('hierarchy', function () {
|
|||||||
fixtures.photo({path: 'one/IMG_000001.jpg'}),
|
fixtures.photo({path: 'one/IMG_000001.jpg'}),
|
||||||
fixtures.photo({path: 'two/IMG_000002.jpg'})
|
fixtures.photo({path: 'two/IMG_000002.jpg'})
|
||||||
]
|
]
|
||||||
const mapper = (file) => path.dirname(file.path)
|
const mapper = mockMapper(file => [path.dirname(file.path)])
|
||||||
const home = hierarchy.createAlbums(files, mapper)
|
const home = hierarchy.createAlbums(files, mapper)
|
||||||
should(home.albums.length).eql(2)
|
should(home.albums.length).eql(2)
|
||||||
should(home.albums[0].title).eql('one')
|
should(home.albums[0].title).eql('one')
|
||||||
@ -81,7 +81,7 @@ describe('hierarchy', function () {
|
|||||||
fixtures.photo({path: 'IMG_000001.jpg'}),
|
fixtures.photo({path: 'IMG_000001.jpg'}),
|
||||||
fixtures.photo({path: 'IMG_000002.jpg'})
|
fixtures.photo({path: 'IMG_000002.jpg'})
|
||||||
]
|
]
|
||||||
const mapper = (file) => 'one/two'
|
const mapper = mockMapper(file => ['one/two'])
|
||||||
const home = hierarchy.createAlbums(files, mapper)
|
const home = hierarchy.createAlbums(files, mapper)
|
||||||
should(home.albums.length).eql(1)
|
should(home.albums.length).eql(1)
|
||||||
should(home.albums[0].title).eql('one')
|
should(home.albums[0].title).eql('one')
|
||||||
@ -95,7 +95,7 @@ describe('hierarchy', function () {
|
|||||||
fixtures.photo({path: 'one/IMG_000001.jpg'}),
|
fixtures.photo({path: 'one/IMG_000001.jpg'}),
|
||||||
fixtures.photo({path: 'one/two/IMG_000002.jpg'})
|
fixtures.photo({path: 'one/two/IMG_000002.jpg'})
|
||||||
]
|
]
|
||||||
const mapper = (file) => path.dirname(file.path)
|
const mapper = mockMapper(file => [path.dirname(file.path)])
|
||||||
const home = hierarchy.createAlbums(files, mapper)
|
const home = hierarchy.createAlbums(files, mapper)
|
||||||
should(home.albums.length).eql(1)
|
should(home.albums.length).eql(1)
|
||||||
should(home.albums[0].title).eql('one')
|
should(home.albums[0].title).eql('one')
|
||||||
@ -106,3 +106,9 @@ describe('hierarchy', function () {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function mockMapper (fn) {
|
||||||
|
return {
|
||||||
|
getAlbums: fn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,32 +0,0 @@
|
|||||||
var should = require('should/as-function')
|
|
||||||
var mapper = require('../../src/input/mapper.js')
|
|
||||||
var fixtures = require('../fixtures.js')
|
|
||||||
|
|
||||||
describe('mapper', function () {
|
|
||||||
it('can create a path mapper', function () {
|
|
||||||
const map = mapper.create({albumsFrom: 'folders'})
|
|
||||||
const entry = fixtures.photo({
|
|
||||||
path: 'holidays/canada/IMG_0001.jpg'
|
|
||||||
})
|
|
||||||
should(map(entry)).eql('holidays/canada')
|
|
||||||
})
|
|
||||||
it('can create a default date mapper', function () {
|
|
||||||
const map = mapper.create({albumsFrom: 'date'})
|
|
||||||
const entry = fixtures.photo({
|
|
||||||
path: 'holidays/canada/IMG_0001.jpg',
|
|
||||||
date: '2016:07:14 12:07:41'
|
|
||||||
})
|
|
||||||
should(map(entry)).eql('2016 July')
|
|
||||||
})
|
|
||||||
it('can create a custom date mapper', function () {
|
|
||||||
const map = mapper.create({
|
|
||||||
albumsFrom: 'date',
|
|
||||||
albumsDateFormat: 'YYYY/MM'
|
|
||||||
})
|
|
||||||
const entry = fixtures.photo({
|
|
||||||
path: 'holidays/canada/IMG_0001.jpg',
|
|
||||||
date: '2016:07:14 12:07:41'
|
|
||||||
})
|
|
||||||
should(map(entry)).eql('2016/07')
|
|
||||||
})
|
|
||||||
})
|
|
Loading…
Reference in New Issue
Block a user