feat: add experimental meaningful preview extraction from videos
For now, it sitll requires gifski. It could be rewritten to use webp instead of gifs, because that is a lot faster, uses less space and we could use ffmpeg for it.
This commit is contained in:
parent
42f1a1003a
commit
a790d7749e
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"discord.enabled": true,
|
||||
"editor.detectIndentation": false,
|
||||
"editor.insertSpaces": false,
|
||||
"files.insertFinalNewline": true,
|
||||
"editor.formatOnPaste": true,
|
||||
"editor.formatOnSave": true,
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
||||
"prettier.eslintIntergration": true,
|
||||
"vetur.validation.template": false,
|
||||
"[javascript]": {
|
||||
"editor.defaultFormatter": "esbenp.prettier-vscode"
|
||||
},
|
||||
"prettier.disableLanguages": ["vue"],
|
||||
"vetur.format.enable": true,
|
||||
"files.eol": "\n"
|
||||
}
|
|
@ -45,6 +45,7 @@
|
|||
"dumper.js": "^1.3.1",
|
||||
"express": "^4.16.4",
|
||||
"express-rate-limit": "^3.4.0",
|
||||
"ffmpeg-generate-video-preview": "^1.0.3",
|
||||
"file-saver": "^2.0.1",
|
||||
"flexsearch": "^0.6.22",
|
||||
"fluent-ffmpeg": "^2.1.2",
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
require('dotenv').config();
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const ThumbUtil = require('./utils/ThumbUtil');
|
||||
|
||||
const start = async () => {
|
||||
|
|
|
@ -2,59 +2,85 @@ const jetpack = require('fs-jetpack');
|
|||
const path = require('path');
|
||||
const sharp = require('sharp');
|
||||
const ffmpeg = require('fluent-ffmpeg');
|
||||
const generatePreview = require('ffmpeg-generate-video-preview');
|
||||
|
||||
const imageExtensions = ['.jpg', '.jpeg', '.gif', '.png', '.webp'];
|
||||
const videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov'];
|
||||
const log = require('./Log');
|
||||
|
||||
class ThumbUtil {
|
||||
static imageExtensions = ['.jpg', '.jpeg', '.gif', '.png', '.webp'];
|
||||
static videoExtensions = ['.webm', '.mp4', '.wmv', '.avi', '.mov'];
|
||||
|
||||
static thumbPath = path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs');
|
||||
static squareThumbPath = path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'square');
|
||||
static videoPreviewPath = path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'preview');
|
||||
|
||||
static generateThumbnails(filename) {
|
||||
const ext = path.extname(filename).toLowerCase();
|
||||
const output = `${filename.slice(0, -ext.length)}.png`;
|
||||
if (imageExtensions.includes(ext)) return this.generateThumbnailForImage(filename, output);
|
||||
if (videoExtensions.includes(ext)) return this.generateThumbnailForVideo(filename);
|
||||
const previewOutput = `${filename.slice(0, -ext.length)}.gif`;
|
||||
|
||||
if (ThumbUtil.imageExtensions.includes(ext)) return this.generateThumbnailForImage(filename, output);
|
||||
if (ThumbUtil.videoExtensions.includes(ext)) return this.generateThumbnailForVideo(filename, previewOutput);
|
||||
return null;
|
||||
}
|
||||
|
||||
static async generateThumbnailForImage(filename, output) {
|
||||
const file = await jetpack.readAsync(
|
||||
path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename),
|
||||
'buffer'
|
||||
);
|
||||
const filePath = path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename);
|
||||
|
||||
const file = await jetpack.readAsync(filePath, 'buffer');
|
||||
await sharp(file)
|
||||
.resize(64, 64)
|
||||
.toFormat('png')
|
||||
.toFile(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'square', output));
|
||||
.toFile(path.join(ThumbUtil.squareThumbPath, output));
|
||||
await sharp(file)
|
||||
.resize(225, null)
|
||||
.toFormat('png')
|
||||
.toFile(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', output));
|
||||
.toFile(path.join(ThumbUtil.thumbPath, output));
|
||||
}
|
||||
|
||||
static generateThumbnailForVideo(filename) {
|
||||
ffmpeg(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename))
|
||||
static generateThumbnailForVideo(filename, output) {
|
||||
const filePath = path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename);
|
||||
|
||||
ffmpeg(filePath)
|
||||
.thumbnail({
|
||||
timestamps: [0],
|
||||
filename: '%b.png',
|
||||
folder: path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'square'),
|
||||
folder: ThumbUtil.squareThumbPath,
|
||||
size: '64x64'
|
||||
})
|
||||
.on('error', error => log.error(error.message));
|
||||
ffmpeg(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename))
|
||||
|
||||
ffmpeg(filePath)
|
||||
.thumbnail({
|
||||
timestamps: [0],
|
||||
filename: '%b.png',
|
||||
folder: path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs'),
|
||||
folder: ThumbUtil.thumbPath,
|
||||
size: '150x?'
|
||||
})
|
||||
.on('error', error => log.error(error.message));
|
||||
|
||||
try {
|
||||
generatePreview({
|
||||
input: filePath,
|
||||
width: 150,
|
||||
output: path.join(ThumbUtil.videoPreviewPath, output)
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
|
||||
static getFileThumbnail(filename) {
|
||||
if (!filename) return null;
|
||||
const ext = path.extname(filename).toLowerCase();
|
||||
if (!imageExtensions.includes(ext) && !videoExtensions.includes(ext)) return null;
|
||||
if (!ThumbUtil.imageExtensions.includes(ext) && !ThumbUtil.videoExtensions.includes(ext)) return null;
|
||||
return `${filename.slice(0, -ext.length)}.png`;
|
||||
}
|
||||
|
||||
static async removeThumbs(thumbName) {
|
||||
await jetpack.removeAsync(path.join(ThumbUtil.thumbPath, thumbName));
|
||||
await jetpack.removeAsync(ThumbUtil.squareThumbPath, thumbName);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ThumbUtil;
|
||||
|
|
|
@ -24,6 +24,8 @@ const ThumbUtil = require('./ThumbUtil');
|
|||
const blockedExtensions = process.env.BLOCKED_EXTENSIONS.split(',');
|
||||
|
||||
class Util {
|
||||
static uploadPath = path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER);
|
||||
|
||||
static uuid() {
|
||||
return uuidv4();
|
||||
}
|
||||
|
@ -55,7 +57,7 @@ class Util {
|
|||
}) + path.extname(name).toLowerCase();
|
||||
|
||||
// TODO: Change this to look for the file in the db instead of in the filesystem
|
||||
const exists = jetpack.exists(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename));
|
||||
const exists = jetpack.exists(path.join(Util.uploadPath, filename));
|
||||
if (!exists) return filename;
|
||||
if (i < 5) return retry(i + 1);
|
||||
log.error('Couldnt allocate identifier for file');
|
||||
|
@ -86,10 +88,7 @@ class Util {
|
|||
}
|
||||
|
||||
static async getFileHash(filename) {
|
||||
const file = await jetpack.readAsync(
|
||||
path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename),
|
||||
'buffer'
|
||||
);
|
||||
const file = await jetpack.readAsync(path.join(Util.uploadPath, filename), 'buffer');
|
||||
if (!file) {
|
||||
log.error(`There was an error reading the file < ${filename} > for hashing`);
|
||||
return null;
|
||||
|
@ -115,13 +114,9 @@ class Util {
|
|||
static async deleteFile(filename, deleteFromDB = false) {
|
||||
const thumbName = ThumbUtil.getFileThumbnail(filename);
|
||||
try {
|
||||
await jetpack.removeAsync(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, filename));
|
||||
await jetpack.removeAsync(
|
||||
path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', thumbName)
|
||||
);
|
||||
await jetpack.removeAsync(
|
||||
path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, 'thumbs', 'square', thumbName)
|
||||
);
|
||||
await jetpack.removeAsync(path.join(Util.uploadPath, filename));
|
||||
await ThumbUtil.removeThumbs(thumbName);
|
||||
|
||||
if (deleteFromDB) {
|
||||
await db
|
||||
.table('files')
|
||||
|
@ -205,7 +200,7 @@ class Util {
|
|||
try {
|
||||
const zip = new Zip();
|
||||
for (const file of files) {
|
||||
zip.addLocalFile(path.join(__dirname, '..', '..', '..', process.env.UPLOAD_FOLDER, file));
|
||||
zip.addLocalFile(path.join(Util.uploadPath, file));
|
||||
}
|
||||
zip.writeZip(
|
||||
path.join(
|
||||
|
|
109
yarn.lock
109
yarn.lock
|
@ -1510,6 +1510,11 @@ append-field@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56"
|
||||
integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=
|
||||
|
||||
append-type@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/append-type/-/append-type-1.0.2.tgz#a492f350e81ddcb46b787fc605becf6dd8bccbf6"
|
||||
integrity sha512-hac740vT/SAbrFBLgLIWZqVT5PUAcGTWS5UkDDhr+OCizZSw90WKw6sWAEgGaYd2viIblggypMXwpjzHXOvAQg==
|
||||
|
||||
aproba@^1.0.3, aproba@^1.1.1:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
|
||||
|
@ -1565,6 +1570,11 @@ array-slice@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.1.0.tgz#e368ea15f89bc7069f7ffb89aec3a6c7d4ac22d4"
|
||||
integrity sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==
|
||||
|
||||
array-to-sentence@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/array-to-sentence/-/array-to-sentence-1.1.0.tgz#c804956dafa53232495b205a9452753a258d39fc"
|
||||
integrity sha1-yASVba+lMjJJWyBalFJ1OiWNOfw=
|
||||
|
||||
array-uniq@1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.2.tgz#5fcc373920775723cfd64d65c64bef53bf9eba6d"
|
||||
|
@ -1596,6 +1606,14 @@ assert-plus@1.0.0, assert-plus@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
|
||||
integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
|
||||
|
||||
assert-valid-glob-opts@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/assert-valid-glob-opts/-/assert-valid-glob-opts-1.0.0.tgz#ab9b5438ec5e929f5bb08201819affb1227f730a"
|
||||
integrity sha512-/mttty5Xh7wE4o7ttKaUpBJl0l04xWe3y6muy1j27gyzSsnceK0AYU9owPtUoL9z8+9hnPxztmuhdFZ7jRoyWw==
|
||||
dependencies:
|
||||
glob-option-error "^1.0.0"
|
||||
validate-glob-opts "^1.0.0"
|
||||
|
||||
assert@^1.1.1:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
|
||||
|
@ -2479,7 +2497,7 @@ commander@2.17.x:
|
|||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
|
||||
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
|
||||
|
||||
commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.3:
|
||||
commander@^2.15.1, commander@^2.18.0, commander@^2.19.0, commander@^2.20.0, commander@~2.20.3:
|
||||
version "2.20.3"
|
||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
|
||||
integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
|
||||
|
@ -2758,7 +2776,7 @@ cross-spawn@^5.0.1:
|
|||
shebang-command "^1.2.0"
|
||||
which "^1.2.9"
|
||||
|
||||
cross-spawn@^6.0.5:
|
||||
cross-spawn@^6.0.0, cross-spawn@^6.0.5:
|
||||
version "6.0.5"
|
||||
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
|
||||
integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
|
||||
|
@ -3660,6 +3678,19 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
|
|||
md5.js "^1.3.4"
|
||||
safe-buffer "^5.1.1"
|
||||
|
||||
execa@^0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.10.0.tgz#ff456a8f53f90f8eccc71a96d11bdfc7f082cb50"
|
||||
integrity sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==
|
||||
dependencies:
|
||||
cross-spawn "^6.0.0"
|
||||
get-stream "^3.0.0"
|
||||
is-stream "^1.1.0"
|
||||
npm-run-path "^2.0.0"
|
||||
p-finally "^1.0.0"
|
||||
signal-exit "^3.0.0"
|
||||
strip-eof "^1.0.0"
|
||||
|
||||
execa@^0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
|
||||
|
@ -3851,6 +3882,25 @@ feature-policy@0.3.0:
|
|||
resolved "https://registry.yarnpkg.com/feature-policy/-/feature-policy-0.3.0.tgz#7430e8e54a40da01156ca30aaec1a381ce536069"
|
||||
integrity sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ==
|
||||
|
||||
ffmpeg-generate-video-preview@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/ffmpeg-generate-video-preview/-/ffmpeg-generate-video-preview-1.0.3.tgz#b0b04dedbdfa7180c00bf6d018563b8966edf499"
|
||||
integrity sha512-IJIs++4mza7u5ShyA6zjNuX0hkqmbkQhOWZjPwWu4gCpNy9NyJ1F8ADm/pV0JqGAuStSCOHRQGuzizxhoHSptA==
|
||||
dependencies:
|
||||
commander "^2.15.1"
|
||||
execa "^0.10.0"
|
||||
ffmpeg-probe "^1.0.1"
|
||||
fluent-ffmpeg "^2.1.2"
|
||||
rmfr "^2.0.0"
|
||||
tempy "^0.2.1"
|
||||
|
||||
ffmpeg-probe@^1.0.1:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/ffmpeg-probe/-/ffmpeg-probe-1.0.6.tgz#4dbb127665ef290fb1b3b51cbecca2d8c7c72406"
|
||||
integrity sha512-zxH4MYEtrbafVQ5p1doGzHjUmjt3zI4cdKFSNVbBMKy0bTc/KwqYwnGsnQVlyBcXgqBPw2YwGBEWF53MRLh3Sw==
|
||||
dependencies:
|
||||
execa "^0.10.0"
|
||||
|
||||
figgy-pudding@^3.5.1:
|
||||
version "3.5.2"
|
||||
resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e"
|
||||
|
@ -4268,6 +4318,11 @@ github-from-package@0.0.0:
|
|||
resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce"
|
||||
integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=
|
||||
|
||||
glob-option-error@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-option-error/-/glob-option-error-1.0.0.tgz#57cc65def9c7d5c1461baf13129bb5403cff6176"
|
||||
integrity sha1-V8xl3vnH1cFGG68TEpu1QDz/YXY=
|
||||
|
||||
glob-parent@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
|
||||
|
@ -4834,6 +4889,13 @@ indent-string@^4.0.0:
|
|||
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
|
||||
integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
|
||||
|
||||
indexed-filter@^1.0.0:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/indexed-filter/-/indexed-filter-1.0.3.tgz#7911439191cac588188464640a8db4f6b324973d"
|
||||
integrity sha512-oBIzs6EARNMzrLgVg20fK52H19WcRHBiukiiEkw9rnnI//8rinEBMLrYdwEfJ9d4K7bjV1L6nSGft6H/qzHNgQ==
|
||||
dependencies:
|
||||
append-type "^1.0.1"
|
||||
|
||||
indexes-of@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
||||
|
@ -4891,6 +4953,13 @@ inquirer@^6.2.2:
|
|||
strip-ansi "^5.1.0"
|
||||
through "^2.3.6"
|
||||
|
||||
inspect-with-kind@^1.0.4:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/inspect-with-kind/-/inspect-with-kind-1.0.5.tgz#fce151d4ce89722c82ca8e9860bb96f9167c316c"
|
||||
integrity sha512-MAQUJuIo7Xqk8EVNP+6d3CKq9c80hi4tjIbIAT6lmGW9W6WzlHiu9PS8uSuUYU+Do+j1baiFp3H25XEVxDIG2g==
|
||||
dependencies:
|
||||
kind-of "^6.0.2"
|
||||
|
||||
interpret@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
|
||||
|
@ -5152,7 +5221,7 @@ is-path-inside@^1.0.0:
|
|||
dependencies:
|
||||
path-is-inside "^1.0.1"
|
||||
|
||||
is-plain-obj@^1.0.0:
|
||||
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
|
||||
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
|
||||
|
@ -8325,6 +8394,17 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
|
|||
hash-base "^3.0.0"
|
||||
inherits "^2.0.1"
|
||||
|
||||
rmfr@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/rmfr/-/rmfr-2.0.0.tgz#8a42e81332550b3f0019b8fb8ab245bea81b6d1c"
|
||||
integrity sha512-nQptLCZeyyJfgbpf2x97k5YE8vzDn7bhwx9NlvODdhgbU0mL1ruh71X0HYdRaOEvWC7Cr+SfV0p5p+Ib5yOl7A==
|
||||
dependencies:
|
||||
assert-valid-glob-opts "^1.0.0"
|
||||
glob "^7.1.2"
|
||||
graceful-fs "^4.1.11"
|
||||
inspect-with-kind "^1.0.4"
|
||||
rimraf "^2.6.2"
|
||||
|
||||
run-async@^2.2.0:
|
||||
version "2.4.0"
|
||||
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.0.tgz#e59054a5b86876cfae07f431d18cbaddc594f1e8"
|
||||
|
@ -9191,6 +9271,19 @@ tarn@^1.1.5:
|
|||
resolved "https://registry.yarnpkg.com/tarn/-/tarn-1.1.5.tgz#7be88622e951738b9fa3fb77477309242cdddc2d"
|
||||
integrity sha512-PMtJ3HCLAZeedWjJPgGnCvcphbCOMbtZpjKgLq3qM5Qq9aQud+XHrL0WlrlgnTyS8U+jrjGbEXprFcQrxPy52g==
|
||||
|
||||
temp-dir@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d"
|
||||
integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=
|
||||
|
||||
tempy@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/tempy/-/tempy-0.2.1.tgz#9038e4dbd1c201b74472214179bc2c6f7776e54c"
|
||||
integrity sha512-LB83o9bfZGrntdqPuRdanIVCPReam9SOZKW0fOy5I9X3A854GGWi0tjCqoXEk84XIEYBc/x9Hq3EFop/H5wJaw==
|
||||
dependencies:
|
||||
temp-dir "^1.0.0"
|
||||
unique-string "^1.0.0"
|
||||
|
||||
term-size@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
|
||||
|
@ -9724,6 +9817,16 @@ v8flags@^3.1.2:
|
|||
dependencies:
|
||||
homedir-polyfill "^1.0.1"
|
||||
|
||||
validate-glob-opts@^1.0.0:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/validate-glob-opts/-/validate-glob-opts-1.0.2.tgz#ef9f98977d965537ea4f51fa7d5799e9c6ebca91"
|
||||
integrity sha512-3PKjRQq/R514lUcG9OEiW0u9f7D4fP09A07kmk1JbNn2tfeQdAHhlT+A4dqERXKu2br2rrxSM3FzagaEeq9w+A==
|
||||
dependencies:
|
||||
array-to-sentence "^1.1.0"
|
||||
indexed-filter "^1.0.0"
|
||||
inspect-with-kind "^1.0.4"
|
||||
is-plain-obj "^1.1.0"
|
||||
|
||||
validate-npm-package-license@^3.0.1:
|
||||
version "3.0.4"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
||||
|
|
Loading…
Reference in New Issue