Added option to skip indexing existing files

Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
Michael Mayer 2019-12-09 08:04:41 +01:00
parent 760df93214
commit 6d4e42c79e
21 changed files with 744 additions and 616 deletions

View file

@ -24,7 +24,7 @@ module.exports = (config) => {
files: [
{pattern: "tests/unit/**/*_test.js", watched: false},
'node_modules/@babel/polyfill/dist/polyfill.js',
"node_modules/@babel/polyfill/dist/polyfill.js",
],
// Preprocess through webpack

View file

@ -5,9 +5,9 @@
"requires": true,
"dependencies": {
"@babel/cli": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.7.4.tgz",
"integrity": "sha512-O7mmzaWdm+VabWQmxuM8hqNrWGGihN83KfhPUzp2lAW4kzIMwBxujXkZbD4fMwKMYY9FXTbDvXsJqU+5XHXi4A==",
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.7.5.tgz",
"integrity": "sha512-y2YrMGXM3NUyu1Myg0pxg+Lx6g8XhEyvLHYNRwTBV6fDek3H7Io6b7N/LXscLs4HWn4HxMdy7f2rM1rTMp2mFg==",
"requires": {
"chokidar": "^2.1.8",
"commander": "^4.0.1",
@ -36,14 +36,14 @@
}
},
"@babel/core": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.4.tgz",
"integrity": "sha512-+bYbx56j4nYBmpsWtnPUsKW3NdnYxbqyfrP2w9wILBuHzdfIKz9prieZK0DFPyIzkjYVUe4QkusGL07r5pXznQ==",
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.7.5.tgz",
"integrity": "sha512-M42+ScN4+1S9iB6f+TL7QBpoQETxbclx+KNoKJABghnKYE+fMzSGqst0BZJc8CpI625bwPwYgUyRvxZ+0mZzpw==",
"requires": {
"@babel/code-frame": "^7.5.5",
"@babel/generator": "^7.7.4",
"@babel/helpers": "^7.7.4",
"@babel/parser": "^7.7.4",
"@babel/parser": "^7.7.5",
"@babel/template": "^7.7.4",
"@babel/traverse": "^7.7.4",
"@babel/types": "^7.7.4",
@ -102,9 +102,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -274,9 +274,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -367,9 +367,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -448,9 +448,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -582,9 +582,9 @@
}
},
"@babel/helper-module-transforms": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.4.tgz",
"integrity": "sha512-ehGBu4mXrhs0FxAqN8tWkzF8GSIGAiEumu4ONZ/hD9M88uHcD+Yu2ttKfOCgwzoesJOJrtQh7trI5YPbRtMmnA==",
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.7.5.tgz",
"integrity": "sha512-A7pSxyJf1gN5qXVcidwLWydjftUN878VkalhXX5iQDuGyiGK3sOrrKKHF4/A4fwHtnsotv/NipwAeLzY4KQPvw==",
"requires": {
"@babel/helper-module-imports": "^7.7.4",
"@babel/helper-simple-access": "^7.7.4",
@ -603,9 +603,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -712,9 +712,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -834,9 +834,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -899,9 +899,9 @@
},
"dependencies": {
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -982,9 +982,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -1095,9 +1095,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -1367,9 +1367,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -1471,9 +1471,9 @@
}
},
"@babel/parser": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.4.tgz",
"integrity": "sha512-jIwvLO0zCL+O/LmEJQjWA75MQTWwx3c3u2JOTDK5D3/9egrWRRA0/0hk9XXywYnXZVVpzrBYeIQTmhwUaePI9g=="
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.7.5.tgz",
"integrity": "sha512-KNlOe9+/nk4i29g0VXgl8PEXIRms5xKLJeuZ6UptN0fHv+jDiriG+y94X6qAgWTR0h3KaoM1wK5G5h7MHFRSig=="
},
"@babel/template": {
"version": "7.7.4",
@ -1514,21 +1514,21 @@
}
},
"@babel/plugin-transform-modules-amd": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.4.tgz",
"integrity": "sha512-/542/5LNA18YDtg1F+QHvvUSlxdvjZoD/aldQwkq+E3WCkbEjNSN9zdrOXaSlfg3IfGi22ijzecklF/A7kVZFQ==",
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.7.5.tgz",
"integrity": "sha512-CT57FG4A2ZUNU1v+HdvDSDrjNWBrtCmSH6YbbgN3Lrf0Di/q/lWRxZrE72p3+HCCz9UjfZOEBdphgC0nzOS6DQ==",
"requires": {
"@babel/helper-module-transforms": "^7.7.4",
"@babel/helper-module-transforms": "^7.7.5",
"@babel/helper-plugin-utils": "^7.0.0",
"babel-plugin-dynamic-import-node": "^2.3.0"
}
},
"@babel/plugin-transform-modules-commonjs": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.4.tgz",
"integrity": "sha512-k8iVS7Jhc367IcNF53KCwIXtKAH7czev866ThsTgy8CwlXjnKZna2VHwChglzLleYrcHz1eQEIJlGRQxB53nqA==",
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.7.5.tgz",
"integrity": "sha512-9Cq4zTFExwFhQI6MT1aFxgqhIsMWQWDVwOgLzl7PTWJHsNaqFvklAU+Oz6AQLAS0dJKTwZSOCo20INwktxpi3Q==",
"requires": {
"@babel/helper-module-transforms": "^7.7.4",
"@babel/helper-module-transforms": "^7.7.5",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-simple-access": "^7.7.4",
"babel-plugin-dynamic-import-node": "^2.3.0"
@ -1617,9 +1617,9 @@
}
},
"@babel/plugin-transform-regenerator": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.4.tgz",
"integrity": "sha512-e7MWl5UJvmPEwFJTwkBlPmqixCtr9yAASBqff4ggXTNicZiwbF8Eefzm6NVgfiBp7JdAGItecnctKTgH44q2Jw==",
"version": "7.7.5",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.7.5.tgz",
"integrity": "sha512-/8I8tPvX2FkuEyWbjRCt4qTAgZK0DVy8QRguhA524UH48RfGJy94On2ri+dCuwOpcerPRl9O4ebQkRcVzIaGBw==",
"requires": {
"regenerator-transform": "^0.14.0"
}
@ -1633,9 +1633,9 @@
}
},
"@babel/plugin-transform-runtime": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.4.tgz",
"integrity": "sha512-O8kSkS5fP74Ad/8pfsCMGa8sBRdLxYoSReaARRNSz3FbFQj3z/QUvoUmJ28gn9BO93YfnXc3j+Xyaqe8cKDNBQ==",
"version": "7.7.6",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.7.6.tgz",
"integrity": "sha512-tajQY+YmXR7JjTwRvwL4HePqoL3DYxpYXIHKVvrOIvJmeHe2y1w4tz5qz9ObUDC9m76rCzIMPyn4eERuwA4a4A==",
"requires": {
"@babel/helper-module-imports": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0",
@ -1711,9 +1711,9 @@
}
},
"@babel/preset-env": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.4.tgz",
"integrity": "sha512-Dg+ciGJjwvC1NIe/DGblMbcGq1HOtKbw8RLl4nIjlfcILKEOkWT/vRqPpumswABEBVudii6dnVwrBtzD7ibm4g==",
"version": "7.7.6",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.7.6.tgz",
"integrity": "sha512-k5hO17iF/Q7tR9Jv8PdNBZWYW6RofxhnxKjBMc0nG4JTaWvOTiPoO/RLFwAKcA4FpmuBFm6jkoqaRJLGi0zdaQ==",
"requires": {
"@babel/helper-module-imports": "^7.7.4",
"@babel/helper-plugin-utils": "^7.0.0",
@ -1743,8 +1743,8 @@
"@babel/plugin-transform-function-name": "^7.7.4",
"@babel/plugin-transform-literals": "^7.7.4",
"@babel/plugin-transform-member-expression-literals": "^7.7.4",
"@babel/plugin-transform-modules-amd": "^7.7.4",
"@babel/plugin-transform-modules-commonjs": "^7.7.4",
"@babel/plugin-transform-modules-amd": "^7.7.5",
"@babel/plugin-transform-modules-commonjs": "^7.7.5",
"@babel/plugin-transform-modules-systemjs": "^7.7.4",
"@babel/plugin-transform-modules-umd": "^7.7.4",
"@babel/plugin-transform-named-capturing-groups-regex": "^7.7.4",
@ -1752,7 +1752,7 @@
"@babel/plugin-transform-object-super": "^7.7.4",
"@babel/plugin-transform-parameters": "^7.7.4",
"@babel/plugin-transform-property-literals": "^7.7.4",
"@babel/plugin-transform-regenerator": "^7.7.4",
"@babel/plugin-transform-regenerator": "^7.7.5",
"@babel/plugin-transform-reserved-words": "^7.7.4",
"@babel/plugin-transform-shorthand-properties": "^7.7.4",
"@babel/plugin-transform-spread": "^7.7.4",
@ -1762,7 +1762,7 @@
"@babel/plugin-transform-unicode-regex": "^7.7.4",
"@babel/types": "^7.7.4",
"browserslist": "^4.6.0",
"core-js-compat": "^3.1.1",
"core-js-compat": "^3.4.7",
"invariant": "^2.2.2",
"js-levenshtein": "^1.1.3",
"semver": "^5.5.0"
@ -2017,19 +2017,19 @@
}
},
"@vue/component-compiler-utils": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-1.3.1.tgz",
"integrity": "sha512-IyjJW6ToMitgAhp3xh22QiEW8JvHfLyzlyY/J+GjJ71miod9tNsy6xT2ckm/VirlhPMfeM43kgYZe34jhmmzpw==",
"version": "2.6.0",
"resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz",
"integrity": "sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==",
"requires": {
"consolidate": "^0.15.1",
"hash-sum": "^1.0.2",
"lru-cache": "^4.1.2",
"merge-source-map": "^1.1.0",
"postcss": "^6.0.20",
"postcss-selector-parser": "^3.1.1",
"prettier": "^1.13.0",
"source-map": "^0.5.6",
"vue-template-es2015-compiler": "^1.6.0"
"postcss": "^7.0.14",
"postcss-selector-parser": "^5.0.0",
"prettier": "1.16.3",
"source-map": "~0.6.1",
"vue-template-es2015-compiler": "^1.9.0"
},
"dependencies": {
"consolidate": {
@ -2040,32 +2040,30 @@
"bluebird": "^3.1.1"
}
},
"postcss": {
"version": "6.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
"integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
"requires": {
"chalk": "^2.4.1",
"source-map": "^0.6.1",
"supports-color": "^5.4.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
"cssesc": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-2.0.0.tgz",
"integrity": "sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg=="
},
"postcss-selector-parser": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-3.1.1.tgz",
"integrity": "sha1-T4dfSvsMllc9XPTXQBGu4lCn6GU=",
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz",
"integrity": "sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==",
"requires": {
"dot-prop": "^4.1.1",
"cssesc": "^2.0.0",
"indexes-of": "^1.0.1",
"uniq": "^1.0.1"
}
},
"prettier": {
"version": "1.16.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.16.3.tgz",
"integrity": "sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
@ -2252,49 +2250,27 @@
"integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw=="
},
"acorn-bigint": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/acorn-bigint/-/acorn-bigint-0.2.0.tgz",
"integrity": "sha1-D0WlKQU3eZo7BwhWiaGGiBy1N4Q=",
"requires": {
"acorn": "^5.2.1"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
}
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/acorn-bigint/-/acorn-bigint-0.3.1.tgz",
"integrity": "sha512-WT9LheDC4/d/sD/jgC6L5UMq4U9X3KNMy0JrXp/MdJL83ZqcuPQuMkj50beOX0dMub8IoZUYycfN7bIVZuU5zg=="
},
"acorn-class-fields": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/acorn-class-fields/-/acorn-class-fields-0.1.2.tgz",
"integrity": "sha1-IHgvMEr0Ilf+/1vUpcM1KRRzv1g=",
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/acorn-class-fields/-/acorn-class-fields-0.3.1.tgz",
"integrity": "sha512-X/8hSJuregAnrvfV1Y80VJNfeJx1uhw7yskOwvL631ygYeCGVLPumCnnPDHYZ8acV3ytHhg53K171H3tAemgiw==",
"requires": {
"acorn": "^5.3.0"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
"acorn-private-class-elements": "^0.1.1"
}
},
"acorn-dynamic-import": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-3.0.0.tgz",
"integrity": "sha512-zVWV8Z8lislJoOKKqdNMOB+s6+XV5WERty8MnKBeFgwA+19XJjJHs2RP5dzM57FftIs+jQnRToLiWazKr6sSWg==",
"requires": {
"acorn": "^5.0.0"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
}
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-4.0.0.tgz",
"integrity": "sha512-d3OEjQV4ROpoflsnUA8HozoIR504TFxNivYEUi6uwz0IYhBkTDXGuWlNdMtybRt3nqVx/L6XqMt0FxkXuWKZhw=="
},
"acorn-export-ns-from": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/acorn-export-ns-from/-/acorn-export-ns-from-0.1.0.tgz",
"integrity": "sha512-QDQJBe2DfxNBIMxs+19XY2i/XXilJn+kPgX30HWNYK4IXoNj3ACNSWPU7szL0SzqjFyOG4zoZxG9P7JfNw5g7A=="
},
"acorn-globals": {
"version": "3.1.0",
@ -2312,106 +2288,110 @@
}
},
"acorn-import-meta": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/acorn-import-meta/-/acorn-import-meta-0.2.1.tgz",
"integrity": "sha512-+KB5Q0P0Q/XpsPHgnLx4XbCGqMogw4yiJJjYsbzPCNrE/IoX+c6J4C+BFcwdWh3CD1zLzMxPITN1jzHd+NiS3w==",
"requires": {
"acorn": "^5.4.1"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
}
},
"acorn-json-superset": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/acorn-json-superset/-/acorn-json-superset-0.1.1.tgz",
"integrity": "sha512-fhvg6mWlulil3spkNL0UQtym0pLAaKsKWmDGuTKlP5PVQwv9DlR1avvnnwl2YT9A61AH5j0idgv5/h9Rdkaqyg==",
"requires": {
"acorn": "^5.4.1"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
}
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/acorn-import-meta/-/acorn-import-meta-1.0.0.tgz",
"integrity": "sha512-yX652u86bKzuM+mzEHV84T0R+srQwTOmprUiFC3zlhlc02lBQzqxkB/H/7jexX9vlz/TRuQiZs9mKEDK3bbmhw=="
},
"acorn-jsx": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.1.0.tgz",
"integrity": "sha512-tMUqwBWfLFbJbizRmEcWSLw6HnFzfdJs2sOJEOwwtVPMoH/0Ay+E703oZz78VSXZiiDcZrQ5XKjPIUQixhmgVw=="
},
"acorn-numeric-separator": {
"acorn-private-class-elements": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/acorn-numeric-separator/-/acorn-numeric-separator-0.1.1.tgz",
"integrity": "sha1-qkVaHZWuiHIx3pfgaBq74osGXo0=",
"resolved": "https://registry.npmjs.org/acorn-private-class-elements/-/acorn-private-class-elements-0.1.1.tgz",
"integrity": "sha512-bZpmSnaOsK3jkF7J8xaLJ05f008vapPX+XliIv8+jjkclvDR+M4OnTHLhFnCCSeJ0fMwRKjbY+BXsglSNpVZtw==",
"requires": {
"acorn": "^5.2.1"
"mocha": "^5.2.0"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
}
},
"acorn-optional-catch-binding": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/acorn-optional-catch-binding/-/acorn-optional-catch-binding-0.1.1.tgz",
"integrity": "sha512-LJn5iDpAU1Zah1sdG2pY4rwv7kSe7ykbKpYrwbw5Igfn3OgPyjSD5f0JPboA1xITYpENS9rtNgN7PaAtTsvI/g==",
"requires": {
"acorn": "^5.2.1"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
"commander": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"requires": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
}
},
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
},
"mocha": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-5.2.0.tgz",
"integrity": "sha512-2IUgKDhc3J7Uug+FxMXuqIyYzH7gJjXECKe/w43IGgQHTSj3InJi+yAA7T24L9bQMRKiUEHxEX37G5JpVUGLcQ==",
"requires": {
"browser-stdout": "1.3.1",
"commander": "2.15.1",
"debug": "3.1.0",
"diff": "3.5.0",
"escape-string-regexp": "1.0.5",
"glob": "7.1.2",
"growl": "1.10.5",
"he": "1.1.1",
"minimatch": "3.0.4",
"mkdirp": "0.5.1",
"supports-color": "5.4.0"
}
},
"supports-color": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"acorn-private-methods": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/acorn-private-methods/-/acorn-private-methods-0.1.1.tgz",
"integrity": "sha1-MsE88k0Fvxyb4EkUtBSRxZ11oZU=",
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/acorn-private-methods/-/acorn-private-methods-0.3.0.tgz",
"integrity": "sha512-+gWTjSA+13lsv1mwCPosSrLzEyghYtWgrr/1Ck7i7Pu5iK7Ke0hOgw3IW1RUxhc4qS2QTQBQx2+qHYqsa4Qlqw==",
"requires": {
"acorn": "^5.4.0"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
"acorn-private-class-elements": "^0.1.0"
}
},
"acorn-stage3": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/acorn-stage3/-/acorn-stage3-0.6.0.tgz",
"integrity": "sha512-/CZrHonJfg5OSTkZ71w4L4JnpsqZyDIXaSot5gUpQriTUavjiuAjkJBxxNGtxTlGBVtOBtYwzqxLDUSOD3amDQ==",
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/acorn-stage3/-/acorn-stage3-2.0.0.tgz",
"integrity": "sha512-1Li6EwvFv/O0rZMDduZY2lOly9fyXanmIsyqe26NppIszWhEQlb7IbUrjFGWyRVjQg3H8k7rO0I/tbAr6dORoQ==",
"requires": {
"acorn": "^5.5.0",
"acorn-bigint": "^0.2.0",
"acorn-class-fields": "^0.1.1",
"acorn-dynamic-import": "^3.0.0",
"acorn-import-meta": "^0.2.1",
"acorn-json-superset": "^0.1.0",
"acorn-numeric-separator": "^0.1.1",
"acorn-optional-catch-binding": "^0.1.0",
"acorn-private-methods": "^0.1.1"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
}
"acorn-bigint": "^0.3.1",
"acorn-class-fields": "^0.3.1",
"acorn-dynamic-import": "^4.0.0",
"acorn-export-ns-from": "^0.1.0",
"acorn-import-meta": "^1.0.0",
"acorn-private-methods": "^0.3.0",
"acorn-static-class-features": "^0.2.0"
}
},
"acorn-static-class-features": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/acorn-static-class-features/-/acorn-static-class-features-0.2.0.tgz",
"integrity": "sha512-46IooHSRsvgSi+t36Wx9iPfF9BKFKVDcAWELXVqvKHmZogSCk11iUCi2FiZmLeTaM0hlJ3EYDyYiVmHRUGPzWA==",
"requires": {
"acorn-private-class-elements": "^0.1.0"
}
},
"acorn-walk": {
@ -3291,19 +3271,19 @@
}
},
"browserslist": {
"version": "4.8.0",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.0.tgz",
"integrity": "sha512-HYnxc/oLRWvJ3TsGegR0SRL/UDnknGq2s/a8dYYEO+kOQ9m9apKoS5oiathLKZdh/e9uE+/J3j92qPlGD/vTqA==",
"version": "4.8.2",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.8.2.tgz",
"integrity": "sha512-+M4oeaTplPm/f1pXDw84YohEv7B1i/2Aisei8s4s6k3QsoSHa7i5sz8u/cGQkkatCPxMASKxPualR4wwYgVboA==",
"requires": {
"caniuse-lite": "^1.0.30001012",
"electron-to-chromium": "^1.3.317",
"node-releases": "^1.1.41"
"caniuse-lite": "^1.0.30001015",
"electron-to-chromium": "^1.3.322",
"node-releases": "^1.1.42"
},
"dependencies": {
"caniuse-lite": {
"version": "1.0.30001012",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz",
"integrity": "sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg=="
"version": "1.0.30001015",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001015.tgz",
"integrity": "sha512-/xL2AbW/XWHNu1gnIrO8UitBGoFthcsDgU9VLK1/dpsoxbaD5LscHozKze05R6WLsBvLhqv78dAPozMFQBYLbQ=="
}
}
},
@ -4040,16 +4020,16 @@
}
},
"core-js": {
"version": "3.4.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.7.tgz",
"integrity": "sha512-qaPVGw30J1wQ0GR3GvoPqlGf9GZfKKF4kFC7kiHlcsPTqH3txrs9crCp3ZiMAXuSenhz89Jnl4GZs/67S5VOSg=="
"version": "3.4.8",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.4.8.tgz",
"integrity": "sha512-b+BBmCZmVgho8KnBUOXpvlqEMguko+0P+kXCwD4vIprsXC6ht1qgPxtb1OK6XgSlrySF71wkwBQ0Hv695bk9gQ=="
},
"core-js-compat": {
"version": "3.4.5",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.5.tgz",
"integrity": "sha512-rYVvzvKJDKoefdAC+q6VP63vp5hMmeVONCi9pVUbU1qRrtVrmAk/nPhnRg+i+XFd775m1hpG2Yd5RY3X45ccuw==",
"version": "3.4.8",
"resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.4.8.tgz",
"integrity": "sha512-l3WTmnXHV2Sfu5VuD7EHE2w7y+K68+kULKt5RJg8ZJk3YhHF1qLD4O8v8AmNq+8vbOwnPFFDvds25/AoEvMqlQ==",
"requires": {
"browserslist": "^4.7.3",
"browserslist": "^4.8.2",
"semver": "^6.3.0"
},
"dependencies": {
@ -4706,25 +4686,22 @@
}
},
"easygettext": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/easygettext/-/easygettext-2.7.0.tgz",
"integrity": "sha512-BaoyxsZtre7Ndvgz3utjrE/6Yo8Txsc4m33ehQ0pBNX3HjcjGQozDhnpqSRhaeD8PQAk0Rgq3vhI+YJvQu0vUQ==",
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/easygettext/-/easygettext-2.8.0.tgz",
"integrity": "sha512-tzEoAL7Er6wtljz9yGh2RShLZtoGj9Yl1icV+oEY0aeSIr8R//t4GdZHjyhQJLuE9i0CntYGbT95SNh3yOoHNA==",
"requires": {
"@vue/component-compiler-utils": "^1.2.1",
"acorn": "^5.5.3",
"acorn-stage3": "^0.6.0",
"cheerio": "^1.0.0-rc.2",
"@vue/component-compiler-utils": "^2.6.0",
"acorn": "^6.4.0",
"acorn-stage3": "^2.0.0",
"acorn-walk": "^6.2.0",
"cheerio": "^1.0.0-rc.3",
"flow-remove-types": "^1.2.3",
"minimist": "^1.2.0",
"pofile": "^1.0.10",
"pug": "^2.0.3",
"vue-template-compiler": "^2.5.16"
"pofile": "^1.1.0",
"pug": "^2.0.4",
"vue-template-compiler": "^2.6.10"
},
"dependencies": {
"acorn": {
"version": "5.7.3",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
"integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
},
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
@ -4743,9 +4720,9 @@
"integrity": "sha512-kS/gEPzZs3Y1rRsbGX4UOSjtP/CeJP0CxSNZHYxGfVM/VgLcv0ZqM7C45YyTj2DI2g7+P9Dd24C+IMIg6D0nYQ=="
},
"electron-to-chromium": {
"version": "1.3.319",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.319.tgz",
"integrity": "sha512-t/lYNZPwS9jLJ9SBLGd6ERYtCtsYPAXzsE1VYLshrUWpQCTAswO1pERZV4iOZipW2uVsGQrJtm2iWiYVp1zTZw=="
"version": "1.3.322",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz",
"integrity": "sha512-Tc8JQEfGQ1MzfSzI/bTlSr7btJv/FFO7Yh6tanqVmIWOuNCu6/D1MilIEgLtmWqIrsv+o4IjpLAhgMBr/ncNAA=="
},
"elliptic": {
"version": "6.5.1",
@ -5782,6 +5759,15 @@
"resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
"integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I="
},
"flow-remove-types": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/flow-remove-types/-/flow-remove-types-1.2.3.tgz",
"integrity": "sha512-ypq/U3V+t9atYiOuSJd40tekCra03EHKoRsiK/wXGrsZimuum0kdwVY7Yv0HTaoXgHW1WiayomYd+Q3kkvPl9Q==",
"requires": {
"babylon": "^6.15.0",
"vlq": "^0.2.1"
}
},
"flush-write-stream": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz",
@ -8619,9 +8605,9 @@
"integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA="
},
"node-releases": {
"version": "1.1.41",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.41.tgz",
"integrity": "sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg==",
"version": "1.1.42",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.42.tgz",
"integrity": "sha512-OQ/ESmUqGawI2PRX+XIRao44qWYBBfN54ImQYdWVTQqUckuejOg76ysSqDBK8NG3zwySRVnX36JwDQ6x+9GxzA==",
"requires": {
"semver": "^6.3.0"
},
@ -9205,9 +9191,9 @@
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs="
},
"postcss": {
"version": "7.0.23",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.23.tgz",
"integrity": "sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ==",
"version": "7.0.24",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.24.tgz",
"integrity": "sha512-Xl0XvdNWg+CblAXzNvbSOUvgJXwSjmbAKORqyw9V2AlHrm1js2gFw9y3jibBAhpKZi8b5JzJCVh/FyzPsTtgTA==",
"requires": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
@ -12416,6 +12402,11 @@
"resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz",
"integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ=="
},
"vlq": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.3.tgz",
"integrity": "sha512-DRibZL6DsNhIgYQ+wNdWDL2SL3bKPlVrRiBqV5yuMm++op8W4kGFtaQfCs4KEJn0wBZcHVHJ3eoywX8983k1ow=="
},
"vm-browserify": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",

View file

@ -16,11 +16,11 @@
"gettext-compile": "gettext-compile --output src/resources/translations.json src/resources/*.po"
},
"dependencies": {
"@babel/cli": "^7.7.4",
"@babel/core": "^7.7.4",
"@babel/plugin-transform-runtime": "^7.7.4",
"@babel/cli": "^7.7.5",
"@babel/core": "^7.7.5",
"@babel/plugin-transform-runtime": "^7.7.6",
"@babel/polyfill": "^7.7.0",
"@babel/preset-env": "^7.7.4",
"@babel/preset-env": "^7.7.6",
"@babel/register": "^7.7.4",
"@fortawesome/fontawesome-free": "^5.11.2",
"@types/leaflet": "^1.5.6",
@ -32,7 +32,7 @@
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"babel-plugin-istanbul": "^5.2.0",
"browserslist": "^4.8.0",
"browserslist": "^4.8.2",
"chai": "^4.2.0",
"chalk": "^2.4.2",
"chart.js": "^2.9.3",
@ -40,12 +40,12 @@
"clean-webpack-plugin": "^3.0.0",
"connect-history-api-fallback": "^1.3.0",
"copy-webpack-plugin": "^5.0.5",
"core-js": "^3.4.7",
"core-js": "^3.4.8",
"cross-env": "^5.2.1",
"crypto-random-string": "^3.0.1",
"css-loader": "^2.1.1",
"cssnano": "^4.1.10",
"easygettext": "^2.7.0",
"easygettext": "^2.8.0",
"eslint": "^6.7.2",
"eslint-config-standard": "^13.0.1",
"eslint-formatter-pretty": "^2.1.1",
@ -79,7 +79,7 @@
"ora": "^3.4.0",
"photoswipe": "^4.1.3",
"pluralize": "^8.0.0",
"postcss": "^7.0.23",
"postcss": "^7.0.24",
"postcss-browser-reporter": "^0.6.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",

View file

@ -15,7 +15,7 @@ class Config {
this.values = values;
this.debug = !!values.debug;
this.page = {
title: "PhotoPrism"
title: "PhotoPrism",
};
this.subscriptionId = Event.subscribe("config.updated", (ev, data) => this.setValues(data));

View file

@ -14,7 +14,7 @@ export default class Util {
IX: 9,
V: 5,
IV: 4,
I: 1
I: 1,
};
let a;
if (number < 1 || number > 3999)

View file

@ -42,17 +42,17 @@
icon large absolute
class="p-photo-select"
@click.stop.prevent="$clipboard.toggle(photo)">
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white">check_circle</v-icon>
<v-icon v-else color="accent lighten-3">radio_button_off</v-icon>
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white" class="p-photo-select-on">check_circle</v-icon>
<v-icon v-else color="accent lighten-3" class="p-photo-select-off">radio_button_off</v-icon>
</v-btn>
<v-btn v-if="hover || photo.PhotoFavorite" :flat="!hover" :ripple="false"
icon large absolute
class="p-photo-like"
@click.stop.prevent="photo.toggleLike()">
<v-icon v-if="photo.PhotoFavorite" color="white">favorite
<v-icon v-if="photo.PhotoFavorite" color="white" class="p-photo-like-on">favorite
</v-icon>
<v-icon v-else color="accent lighten-3">favorite_border</v-icon>
<v-icon v-else color="accent lighten-3" class="p-photo-like-off">favorite_border</v-icon>
</v-btn>
</v-img>

View file

@ -41,16 +41,16 @@
icon small absolute
class="p-photo-select"
@click.stop.prevent="$clipboard.toggle(photo)">
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white">check_circle</v-icon>
<v-icon v-else color="accent lighten-3">radio_button_off</v-icon>
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white" class="p-photo-select-on">check_circle</v-icon>
<v-icon v-else color="accent lighten-3" class="p-photo-select-off">radio_button_off</v-icon>
</v-btn>
<v-btn v-if="hover || photo.PhotoFavorite" :flat="!hover" :ripple="false"
icon small absolute
class="p-photo-like"
@click.stop.prevent="photo.toggleLike()">
<v-icon v-if="photo.PhotoFavorite" color="white">favorite</v-icon>
<v-icon v-else color="accent lighten-3">favorite_border</v-icon>
<v-icon v-if="photo.PhotoFavorite" color="white" class="p-photo-like-on">favorite</v-icon>
<v-icon v-else color="accent lighten-3" class="p-photo-like-off">favorite_border</v-icon>
</v-btn>
</v-img>

View file

@ -41,16 +41,16 @@
icon large absolute
class="p-photo-select"
@click.stop.prevent="$clipboard.toggle(photo)">
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white">check_circle</v-icon>
<v-icon v-else-if="!$clipboard.has(photo)" color="accent lighten-3">radio_button_off</v-icon>
<v-icon v-if="selection.length && $clipboard.has(photo)" color="white" class="p-photo-select-on">check_circle</v-icon>
<v-icon v-else-if="!$clipboard.has(photo)" color="accent lighten-3" class="p-photo-select-off">radio_button_off</v-icon>
</v-btn>
<v-btn v-if="hover || photo.PhotoFavorite" :flat="!hover" :ripple="false"
icon large absolute
class="p-photo-like"
@click.stop.prevent="photo.toggleLike()">
<v-icon v-if="photo.PhotoFavorite" color="white">favorite</v-icon>
<v-icon v-else color="accent lighten-3">favorite_border</v-icon>
<v-icon v-if="photo.PhotoFavorite" color="white" class="p-photo-like-on">favorite</v-icon>
<v-icon v-else color="accent lighten-3" class="p-photo-like-off">favorite_border</v-icon>
</v-btn>
</v-img>

View file

@ -4,12 +4,21 @@
<v-container fluid>
<p class="subheading">
<span v-if="fileName">Indexing {{ fileName }}...</span>
<span v-else-if="busy">Re-indexing existing files and photos...</span>
<span v-else-if="busy">Indexing photos and sidecar files...</span>
<span v-else-if="completed">Done.</span>
<span v-else>Press button to re-index existing files and photos...</span>
<span v-else>Press button to start indexing...</span>
</p>
<v-progress-linear color="secondary-dark" :value="completed" :indeterminate="busy"></v-progress-linear>
<p class="options">
<v-progress-linear color="secondary-dark" :value="completed" :indeterminate="busy"></v-progress-linear>
</p>
<v-checkbox
v-model="options.skip"
color="secondary-dark"
:disabled="busy"
label="Skip existing photos and sidecar files"
></v-checkbox>
<v-btn
:disabled="busy"
@ -41,6 +50,9 @@
completed: 0,
subscriptionId: '',
fileName: '',
options: {
skip: true
},
source: null,
}
},
@ -58,7 +70,7 @@
const ctx = this;
Notify.blockUI();
Api.post('index', {}, { cancelToken: this.source.token }).then(function () {
Api.post('index', this.options, { cancelToken: this.source.token }).then(function () {
Notify.unblockUI();
ctx.busy = false;
ctx.completed = 100;

View file

@ -9,7 +9,9 @@ import (
"github.com/gin-gonic/gin"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/form"
"github.com/photoprism/photoprism/internal/photoprism"
"github.com/photoprism/photoprism/internal/util"
)
var indexer *photoprism.Indexer
@ -33,13 +35,25 @@ func Index(router *gin.RouterGroup, conf *config.Config) {
}
start := time.Now()
var f form.IndexerOptions
if err := c.BindJSON(&f); err != nil {
c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": util.UcFirst(err.Error())})
return
}
path := conf.OriginalsPath()
event.Info(fmt.Sprintf("indexing photos in \"%s\"", filepath.Base(path)))
initIndexer(conf)
indexer.IndexAll()
if f.SkipExisting {
indexer.IndexOriginals(photoprism.IndexerOptionsNone())
} else {
indexer.IndexOriginals(photoprism.IndexerOptionsAll())
}
elapsed := int(time.Since(start).Seconds())

View file

@ -21,7 +21,7 @@ import (
// label: string Label
// cat: string Category
// country: string Country code
// camera: int Camera ID
// camera: int UpdateCamera ID
// order: string Sort order
// count: int Max result count (required)
// offset: int Result offset

View file

@ -42,7 +42,8 @@ func indexAction(ctx *cli.Context) error {
indexer := photoprism.NewIndexer(conf, tensorFlow)
files := indexer.IndexAll()
options := photoprism.IndexerOptionsAll()
files := indexer.IndexOriginals(options)
elapsed := time.Since(start)

View file

@ -0,0 +1,5 @@
package form
type IndexerOptions struct {
SkipExisting bool `json:"skip"`
}

View file

@ -8,7 +8,7 @@ import (
"github.com/jinzhu/gorm"
)
// Camera model and make (as extracted from EXIF metadata)
// Camera model and make (as extracted from UpdateExif metadata)
type Camera struct {
Model
CameraSlug string

View file

@ -5,7 +5,7 @@ import (
"github.com/jinzhu/gorm"
)
// Camera lens (as extracted from EXIF metadata)
// Camera lens (as extracted from UpdateExif metadata)
type Lens struct {
Model
LensSlug string

View file

@ -44,7 +44,7 @@ func TestConverter_ConvertToJpeg(t *testing.T) {
infoJpeg, err := imageJpeg.Exif()
assert.Nilf(t, err, "Exif() failed for "+imageJpeg.Filename())
assert.Nilf(t, err, "UpdateExif() failed for "+imageJpeg.Filename())
if err != nil {
return
@ -52,7 +52,7 @@ func TestConverter_ConvertToJpeg(t *testing.T) {
assert.Equal(t, jpegFilename, imageJpeg.filename)
assert.False(t, infoJpeg == nil || err != nil, "Could not read EXIF data of JPEG image")
assert.False(t, infoJpeg == nil || err != nil, "Could not read UpdateExif data of JPEG image")
assert.Equal(t, "Canon EOS 7D", infoJpeg.CameraModel)
@ -72,7 +72,7 @@ func TestConverter_ConvertToJpeg(t *testing.T) {
infoRaw, err := imageRaw.Exif()
assert.False(t, infoRaw == nil || err != nil, "Could not read EXIF data of RAW image")
assert.False(t, infoRaw == nil || err != nil, "Could not read UpdateExif data of RAW image")
assert.Equal(t, "Canon EOS 6D", infoRaw.CameraModel)
}
@ -102,9 +102,9 @@ func TestConverter_ConvertAll(t *testing.T) {
infoRaw, err := image.Exif()
assert.False(t, infoRaw == nil || err != nil, "Could not read EXIF data of RAW image")
assert.False(t, infoRaw == nil || err != nil, "Could not read UpdateExif data of RAW image")
assert.Equal(t, "Canon EOS 6D", infoRaw.CameraModel, "Camera model should be Canon EOS M10")
assert.Equal(t, "Canon EOS 6D", infoRaw.CameraModel, "UpdateCamera model should be Canon EOS M10")
existingJpegFilename := conf.ImportPath() + "/raw/IMG_2567.jpg"

View file

@ -47,6 +47,7 @@ func (i *Importer) originalsPath() string {
// This function ignores errors.
func (i *Importer) ImportPhotosFromDirectory(importPath string) {
var directories []string
options := IndexerOptionsAll()
err := filepath.Walk(importPath, func(filename string, fileInfo os.FileInfo, err error) error {
var destinationMainFilename string
@ -144,7 +145,7 @@ func (i *Importer) ImportPhotosFromDirectory(importPath string) {
}
}
i.indexer.IndexRelated(importedMainFile)
i.indexer.IndexRelated(importedMainFile, options)
}
return nil

View file

@ -1,23 +1,12 @@
package photoprism
import (
"fmt"
"os"
"path/filepath"
"sort"
"strings"
"time"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/config"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/models"
"github.com/photoprism/photoprism/internal/util"
)
const (
indexResultUpdated = "updated"
indexResultAdded = "added"
)
// Indexer defines an indexer with originals path tensorflow and a db.
@ -47,315 +36,8 @@ func (i *Indexer) thumbnailsPath() string {
return i.conf.ThumbnailsPath()
}
// classifyImage returns all matching labels for a media file.
func (i *Indexer) classifyImage(jpeg *MediaFile) (results Labels) {
start := time.Now()
var thumbs []string
if jpeg.AspectRatio() == 1 {
thumbs = []string{"tile_224"}
} else {
thumbs = []string{"tile_224", "left_224", "right_224"}
}
var labels Labels
for _, thumb := range thumbs {
filename, err := jpeg.Thumbnail(i.thumbnailsPath(), thumb)
if err != nil {
log.Error(err)
continue
}
imageLabels, err := i.tensorFlow.LabelsFromFile(filename)
if err != nil {
log.Error(err)
continue
}
labels = append(labels, imageLabels...)
}
// Sort by priority and uncertainty
sort.Sort(labels)
var confidence int
for _, label := range labels {
if confidence == 0 {
confidence = 100 - label.Uncertainty
}
if (100 - label.Uncertainty) > (confidence / 3) {
results = append(results, label)
}
}
elapsed := time.Since(start)
log.Debugf("finding %+v labels for %s took %s", results, jpeg.Filename(), elapsed)
return results
}
func (i *Indexer) indexMediaFile(mediaFile *MediaFile) string {
var photo models.Photo
var file, primaryFile models.File
var isPrimary = false
var exifData *Exif
var photoQuery, fileQuery *gorm.DB
var keywords []string
labels := Labels{}
fileBase := mediaFile.Basename()
filePath := mediaFile.RelativePath(i.originalsPath())
fileName := mediaFile.RelativeFilename(i.originalsPath())
fileHash := mediaFile.Hash()
event.Publish("index.file", event.Data{
"fileHash": fileHash,
"fileName": fileName,
"baseName": filepath.Base(fileName),
})
exifData, err := mediaFile.Exif()
if err != nil {
log.Debug(err)
}
fileQuery = i.db.Unscoped().First(&file, "file_hash = ? OR file_name = ?", fileHash, fileName)
if fileQuery.Error != nil {
photoQuery = i.db.Unscoped().First(&photo, "photo_path = ? AND photo_name = ?", filePath, fileBase)
if photoQuery.Error != nil && mediaFile.HasTimeAndPlace() {
photoQuery = i.db.Unscoped().First(&photo, "photo_lat = ? AND photo_long = ? AND taken_at = ?", exifData.Lat, exifData.Long, exifData.TakenAt)
}
} else {
photoQuery = i.db.Unscoped().First(&photo, "id = ?", file.PhotoID)
}
photo.PhotoPath = filePath
photo.PhotoName = fileBase
if jpeg, err := mediaFile.Jpeg(); err == nil {
// Image classification labels
labels = i.classifyImage(jpeg)
// Read Exif data
if exifData, err := jpeg.Exif(); err == nil {
photo.PhotoLat = exifData.Lat
photo.PhotoLong = exifData.Long
photo.TakenAt = exifData.TakenAt
photo.TakenAtLocal = exifData.TakenAtLocal
photo.TimeZone = exifData.TimeZone
photo.PhotoAltitude = exifData.Altitude
photo.PhotoArtist = exifData.Artist
if exifData.UUID != "" {
log.Debugf("photo uuid: %s", exifData.UUID)
photo.PhotoUUID = exifData.UUID
} else {
log.Debug("no photo uuid")
}
}
// Set Camera, Lens, Focal Length and F Number
photo.Camera = models.NewCamera(mediaFile.CameraModel(), mediaFile.CameraMake()).FirstOrCreate(i.db)
photo.Lens = models.NewLens(mediaFile.LensModel(), mediaFile.LensMake()).FirstOrCreate(i.db)
photo.PhotoFocalLength = mediaFile.FocalLength()
photo.PhotoFNumber = mediaFile.FNumber()
photo.PhotoIso = mediaFile.Iso()
photo.PhotoExposure = mediaFile.Exposure()
}
if photo.TakenAt.IsZero() || photo.TakenAtLocal.IsZero() {
photo.TakenAt = mediaFile.DateCreated()
photo.TakenAtLocal = photo.TakenAt
}
if location, err := mediaFile.Location(); err == nil {
i.db.FirstOrCreate(location, "id = ?", location.ID)
photo.Location = location
photo.LocationEstimated = false
photo.Country = models.NewCountry(location.LocCountryCode, location.LocCountry).FirstOrCreate(i.db)
keywords = append(keywords, util.Keywords(location.LocDisplayName)...)
// Append labels from OpenStreetMap
if location.LocCity != "" {
labels = append(labels, NewLocationLabel(location.LocCity, 0, -2))
}
if location.LocCountry != "" {
labels = append(labels, NewLocationLabel(location.LocCountry, 0, -2))
}
if location.LocCategory != "" {
labels = append(labels, NewLocationLabel(location.LocCategory, 0, -2))
}
if location.LocType != "" {
labels = append(labels, NewLocationLabel(location.LocType, 0, -1))
}
// Sort by priority and uncertainty
sort.Sort(labels)
if photo.PhotoTitleChanged == false {
log.Infof("setting title based on the following labels: %#v", labels)
if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 60 && labels[0].Name != "" { // TODO: User defined title format
log.Infof("label for title: %#v", labels[0])
if location.LocCity == "" || len(location.LocCity) > 16 || strings.Contains(labels[0].Name, location.LocCity) {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCountry, photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCity, photo.TakenAt.Format("2006"))
}
} else if location.LocName != "" && location.LocCity != "" {
if len(location.LocName) > 45 {
photo.PhotoTitle = util.Title(location.LocName)
} else if len(location.LocName) > 20 || len(location.LocCity) > 16 || strings.Contains(location.LocName, location.LocCity) {
photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(location.LocName), photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(location.LocName), location.LocCity, photo.TakenAt.Format("2006"))
}
} else if location.LocCity != "" && location.LocCountry != "" {
if len(location.LocCity) > 20 {
photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCity, photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCity, location.LocCountry, photo.TakenAt.Format("2006"))
}
} else if location.LocCounty != "" && location.LocCountry != "" {
if len(location.LocCounty) > 20 {
photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCounty, photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCounty, location.LocCountry, photo.TakenAt.Format("2006"))
}
}
}
} else {
log.Debugf("location cannot be determined precisely: %s", err)
}
if photo.PhotoTitleChanged == false && photo.PhotoTitle == "" {
if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 85 && labels[0].Name != "" {
photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(labels[0].Name), mediaFile.DateCreated().Format("2006"))
} else if !photo.TakenAtLocal.IsZero() {
var daytimeString string
hour := photo.TakenAtLocal.Hour()
switch {
case hour < 17:
daytimeString = "Unknown"
case hour < 20:
daytimeString = "Sunset"
default:
daytimeString = "Unknown"
}
photo.PhotoTitle = fmt.Sprintf("%s / %s", daytimeString, photo.TakenAtLocal.Format("2006"))
}
}
log.Debugf("title: \"%s\"", photo.PhotoTitle)
if photoQuery.Error != nil {
photo.PhotoFavorite = false
i.db.Create(&photo)
} else {
// Estimate location
if photo.LocationID == 0 {
var recentPhoto models.Photo
if result := i.db.Unscoped().Order(gorm.Expr("ABS(DATEDIFF(taken_at, ?)) ASC", photo.TakenAt)).Preload("Country").First(&recentPhoto); result.Error == nil {
if recentPhoto.Country != nil {
photo.Country = recentPhoto.Country
photo.LocationEstimated = true
log.Debugf("approximate location: %s", recentPhoto.Country.CountryName)
}
}
}
i.db.Unscoped().Save(&photo)
}
log.Infof("adding labels: %+v", labels)
for _, label := range labels {
lm := models.NewLabel(label.Name, label.Priority).FirstOrCreate(i.db)
if lm.LabelPriority != label.Priority {
lm.LabelPriority = label.Priority
i.db.Save(&lm)
}
plm := models.NewPhotoLabel(photo.ID, lm.ID, label.Uncertainty, label.Source).FirstOrCreate(i.db)
// Add categories
for _, category := range label.Categories {
sn := models.NewLabel(category, -1).FirstOrCreate(i.db)
i.db.Model(&lm).Association("LabelCategories").Append(sn)
}
if plm.LabelUncertainty > label.Uncertainty {
plm.LabelUncertainty = label.Uncertainty
plm.LabelSource = label.Source
i.db.Save(&plm)
}
}
if result := i.db.Where("file_type = 'jpg' AND file_primary = 1 AND photo_id = ?", photo.ID).First(&primaryFile); result.Error != nil {
isPrimary = mediaFile.IsJpeg()
} else {
isPrimary = mediaFile.IsJpeg() && (fileName == primaryFile.FileName || fileHash == primaryFile.FileHash)
}
if isPrimary {
photo.IndexKeywords(keywords, i.db)
}
file.PhotoID = photo.ID
file.PhotoUUID = photo.PhotoUUID
file.FilePrimary = isPrimary
file.FileMissing = false
file.FileName = fileName
file.FileHash = fileHash
file.FileType = mediaFile.Type()
file.FileMime = mediaFile.MimeType()
file.FileOrientation = mediaFile.Orientation()
// Color information
if p, err := mediaFile.Colors(i.thumbnailsPath()); err == nil {
file.FileMainColor = p.MainColor.Name()
file.FileColors = p.Colors.Hex()
file.FileLuminance = p.Luminance.Hex()
file.FileChroma = p.Chroma.Uint()
}
if mediaFile.Width() > 0 && mediaFile.Height() > 0 {
file.FileWidth = mediaFile.Width()
file.FileHeight = mediaFile.Height()
file.FileAspectRatio = mediaFile.AspectRatio()
file.FilePortrait = mediaFile.Width() < mediaFile.Height()
}
if fileQuery.Error == nil {
i.db.Unscoped().Save(&file)
return indexResultUpdated
}
i.db.Create(&file)
return indexResultAdded
}
// IndexRelated will index all mediafiles which has relate to a given mediafile.
func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool {
func (i *Indexer) IndexRelated(mediaFile *MediaFile, o IndexerOptions) map[string]bool {
indexed := make(map[string]bool)
relatedFiles, mainFile, err := mediaFile.RelatedFiles()
@ -366,7 +48,7 @@ func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool {
return indexed
}
mainIndexResult := i.indexMediaFile(mainFile)
mainIndexResult := i.indexMediaFile(mainFile, o)
indexed[mainFile.Filename()] = true
log.Infof("%s main %s file \"%s\"", mainIndexResult, mainFile.Type(), mainFile.RelativeFilename(i.originalsPath()))
@ -376,7 +58,7 @@ func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool {
continue
}
indexResult := i.indexMediaFile(relatedMediaFile)
indexResult := i.indexMediaFile(relatedMediaFile, o)
indexed[relatedMediaFile.Filename()] = true
log.Infof("%s related %s file \"%s\"", indexResult, relatedMediaFile.Type(), relatedMediaFile.RelativeFilename(i.originalsPath()))
@ -385,8 +67,8 @@ func (i *Indexer) IndexRelated(mediaFile *MediaFile) map[string]bool {
return indexed
}
// IndexAll will index all mediafiles.
func (i *Indexer) IndexAll() map[string]bool {
// IndexOriginals will index mediafiles in the originals directory.
func (i *Indexer) IndexOriginals(o IndexerOptions) map[string]bool {
indexed := make(map[string]bool)
err := filepath.Walk(i.originalsPath(), func(filename string, fileInfo os.FileInfo, err error) error {
@ -409,7 +91,7 @@ func (i *Indexer) IndexAll() map[string]bool {
return nil
}
for relatedFilename := range i.IndexRelated(mediaFile) {
for relatedFilename := range i.IndexRelated(mediaFile, o) {
indexed[relatedFilename] = true
}

View file

@ -0,0 +1,361 @@
package photoprism
import (
"fmt"
"path/filepath"
"sort"
"strings"
"time"
"github.com/jinzhu/gorm"
"github.com/photoprism/photoprism/internal/event"
"github.com/photoprism/photoprism/internal/models"
"github.com/photoprism/photoprism/internal/util"
)
const (
indexResultUpdated IndexResult = "updated"
indexResultAdded IndexResult = "added"
indexResultSkipped IndexResult = "skipped"
)
type IndexResult string
// classifyImage returns all matching labels for a media file.
func (i *Indexer) classifyImage(jpeg *MediaFile) (results Labels) {
start := time.Now()
var thumbs []string
if jpeg.AspectRatio() == 1 {
thumbs = []string{"tile_224"}
} else {
thumbs = []string{"tile_224", "left_224", "right_224"}
}
var labels Labels
for _, thumb := range thumbs {
filename, err := jpeg.Thumbnail(i.thumbnailsPath(), thumb)
if err != nil {
log.Error(err)
continue
}
imageLabels, err := i.tensorFlow.LabelsFromFile(filename)
if err != nil {
log.Error(err)
continue
}
labels = append(labels, imageLabels...)
}
// Sort by priority and uncertainty
sort.Sort(labels)
var confidence int
for _, label := range labels {
if confidence == 0 {
confidence = 100 - label.Uncertainty
}
if (100 - label.Uncertainty) > (confidence / 3) {
results = append(results, label)
}
}
elapsed := time.Since(start)
log.Debugf("finding %+v labels for %s took %s", results, jpeg.Filename(), elapsed)
return results
}
func (i *Indexer) indexMediaFile(mediaFile *MediaFile, o IndexerOptions) IndexResult {
var photo models.Photo
var file, primaryFile models.File
var isPrimary = false
var exifData *Exif
var photoQuery, fileQuery *gorm.DB
var keywords []string
labels := Labels{}
fileBase := mediaFile.Basename()
filePath := mediaFile.RelativePath(i.originalsPath())
fileName := mediaFile.RelativeFilename(i.originalsPath())
fileHash := mediaFile.Hash()
fileExists := false
photoExists := false
exists := false
isNew := true
event.Publish("index.file", event.Data{
"fileHash": fileHash,
"fileName": fileName,
"baseName": filepath.Base(fileName),
})
exifData, err := mediaFile.Exif()
if err != nil {
log.Debug(err)
}
fileQuery = i.db.Unscoped().First(&file, "file_hash = ? OR file_name = ?", fileHash, fileName)
fileExists = fileQuery.Error == nil
if !fileExists {
photoQuery = i.db.Unscoped().First(&photo, "photo_path = ? AND photo_name = ?", filePath, fileBase)
if photoQuery.Error != nil && mediaFile.HasTimeAndPlace() {
photoQuery = i.db.Unscoped().First(&photo, "photo_lat = ? AND photo_long = ? AND taken_at = ?", exifData.Lat, exifData.Long, exifData.TakenAt)
}
} else {
photoQuery = i.db.Unscoped().First(&photo, "id = ?", file.PhotoID)
}
photoExists = photoQuery.Error == nil
exists = fileExists && photoExists
isNew = !exists
if exists && o.SkipExisting() {
return indexResultSkipped
}
photo.PhotoPath = filePath
photo.PhotoName = fileBase
if jpeg, err := mediaFile.Jpeg(); err == nil {
if isNew || o.UpdateLabels {
// Image classification labels
labels = i.classifyImage(jpeg)
}
if isNew || o.UpdateExif {
// Read UpdateExif data
if exifData, err := jpeg.Exif(); err == nil {
photo.PhotoLat = exifData.Lat
photo.PhotoLong = exifData.Long
photo.TakenAt = exifData.TakenAt
photo.TakenAtLocal = exifData.TakenAtLocal
photo.TimeZone = exifData.TimeZone
photo.PhotoAltitude = exifData.Altitude
photo.PhotoArtist = exifData.Artist
if exifData.UUID != "" {
log.Debugf("photo uuid: %s", exifData.UUID)
photo.PhotoUUID = exifData.UUID
} else {
log.Debug("no photo uuid")
}
}
}
if isNew || o.UpdateCamera {
// Set UpdateCamera, Lens, Focal Length and F Number
photo.Camera = models.NewCamera(mediaFile.CameraModel(), mediaFile.CameraMake()).FirstOrCreate(i.db)
photo.Lens = models.NewLens(mediaFile.LensModel(), mediaFile.LensMake()).FirstOrCreate(i.db)
photo.PhotoFocalLength = mediaFile.FocalLength()
photo.PhotoFNumber = mediaFile.FNumber()
photo.PhotoIso = mediaFile.Iso()
photo.PhotoExposure = mediaFile.Exposure()
}
}
if isNew || o.UpdateDate {
if photo.TakenAt.IsZero() || photo.TakenAtLocal.IsZero() {
photo.TakenAt = mediaFile.DateCreated()
photo.TakenAtLocal = photo.TakenAt
}
}
if isNew || o.UpdateLocation {
if location, err := mediaFile.Location(); err == nil {
i.db.FirstOrCreate(location, "id = ?", location.ID)
photo.Location = location
photo.LocationEstimated = false
photo.Country = models.NewCountry(location.LocCountryCode, location.LocCountry).FirstOrCreate(i.db)
keywords = append(keywords, util.Keywords(location.LocDisplayName)...)
// Append labels from OpenStreetMap
if location.LocCity != "" {
labels = append(labels, NewLocationLabel(location.LocCity, 0, -2))
}
if location.LocCountry != "" {
labels = append(labels, NewLocationLabel(location.LocCountry, 0, -2))
}
if location.LocCategory != "" {
labels = append(labels, NewLocationLabel(location.LocCategory, 0, -2))
}
if location.LocType != "" {
labels = append(labels, NewLocationLabel(location.LocType, 0, -1))
}
// Sort by priority and uncertainty
sort.Sort(labels)
if (isNew || o.UpdateTitle) && photo.PhotoTitleChanged == false {
log.Infof("setting title based on the following labels: %#v", labels)
if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 60 && labels[0].Name != "" { // TODO: User defined title format
log.Infof("label for title: %#v", labels[0])
if location.LocCity == "" || len(location.LocCity) > 16 || strings.Contains(labels[0].Name, location.LocCity) {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCountry, photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(labels[0].Name), location.LocCity, photo.TakenAt.Format("2006"))
}
} else if location.LocName != "" && location.LocCity != "" {
if len(location.LocName) > 45 {
photo.PhotoTitle = util.Title(location.LocName)
} else if len(location.LocName) > 20 || len(location.LocCity) > 16 || strings.Contains(location.LocName, location.LocCity) {
photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(location.LocName), photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", util.Title(location.LocName), location.LocCity, photo.TakenAt.Format("2006"))
}
} else if location.LocCity != "" && location.LocCountry != "" {
if len(location.LocCity) > 20 {
photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCity, photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCity, location.LocCountry, photo.TakenAt.Format("2006"))
}
} else if location.LocCounty != "" && location.LocCountry != "" {
if len(location.LocCounty) > 20 {
photo.PhotoTitle = fmt.Sprintf("%s / %s", location.LocCounty, photo.TakenAt.Format("2006"))
} else {
photo.PhotoTitle = fmt.Sprintf("%s / %s / %s", location.LocCounty, location.LocCountry, photo.TakenAt.Format("2006"))
}
}
}
} else {
log.Debugf("location cannot be determined precisely: %s", err)
}
}
if (isNew || o.UpdateTitle) && photo.PhotoTitleChanged == false && photo.PhotoTitle == "" {
if len(labels) > 0 && labels[0].Priority >= -1 && labels[0].Uncertainty <= 85 && labels[0].Name != "" {
photo.PhotoTitle = fmt.Sprintf("%s / %s", util.Title(labels[0].Name), mediaFile.DateCreated().Format("2006"))
} else if !photo.TakenAtLocal.IsZero() {
var daytimeString string
hour := photo.TakenAtLocal.Hour()
switch {
case hour < 17:
daytimeString = "Unknown"
case hour < 20:
daytimeString = "Sunset"
default:
daytimeString = "Unknown"
}
photo.PhotoTitle = fmt.Sprintf("%s / %s", daytimeString, photo.TakenAtLocal.Format("2006"))
}
}
log.Debugf("title: \"%s\"", photo.PhotoTitle)
if photoExists {
// Estimate location
if o.UpdateLocation && photo.LocationID == 0 {
var recentPhoto models.Photo
if result := i.db.Unscoped().Order(gorm.Expr("ABS(DATEDIFF(taken_at, ?)) ASC", photo.TakenAt)).Preload("Country").First(&recentPhoto); result.Error == nil {
if recentPhoto.Country != nil {
photo.Country = recentPhoto.Country
photo.LocationEstimated = true
log.Debugf("approximate location: %s", recentPhoto.Country.CountryName)
}
}
}
i.db.Unscoped().Save(&photo)
} else {
photo.PhotoFavorite = false
i.db.Create(&photo)
}
log.Infof("adding labels: %+v", labels)
if isNew || o.UpdateLabels {
for _, label := range labels {
lm := models.NewLabel(label.Name, label.Priority).FirstOrCreate(i.db)
if lm.LabelPriority != label.Priority {
lm.LabelPriority = label.Priority
i.db.Save(&lm)
}
plm := models.NewPhotoLabel(photo.ID, lm.ID, label.Uncertainty, label.Source).FirstOrCreate(i.db)
// Add categories
for _, category := range label.Categories {
sn := models.NewLabel(category, -1).FirstOrCreate(i.db)
i.db.Model(&lm).Association("LabelCategories").Append(sn)
}
if plm.LabelUncertainty > label.Uncertainty {
plm.LabelUncertainty = label.Uncertainty
plm.LabelSource = label.Source
i.db.Save(&plm)
}
}
}
if result := i.db.Where("file_type = 'jpg' AND file_primary = 1 AND photo_id = ?", photo.ID).First(&primaryFile); result.Error != nil {
isPrimary = mediaFile.IsJpeg()
} else {
isPrimary = mediaFile.IsJpeg() && (fileName == primaryFile.FileName || fileHash == primaryFile.FileHash)
}
if (isNew || o.UpdateKeywords) && isPrimary {
photo.IndexKeywords(keywords, i.db)
}
file.PhotoID = photo.ID
file.PhotoUUID = photo.PhotoUUID
file.FilePrimary = isPrimary
file.FileMissing = false
file.FileName = fileName
file.FileHash = fileHash
file.FileType = mediaFile.Type()
file.FileMime = mediaFile.MimeType()
file.FileOrientation = mediaFile.Orientation()
if isNew || o.UpdateColors {
// Color information
if p, err := mediaFile.Colors(i.thumbnailsPath()); err == nil {
file.FileMainColor = p.MainColor.Name()
file.FileColors = p.Colors.Hex()
file.FileLuminance = p.Luminance.Hex()
file.FileChroma = p.Chroma.Uint()
}
}
if isNew || o.UpdateSize {
if mediaFile.Width() > 0 && mediaFile.Height() > 0 {
file.FileWidth = mediaFile.Width()
file.FileHeight = mediaFile.Height()
file.FileAspectRatio = mediaFile.AspectRatio()
file.FilePortrait = mediaFile.Width() < mediaFile.Height()
}
}
if fileQuery.Error == nil {
i.db.Unscoped().Save(&file)
return indexResultUpdated
}
i.db.Create(&file)
return indexResultAdded
}

View file

@ -0,0 +1,59 @@
package photoprism
import (
"reflect"
)
type IndexerOptions struct {
UpdateDate bool
UpdateColors bool
UpdateSize bool
UpdateTitle bool
UpdateLocation bool
UpdateCamera bool
UpdateLabels bool
UpdateKeywords bool
UpdateXMP bool
UpdateExif bool
}
func (o *IndexerOptions) UpdateAny() bool {
v := reflect.ValueOf(o).Elem()
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Bool() {
return true
}
}
return false
}
func (o *IndexerOptions) SkipExisting() bool {
return !o.UpdateAny()
}
// IndexerOptionsAll returns new indexer options with all options set to true.
func IndexerOptionsAll() IndexerOptions {
instance := IndexerOptions{
UpdateDate: true,
UpdateColors: true,
UpdateSize: true,
UpdateTitle: true,
UpdateLocation: true,
UpdateCamera: true,
UpdateLabels: true,
UpdateKeywords: true,
UpdateXMP: true,
UpdateExif: true,
}
return instance
}
// IndexerOptionsNone returns new indexer options with all options set to false.
func IndexerOptionsNone() IndexerOptions {
instance := IndexerOptions{}
return instance
}

View file

@ -24,5 +24,7 @@ func TestIndexer_IndexAll(t *testing.T) {
importer.ImportPhotosFromDirectory(conf.ImportPath())
indexer.IndexAll()
options := IndexerOptionsAll()
indexer.IndexOriginals(options)
}