fix: support files and albums with special characters

Fixes #240
pull/231/head
Romain 3 years ago
parent 4ee04723b2
commit 008bb4c54f

@ -9,6 +9,8 @@ A single photo/video could exist in multiple albums
const _ = require('lodash')
const path = require('path')
const slugify = require('slugify')
const url = require('./url')
var index = 0
// number of images to show in the album preview grid
@ -59,7 +61,7 @@ Album.prototype.finalize = function (options, parent) {
this.basename = parent.basename + '-' + this.basename
}
this.path = path.join(albumsOutputFolder, this.basename + '.html')
this.url = this.getUrl(albumsOutputFolder, this.basename + '.html')
this.url = url.fromPath(this.path)
this.depth = parent.depth + 1
}
// path to the optional ZIP file
@ -110,18 +112,6 @@ Album.prototype.calculateSummary = function () {
this.summary = _.compact(items).join(', ')
}
Album.prototype.getUrl = function (albumsOutputFolder, documentPath) {
// Encode characters like ?, # and space, however, undo the encoding for slashes.
// This is needed to support albums and files with these URI-unfriendly characters.
// See https://github.com/thumbsup/thumbsup/issues/234
let url = encodeURIComponent(albumsOutputFolder + '/' + documentPath).replace(/%2F/g, '/')
// Shorten the url if it starts with './'
if (url.startsWith('./')) {
url = url.slice(2)
}
return url
}
Album.prototype.sort = function (options) {
const sortAlbumsBy = getItemOrLast(options.sortAlbumsBy, this.depth)
const sortAlbumsDirection = getItemOrLast(options.sortAlbumsDirection, this.depth)

@ -9,6 +9,7 @@ const _ = require('lodash')
const path = require('path')
const moment = require('moment')
const output = require('./output')
const url = require('./url')
const MIME_REGEX = /([^/]+)\/(.*)/
const EXIF_DATE_FORMAT = 'YYYY:MM:DD HH:mm:ssZ'
@ -24,7 +25,7 @@ class File {
this.type = mediaType(dbEntry)
this.isVideo = (this.type === 'video')
this.output = output.paths(this.path, this.type, opts || {})
this.urls = _.mapValues(this.output, o => pathToUrl(o.path))
this.urls = _.mapValues(this.output, o => url.fromPath(o.path))
this.meta = meta
}
}
@ -40,11 +41,4 @@ function mediaType (dbEntry) {
return 'unknown'
}
function pathToUrl (filepath) {
// Encode characters like ?, #, and space, however, undo the encoding for slashes.
// This is needed to support albums and files with these URI-unfriendly characters.
// See https://github.com/thumbsup/thumbsup/issues/234
return encodeURIComponent(filepath.replace('\\', '/')).replace(/%2F/g, '/')
}
module.exports = File

@ -0,0 +1,9 @@
const process = require('process')
exports.fromPath = function (filepath) {
if (process.platform === 'win32') {
filepath = filepath.replace(/\\/g, '/')
}
const encoded = encodeURIComponent(filepath)
return encoded.replace(/%2F/g, '/')
}

@ -90,24 +90,6 @@ describe('Album', function () {
should(root.albums[0].url).eql('2010.html')
})
it('encodes # characters when calculating the URL for the browser', function () {
const root = new Album({
title: 'home',
albums: [new Album({ title: '#2010#' })]
})
root.finalize({ index: 'index.html' })
should(root.albums[0].url).eql('%232010%23.html')
})
it('encodes ? characters when calculating the URL for the browser', function () {
const root = new Album({
title: 'home',
albums: [new Album({ title: '?2010?' })]
})
root.finalize({ index: 'index.html' })
should(root.albums[0].url).eql('%3F2010%3F.html')
})
it('calculates the output path with a target folder (slashes match the OS)', function () {
const root = new Album({
title: 'home',
@ -125,7 +107,7 @@ describe('Album', function () {
})
root.finalize({ index: 'index.html', albumsOutputFolder: 'albums' })
should(root.path).eql('index.html')
should(root.albums[0].path).eql('albums/2010.html')
should(root.albums[0].url).eql('albums/2010.html')
})
})

@ -0,0 +1,58 @@
const _ = require('lodash')
const process = require('process')
const should = require('should/as-function')
const url = require('../../src/model/url')
const realPlatform = process.platform
describe('URLs', () => {
it('escapes non-URL-friendly characters', () => {
const chars = {
'%': '%25',
'#': '%23',
'?': '%3F'
}
_.each(chars, (encoded, character) => {
const res = url.fromPath(`photos/image${character}.jpg`)
should(res).eql(`photos/image${encoded}.jpg`)
})
})
describe('Linux', () => {
before(() => {
Object.defineProperty(process, 'platform', { value: 'linux' })
})
after(() => {
Object.defineProperty(process, 'platform', { value: realPlatform })
})
it('converts standard Linux paths', function () {
const res = url.fromPath('photos/holidays/IMG_001.jpg')
should(res).eql('photos/holidays/IMG_001.jpg')
})
it('encodes backslash in Linux paths', function () {
const res = url.fromPath('photos/my\\holidays.jpg')
should(res).eql('photos/my%5Cholidays.jpg')
})
})
describe('Windows', () => {
before(() => {
Object.defineProperty(process, 'platform', { value: 'win32' })
})
after(() => {
Object.defineProperty(process, 'platform', { value: realPlatform })
})
it('converts standard Windows paths', function () {
const res = url.fromPath('photos\\holidays\\IMG_001.jpg')
should(res).eql('photos/holidays/IMG_001.jpg')
})
it('slashes are also valid path separators on Windows', function () {
const res = url.fromPath('photos/holidays/IMG_001.jpg')
should(res).eql('photos/holidays/IMG_001.jpg')
})
})
})
Loading…
Cancel
Save