瀏覽代碼

Meta management

isundil 1 年之前
父節點
當前提交
7cd3a16f4a
共有 7 個文件被更改,包括 40 次插入14 次删除
  1. 3 2
      .gitignore
  2. 7 3
      model/mediaItemMeta.js
  3. 5 2
      model/mediaService.js
  4. 1 0
      package.json
  5. 8 0
      src/filetype/imagemagick.js
  6. 15 6
      src/library.js
  7. 1 1
      static/public/js/medias.js

+ 3 - 2
.gitignore

@@ -1,5 +1,6 @@
-/config.json
+/config*.json
 /node_modules/
 /package-lock.json
-/memory.sqlite
+/memory*.sqlite
+/setup*.sql
 

+ 7 - 3
model/mediaItemMeta.js

@@ -1,11 +1,12 @@
 
 const DatabaseModel = require("./DatabaseModel.js").DatabaseModel;
 
-function MediaFileMetaModel(md5sum, key, value) {
+function MediaFileMetaModel(md5sum, key, value, fromFile) {
     DatabaseModel.call(this);
     this.md5sum = md5sum || "";
     this.key = key || "";
     this.value = value || "";
+    this.fromFile = fromFile;
 }
 
 MediaFileMetaModel.prototype = Object.create(DatabaseModel.prototype);
@@ -19,14 +20,16 @@ MediaFileMetaModel.prototype.createOrUpdateBase = async function(dbHelper) {
         md5sum STRING NOT NULL,
         key varchar(32) NOT NULL,
         value varchar(32) NOT NULL,
-        PRIMARY KEY (md5sum, key))`);
+        fromFile boolean NOT NULL,
+        PRIMARY KEY (md5sum, key, fromFile))`);
 }
 
 MediaFileMetaModel.prototype.describe = function() {
     return {
         "md5sum": this.md5sum,
         "key": this.key,
-        "value": this.value
+        "value": this.value,
+        "fromFile": this.fromFile
     };
 }
 
@@ -36,6 +39,7 @@ MediaFileMetaModel.prototype.fromDb = function(dbObj) {
     this.md5sum = dbObj["md5sum"];
     this.key = dbObj["key"];
     this.value = dbObj["value"];
+    this.fromFile = dbObj["fromFile"];
 }
 
 module.exports.MediaFileMetaModel = MediaFileMetaModel;

+ 5 - 2
model/mediaService.js

@@ -25,11 +25,14 @@ MediaStruct.prototype.pushMeta = function(key, value) {
             type = 'date';
         else if (['height', 'width', 'iso', 'focal', 'fNumber', 'exposureTime'].indexOf(key) >= 0)
             type = 'number';
-        else if (['artist', 'camera', 'lensModel', 'exposureTimeStr', 'libraryPath', 'compression', 'software'].indexOf(key) >= 0)
+        else if (['geoHash', 'gpsLocation'].indexOf(key) >= 0)
+            type = 'geoData';
+        else if (['artist', 'camera', 'lensModel', 'exposureTimeStr', 'libraryPath', 'compression',
+                'software', 'geoCountry'].indexOf(key) >= 0)
             type = 'string';
         else if (['fileSize'].indexOf(key) >= 0)
             type = 'octet';
-        else console.log(key, value);
+        else console.log(`Unknown meta type ${key} (${value})`);
         this.meta[key] = { type: type, value: value };
     }
 }

+ 1 - 0
package.json

@@ -20,6 +20,7 @@
     "bootstrap-icons": "^1.11.2",
     "craftlabhttpserver": "git:isundil/craftlabHttpServer",
     "crypto": "^1.0.1",
+    "geo-reverse": "^1.0.13",
     "geokit": "^1.1.0",
     "imagemagick": "^0.1.3",
     "ldap": "^0.7.1",

+ 8 - 0
src/filetype/imagemagick.js

@@ -3,6 +3,7 @@ const fs = require('fs');
 const tmp = require('tmp');
 const im = require('imagemagick');
 const geokit = require('geokit');
+const geoRev = require('geo-reverse');
 
 function readMeta(path) {
     return new Promise((ok, ko) => {
@@ -93,6 +94,12 @@ ExifGps.prototype.toGeoHash = function() {
     return geokit.hash({lat: this.data.lat, lng: this.data.lon});
 }
 
+ExifGps.prototype.toCountry = function() {
+    if (!this.data)
+        return undefined;
+    return geoRev.country(this.data.lat, this.data.lon)[0]?.name;
+}
+
 function readTags(data) {
     let result = [];
     if (data['winXP-Keywords']) {
@@ -124,6 +131,7 @@ module.exports.parse = async (fileObj) => {
     const gpsData = new ExifGps(imdata);
     result.gpsLocation = gpsData.toGps();
     result.geoHash = gpsData.toGeoHash();
+    result.geoCountry = gpsData.toCountry();
     result.tags = readTags(imdata);
     for (let i of Object.keys(result))
         if (result[i] === undefined || result[i].length === 0)

+ 15 - 6
src/library.js

@@ -9,7 +9,7 @@ const { ACCESS_TO, AccessModel } = require("../model/access.js");
 const MediaFileModel = require("../model/mediaItem.js").MediaFileModel;
 const MediaFileMetaModel = require("../model/mediaItemMeta.js").MediaFileMetaModel;
 const MediaFileTagModel = require("../model/mediaItemTag.js").MediaFileTagModel;
-const MANAGED_FILES = [ ".cr2" ]; // TODO
+const MANAGED_FILES = [ /* ".cr2" */ ]; // TODO
 const BUFFER_MAXSIZE = 100;
 
 function File(fullPath, name) {
@@ -28,7 +28,7 @@ File.prototype.getIsMedia = function() {
         return this.isMedia;
     if (!this.mimeType)
         this.mimeType = mime.lookup(this.name) || "";
-    this.isMedia = this.mimeType.startsWith("image/") || this.mimeType.startsWith("video/") || !!MANAGED_FILES.find(i => lowerName.endsWith(i));
+    this.isMedia = this.mimeType.startsWith("image/") || /*this.mimeType.startsWith("video/") || */!!MANAGED_FILES.find(i => this.name.toLowerCase().endsWith(i));
     return this.isMedia;
 }
 
@@ -55,9 +55,10 @@ File.prototype.enrich = async function() {
 File.prototype.saveDb = async function(db, libraryHash) {
     if (this.dbItem) {
         await db.remove(MediaFileModel, { path: this.dbItem.path, md5sum: this.dbItem.md5sum });
-        await db.remove(MediaFileMetaModel, { md5sum: this.dbItem.md5sum });
+        await db.remove(MediaFileMetaModel, { md5sum: this.dbItem.md5sum, fromFile: 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();
@@ -68,7 +69,7 @@ File.prototype.saveDb = async function(db, libraryHash) {
     await db.insertOne(entity);
     this.meta.photochamberImport = new Date();
     this.meta.libraryPath = libraryHash;
-    let metaEntities = Object.keys(this.meta).filter(i => i !== 'tags').map(i => new MediaFileMetaModel(_this.checksum, i, _this.meta[i]));
+    let metaEntities = Object.keys(this.meta).filter(i => i !== 'tags').map(i => new MediaFileMetaModel(_this.checksum, i, _this.meta[i], true));
     await db.insertMultipleSameTable(metaEntities);
     if (this.tags.length) {
         let tagsEntities = this.tags.map(i => new MediaFileTagModel(_this.checksum, i, true));
@@ -106,6 +107,8 @@ async function Library_depthupdate(dbHelper, library, dir) {
             await Library_depthupdate(dbHelper, library, fullPath);
         else if (o.isFile()) {
             let f = new File(fullPath, o.name);
+            if (!f.getIsMedia())
+                continue;
             await f.computeChecksum();
             library.buff.push(f);
             if (library.buff.length >= BUFFER_MAXSIZE)
@@ -115,7 +118,9 @@ async function Library_depthupdate(dbHelper, library, dir) {
 }
 
 function Library_isValid(_this) {
-    return fs.existsSync(_this.path);
+    if (fs.existsSync(_this.path))
+        return true;
+    console.error(`Library folder not found (${_this.path})`);
 }
 
 function Library(p) {
@@ -124,6 +129,7 @@ function Library(p) {
 }
 
 Library.prototype.updateLibrary = async function(dbHelper) {
+    const startTime = Date.now();
     console.log(`Starting update of library ${this.path}`);
     this.foundMedias = [];
     this.buff = [];
@@ -135,7 +141,10 @@ Library.prototype.updateLibrary = async function(dbHelper) {
     } catch (err) {
         console.err(`Cannot update Library ${this.path}:`, err);
     }
-    console.log(`Done updating library ${this.path}. Managed ${this.foundMedias.length} new media files.`);
+    let timeDiff = (Date.now() - startTime) / 1000;
+    const timeDiffMin = Math.floor(timeDiff / 60);
+    timeDiff -= timeDiffMin*60;
+    console.log(`Done updating library ${this.path}. Managed ${this.foundMedias.length} new media files. in ${timeDiffMin}m ${timeDiff}s`);
 }
 
 Library.prototype.findMedia = async function(p) {

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

@@ -38,7 +38,7 @@ class Media {
     }
 
     allTags() {
-        return Array.from(new Set(this.fixedTags, this.tags)).sort();
+        return Array.from(new Set([...this.fixedTags, ...this.tags])).sort();
     }
 }