diff --git a/util/check.js b/util/check.js index 9806bb7..d983b07 100644 --- a/util/check.js +++ b/util/check.js @@ -131,6 +131,28 @@ function getAssetInfoFromDB(asset, id) { }); } +function computeHash(filepath) { + return new Promise(function(resolve, reject) { + let input = fs.createReadStream(filepath), + hash = crypto.createHash("sha256"); + if (!input) { + return reject() + } + + input.on("readable", function() { + const data = input.read(); + if (data) { + hash.update(data); + } else { + input.close(); + resolve(hash.digest("hex")); + hash = null; + input = null; + } + }); + }); +} + let photoDB; require("../server/db/photos").then(function(db) { @@ -139,6 +161,7 @@ require("../server/db/photos").then(function(db) { return Promise.mapSeries(items, function(item) { const asset = {}; + console.log("Processing " + item.value); return Promise.resolve().then(function() { switch (item.type) { case "file": @@ -151,15 +174,17 @@ require("../server/db/photos").then(function(db) { } }).then(function() { if (!asset.stats && !asset.id) { - throw "Item " + item.value + " exists neither on disk nor in the DB."; + throw "...exists neither on disk nor in the DB."; } }).then(function() { if (asset.id) { return; } - console.log("Item " + asset.filepath + " does not exist in the DB."); + console.log("...does not exist in the DB."); + asset.size = asset.stats.size; + asset.needsHash = true; asset.needsUpdate = true; return photoDB.sequelize.query("INSERT INTO photos " + "(albumId,filename,name,size) VALUES(:albumId,:filename,:name,:size)", { @@ -169,8 +194,10 @@ require("../server/db/photos").then(function(db) { }); }).then(function() { if (asset.stats) { - if (asset.modified > asset.stats.mtime) { + if (asset.modified < asset.stats.mtime) { + asset.modified = asset.stats.mtime; asset.needsUpdate = true; + asset.needsHash = true; } if (asset.deleted) { @@ -182,16 +209,79 @@ require("../server/db/photos").then(function(db) { return; } - console.log("Item " + asset.filepath + " does not exist on disk."); + console.log("...does not exist on disk."); + if (!asset.deleted) { console.log("...setting deleted=1 for " + asset.id); return photoDB.sequelize.query("UPDATE photos SET deleted=1 WHERE id=:id", { replacements: asset }); } + }).then(function() { + if (!asset.needsHash) { + return; + } + + return computeHash(asset.path + asset.filename).then(function(hash) { + asset.hash = hash; + }).then(function() { + return photoDB.sequelize.query("SELECT photos.id,photohashes.*,photos.filename,albums.path FROM photohashes " + + "LEFT JOIN photos ON (photos.id=photohashes.photoId) " + + "LEFT JOIN albums ON (albums.id=photos.albumId) " + + "WHERE hash=:hash OR photoId=:id", { + replacements: asset, + type: photoDB.sequelize.QueryTypes.SELECT + }).then(function(results) { + let query; + + if (results.length == 0) { + query = "INSERT INTO photohashes (hash,photoId) VALUES(:hash,:id)"; + console.log("...creating photohash."); + } else if (results[0].hash != asset.hash) { + query = "UPDATE photohashes SET hash=:hash WHERE photoId=:id"; + console.log("...updating photohash."); + } else if (results[0].photoId != asset.id) { + console.log("...duplicate asset: " + + "'" + asset.album.path + asset.filename + "' is a copy of " + + "'" + results[0].path + results[0].filename + "'"); + asset.duplicate = results[0].id; + } + + if (!query) { + return asset; + } + + return photoDB.sequelize.query(query, { + replacements: asset, + }); + }); + }); + }).then(function() { + if (asset.deleted) { + throw "...deleted. Skipping rest of processing."; + } + if (asset.duplicate) { + throw "...duplicate of " + asset.duplicate + ". Skipping rest of processing."; + } + + return exists(asset.path + "thumbs/" + asset.filename).then(function(stats) { + if (!stats || stats.mtime < asset.modified) { + console.log("...needs thumb"); + asset.needsThumb = true; + } + }); + }).then(function() { + return exists(asset.path + "thumbs/scaled/" + asset.filename).then(function(stats) { + if (!stats || stats.mtime < asset.modified) { + console.log("...needs scaled"); + asset.needsScaled = true; + } + }); }).then(function() { if (asset.needsUpdate) { - console.log("DB needs to be updated for " + item.value); + console.log("...DB needs to be updated for " + item.value); + } else { + console.log("...does not need to be updated."); } }).catch(function(error) { console.log(error);