Added option to skip indexing existing files
Signed-off-by: Michael Mayer <michael@liquidbytes.net>
This commit is contained in:
parent
760df93214
commit
6d4e42c79e
21 changed files with 744 additions and 616 deletions
|
@ -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
|
||||
|
|
497
frontend/package-lock.json
generated
497
frontend/package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
5
internal/form/indexer_options.go
Normal file
5
internal/form/indexer_options.go
Normal file
|
@ -0,0 +1,5 @@
|
|||
package form
|
||||
|
||||
type IndexerOptions struct {
|
||||
SkipExisting bool `json:"skip"`
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
361
internal/photoprism/indexer_mediafile.go
Normal file
361
internal/photoprism/indexer_mediafile.go
Normal 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
|
||||
}
|
59
internal/photoprism/indexer_options.go
Normal file
59
internal/photoprism/indexer_options.go
Normal 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
|
||||
}
|
|
@ -24,5 +24,7 @@ func TestIndexer_IndexAll(t *testing.T) {
|
|||
|
||||
importer.ImportPhotosFromDirectory(conf.ImportPath())
|
||||
|
||||
indexer.IndexAll()
|
||||
options := IndexerOptionsAll()
|
||||
|
||||
indexer.IndexOriginals(options)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue