diff --git a/Dockerfile b/Dockerfile
index 067a869..f5929ee 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,6 +2,8 @@ FROM node:alpine
WORKDIR /app
+RUN apk add ffmpeg
+
RUN npm i -g pnpm
COPY . .
diff --git a/assets/music.jpg b/assets/music.jpg
new file mode 100644
index 0000000..fa3965e
Binary files /dev/null and b/assets/music.jpg differ
diff --git a/styles.css b/assets/styles.css
similarity index 100%
rename from styles.css
rename to assets/styles.css
diff --git a/view.html b/assets/view.html
similarity index 100%
rename from view.html
rename to assets/view.html
diff --git a/index.js b/index.js
index 99753b8..064f7a8 100644
--- a/index.js
+++ b/index.js
@@ -30,14 +30,63 @@ fastify.register(fastifyStatic, {
// Handle CSS file, by sending `styles.css` file from the current directory
fastify.get('/styles.css', async (request, reply) => {
- const cssContent = await fs.promises.readFile('styles.css', 'utf8')
+ const cssContent = await fs.promises.readFile('assets/styles.css', 'utf8')
reply.header('Content-Type', 'text/css').send(cssContent)
});
+fastify.get('/music.jpg', async (request, reply) => {
+ const musicImage = await fs.promises.readFile('assets/music.jpg')
+ reply.header('Content-Type', 'image/jpeg').send(musicImage)
+});
+
+const assetSizeCache = new Map()
+
+//Find the width and height of a file either an image or video, and cache the result
+async function getAssetSize(filePath) {
+ if (assetSizeCache.has(filePath)) {
+ return assetSizeCache.get(filePath)
+ }
+
+ const mimeType = mime.lookup(filePath) || 'application/octet-stream'
+
+ let assetSize = { width: 0, height: 0 }
+
+ //Use ffprobe to get the width and height of a video file
+ if (mimeType.startsWith('video/')) {
+ const { exec } = require('child_process')
+ const { promisify } = require('util')
+ const execAsync = promisify(exec)
+
+ try {
+ const { stdout } = await execAsync(`ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 ${filePath}`)
+ const [width, height] = stdout.trim().split('x').map(Number)
+ assetSize = { width, height }
+ } catch (error) {
+ console.error(error)
+ }
+ //Use sharp to get the width and height of an image file
+ } else if (mimeType.startsWith('image/')) {
+ const sharp = require('sharp')
+ try {
+ const metadata = await sharp(filePath).metadata()
+ assetSize = { width: metadata.width, height: metadata.height }
+ } catch (error) {
+ console.error(error)
+ }
+ }
+
+ assetSizeCache.set(filePath, assetSize)
+
+ return assetSize
+}
+
// Serve HTML page with embedded file (public)
fastify.get('/s/:date/:filename', async (request, reply) => {
let { filename, date } = request.params
+ //Log the user agent
+ console.log(request.headers['user-agent'])
+
// Sanitize filename & date
filename = sanitize(filename)
date = sanitize(date)
@@ -53,21 +102,36 @@ fastify.get('/s/:date/:filename', async (request, reply) => {
//Check if the file exists, if not, return 404
await fs.promises.access(filePath)
+ const {width, height} = await getAssetSize(filePath);
+
const mimeType = mime.lookup(filename) || 'application/octet-stream'
let fileContent = '';
- let ogTags = '';
+ let ogTags = `
+ \n`;
if (mimeType.startsWith('image/')) {
- fileContent = ``
- ogTags = ``
+ fileContent = `
+
+
+
+
+ `
} else if (mimeType.startsWith('video/')) {
- fileContent = ``
- ogTags = `
- `
+ fileContent = ``
+ ogTags += `
+
+
+
+
+
+ `
} else if (mimeType.startsWith('audio/')) {
fileContent = ``
- ogTags = `
- `
+ ogTags += `
+
+
+ `
} else if (mimeType.startsWith('text/')) {
const fileData = await fs.promises.readFile(filePath, 'utf8');
fileContent = `
${fileData}`
@@ -75,7 +139,7 @@ fastify.get('/s/:date/:filename', async (request, reply) => {
fileContent = `Download File`
}
- const htmlContent = await fs.promises.readFile('view.html', 'utf8');
+ const htmlContent = await fs.promises.readFile('assets/view.html', 'utf8');
//Replace placeholders with actual content
const html = htmlContent
@@ -137,6 +201,21 @@ fastify.put('/upload', {
message: 'File uploaded successfully',
fileName: host.replace(/\/$/, '') + '/s/' + path.join(dateFolder, fileName)
})
+
+ //If the file is a video, generate a thumbnail
+ const mimeType = mime.lookup(fileName) || 'application/octet-stream'
+ if (mimeType.startsWith('video/')) {
+ const { exec } = require('child_process')
+ const { promisify } = require('util')
+ const execAsync = promisify(exec)
+
+ const thumbnailPath = path.join(fullUploadDir, fileName + '.thumb.jpg')
+ try {
+ await execAsync(`ffmpeg -i ${filePath} -ss 00:00:01 -vframes 1 ${thumbnailPath}`)
+ } catch (error) {
+ console.error(error)
+ }
+ }
} catch (err) {
reply.code(500).send({ error: 'Error uploading file' })
}
diff --git a/package.json b/package.json
index e4c1bb3..13170f2 100644
--- a/package.json
+++ b/package.json
@@ -15,7 +15,13 @@
"dotenv": "^16.4.7",
"fastify": "^5.2.1",
"mime-types": "^2.1.35",
- "sanitize-filename": "^1.6.3"
+ "sanitize-filename": "^1.6.3",
+ "sharp": "^0.33.5"
},
- "type": "module"
+ "type": "module",
+ "pnpm": {
+ "onlyBuiltDependencies": [
+ "sharp"
+ ]
+ }
}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 1c10f8a..6780f9c 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -26,9 +26,15 @@ importers:
sanitize-filename:
specifier: ^1.6.3
version: 1.6.3
+ sharp:
+ specifier: ^0.33.5
+ version: 0.33.5
packages:
+ '@emnapi/runtime@1.3.1':
+ resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
+
'@fastify/accept-negotiator@2.0.1':
resolution: {integrity: sha512-/c/TW2bO/v9JeEgoD/g1G5GxGeCF1Hafdf79WPmUlgYiBXummY0oX3VVq4yFkKKVBKDNlaDUYoab7g38RpPqCQ==}
@@ -65,6 +71,111 @@ packages:
'@fastify/static@8.1.0':
resolution: {integrity: sha512-lPb8+1ulvbGSUSQ0/adBDyp/Ye/MX+pBwhkLAr8/GU88kNnJlSu7KXdyW6CCOROcr5BgrqJD01lEOosozFAegw==}
+ '@img/sharp-darwin-arm64@0.33.5':
+ resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-darwin-x64@0.33.5':
+ resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-arm64@1.0.4':
+ resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@img/sharp-libvips-darwin-x64@1.0.4':
+ resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@img/sharp-libvips-linux-arm64@1.0.4':
+ resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-arm@1.0.5':
+ resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-s390x@1.0.4':
+ resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-libvips-linux-x64@1.0.4':
+ resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
+ resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-libvips-linuxmusl-x64@1.0.4':
+ resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linux-arm64@0.33.5':
+ resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linux-arm@0.33.5':
+ resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@img/sharp-linux-s390x@0.33.5':
+ resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@img/sharp-linux-x64@0.33.5':
+ resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-arm64@0.33.5':
+ resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@img/sharp-linuxmusl-x64@0.33.5':
+ resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@img/sharp-wasm32@0.33.5':
+ resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [wasm32]
+
+ '@img/sharp-win32-ia32@0.33.5':
+ resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@img/sharp-win32-x64@0.33.5':
+ resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+ cpu: [x64]
+ os: [win32]
+
'@isaacs/cliui@8.0.2':
resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==}
engines: {node: '>=12'}
@@ -123,6 +234,13 @@ packages:
color-name@1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
+ color-string@1.9.1:
+ resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
+
+ color@4.2.3:
+ resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
+ engines: {node: '>=12.5.0'}
+
content-disposition@0.5.4:
resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==}
engines: {node: '>= 0.6'}
@@ -143,6 +261,10 @@ packages:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
+ detect-libc@2.0.3:
+ resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==}
+ engines: {node: '>=8'}
+
dotenv@16.4.7:
resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==}
engines: {node: '>=12'}
@@ -211,6 +333,9 @@ packages:
resolution: {integrity: sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA==}
engines: {node: '>= 10'}
+ is-arrayish@0.3.2:
+ resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
+
is-fullwidth-code-point@3.0.0:
resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==}
engines: {node: '>=8'}
@@ -333,6 +458,10 @@ packages:
setprototypeof@1.2.0:
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
+ sharp@0.33.5:
+ resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==}
+ engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0}
+
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
@@ -345,6 +474,9 @@ packages:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
+ simple-swizzle@0.2.2:
+ resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
+
sonic-boom@4.2.0:
resolution: {integrity: sha512-INb7TM37/mAcsGmc9hyyI6+QR3rR1zVRu36B0NeGXKnOOLiZOfER5SA+N7X7k3yUYRzLWafduTDvJAfDswwEww==}
@@ -386,6 +518,9 @@ packages:
truncate-utf8-bytes@1.0.2:
resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==}
+ tslib@2.8.1:
+ resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+
utf8-byte-length@1.0.5:
resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==}
@@ -404,6 +539,11 @@ packages:
snapshots:
+ '@emnapi/runtime@1.3.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
'@fastify/accept-negotiator@2.0.1': {}
'@fastify/ajv-compiler@4.0.2':
@@ -458,6 +598,81 @@ snapshots:
fastq: 1.19.0
glob: 11.0.1
+ '@img/sharp-darwin-arm64@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-arm64': 1.0.4
+ optional: true
+
+ '@img/sharp-darwin-x64@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-darwin-x64': 1.0.4
+ optional: true
+
+ '@img/sharp-libvips-darwin-arm64@1.0.4':
+ optional: true
+
+ '@img/sharp-libvips-darwin-x64@1.0.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm64@1.0.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-arm@1.0.5':
+ optional: true
+
+ '@img/sharp-libvips-linux-s390x@1.0.4':
+ optional: true
+
+ '@img/sharp-libvips-linux-x64@1.0.4':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-arm64@1.0.4':
+ optional: true
+
+ '@img/sharp-libvips-linuxmusl-x64@1.0.4':
+ optional: true
+
+ '@img/sharp-linux-arm64@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm64': 1.0.4
+ optional: true
+
+ '@img/sharp-linux-arm@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-arm': 1.0.5
+ optional: true
+
+ '@img/sharp-linux-s390x@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-s390x': 1.0.4
+ optional: true
+
+ '@img/sharp-linux-x64@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linux-x64': 1.0.4
+ optional: true
+
+ '@img/sharp-linuxmusl-arm64@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
+ optional: true
+
+ '@img/sharp-linuxmusl-x64@0.33.5':
+ optionalDependencies:
+ '@img/sharp-libvips-linuxmusl-x64': 1.0.4
+ optional: true
+
+ '@img/sharp-wasm32@0.33.5':
+ dependencies:
+ '@emnapi/runtime': 1.3.1
+ optional: true
+
+ '@img/sharp-win32-ia32@0.33.5':
+ optional: true
+
+ '@img/sharp-win32-x64@0.33.5':
+ optional: true
+
'@isaacs/cliui@8.0.2':
dependencies:
string-width: 5.1.2
@@ -511,6 +726,16 @@ snapshots:
color-name@1.1.4: {}
+ color-string@1.9.1:
+ dependencies:
+ color-name: 1.1.4
+ simple-swizzle: 0.2.2
+
+ color@4.2.3:
+ dependencies:
+ color-convert: 2.0.1
+ color-string: 1.9.1
+
content-disposition@0.5.4:
dependencies:
safe-buffer: 5.2.1
@@ -527,6 +752,8 @@ snapshots:
dequal@2.0.3: {}
+ detect-libc@2.0.3: {}
+
dotenv@16.4.7: {}
eastasianwidth@0.2.0: {}
@@ -614,6 +841,8 @@ snapshots:
ipaddr.js@2.2.0: {}
+ is-arrayish@0.3.2: {}
+
is-fullwidth-code-point@3.0.0: {}
isexe@2.0.0: {}
@@ -715,6 +944,32 @@ snapshots:
setprototypeof@1.2.0: {}
+ sharp@0.33.5:
+ dependencies:
+ color: 4.2.3
+ detect-libc: 2.0.3
+ semver: 7.7.1
+ optionalDependencies:
+ '@img/sharp-darwin-arm64': 0.33.5
+ '@img/sharp-darwin-x64': 0.33.5
+ '@img/sharp-libvips-darwin-arm64': 1.0.4
+ '@img/sharp-libvips-darwin-x64': 1.0.4
+ '@img/sharp-libvips-linux-arm': 1.0.5
+ '@img/sharp-libvips-linux-arm64': 1.0.4
+ '@img/sharp-libvips-linux-s390x': 1.0.4
+ '@img/sharp-libvips-linux-x64': 1.0.4
+ '@img/sharp-libvips-linuxmusl-arm64': 1.0.4
+ '@img/sharp-libvips-linuxmusl-x64': 1.0.4
+ '@img/sharp-linux-arm': 0.33.5
+ '@img/sharp-linux-arm64': 0.33.5
+ '@img/sharp-linux-s390x': 0.33.5
+ '@img/sharp-linux-x64': 0.33.5
+ '@img/sharp-linuxmusl-arm64': 0.33.5
+ '@img/sharp-linuxmusl-x64': 0.33.5
+ '@img/sharp-wasm32': 0.33.5
+ '@img/sharp-win32-ia32': 0.33.5
+ '@img/sharp-win32-x64': 0.33.5
+
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
@@ -723,6 +978,10 @@ snapshots:
signal-exit@4.1.0: {}
+ simple-swizzle@0.2.2:
+ dependencies:
+ is-arrayish: 0.3.2
+
sonic-boom@4.2.0:
dependencies:
atomic-sleep: 1.0.0
@@ -763,6 +1022,9 @@ snapshots:
dependencies:
utf8-byte-length: 1.0.5
+ tslib@2.8.1:
+ optional: true
+
utf8-byte-length@1.0.5: {}
which@2.0.2: