🤼‍♀️ P99 of a cover matching + metadata extraction first draft

This commit is contained in:
2022-03-16 20:53:26 -07:00
parent 89a0fc7090
commit 2cc00aff94
7 changed files with 513 additions and 255 deletions

View File

@@ -0,0 +1 @@
export const IMPORT_IMAGE_FILE_FORMATS = [".jpg", ".jpeg", ".bmp", ".png", ".gif"]

327
package-lock.json generated
View File

@@ -46,7 +46,7 @@
"node-7z-forall": "^2.1.5",
"node-calibre": "^2.1.1",
"node-unrar-js": "^1.0.5",
"sharp": "^0.28.3",
"sharp": "^0.30.3",
"socket.io": "^4.4.0",
"threetwo-ui-typings": "^1.0.13",
"through2": "^4.0.2",
@@ -3276,12 +3276,15 @@
"dev": true
},
"node_modules/color": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.1.tgz",
"integrity": "sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw==",
"dependencies": {
"color-convert": "^1.9.3",
"color-string": "^1.6.0"
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"engines": {
"node": ">=12.5.0"
}
},
"node_modules/color-convert": {
@@ -3306,6 +3309,22 @@
"simple-swizzle": "^0.2.2"
}
},
"node_modules/color/node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color/node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
"node_modules/combine-errors": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/combine-errors/-/combine-errors-3.0.3.tgz",
@@ -3688,14 +3707,11 @@
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"node_modules/detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
"bin": {
"detect-libc": "bin/detect-libc.js"
},
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
"integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==",
"engines": {
"node": ">=0.10"
"node": ">=8"
}
},
"node_modules/detect-newline": {
@@ -9413,25 +9429,20 @@
}
},
"node_modules/node-abi": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz",
"integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==",
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz",
"integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==",
"dependencies": {
"semver": "^5.4.1"
}
},
"node_modules/node-abi/node_modules/semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
"bin": {
"semver": "bin/semver"
"semver": "^7.3.5"
},
"engines": {
"node": ">=10"
}
},
"node_modules/node-addon-api": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
},
"node_modules/node-calibre": {
"version": "2.1.1",
@@ -12770,21 +12781,21 @@
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
},
"node_modules/prebuild-install": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
"integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz",
"integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==",
"dependencies": {
"detect-libc": "^1.0.3",
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3",
"napi-build-utils": "^1.0.1",
"node-abi": "^2.21.0",
"node-abi": "^3.3.0",
"npmlog": "^4.0.1",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^3.0.3",
"simple-get": "^4.0.0",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0"
},
@@ -12792,7 +12803,56 @@
"prebuild-install": "bin.js"
},
"engines": {
"node": ">=6"
"node": ">=10"
}
},
"node_modules/prebuild-install/node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dependencies": {
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/prebuild-install/node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/prebuild-install/node_modules/simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/prelude-ls": {
@@ -13535,25 +13595,74 @@
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/sharp": {
"version": "0.28.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.28.3.tgz",
"integrity": "sha512-21GEP45Rmr7q2qcmdnjDkNP04Ooh5v0laGS5FDpojOO84D1DJwUijLiSq8XNNM6e8aGXYtoYRh3sVNdm8NodMA==",
"version": "0.30.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.3.tgz",
"integrity": "sha512-rjpfJFK58ZOFSG8sxYSo3/JQb4ej095HjXp9X7gVu7gEn1aqSG8TCW29h/Rr31+PXrFADo1H/vKfw0uhMQWFtg==",
"hasInstallScript": true,
"dependencies": {
"color": "^3.1.3",
"detect-libc": "^1.0.3",
"node-addon-api": "^3.2.0",
"prebuild-install": "^6.1.2",
"color": "^4.2.1",
"detect-libc": "^2.0.1",
"node-addon-api": "^4.3.0",
"prebuild-install": "^7.0.1",
"semver": "^7.3.5",
"simple-get": "^3.1.0",
"simple-get": "^4.0.1",
"tar-fs": "^2.1.1",
"tunnel-agent": "^0.6.0"
},
"engines": {
"node": ">=12.13.0"
},
"funding": {
"url": "https://opencollective.com/libvips"
}
},
"node_modules/sharp/node_modules/decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"dependencies": {
"mimic-response": "^3.1.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://opencollective.com/libvips"
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/sharp/node_modules/mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==",
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/sharp/node_modules/simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
],
"dependencies": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"node_modules/shebang-command": {
@@ -17581,12 +17690,27 @@
"dev": true
},
"color": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
"integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/color/-/color-4.2.1.tgz",
"integrity": "sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw==",
"requires": {
"color-convert": "^1.9.3",
"color-string": "^1.6.0"
"color-convert": "^2.0.1",
"color-string": "^1.9.0"
},
"dependencies": {
"color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"requires": {
"color-name": "~1.1.4"
}
},
"color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
}
}
},
"color-convert": {
@@ -17913,9 +18037,9 @@
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
},
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz",
"integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w=="
},
"detect-newline": {
"version": "3.1.0",
@@ -22151,24 +22275,17 @@
}
},
"node-abi": {
"version": "2.30.1",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz",
"integrity": "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w==",
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz",
"integrity": "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw==",
"requires": {
"semver": "^5.4.1"
},
"dependencies": {
"semver": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
}
"semver": "^7.3.5"
}
},
"node-addon-api": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
"integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
},
"node-calibre": {
"version": "2.1.1",
@@ -24566,23 +24683,48 @@
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
},
"prebuild-install": {
"version": "6.1.4",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz",
"integrity": "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz",
"integrity": "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg==",
"requires": {
"detect-libc": "^1.0.3",
"detect-libc": "^2.0.0",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.3",
"mkdirp-classic": "^0.5.3",
"napi-build-utils": "^1.0.1",
"node-abi": "^2.21.0",
"node-abi": "^3.3.0",
"npmlog": "^4.0.1",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^3.0.3",
"simple-get": "^4.0.0",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0"
},
"dependencies": {
"decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"requires": {
"mimic-response": "^3.1.0"
}
},
"mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
},
"simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"requires": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
}
}
},
"prelude-ls": {
@@ -25138,18 +25280,43 @@
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"sharp": {
"version": "0.28.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.28.3.tgz",
"integrity": "sha512-21GEP45Rmr7q2qcmdnjDkNP04Ooh5v0laGS5FDpojOO84D1DJwUijLiSq8XNNM6e8aGXYtoYRh3sVNdm8NodMA==",
"version": "0.30.3",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.30.3.tgz",
"integrity": "sha512-rjpfJFK58ZOFSG8sxYSo3/JQb4ej095HjXp9X7gVu7gEn1aqSG8TCW29h/Rr31+PXrFADo1H/vKfw0uhMQWFtg==",
"requires": {
"color": "^3.1.3",
"detect-libc": "^1.0.3",
"node-addon-api": "^3.2.0",
"prebuild-install": "^6.1.2",
"color": "^4.2.1",
"detect-libc": "^2.0.1",
"node-addon-api": "^4.3.0",
"prebuild-install": "^7.0.1",
"semver": "^7.3.5",
"simple-get": "^3.1.0",
"simple-get": "^4.0.1",
"tar-fs": "^2.1.1",
"tunnel-agent": "^0.6.0"
},
"dependencies": {
"decompress-response": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz",
"integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==",
"requires": {
"mimic-response": "^3.1.0"
}
},
"mimic-response": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz",
"integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
},
"simple-get": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz",
"integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==",
"requires": {
"decompress-response": "^6.0.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
}
}
},
"shebang-command": {

View File

@@ -77,7 +77,7 @@
"node-7z-forall": "^2.1.5",
"node-calibre": "^2.1.1",
"node-unrar-js": "^1.0.5",
"sharp": "^0.28.3",
"sharp": "^0.30.3",
"socket.io": "^4.4.0",
"threetwo-ui-typings": "^1.0.13",
"through2": "^4.0.2",

View File

@@ -77,7 +77,6 @@ export default class QueueService extends Service {
Object.assign(result, {
fileSize: job.data.fileObject.fileSize,
});
console.log("KEYSS TO THE KINGDOM:", result)
const {
name,
filePath,

View File

@@ -8,7 +8,8 @@
"sourceMap": true,
"pretty": true,
"target": "es6",
"outDir": "dist"
"outDir": "dist",
"lib": ["es5", "es6", "dom", "dom.iterable"]
},
"include": ["./**/*"],
"exclude": [

View File

@@ -36,6 +36,7 @@ import {
createReadStream,
promises as fs,
readFileSync,
existsSync,
} from "fs";
const fse = require("fs-extra");
const Unrar = require("unrar");
@@ -44,13 +45,25 @@ import { list, extract, onlyArchive } from "node-7z-forall";
import { IExtractedComicBookCoverFile } from "threetwo-ui-typings";
import sharp from "sharp";
import { getFileConstituents } from "../utils/file.utils";
import { isNil, isUndefined, remove } from "lodash";
import { flatten, isEmpty, isNil, isUndefined, remove } from "lodash";
import { convertXMLToJSON } from "./xml.utils";
import { USERDATA_DIRECTORY, COMICS_DIRECTORY } from "../constants/directories";
import { IMPORT_IMAGE_FILE_FORMATS } from "../constants/allowedFileFormats";
interface RarFile {
name: string;
type: string;
size?: string;
packedSize?: string;
ratio?: string;
mtime: string;
attributes: string;
crc32: string;
hostOS: string;
compression: string;
}
export const extractComicInfoXMLFromRar = async (
filePath: string
): Promise<Partial<IExtractedComicBookCoverFile>> => {
): Promise<any> => {
const result = {
filePath,
};
@@ -64,82 +77,104 @@ export const extractComicInfoXMLFromRar = async (
const targetDirectory = `${USERDATA_DIRECTORY}/covers/${fileNameWithoutExtension}`;
await fse.ensureDir(targetDirectory, directoryOptions);
console.info(`%s was created.`, targetDirectory);
return new Promise((resolve, reject) => {
const archive = new Unrar({
path: path.resolve(filePath),
bin: `/usr/local/bin/unrar`, // this will change depending on Docker base OS
const archive = new Unrar({
path: path.resolve(filePath),
bin: `/usr/local/bin/unrar`, // this will change depending on Docker base OS
});
const filesInArchive: [RarFile] = await new Promise((resolve, reject) => {
return archive.list((err, entries) => {
resolve(entries);
});
});
archive.list(async (err, entries) => {
remove(entries, ({ type }) => type === "Directory");
const comicInfoXML = remove(
entries,
({ name }) => name.toLowerCase() === "comicinfo.xml"
remove(filesInArchive, ({ type }) => type === "Directory");
const comicInfoXML = remove(
filesInArchive,
({ name }) => path.basename(name).toLowerCase() === "comicinfo.xml"
);
remove(
filesInArchive,
({ name }) => !IMPORT_IMAGE_FILE_FORMATS.includes(path.extname(name))
);
const files = filesInArchive.sort((a, b) => {
if (!isUndefined(a) && !isUndefined(b)) {
return path
.basename(a.name)
.toLowerCase()
.localeCompare(path.basename(b.name).toLowerCase());
}
});
const comicInfoXMLFilePromise = new Promise((resolve, reject) => {
let comicinfostring = "";
if (!isUndefined(comicInfoXML[0])) {
const writeStream = createWriteStream(
`${targetDirectory}/${comicInfoXML[0].name}`
);
const files = entries.sort((a, b) => {
if (!isUndefined(a) && !isUndefined(b)) {
return a.name
.toLowerCase()
.localeCompare(b.name.toLowerCase());
}
});
const filesToWriteToDisk = [files[0].name, comicInfoXML[0]["name"]];
remove(filesToWriteToDisk, (file) => !isNil(file.name));
if (!isUndefined(comicInfoXML[0]["name"])) {
let comicinfostring = "";
const writeStream = createWriteStream(
`${targetDirectory}/${comicInfoXML[0]["name"]}`
archive.stream(comicInfoXML[0]["name"]).pipe(writeStream);
writeStream.on("finish", async () => {
const readStream = createReadStream(
`${targetDirectory}/${comicInfoXML[0].name}`
);
await archive.stream(comicInfoXML[0]["name"]).pipe(writeStream);
writeStream.on("finish", async () => {
const readStream = createReadStream(
`${targetDirectory}/${comicInfoXML[0]["name"]}`
);
readStream.on("data", (data) => {
comicinfostring += data;
});
readStream.on("error", (error) => reject(error));
readStream.on("end", async () => {
readStream.on("data", (data) => {
comicinfostring += data;
});
readStream.on("error", (error) => reject(error));
readStream.on("end", async () => {
if (
existsSync(
`${targetDirectory}/${path.basename(
comicInfoXML[0].name
)}`
)
) {
const comicInfoJSON = await convertXMLToJSON(
comicinfostring.toString()
);
Object.assign(result, {
comicInfoJSON: comicInfoJSON.comicinfo,
});
});
resolve({ comicInfoJSON: comicInfoJSON.comicinfo });
}
});
});
} else {
resolve({ comicInfoJSON: null });
}
});
const coverFilePromise = new Promise((resolve, reject) => {
const coverFile = path.basename(files[0].name);
const sharpStream = sharp().resize(275);
const coverExtractionStream = archive.stream(files[0].name);
const resizeStream = coverExtractionStream.pipe(sharpStream);
resizeStream.toFile(`${targetDirectory}/${coverFile}`, (err, info) => {
if (err) {
reject(err);
}
if (existsSync(`${targetDirectory}/${coverFile}`)) {
// orchestrate result
console.log("ASDAsd");
resolve({
name: fileNameWithoutExtension,
extension,
containedIn: targetDirectory,
cover: {
filePath: path.relative(
process.cwd(),
`${targetDirectory}/${coverFile}`
),
},
});
}
const sharpStream = sharp().resize(275);
const coverExtractionStream = archive.stream(files[0].name);
await coverExtractionStream
.pipe(sharpStream)
.toFile(`${targetDirectory}/${files[0].name}`);
// orchestrate result
Object.assign(result, {
name: fileNameWithoutExtension,
extension,
containedIn: targetDirectory,
cover: {
filePath: path.relative(
process.cwd(),
`${targetDirectory}/${files[0].name}`
),
},
});
resolve(result);
});
});
return Promise.all([comicInfoXMLFilePromise, coverFilePromise]);
};
export const extractComicInfoXMLFromZip = async (
filePath: string
): Promise<Partial<IExtractedComicBookCoverFile>> => {
const result = {
filePath,
};
): Promise<any> => {
// Create the target directory
const directoryOptions = {
mode: 0o2775,
@@ -149,81 +184,108 @@ export const extractComicInfoXMLFromZip = async (
const targetDirectory = `${USERDATA_DIRECTORY}/covers/${fileNameWithoutExtension}`;
await fse.ensureDir(targetDirectory, directoryOptions);
console.info(`%s was created.`, targetDirectory);
let sortedFiles = [];
const filesToWriteToDisk = [];
return await list(filePath)
.progress((files) => {
// Do stuff with files...
sortedFiles = files.sort((a, b) => {
if (!isUndefined(a) && !isUndefined(b)) {
return a.name
.toLowerCase()
.localeCompare(b.name.toLowerCase());
}
});
const comicInfoXML = remove(
sortedFiles,
(file) => file.name.toLowerCase() === "comicinfo.xml"
let filesFromArchive = [];
let filesToWriteToDisk = { coverFile: null, comicInfoXML: null };
const extractionTargets = [];
await list(filePath).progress((files) => {
filesFromArchive.push(...files);
return filesFromArchive;
});
remove(
filesFromArchive,
({ name }) => !IMPORT_IMAGE_FILE_FORMATS.includes(path.extname(name))
);
remove(
filesFromArchive,
(file) => file.attr === "D...." && file.size === 0
);
const comicInfoXMLFileObject = remove(
filesFromArchive,
(file) => path.basename(file.name.toLowerCase()) === "comicinfo.xml"
);
if (!isEmpty(comicInfoXMLFileObject)) {
filesToWriteToDisk.comicInfoXML = comicInfoXMLFileObject[0].name;
extractionTargets.push(filesToWriteToDisk.comicInfoXML);
}
filesToWriteToDisk.coverFile = filesFromArchive[0].name;
extractionTargets.push(filesToWriteToDisk.coverFile);
await extract(path.resolve(filePath), targetDirectory, {
r: true,
raw: [...extractionTargets],
});
// ComicInfoXML detection, parsing and conversion to JSON
// Write ComicInfo.xml to disk
let comicinfostring = "";
const comicInfoXMLPromise = new Promise((resolve, reject) => {
if (
!isNil(filesToWriteToDisk.comicInfoXML) &&
existsSync(
`${targetDirectory}/${path.basename(
filesToWriteToDisk.comicInfoXML
)}`
)
) {
let comicinfoString = "";
const comicInfoXMLStream = createReadStream(
`${targetDirectory}/${path.basename(
filesToWriteToDisk.comicInfoXML
)}`
);
if (!isUndefined(comicInfoXML)) {
filesToWriteToDisk.push(comicInfoXML[0].name);
}
filesToWriteToDisk.push(sortedFiles[0].name);
})
.then((d) => {
return extract(path.resolve(filePath), targetDirectory, {
r: true,
raw: [...filesToWriteToDisk],
})
.progress((files) => {
console.log(files);
})
.then(() => {
const coverFile = filesToWriteToDisk.find(
(file) => file.toLowerCase() !== "comicinfo.xml"
);
Object.assign(result, {
comicInfoXMLStream.on("data", (data) => (comicinfoString += data));
comicInfoXMLStream.on("end", async () => {
const comicInfoJSON = await convertXMLToJSON(
comicinfoString.toString()
);
resolve({
comicInfoJSON: comicInfoJSON.comicinfo,
});
});
} else {
resolve({
comicInfoJSON: null,
});
}
});
// Write the cover to disk
const coverFilePromise = new Promise((resolve, reject) => {
const sharpStream = sharp().resize(275);
const coverStream = createReadStream(
`${targetDirectory}/${path.basename(filesToWriteToDisk.coverFile)}`
);
coverStream
.pipe(sharpStream)
.toFile(
`${targetDirectory}/${path.basename(
filesToWriteToDisk.coverFile
)}`,
(err, info) => {
if (err) {
reject(err);
}
// Update metadata
resolve({
filePath,
name: fileNameWithoutExtension,
extension,
containedIn: targetDirectory,
cover: {
filePath: path.relative(
process.cwd(),
`${targetDirectory}/${coverFile}`
`${targetDirectory}/${path.basename(
filesToWriteToDisk.coverFile
)}`
),
},
});
// ComicInfoXML detection, parsing and conversion to JSON
let comicinfostring = "";
const comicInfoFile = filesToWriteToDisk.find(
(file) => file.toLowerCase() === "comicinfo.xml"
);
return new Promise((resolve, reject) => {
const comicInfoXMLStream = createReadStream(
`${targetDirectory}/${comicInfoFile}`
);
comicInfoXMLStream.on("data", (data) => {
comicinfostring += data;
});
comicInfoXMLStream.on("error", (error) =>
console.log(error)
);
comicInfoXMLStream.on("end", async () => {
const comicInfoJSON = await convertXMLToJSON(
comicinfostring.toString()
);
Object.assign(result, {
comicInfoJSON: comicInfoJSON.comicinfo,
});
}
);
});
resolve(result);
});
});
})
.catch((error) => {
console.log(error);
});
});
return Promise.all([comicInfoXMLPromise, coverFilePromise]);
};
export const extractFromArchive = async (filePath: string) => {
@@ -233,13 +295,16 @@ export const extractFromArchive = async (filePath: string) => {
console.log(
"Detected file type is cbz, looking for comicinfo.xml..."
);
return await extractComicInfoXMLFromZip(filePath);
const result = await extractComicInfoXMLFromZip(filePath);
return Object.assign({}, ...result);
case ".cbr":
console.log(
"Detected file type is cbr, looking for comicinfo.xml..."
);
return await extractComicInfoXMLFromRar(filePath);
const CbrResult = await extractComicInfoXMLFromRar(filePath);
console.log(CbrResult);
return Object.assign({}, ...CbrResult);
default:
console.log(

111
yarn.lock
View File

@@ -1950,7 +1950,7 @@
"resolved" "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz"
"version" "1.0.1"
"color-convert@^1.9.0", "color-convert@^1.9.3":
"color-convert@^1.9.0":
"integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="
"resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
"version" "1.9.3"
@@ -1974,7 +1974,7 @@
"resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
"version" "1.1.4"
"color-string@^1.6.0":
"color-string@^1.9.0":
"integrity" "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ=="
"resolved" "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz"
"version" "1.9.0"
@@ -1985,13 +1985,13 @@
"color-support@^1.1.2":
"version" "1.1.3"
"color@^3.1.3":
"integrity" "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA=="
"resolved" "https://registry.npmjs.org/color/-/color-3.2.1.tgz"
"version" "3.2.1"
"color@^4.2.1":
"integrity" "sha512-MFJr0uY4RvTQUKvPq7dh9grVOTYSFeXja2mBXioCGjnjJoXrAp9jJ1NQTDR73c9nwBSAQiNKloKl5zq9WB9UPw=="
"resolved" "https://registry.npmjs.org/color/-/color-4.2.1.tgz"
"version" "4.2.1"
dependencies:
"color-convert" "^1.9.3"
"color-string" "^1.6.0"
"color-convert" "^2.0.1"
"color-string" "^1.9.0"
"colors@1.4.0":
"version" "1.4.0"
@@ -2264,6 +2264,13 @@
dependencies:
"mimic-response" "^2.0.0"
"decompress-response@^6.0.0":
"integrity" "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ=="
"resolved" "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz"
"version" "6.0.0"
dependencies:
"mimic-response" "^3.1.0"
"dedent@^0.7.0":
"integrity" "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw="
"resolved" "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz"
@@ -2331,10 +2338,10 @@
"resolved" "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz"
"version" "1.0.4"
"detect-libc@^1.0.3":
"integrity" "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
"resolved" "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz"
"version" "1.0.3"
"detect-libc@^2.0.0", "detect-libc@^2.0.1":
"integrity" "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w=="
"resolved" "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz"
"version" "2.0.1"
"detect-newline@^3.0.0":
"integrity" "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="
@@ -4844,6 +4851,11 @@
"resolved" "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz"
"version" "2.1.0"
"mimic-response@^3.1.0":
"integrity" "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ=="
"resolved" "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz"
"version" "3.1.0"
"minimatch@^3.0.4":
"integrity" "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA=="
"resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"
@@ -5176,17 +5188,17 @@
"system-installer" "^1.1.6"
"when" "^3.7.8"
"node-abi@^2.21.0":
"integrity" "sha512-/2D0wOQPgaUWzVSVgRMx+trKJRC2UG4SUc4oCJoXx9Uxjtp0Vy3/kt7zcbxHF8+Z/pK3UloLWzBISg72brfy1w=="
"resolved" "https://registry.npmjs.org/node-abi/-/node-abi-2.30.1.tgz"
"version" "2.30.1"
"node-abi@^3.3.0":
"integrity" "sha512-tzua9qWWi7iW4I42vUPKM+SfaF0vQSLAm4yO5J83mSwB7GeoWrDKC/K+8YCnYNwqP5duwazbw2X9l4m8SC2cUw=="
"resolved" "https://registry.npmjs.org/node-abi/-/node-abi-3.8.0.tgz"
"version" "3.8.0"
dependencies:
"semver" "^5.4.1"
"semver" "^7.3.5"
"node-addon-api@^3.2.0":
"integrity" "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A=="
"resolved" "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz"
"version" "3.2.1"
"node-addon-api@^4.3.0":
"integrity" "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ=="
"resolved" "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz"
"version" "4.3.0"
"node-calibre@^2.1.1":
"integrity" "sha512-t68lVmU+VznsivQKM6Fr1HSRQ2+m54OouiDkeCzRUQJO3N4h9l60DlcHFu2HAn6Kw5nsZEbOtnkk5OBhhOErxA=="
@@ -5749,22 +5761,22 @@
"resolved" "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz"
"version" "1.1.0"
"prebuild-install@^6.1.2":
"integrity" "sha512-Z4vpywnK1lBg+zdPCVCsKq0xO66eEV9rWo2zrROGGiRS4JtueBOdlB1FnY8lcy7JsUud/Q3ijUxyWN26Ika0vQ=="
"resolved" "https://registry.npmjs.org/prebuild-install/-/prebuild-install-6.1.4.tgz"
"version" "6.1.4"
"prebuild-install@^7.0.1":
"integrity" "sha512-QBSab31WqkyxpnMWQxubYAHR5S9B2+r81ucocew34Fkl98FhvKIF50jIJnNOBmAZfyNV7vE5T6gd3hTVWgY6tg=="
"resolved" "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.0.1.tgz"
"version" "7.0.1"
dependencies:
"detect-libc" "^1.0.3"
"detect-libc" "^2.0.0"
"expand-template" "^2.0.3"
"github-from-package" "0.0.0"
"minimist" "^1.2.3"
"mkdirp-classic" "^0.5.3"
"napi-build-utils" "^1.0.1"
"node-abi" "^2.21.0"
"node-abi" "^3.3.0"
"npmlog" "^4.0.1"
"pump" "^3.0.0"
"rc" "^1.2.7"
"simple-get" "^3.0.3"
"simple-get" "^4.0.0"
"tar-fs" "^2.0.0"
"tunnel-agent" "^0.6.0"
@@ -6231,11 +6243,6 @@
dependencies:
"lru-cache" "^6.0.0"
"semver@^5.4.1":
"integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
"resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
"version" "5.7.1"
"semver@^6.0.0":
"integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
"resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
@@ -6293,17 +6300,17 @@
"resolved" "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz"
"version" "1.2.0"
"sharp@^0.28.3":
"integrity" "sha512-21GEP45Rmr7q2qcmdnjDkNP04Ooh5v0laGS5FDpojOO84D1DJwUijLiSq8XNNM6e8aGXYtoYRh3sVNdm8NodMA=="
"resolved" "https://registry.npmjs.org/sharp/-/sharp-0.28.3.tgz"
"version" "0.28.3"
"sharp@^0.30.3":
"integrity" "sha512-rjpfJFK58ZOFSG8sxYSo3/JQb4ej095HjXp9X7gVu7gEn1aqSG8TCW29h/Rr31+PXrFADo1H/vKfw0uhMQWFtg=="
"resolved" "https://registry.npmjs.org/sharp/-/sharp-0.30.3.tgz"
"version" "0.30.3"
dependencies:
"color" "^3.1.3"
"detect-libc" "^1.0.3"
"node-addon-api" "^3.2.0"
"prebuild-install" "^6.1.2"
"color" "^4.2.1"
"detect-libc" "^2.0.1"
"node-addon-api" "^4.3.0"
"prebuild-install" "^7.0.1"
"semver" "^7.3.5"
"simple-get" "^3.1.0"
"simple-get" "^4.0.1"
"tar-fs" "^2.1.1"
"tunnel-agent" "^0.6.0"
@@ -6343,7 +6350,7 @@
"resolved" "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz"
"version" "1.0.1"
"simple-get@^3.0.3", "simple-get@^3.1.0":
"simple-get@^3.1.0":
"integrity" "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA=="
"resolved" "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz"
"version" "3.1.1"
@@ -6352,6 +6359,24 @@
"once" "^1.3.1"
"simple-concat" "^1.0.0"
"simple-get@^4.0.0":
"integrity" "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="
"resolved" "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz"
"version" "4.0.1"
dependencies:
"decompress-response" "^6.0.0"
"once" "^1.3.1"
"simple-concat" "^1.0.0"
"simple-get@^4.0.1":
"integrity" "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA=="
"resolved" "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz"
"version" "4.0.1"
dependencies:
"decompress-response" "^6.0.0"
"once" "^1.3.1"
"simple-concat" "^1.0.0"
"simple-swizzle@^0.2.2":
"integrity" "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo="
"resolved" "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz"