isundil 2 лет назад
Родитель
Сommit
cbbebd37f9

+ 4 - 0
model/mediaItem.js

@@ -5,6 +5,7 @@ function MediaFileModel() {
     DatabaseModel.call(this);
     DatabaseModel.call(this);
     this.path = "";
     this.path = "";
     this.md5sum = "";
     this.md5sum = "";
+    this.fixedSum = "";
     this.date = null;
     this.date = null;
 }
 }
 
 
@@ -18,6 +19,7 @@ MediaFileModel.prototype.createOrUpdateBase = async function(dbHelper) {
     await dbHelper.runSql(`CREATE TABLE IF NOT EXISTS 'mediaFile' (
     await dbHelper.runSql(`CREATE TABLE IF NOT EXISTS 'mediaFile' (
         path STRING NOT NULL,
         path STRING NOT NULL,
         md5sum varchar(32) NOT NULL,
         md5sum varchar(32) NOT NULL,
+        fixedSum varchar(32) NOT NULL,
         date DateTime NOT NULL,
         date DateTime NOT NULL,
         PRIMARY KEY (path, md5sum))`);
         PRIMARY KEY (path, md5sum))`);
 }
 }
@@ -26,6 +28,7 @@ MediaFileModel.prototype.describe = function() {
     return {
     return {
         "path": this.path,
         "path": this.path,
         "md5sum": this.md5sum,
         "md5sum": this.md5sum,
+        "fixedSum": this.fixedSum,
         "date": this.date?.getTime()
         "date": this.date?.getTime()
     };
     };
 }
 }
@@ -35,6 +38,7 @@ MediaFileModel.prototype.versionColumn = function() { return ""; }
 MediaFileModel.prototype.fromDb = function(dbObj) {
 MediaFileModel.prototype.fromDb = function(dbObj) {
     this.path = dbObj["path"];
     this.path = dbObj["path"];
     this.md5sum = dbObj["md5sum"];
     this.md5sum = dbObj["md5sum"];
+    this.fixedSum = dbObj["fixedSum"];
     this.date = new Date(dbObj["date"]);
     this.date = new Date(dbObj["date"]);
 }
 }
 
 

+ 12 - 11
model/mediaService.js

@@ -11,6 +11,7 @@ function MediaStruct(i) {
     this.path = i.path;
     this.path = i.path;
     this.fileName = path.parse(i.path).name;
     this.fileName = path.parse(i.path).name;
     this.md5sum = i.md5sum;
     this.md5sum = i.md5sum;
+    this.fixedSum = i.fixedSum;
     this.date = i.date;
     this.date = i.date;
     this.meta = {};
     this.meta = {};
     this.tags = [];
     this.tags = [];
@@ -79,7 +80,7 @@ MediaStruct.prototype.computeAccess = function(accessList) {
     this.accessType = ACCESS_GRANT.none;
     this.accessType = ACCESS_GRANT.none;
     for (let i of accessList) {
     for (let i of accessList) {
         if (i.accessTo === ACCESS_TO.everything ||
         if (i.accessTo === ACCESS_TO.everything ||
-            (i.accessTo === ACCESS_TO.item && i.accessToData === this.md5sum) ||
+            (i.accessTo === ACCESS_TO.item && i.accessToData === this.fixedSum) ||
             (i.accessTo === ACCESS_TO.meta && checkMeta(this.meta, i)) ||
             (i.accessTo === ACCESS_TO.meta && checkMeta(this.meta, i)) ||
             (i.accessTo === ACCESS_TO.tag && checkTag([].concat(this.fixedTags, this.tags), i))) {
             (i.accessTo === ACCESS_TO.tag && checkTag([].concat(this.fixedTags, this.tags), i))) {
             if (i.grant === ACCESS_GRANT.write)
             if (i.grant === ACCESS_GRANT.write)
@@ -121,7 +122,7 @@ async function buildAccessList(app, accessIds) {
 }
 }
 
 
 function reduceReqToMediaStruct(acc, i) {
 function reduceReqToMediaStruct(acc, i) {
-    let obj = acc[i.md5sum] = acc[i.md5sum] || new MediaStruct(i);
+    let obj = acc[i.fixedSum] = acc[i.fixedSum] || new MediaStruct(i);
     obj.pushMeta(i.metaKey, i.metaValue);
     obj.pushMeta(i.metaKey, i.metaValue);
     obj.pushTag(i.mediaTag, i.isFixedTag);
     obj.pushTag(i.mediaTag, i.isFixedTag);
     return acc;
     return acc;
@@ -129,27 +130,27 @@ function reduceReqToMediaStruct(acc, i) {
 
 
 module.exports.fetchOne = async function(app, md5sum, accessList) {
 module.exports.fetchOne = async function(app, md5sum, accessList) {
     let result = ((await app.databaseHelper.runSql(`
     let result = ((await app.databaseHelper.runSql(`
-        select mediaFile.path, mediaFile.md5sum, mediaFile.date,
+        select mediaFile.path, mediaFile.md5sum, mediaFile.date, mediaFile.fixedSum,
         mediaMeta.key as metaKey, mediaMeta.value as metaValue,
         mediaMeta.key as metaKey, mediaMeta.value as metaValue,
         mediaTag.tag as mediaTag, mediaTag.fromMeta as isFixedTag
         mediaTag.tag as mediaTag, mediaTag.fromMeta as isFixedTag
         from mediaFile
         from mediaFile
-        left join mediaMeta on mediaMeta.md5sum=mediaFile.md5sum
-        left join mediaTag on mediaTag.md5sum=mediaFile.md5sum
-        where mediaFile.md5sum=?`, md5sum)) || []).reduce(reduceReqToMediaStruct, {})[md5sum] || null;
+        left join mediaMeta on mediaMeta.md5sum=mediaFile.fixedSum
+        left join mediaTag on mediaTag.md5sum=mediaFile.fixedSum
+        where mediaFile.fixedSum=?`, md5sum)) || []).reduce(reduceReqToMediaStruct, {})[md5sum] || null;
     accessList = await buildAccessList(app, accessList);
     accessList = await buildAccessList(app, accessList);
     return result?.HaveAccess(accessList) ? result : null;
     return result?.HaveAccess(accessList) ? result : null;
 }
 }
 
 
 module.exports.fetchMedias = async function(app, startTs, count) {
 module.exports.fetchMedias = async function(app, startTs, count) {
     let result = ((await app.databaseHelper.runSql(`
     let result = ((await app.databaseHelper.runSql(`
-        select mediaFile.path, mediaFile.md5sum, mediaFile.date,
+        select mediaFile.path, mediaFile.md5sum, mediaFile.date, mediaFile.fixedSum,
         mediaMeta.key as metaKey, mediaMeta.value as metaValue,
         mediaMeta.key as metaKey, mediaMeta.value as metaValue,
         mediaTag.tag as mediaTag, mediaTag.fromMeta as isFixedTag
         mediaTag.tag as mediaTag, mediaTag.fromMeta as isFixedTag
         from mediaFile
         from mediaFile
-        left join mediaMeta on mediaMeta.md5sum=mediaFile.md5sum
-        left join mediaTag on mediaTag.md5sum=mediaFile.md5sum
-        where mediaFile.md5sum in
-            (select md5sum from mediaFile `
+        left join mediaMeta on mediaMeta.md5sum=mediaFile.fixedSum
+        left join mediaTag on mediaTag.md5sum=mediaFile.fixedSum
+        where mediaFile.fixedSum in
+            (select fixedSum from mediaFile `
             +(startTs ? "where date <? " : "")
             +(startTs ? "where date <? " : "")
             +"order by date desc limit ?)", startTs ? [startTs, count] : [count])) || [])
             +"order by date desc limit ?)", startTs ? [startTs, count] : [count])) || [])
     .reduce(reduceReqToMediaStruct, {});
     .reduce(reduceReqToMediaStruct, {});

+ 4 - 4
router/api.js

@@ -46,7 +46,7 @@ module.exports = { register: app => {
         let data = await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList);
         let data = await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList);
         if (!data || data.accessType !== ACCESS_GRANT.write)
         if (!data || data.accessType !== ACCESS_GRANT.write)
             return app.routerUtils.onPageNotFound(res);
             return app.routerUtils.onPageNotFound(res);
-        await app.databaseHelper.remove(MediaFileTagModel, { md5sum: data.md5sum, tag: decodeURIComponent(req.params.tag), fromMeta: 0 });
+        await app.databaseHelper.remove(MediaFileTagModel, { md5sum: data.fixedSum, tag: decodeURIComponent(req.params.tag), fromMeta: 0 });
         app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
         app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
     });
     });
     app.router.put("/api/media/:id/tag", async (req, res) => {
     app.router.put("/api/media/:id/tag", async (req, res) => {
@@ -62,7 +62,7 @@ module.exports = { register: app => {
                 return app.routerUtils.jsonResponse(res, data);
                 return app.routerUtils.jsonResponse(res, data);
             }
             }
         }
         }
-        let tag = new MediaFileTagModel(data.md5sum, requestedTag, false);
+        let tag = new MediaFileTagModel(data.fixedSum, requestedTag, false);
         await app.databaseHelper.insertOne(tag);
         await app.databaseHelper.insertOne(tag);
         app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
         app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
     });
     });
@@ -74,9 +74,9 @@ module.exports = { register: app => {
         if (!data || data.accessType !== ACCESS_GRANT.write)
         if (!data || data.accessType !== ACCESS_GRANT.write)
             return app.routerUtils.onPageNotFound(res);
             return app.routerUtils.onPageNotFound(res);
         if (!req.body.value) {
         if (!req.body.value) {
-            await app.databaseHelper.remove(MediaFileMetaModel, { md5sum: data.md5sum, key: req.params.key, fromFile: 0 });
+            await app.databaseHelper.remove(MediaFileMetaModel, { md5sum: data.fixedSum, key: req.params.key, fromFile: 0 });
         } else {
         } else {
-            let newMediaItemMedia = new MediaFileMetaModel(data.md5sum, req.params.key, req.body.value, false);
+            let newMediaItemMedia = new MediaFileMetaModel(data.fixedSum, req.params.key, req.body.value, false);
             await app.databaseHelper.upsertOne(newMediaItemMedia);
             await app.databaseHelper.upsertOne(newMediaItemMedia);
         }
         }
         app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
         app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));

+ 72 - 77
src/filetype/imagemagick.js

@@ -1,36 +1,32 @@
 
 
 const fs = require('fs');
 const fs = require('fs');
 const tmp = require('tmp');
 const tmp = require('tmp');
-const im = require('imagemagick');
+const im = require('./../imagemagickWrapper.js');
 const geokit = require('geokit');
 const geokit = require('geokit');
 const geocoder = require('offline-geocoder')({ database: 'static/db.sqlite'});
 const geocoder = require('offline-geocoder')({ database: 'static/db.sqlite'});
 
 
 function readMeta(path) {
 function readMeta(path) {
-    return new Promise((ok, ko) => {
+    return new Promise(async (ok, ko) => {
         try {
         try {
-            im.identify(['-format', '%[EXIF:*]Compression=%[compression]\nWidth=%w\nHeight=%h\n', path], function(err, stdout)
+            let stdout = await im.readMeta(path);
+            var meta = {};
+            for (const line of stdout.split(/\n/))
             {
             {
-                if (err)
-                    return ok(null);
-                var meta = {};
-                for (const line of stdout.split(/\n/))
-                {
-                    var eq_p = line.indexOf('=');
-                    if (eq_p === -1)
-                        continue;
-                    var key = line.substr(0, eq_p).replace('/','-'),
-                        value = line.substr(eq_p+1).trim();
-                    var p = key.indexOf(':');
-                    if (p !== -1)
-                        key = key.substr(p+1);
-                    key = key.charAt(0).toLowerCase() + key.slice(1);
-                    meta[key] = value;
-                }
-                ok(meta);
-            });
+                var eq_p = line.indexOf('=');
+                if (eq_p === -1)
+                    continue;
+                var key = line.substr(0, eq_p).replace('/','-'),
+                    value = line.substr(eq_p+1).trim();
+                var p = key.indexOf(':');
+                if (p !== -1)
+                    key = key.substr(p+1);
+                key = key.charAt(0).toLowerCase() + key.slice(1);
+                meta[key] = value;
+            }
+            ok(meta);
         } catch (err) {
         } catch (err) {
             console.error("readMeta from Imagemagick: ", err);
             console.error("readMeta from Imagemagick: ", err);
-            ok(null);
+            ko(err);
         }
         }
     });
     });
 }
 }
@@ -125,67 +121,66 @@ function exposureProgram(programId) {
 module.exports.parse = async (fileObj) => {
 module.exports.parse = async (fileObj) => {
     if (!fileObj.mimeType.startsWith('image/'))
     if (!fileObj.mimeType.startsWith('image/'))
         return {};
         return {};
-    let imdata = await readMeta(fileObj.path);
-    if (!imdata)
-        return {};
     let result = {};
     let result = {};
-    result.artist = imdata.artist || undefined;
-    result.exposureProgram = exposureProgram(Number.parseInt(imdata.exposureProgram));
-    result.exposureTime = exifSlash(imdata.exposureTime);
-    result.exposureTimeStr = imdata.exposureTime || undefined;
-    result.dateTime = exifDate(imdata.dateTimeDigitized || imdata.dateTimeOriginal);
-    result.fNumber = exifSlash(imdata.fNumber);
-    result.focal = exifSlash(imdata.focalLength);
-    result.lensModel = imdata.lensModel || undefined;
-    result.camera = ((imdata.model || "") + (imdata.model && imdata.make ? " " : "") + (imdata.make || "")) || "";
-    result.software = imdata.software || undefined;
-    result.iso = Number.parseInt(imdata.photographicSensitivity) || undefined;
-    result.width = imdata.width || undefined;
-    result.height = imdata.height || undefined;
-    result.compression = imdata.compression || undefined;
-    const gpsData = new ExifGps(imdata);
-    result.gpsLocation = gpsData.toGps();
-    result.geoHash = gpsData.toGeoHash();
-    const address = await gpsData.toAddress();
-    result.geoCountry = address?.country;
-    result.geoAdmin = address?.admin;
-    result.geoCity = address?.city;
-    result.tags = readTags(imdata);
+    try {
+        let imdata = await readMeta(fileObj.path);
+        if (!imdata)
+            return {};
+        result.artist = imdata.artist || undefined;
+        result.exposureProgram = exposureProgram(Number.parseInt(imdata.exposureProgram));
+        result.exposureTime = exifSlash(imdata.exposureTime);
+        result.exposureTimeStr = imdata.exposureTime || undefined;
+        result.dateTime = exifDate(imdata.dateTimeDigitized || imdata.dateTimeOriginal);
+        result.fNumber = exifSlash(imdata.fNumber);
+        result.focal = exifSlash(imdata.focalLength);
+        result.lensModel = imdata.lensModel || undefined;
+        result.camera = ((imdata.model || "") + (imdata.model && imdata.make ? " " : "") + (imdata.make || "")) || "";
+        result.software = imdata.software || undefined;
+        result.iso = Number.parseInt(imdata.photographicSensitivity) || undefined;
+        result.width = imdata.width || undefined;
+        result.height = imdata.height || undefined;
+        result.compression = imdata.compression || undefined;
+        const gpsData = new ExifGps(imdata);
+        result.gpsLocation = gpsData.toGps();
+        result.geoHash = gpsData.toGeoHash();
+        const address = await gpsData.toAddress();
+        result.geoCountry = address?.country;
+        result.geoAdmin = address?.admin;
+        result.geoCity = address?.city;
+        result.tags = readTags(imdata);
+    }
+    catch (err) {
+        result.imException = err;
+    }
     for (let i of Object.keys(result))
     for (let i of Object.keys(result))
         if (result[i] === undefined || result[i].length === 0)
         if (result[i] === undefined || result[i].length === 0)
             delete result[i];
             delete result[i];
     return result;
     return result;
 }
 }
 
 
-module.exports.createThumbnail = (fileObj, width, height, quality) => {
-    return new Promise((ok, ko) => {
-        if (!fileObj?.meta?.width || !fileObj?.meta?.height)
-            return null;
-        if (!width && !height)
-            width = height = 420;
-        let ratio = Math.min((width / fileObj.meta.width) || 1, (height / fileObj.meta.height) || 1, 1);
-        const output = tmp.fileSync({ discardDescriptor: true });
-        try {
-            im.convert([
-                fileObj.path,
-                '-strip',
-                '-interlace', 'Plane',
-                '-resize', (Math.floor(fileObj.meta.width * ratio)),
-                '-quality', '' + (Math.floor(Math.max(0, Math.min(100, (quality *10))))) + '%',
-                '-sampling-factor', '4:2:0',
-                `JPG:${output.name}`,
-            ], err => {
-                if (err) {
-                    console.error("Imagemagick createThumbnail error: ", err);
-                    ko();
-                } else {
-                    ok(output);
-                }
-            });
-        }
-        catch (err) {
-            ko(err);
-        }
-    });
+module.exports.createThumbnail = async (fileObj, width, height, quality) => {
+    if (!fileObj?.meta?.width || !fileObj?.meta?.height)
+        return null;
+    if (!width && !height)
+        width = height = 420;
+    let ratio = Math.min((width / fileObj.meta.width) || 1, (height / fileObj.meta.height) || 1, 1);
+    const output = tmp.fileSync({ discardDescriptor: true });
+    try {
+        await im.convert([
+            fileObj.path,
+            '-strip',
+            '-interlace', 'Plane',
+            '-resize', (Math.floor(fileObj.meta.width * ratio)),
+            '-quality', '' + (Math.floor(Math.max(0, Math.min(100, (quality *10))))) + '%',
+            '-sampling-factor', '4:2:0',
+            `JPG:${output.name}`,
+        ]);
+        ok(output);
+    }
+    catch (err) {
+        console.error("Imagemagick createThumbnail error: ", err);
+        throw err;
+    }
+    return output;
 };
 };
 
 

+ 65 - 0
src/imagemagickWrapper.js

@@ -0,0 +1,65 @@
+
+const im = require('imagemagick');
+
+class ImagemagickWrapper {
+    #tasks = [];
+    #activeTask = null;
+    #runNextTask() {
+        if (this.#activeTask || this.#tasks.length === 0)
+            return;
+        this.#activeTask = (this.#tasks.shift());
+        let taskResult = null;
+        try {
+            taskResult = this.#activeTask.fnc();
+        }
+        catch (err) {
+            taskResult = Promise.reject(err);
+        }
+        if (!(taskResult instanceof Promise))
+            taskResult = Promise.resolve(this.#activeTask);
+        taskResult
+            .then(result => {
+                let ok = this.#activeTask.ok;
+                this.#activeTask = null;
+                ok(result);
+            })
+            .catch(() => {
+                let ko = this.#activeTask.ko;
+                this.#activeTask = null;
+                ko(taskResult.result);
+            })
+            .finally(() => {
+                this.#runNextTask();
+            });
+    };
+
+    async #pushTask(task) {
+        return new Promise((ok, ko) => {
+            this.#tasks.push({ fnc: task, ok: ok, ko: ko });
+            this.#runNextTask();
+        });
+    }
+
+    readMeta(path) {
+        return this.#pushTask(() => new Promise((ok, ko) => {
+            im.identify(['-format', '%[EXIF:*]Compression=%[compression]\nWidth=%w\nHeight=%h\n', path], (err, stdout) => {
+                if (err)
+                    return ko(err);
+                ok(stdout);
+            });
+        }));
+    }
+
+    convert(args) {
+        return this.#pushTask(() => new Promise((ok, ko) => {
+            im.convert(args, (err, stdout) => {
+                if (err)
+                    return ko(err);
+                ok(stdout);
+            });
+        }));
+    }
+}
+
+module.exports = new ImagemagickWrapper();
+

+ 11 - 10
src/library.js

@@ -15,6 +15,7 @@ const BUFFER_MAXSIZE = 100;
 function File(fullPath, name) {
 function File(fullPath, name) {
     this.name = name;
     this.name = name;
     this.path = fullPath;
     this.path = fullPath;
+    this.fixedSum = null;
     this.checksum = null;
     this.checksum = null;
     this.mimeType = null;
     this.mimeType = null;
     this.isMedia = null;
     this.isMedia = null;
@@ -33,10 +34,10 @@ File.prototype.getIsMedia = function() {
 }
 }
 
 
 File.prototype.computeChecksum = async function() {
 File.prototype.computeChecksum = async function() {
-    if (this.checksum)
-        return;
-    if (this.getIsMedia())
+    if (!this.checksum && this.getIsMedia())
         this.checksum = await md5Stats(this.path);
         this.checksum = await md5Stats(this.path);
+    if (!this.fixedSum)
+        this.fixedSum = this.checksum;
     return this.checksum;
     return this.checksum;
 }
 }
 
 
@@ -54,25 +55,24 @@ File.prototype.enrich = async function() {
 
 
 File.prototype.saveDb = async function(db, libraryHash) {
 File.prototype.saveDb = async function(db, libraryHash) {
     if (this.dbItem) {
     if (this.dbItem) {
+        this.fixedSum = this.dbItem.fixedSum;
         await db.remove(MediaFileModel, { path: this.dbItem.path, md5sum: this.dbItem.md5sum });
         await db.remove(MediaFileModel, { path: this.dbItem.path, md5sum: this.dbItem.md5sum });
         await db.remove(MediaFileMetaModel, { md5sum: this.dbItem.md5sum, fromFile: true });
         await db.remove(MediaFileMetaModel, { md5sum: this.dbItem.md5sum, fromFile: true });
         await db.remove(MediaFileTagModel, { md5sum: this.dbItem.md5sum, fromMeta: true });
         await db.remove(MediaFileTagModel, { md5sum: this.dbItem.md5sum, fromMeta: true });
-        await db.rawUpdate(MediaFileTagModel, { md5sum: this.dbItem.md5sum }, { md5sum: this.checksum });
-        await db.rawUpdate(MediaFileMetaModel, { md5sum: this.dbItem.md5sum }, { md5sum: this.checksum });
-        await db.rawUpdate(AccessModel, { accessToData: this.dbItem.md5sum, accessTo: ACCESS_TO.item }, { accessToData: this.checksum });
     }
     }
     let entity = new MediaFileModel();
     let entity = new MediaFileModel();
     let _this = this;
     let _this = this;
     entity.path = this.path;
     entity.path = this.path;
-    entity.md5sum = this.checksum;
+    entity.md5sum = await this.computeChecksum();
+    entity.fixedSum = this.fixedSum;
     entity.date = this.meta.dateTime || new Date(fs.statSync(this.path)?.birthtimeMs || Date.now());
     entity.date = this.meta.dateTime || new Date(fs.statSync(this.path)?.birthtimeMs || Date.now());
     await db.insertOne(entity);
     await db.insertOne(entity);
     this.meta.photochamberImport = new Date();
     this.meta.photochamberImport = new Date();
     this.meta.libraryPath = libraryHash;
     this.meta.libraryPath = libraryHash;
-    let metaEntities = Object.keys(this.meta).filter(i => i !== 'tags').map(i => new MediaFileMetaModel(_this.checksum, i, _this.meta[i], true));
+    let metaEntities = Object.keys(this.meta).filter(i => i !== 'tags').map(i => new MediaFileMetaModel(_this.fixedSum, i, _this.meta[i], true));
     await db.insertMultipleSameTable(metaEntities);
     await db.insertMultipleSameTable(metaEntities);
     if (this.tags.length) {
     if (this.tags.length) {
-        let tagsEntities = this.tags.map(i => new MediaFileTagModel(_this.checksum, i, true));
+        let tagsEntities = this.tags.map(i => new MediaFileTagModel(_this.fixedSum, i, true));
         await db.insertMultipleSameTable(tagsEntities);
         await db.insertMultipleSameTable(tagsEntities);
     }
     }
     this.dbItem = null;
     this.dbItem = null;
@@ -91,12 +91,13 @@ async function Library_doUpdate(dbHelper, lib) {
     lib.buff = lib.buff.filter(i => !!i.checksum);
     lib.buff = lib.buff.filter(i => !!i.checksum);
     if (lib.buff.length === 0)
     if (lib.buff.length === 0)
         return;
         return;
-    const dbItems = (await dbHelper.fetchRaw(["path", "md5sum"], MediaFileModel.prototype.getTableName.call(null), { "path": lib.buff.map(i => i.path) }));
+    const dbItems = (await dbHelper.fetchRaw(["path", "md5sum", "fixedSum"], MediaFileModel.prototype.getTableName.call(null), { "path": lib.buff.map(i => i.path) }));
     lib.buff.forEach(i => i.dbItem = dbItems.find(x => x.path == i.path));
     lib.buff.forEach(i => i.dbItem = dbItems.find(x => x.path == i.path));
     lib.buff = lib.buff.filter(i => !i.dbItem || i.dbItem.md5sum != i.checksum);
     lib.buff = lib.buff.filter(i => !i.dbItem || i.dbItem.md5sum != i.checksum);
     await enrichAll(lib);
     await enrichAll(lib);
     (await Promise.allSettled(lib.buff.map(i => i.saveDb(dbHelper, lib.dbHash)))).forEach(x => { if (x.status === 'rejected') { console.log(`Cannot update item: `, x.reason); }});
     (await Promise.allSettled(lib.buff.map(i => i.saveDb(dbHelper, lib.dbHash)))).forEach(x => { if (x.status === 'rejected') { console.log(`Cannot update item: `, x.reason); }});
     lib.foundMedias = lib.foundMedias.concat(lib.buff);
     lib.foundMedias = lib.foundMedias.concat(lib.buff);
+    console.log(`Updated ${lib.buff.length} media items`);
     lib.buff = [];
     lib.buff = [];
 }
 }
 
 

+ 9 - 9
static/public/js/medias.js

@@ -3,6 +3,7 @@ class Media {
     constructor(data) {
     constructor(data) {
         this.date = new Date(data.date);
         this.date = new Date(data.date);
         this.md5sum = data.md5sum;
         this.md5sum = data.md5sum;
+        this.fixedSum = data.fixedSum;
         this.path = data.path;
         this.path = data.path;
         this.fileName = data.fileName;
         this.fileName = data.fileName;
         this.meta = data.meta || {};
         this.meta = data.meta || {};
@@ -10,8 +11,8 @@ class Media {
 
 
         this.tags = [];
         this.tags = [];
         this.writeAccess = data.accessType === 2;
         this.writeAccess = data.accessType === 2;
-        this.thumbnail = `/api/media/thumbnail/${data.md5sum}.jpg`;
-        this.original = `/api/media/original/${data.md5sum}`;
+        this.thumbnail = `/api/media/thumbnail/${data.fixedSum}.jpg`;
+        this.original = `/api/media/original/${data.fixedSum}`;
         this.ui = null;
         this.ui = null;
 
 
         this.setTags(data.fixedTags || [], data.tags || []);
         this.setTags(data.fixedTags || [], data.tags || []);
@@ -106,7 +107,6 @@ class MediaStorage extends EventTarget
             if (!media.meta[key])
             if (!media.meta[key])
                 this.allMetaTypes[key].canBeEmpty = true;
                 this.allMetaTypes[key].canBeEmpty = true;
         this.medias.push(media);
         this.medias.push(media);
-        media.md5sum === 'b1bc7614d67333cacb60af149ed5ee1f' && console.log(this);
     }
     }
 
 
     pushAll(arr, partialLoad) {
     pushAll(arr, partialLoad) {
@@ -119,7 +119,7 @@ class MediaStorage extends EventTarget
             }
             }
             if (this.medias.length && this.medias[this.medias.length -1].date.getTime() < i.date.getTime())
             if (this.medias.length && this.medias[this.medias.length -1].date.getTime() < i.date.getTime())
                 reorder = true;
                 reorder = true;
-            if (this.medias.find(x => x.md5sum === i.md5sum))
+            if (this.medias.find(x => x.fixedSum === i.fixedSum))
                 continue;
                 continue;
             this.#pushUnique(i);
             this.#pushUnique(i);
             result.push(i);
             result.push(i);
@@ -163,11 +163,11 @@ class MediaStorage extends EventTarget
     }
     }
 
 
     getMediaLocal(md5sum) {
     getMediaLocal(md5sum) {
-        return this.medias.find(x => x.md5sum === md5sum);
+        return this.medias.find(x => x.fixedSum === md5sum);
     }
     }
 
 
     async getMedia(md5sum) {
     async getMedia(md5sum) {
-        let media = this.medias.find(x => x.md5sum === md5sum);
+        let media = this.medias.find(x => x.fixedSum === md5sum);
         if (media)
         if (media)
             return media;
             return media;
         return await tryLoadMedia(md5sum);
         return await tryLoadMedia(md5sum);
@@ -176,7 +176,7 @@ class MediaStorage extends EventTarget
     setMetaValue(md5sum, key, value) {
     setMetaValue(md5sum, key, value) {
         return LoadingTasks.push(() => {
         return LoadingTasks.push(() => {
             return new Promise(ok => {
             return new Promise(ok => {
-                let media = this.medias.find(x => x.md5sum === md5sum);
+                let media = this.medias.find(x => x.fixedSum === md5sum);
                 if (!media || !media.writeAccess)
                 if (!media || !media.writeAccess)
                     return ok(false);
                     return ok(false);
                 $.ajax({
                 $.ajax({
@@ -200,7 +200,7 @@ class MediaStorage extends EventTarget
     removeTag(md5sum, tagName) {
     removeTag(md5sum, tagName) {
         return LoadingTasks.push(() => {
         return LoadingTasks.push(() => {
             return new Promise(ok => {
             return new Promise(ok => {
-                let media = this.medias.find(x => x.md5sum === md5sum);
+                let media = this.medias.find(x => x.fixedSum === md5sum);
                 if (!media || !media.writeAccess)
                 if (!media || !media.writeAccess)
                     return ok(false);
                     return ok(false);
                 $.ajax({
                 $.ajax({
@@ -223,7 +223,7 @@ class MediaStorage extends EventTarget
     addTag(md5sum, tagName) {
     addTag(md5sum, tagName) {
         return LoadingTasks.push(() => {
         return LoadingTasks.push(() => {
             return new Promise(ok => {
             return new Promise(ok => {
-                let media = this.medias.find(x => x.md5sum === md5sum);
+                let media = this.medias.find(x => x.fixedSum === md5sum);
                 if (!media || !media.writeAccess)
                 if (!media || !media.writeAccess)
                     return ok(false);
                     return ok(false);
                 $.ajax({
                 $.ajax({

+ 2 - 2
static/public/js/uiMedia.js

@@ -31,7 +31,7 @@ $(() => {
         container.className = "pch-image loading col-12 col-md-6 col-xl-4";
         container.className = "pch-image loading col-12 col-md-6 col-xl-4";
         loadingImg.classList.add("spinner");
         loadingImg.classList.add("spinner");
         loadingImg.innerHTML = "<span class='spinner-grow'></span>";
         loadingImg.innerHTML = "<span class='spinner-grow'></span>";
-        container.dataset.md5sum = mediaItem.md5sum;
+        container.dataset.md5sum = mediaItem.fixedSum;
         img.loading = "lazy";
         img.loading = "lazy";
         let requestSize = mediaItem.resize(450, 450);
         let requestSize = mediaItem.resize(450, 450);
         requestSize = requestSize ? `w=${requestSize.width}&h=${requestSize.height}&` : "";
         requestSize = requestSize ? `w=${requestSize.width}&h=${requestSize.height}&` : "";
@@ -102,7 +102,7 @@ $(() => {
                 cascadeSetSelectionCheckboxValue(value);
                 cascadeSetSelectionCheckboxValue(value);
                 return;
                 return;
             }
             }
-            document.location.hash = mediaItem.md5sum;
+            document.location.hash = mediaItem.fixedSum;
         });
         });
         checkbox.addEventListener("click", evt => {
         checkbox.addEventListener("click", evt => {
             evt.stopPropagation();
             evt.stopPropagation();

+ 7 - 7
static/public/js/uiMediaFullpage.js

@@ -55,10 +55,10 @@ $(() => {
             bt.type = 'button';
             bt.type = 'button';
             bt.innerHTML = '<i class="bi bi-pen"></i>';
             bt.innerHTML = '<i class="bi bi-pen"></i>';
             inputGroup.appendChild(bt);
             inputGroup.appendChild(bt);
-            bt.addEventListener('click', () => MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.md5sum, key, valInput.value));
+            bt.addEventListener('click', () => MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.fixedSum, key, valInput.value));
             inputGroup.addEventListener('submit', evt => {
             inputGroup.addEventListener('submit', evt => {
                 evt.preventDefault();
                 evt.preventDefault();
-                MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.md5sum, key, valInput.value);
+                MediaStorage.Instance.setMetaValue(fullPageMediaDisplayed.fixedSum, key, valInput.value);
             });
             });
         }
         }
         li.appendChild(keySpan);
         li.appendChild(keySpan);
@@ -124,7 +124,7 @@ $(() => {
                 btItem.href = '#';
                 btItem.href = '#';
                 btItem.addEventListener('click', async e => {
                 btItem.addEventListener('click', async e => {
                     e.preventDefault();
                     e.preventDefault();
-                    await MediaStorage.Instance.removeTag(fullPageMediaDisplayed.md5sum, i);
+                    await MediaStorage.Instance.removeTag(fullPageMediaDisplayed.fixedSum, i);
                     reloadCurrentMedia();
                     reloadCurrentMedia();
                 });
                 });
                 uiItem.appendChild(btItem);
                 uiItem.appendChild(btItem);
@@ -149,10 +149,10 @@ $(() => {
             bt.type = 'button';
             bt.type = 'button';
             bt.innerHTML = '<i class="bi bi-tags"></i>';
             bt.innerHTML = '<i class="bi bi-tags"></i>';
             inputGroup.appendChild(bt);
             inputGroup.appendChild(bt);
-            bt.addEventListener('click', async () => { await MediaStorage.Instance.addTag(fullPageMediaDisplayed.md5sum, valInput.value); reloadCurrentMedia(); });
+            bt.addEventListener('click', async () => { await MediaStorage.Instance.addTag(fullPageMediaDisplayed.fixedSum, valInput.value); reloadCurrentMedia(); });
             inputGroup.addEventListener('submit', async evt => {
             inputGroup.addEventListener('submit', async evt => {
                 evt.preventDefault();
                 evt.preventDefault();
-                await MediaStorage.Instance.addTag(fullPageMediaDisplayed.md5sum, valInput.value);
+                await MediaStorage.Instance.addTag(fullPageMediaDisplayed.fixedSum, valInput.value);
                 reloadCurrentMedia();
                 reloadCurrentMedia();
             });
             });
         }
         }
@@ -234,8 +234,8 @@ $(() => {
             fixedTags: mediaItem.fixedTags,
             fixedTags: mediaItem.fixedTags,
             tags: mediaItem.tags
             tags: mediaItem.tags
         };
         };
-        if (document.location.hash != `#${mediaItem.md5sum}`)
-            history.pushState({}, '', `#${mediaItem.md5sum}`);
+        if (document.location.hash != `#${mediaItem.fixedSum}`)
+            history.pushState({}, '', `#${mediaItem.fixedSum}`);
         const requestSizeQuery = requestSize ? `&w=${requestSize.width}&h=${requestSize.height}` : "";
         const requestSizeQuery = requestSize ? `&w=${requestSize.width}&h=${requestSize.height}` : "";
         return _displayMediaFullPage(mediaItem.fileName, `${mediaItem.thumbnail}?q=6${requestSizeQuery}`, meta, `${mediaItem.original}?trim`, mediaItem.writeAccess);
         return _displayMediaFullPage(mediaItem.fileName, `${mediaItem.thumbnail}?q=6${requestSizeQuery}`, meta, `${mediaItem.original}?trim`, mediaItem.writeAccess);
     }
     }