Updated thumbnail creation to create a scaled version

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-09-20 20:44:13 -07:00
parent baf152d57c
commit e9fd50a054
3 changed files with 169 additions and 166 deletions

View File

@ -151,7 +151,7 @@ Polymer({
download: function(event) { download: function(event) {
console.log("Download tapped"); console.log("Download tapped");
var anchor = document.createElement('a'); var anchor = document.createElement('a');
anchor.href = this.src; anchor.href = this.base + this.item.path + "/" + this.item.filename;
anchor.setAttribute("download", this.src.replace(/.*\/([^/]+)$/, "$1")); anchor.setAttribute("download", this.src.replace(/.*\/([^/]+)$/, "$1"));
anchor.style.display = "none"; anchor.style.display = "none";
document.body.appendChild(anchor); document.body.appendChild(anchor);
@ -233,6 +233,12 @@ Polymer({
}, },
attached: function() { attached: function() {
var base = document.querySelector("base");
if (base) {
this.base = new URL(base.href).pathname.replace(/\/$/, ""); /* Remove trailing slash if there */
} else {
this.base = "";
}
} }
}); });
</script> </script>

View File

@ -876,7 +876,8 @@
this.lightBoxElement.selected = false; this.lightBoxElement.selected = false;
} }
this.$.lightbox.src = this.base + el.item.path + "/" + el.item.filename; this.$.lightbox.item = el.item;
this.$.lightbox.src = this.base + el.item.path + "/thumbs/scaled/" + el.item.filename;
this.lightBoxElement = el; this.lightBoxElement = el;
this.lightBoxElement.selected = true; this.lightBoxElement.selected = true;
this.disableScrolling = true; this.disableScrolling = true;

View File

@ -71,112 +71,83 @@ function scanDir(parent, path) {
} }
}).then(function(parent) { }).then(function(parent) {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
console.log("Scanning " + replacements.path); console.log("Scanning ..." + replacements.path);
fs.readdir(path, function(err, files) { fs.readdir(path, function(err, files) {
if (err) { if (err) {
console.warn(" Could not readdir " + path); console.warn("Could not readdir " + path);
return resolve(null); return resolve([]);
} }
scanning++; return resolve(files);
});
}).then(function(files) {
scanning++;
let hasThumbs = false; /* Remove 'thumbs' and 'raw' directories from being processed */
for (let i = 0; i < files.length; i++) { files = files.filter(function(file) {
if (files[i] == "thumbs") { for (var i = 0; i < files.length; i++) {
hasThumbs = true; /* If this file has an original NEF/ORF on the system, don't add the JPG to the DB */
break; if (rawExtension.exec(files[i]) && file == files[i].replace(rawExtension, ".jpg")) {
return false;
}
/* If there is a different CASE (eg. JPG vs jpg) don't add it, and remove the 'lower case'
* version from disk. */
if (file != files[i] && file.toUpperCase() == files[i]) {
removeNewerFile(path, file, files[i]);
console.log("Duplicate file in " + path + ": ", file, files[i]);
return false;
} }
} }
let tmp; return file != "raw" && file != "thumbs" && file != ".git" && file != "corrupt";
if (!hasThumbs) { });
tmp = mkdirPromise(path + "/thumbs");
} else {
tmp = Promise.resolve();
}
/* Remove 'thumbs' and 'raw' directories from being processed */ return mkdir(path + "/thumbs/scaled").then(function() {
files = files.filter(function(file) { return Promise.map(files, function(file) {
for (var i = 0; i < files.length; i++) { let filepath = path + "/" + file;
/* If this file has an original NEF/ORF on the system, don't add the JPG to the DB */
if (rawExtension.exec(files[i]) && file == files[i].replace(rawExtension, ".jpg")) {
return false;
}
/* If there is a different CASE (eg. JPG vs jpg) don't add it, and remove the 'lower case' return stat(filepath).then(function(stats) {
* version from disk. */ if (stats.isDirectory()) {
if (file != files[i] && file.toUpperCase() == files[i]) { return scanDir(parent, filepath).catch(function(error) {
removeNewerFile(path, file, files[i]); console.warn("Could not scanDir " + filepath + ": " + error);
console.log("Duplicate file in " + path + ": ", file, files[i]);
return false;
}
}
return file != "raw" && file != "thumbs" && file != ".git" && file != "corrupt";
});
return tmp.then(function() {
return Promise.map(files, function(file) {
let filepath = path + "/" + file;
return new Promise(function(resolve, reject) {
fs.stat(filepath, function(err, stats) {
if (err) {
console.warn("Could not stat " + filepath);
return resolve(false);
}
if (stats.isDirectory()) {
return scanDir(parent, filepath, stats).then(function(entry) {
return resolve(true);
}).catch(function(error) {
console.warn("scanDir failed");
return reject(error);
});
}
/* Check file extensions */
if (!re.exec(file)) {
return resolve(true);
}
const replacements = {
path: path.slice(picturesPath.length),
filename: file.replace(rawExtension, ".jpg") /* We will be converting from NEF/ORF => JPG */
};
replacements.path = replacements.path || "/";
return photoDB.sequelize.query("SELECT id FROM photos WHERE path=:path AND filename=:filename", {
replacements: replacements,
type: photoDB.sequelize.QueryTypes.SELECT
}).then(function(photo) {
if (photo.length == 0) {
processQueue.push([ replacements.path, file, stats.mtime, parent ]);
}
return resolve(true);
}).catch(function(error) {
console.error("Sequelize.query failed");
return reject(error);
});
}); });
});
}, {
concurrency: 1
}).then(function() {
scanning--;
if (scanning == 0) {
const endStamp = Date.now();
console.log("Scanning completed in " + Math.round(((endStamp - startStamp))) + "ms. " + processQueue.length + " items to process.");
} }
}).then(function() {
return resolve(); /* Check file extensions */
if (!re.exec(file)) {
return;
}
const replacements = {
path: path.slice(picturesPath.length),
filename: file.replace(rawExtension, ".jpg") /* We will be converting from NEF/ORF => JPG */
};
replacements.path = replacements.path || "/";
return photoDB.sequelize.query("SELECT id FROM photos WHERE path=:path AND filename=:filename", {
replacements: replacements,
type: photoDB.sequelize.QueryTypes.SELECT
}).then(function(photo) {
if (photo.length == 0) {
processQueue.push([ replacements.path, file, stats.mtime, parent ]);
}
}).catch(function(error) {
console.error("Sequelize.query failed: ", error);
});
}).catch(function(error) {
console.warn("Could not stat " + filepath + ": " + error);
}); });
}).catch(function(error) { }, {
console.error("Processing 'tmp' failed"); concurrency: 1
return reject(error); }).then(function() {
scanning--;
if (scanning == 0) {
const endStamp = Date.now();
console.log("Scanning completed in " + Math.round(((endStamp - startStamp))) + "ms. " + processQueue.length + " items to process.");
}
}); });
}); });
}); });
@ -190,44 +161,59 @@ let processRunning = false;
const { spawn } = require('child_process'); const { spawn } = require('child_process');
const sharp = require("sharp"), exif = require("exif-reader"); const sharp = require("sharp"), exif = require("exif-reader");
const stat = function (path) {
function mkdirPromise(path) {
if (path.indexOf(picturesPath) != 0) { if (path.indexOf(picturesPath) != 0) {
path = picturesPath + path; path = picturesPath + path;
} }
return new Promise(function(resolve, reject) { return new Promise(function (resolve, reject) {
fs.stat(path, function(err) { fs.stat(path, function (error, stats) {
if (err && err.code != 'ENOENT') { if (error) {
console.warn("Could not stat " + path); return reject(error);
return reject(); }
return resolve(stats);
});
});
}
const mkdir = function (_path) {
if (_path.indexOf(picturesPath) == 0) {
_path = _path.substring(picturesPath.length + 1);
}
let parts = _path.split("/"), path;
parts.unshift(picturesPath);
return Promise.mapSeries(parts, function (part) {
if (!path) {
path = picturesPath;
} else {
path += "/" + part;
}
return stat(path).catch(function (error) {
if (error.code != "ENOENT") {
throw error;
} }
if (!err) { return new Promise(function (resolve, reject) {
return resolve(); console.log("mkdir " + path);
} fs.mkdir(path, function (error) {
if (error) {
return reject(error);
}
fs.mkdir(path, function(err) { return resolve();
if (err && err.code != 'EEXIST') { });
return reject("Unable to create " + path + "\n" + err);
}
return resolve();
}); });
}); });
}); });
} }
function existsPromise(path) {
return new Promise(function(resolve, reject) { const exists = function(path) {
fs.stat(path, function(err, stats) { return stat(path).then(function() {
if (!err) { return true;
return resolve(true); }).catch(function() {
} return false;
if (err.code == 'ENOENT') { });
return resolve(false);
}
return reject(err);
});
})
} }
function convertRawToJpg(path, file) { function convertRawToJpg(path, file) {
@ -236,10 +222,10 @@ function convertRawToJpg(path, file) {
path = picturesPath + path; path = picturesPath + path;
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
fs.stat(path + "/" + file.replace(rawExtension, ".jpg"), function(err, stats) { return exists(path + "/" + file.replace(rawExtension, ".jpg")).then(function(exist) {
if (!err) { if (exist) {
console.log("Skipping already converted file: " + file); console.log("Skipping already converted file: " + file);
return resolve(); return;
} }
const ufraw = spawn("ufraw-batch", [ const ufraw = spawn("ufraw-batch", [
@ -259,30 +245,32 @@ function convertRawToJpg(path, file) {
stderr.push(data); stderr.push(data);
}); });
ufraw.on('exit', function(stderr, code, signal) { return new Promise(function(ufraw, resolve, reject) {
if (signal || code != 0) { ufraw.on('exit', function(stderr, code, signal) {
let error = "UFRAW for " + path + "/" + file + " returned an error: " + code + "\n" + signal + "\n" + stderr.join("\n") + "\n"; if (signal || code != 0) {
console.error(error); let error = "UFRAW for " + path + "/" + file + " returned an error: " + code + "\n" + signal + "\n" + stderr.join("\n") + "\n";
return moveCorrupt(path, file).then(function() { console.error(error);
console.warn("ufraw failed"); return moveCorrupt(path, file).then(function() {
return reject(error); console.warn("ufraw failed");
return reject(error);
}).catch(function(error) {
console.warn("moveCorrupt failed");
return reject(error);
});
}
return mkdir(path + "/raw").then(function() {
fs.rename(path + "/" + file, path + "/raw/" + file, function(err) {
if (err) {
console.error("Unable to move RAW file: " + path + "/" + file);
return reject(err);
}
return resolve();
});
}).catch(function(error) { }).catch(function(error) {
console.warn("moveCorrupt failed"); console.warn("mkdir failed");
return reject(error); return reject(error);
}); });
} }.bind(this, ufraw));
return mkdirPromise(path + "/raw").then(function() {
fs.rename(path + "/" + file, path + "/raw/" + file, function(err) {
if (err) {
console.error("Unable to move RAW file: " + path + "/" + file);
return reject(err);
}
return resolve();
});
}).catch(function(error) {
console.warn("mkdirPromise failed");
return reject(error);
});
}.bind(this, stderr)); }.bind(this, stderr));
}); });
}); });
@ -295,7 +283,7 @@ function moveCorrupt(path, file) {
console.warn("Moving corrupt file '" + file + "' to " + path + "/corrupt"); console.warn("Moving corrupt file '" + file + "' to " + path + "/corrupt");
return mkdirPromise(path + "/corrupt").then(function() { return mkdir(path + "/corrupt").then(function() {
return new Promise(function(resolve, reject) { return new Promise(function(resolve, reject) {
fs.rename(path + "/" + file, path + "/corrupt/" + file, function(err) { fs.rename(path + "/" + file, path + "/corrupt/" + file, function(err) {
if (err) { if (err) {
@ -323,17 +311,15 @@ function triggerWatcher() {
return Promise.map(processing, function(entry) { return Promise.map(processing, function(entry) {
var path = entry[0], file = entry[1], created = entry[2], albumId = entry[3]; var path = entry[0], file = entry[1], created = entry[2], albumId = entry[3];
// console.log("Processing " + src);
let tmp = Promise.resolve(file); let tmp = Promise.resolve(file);
/* If this is a Nikon RAW file, convert it to JPG and move to /raw dir */ /* If this is a Nikon RAW file, convert it to JPG and move to /raw dir */
if (rawExtension.exec(file)) { if (rawExtension.exec(file)) {
tmp = existsPromise(picturesPath + path + "/" + file.replace(rawExtension, ".jpg")).then(function(exists) { tmp = exists(picturesPath + path + "/" + file.replace(rawExtension, ".jpg")).then(function(exist) {
if (exists) { if (exist) {
return file.replace(rawExtension, ".jpg"); /* We converted from NEF/ORF => JPG */ return file.replace(rawExtension, ".jpg"); /* We converted from NEF/ORF => JPG */
} }
return mkdirPromise(picturesPath + path + "/raw").then(function() { return mkdir(picturesPath + path + "/raw").then(function() {
return convertRawToJpg(path, file); return convertRawToJpg(path, file);
}).then(function() { }).then(function() {
return file.replace(rawExtension, ".jpg"); /* We converted from NEF/ORF => JPG */ return file.replace(rawExtension, ".jpg"); /* We converted from NEF/ORF => JPG */
@ -343,7 +329,6 @@ function triggerWatcher() {
return tmp.then(function(file) { return tmp.then(function(file) {
var src = picturesPath + path + "/" + file, var src = picturesPath + path + "/" + file,
dst = picturesPath + path + "/thumbs/" + file,
image = sharp(src); image = sharp(src);
return image.limitInputPixels(1073741824).metadata().then(function(metadata) { return image.limitInputPixels(1073741824).metadata().then(function(metadata) {
@ -407,24 +392,35 @@ function triggerWatcher() {
replacements.taken = replacements.modified = date; replacements.taken = replacements.modified = date;
} }
return existsPromise(dst).then(function(exists) { let dst = picturesPath + path + "/thumbs/" + file;
let resize;
if (!exists) { return exists(dst).then(function(exist) {
resize = image.resize(256, 256).toFile(dst); if (exist) {
} else { return;
resize = Promise.resolve();
} }
return resize.then(function() { return image.resize(256, 256).toFile(dst).catch(function(error) {
return photoDB.sequelize.query("INSERT INTO photos " + console.error("Error resizing image: " + dst, error);
"(albumId,path,filename,added,modified,taken,width,height,name)" +
"VALUES(:albumId,:path,:filename,DATETIME(:added),DATETIME(:modified),DATETIME(:taken),:width,:height,:name)", {
replacements: replacements
});
}).catch(function(error) {
console.error("Error resizing image, writing to disc, or updating DB: " + src, error);
throw error; throw error;
}); });
}).then(function() {
let dst = picturesPath + path + "/thumbs/scaled/" + file;
return exists(dst).then(function(exist) {
if (exist) {
return;
}
return image.resize(Math.min(1024, metadata.width)).toFile(dst).catch(function(error) {
console.error("Error resizing image: " + dst, error);
throw error;
});
});
}).then(function() {
return photoDB.sequelize.query("INSERT INTO photos " +
"(albumId,path,filename,added,modified,taken,width,height,name)" +
"VALUES(:albumId,:path,:filename,DATETIME(:added),DATETIME(:modified),DATETIME(:taken),:width,:height,:name)", {
replacements: replacements
});
}).then(function() { }).then(function() {
toProcess--; toProcess--;
if (moment().add(-5, 'seconds') > lastMessage) { if (moment().add(-5, 'seconds') > lastMessage) {