From 9c395d82f324c2ad9d5b716b401925ecbb8616c1 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 13 Nov 2023 14:09:38 +0100 Subject: [PATCH] feat: compress EVERYTHING! --- bin/compress_s3.js | 106 +++++++++ bin/compress_s3.ts | 55 ----- package.json | 4 +- pnpm-lock.yaml | 249 +++++++++++++++++++++- src/lib/components/ImageFrame.svelte | 46 +++- src/lib/components/Questions.svelte | 20 +- src/lib/helpers/pb.ts | 5 +- src/routes/api/ai/image/[name]/+server.ts | 65 ++++-- src/routes/api/invites/+server.ts | 1 + src/routes/gallery/+page.svelte | 1 + src/routes/image/+page.svelte | 7 - static/frames/frame_01.avif | Bin 0 -> 59594 bytes static/frames/frame_01.png | Bin 1940372 -> 436965 bytes static/frames/frame_01.webp | Bin 0 -> 44096 bytes static/frames/frame_02.avif | Bin 0 -> 50008 bytes static/frames/frame_02.png | Bin 685497 -> 627453 bytes static/frames/frame_02.webp | Bin 0 -> 50454 bytes static/frames/frame_03.avif | Bin 0 -> 27240 bytes static/frames/frame_03.png | Bin 1592113 -> 426782 bytes static/frames/frame_03.webp | Bin 0 -> 43942 bytes static/frames/frame_04.avif | Bin 0 -> 49760 bytes static/frames/frame_04.png | Bin 1928434 -> 623056 bytes static/frames/frame_04.webp | Bin 0 -> 75474 bytes static/frames/frame_05.avif | Bin 0 -> 64949 bytes static/frames/frame_05.png | Bin 12170858 -> 490662 bytes static/frames/frame_05.webp | Bin 0 -> 82452 bytes static/frames/frame_06.avif | Bin 0 -> 23557 bytes static/frames/frame_06.png | Bin 1858382 -> 406486 bytes static/frames/frame_06.webp | Bin 0 -> 41006 bytes static/frames/frame_07.avif | Bin 0 -> 21757 bytes static/frames/frame_07.png | Bin 1132604 -> 434090 bytes static/frames/frame_07.webp | Bin 0 -> 39410 bytes static/frames/frame_08.avif | Bin 0 -> 21270 bytes static/frames/frame_08.png | Bin 464031 -> 336061 bytes static/frames/frame_08.webp | Bin 0 -> 37918 bytes 35 files changed, 462 insertions(+), 97 deletions(-) create mode 100644 bin/compress_s3.js delete mode 100644 bin/compress_s3.ts delete mode 100644 src/routes/image/+page.svelte create mode 100644 static/frames/frame_01.avif create mode 100644 static/frames/frame_01.webp create mode 100644 static/frames/frame_02.avif create mode 100644 static/frames/frame_02.webp create mode 100644 static/frames/frame_03.avif create mode 100644 static/frames/frame_03.webp create mode 100644 static/frames/frame_04.avif create mode 100644 static/frames/frame_04.webp create mode 100644 static/frames/frame_05.avif create mode 100644 static/frames/frame_05.webp create mode 100644 static/frames/frame_06.avif create mode 100644 static/frames/frame_06.webp create mode 100644 static/frames/frame_07.avif create mode 100644 static/frames/frame_07.webp create mode 100644 static/frames/frame_08.avif create mode 100644 static/frames/frame_08.webp diff --git a/bin/compress_s3.js b/bin/compress_s3.js new file mode 100644 index 0000000..4dd0491 --- /dev/null +++ b/bin/compress_s3.js @@ -0,0 +1,106 @@ +import { Client } from "minio"; +import sharp from "sharp" +import {config} from "dotenv" +config() + +// Retrieve MinIO details from environment variables +const minioEndpoint = process.env["S3_ENDPOINT_URL"] || "your-minio-endpoint"; +const minioAccessKey = process.env["S3_ACCESS_KEY"] || "your-access-key"; +const minioSecretKey = process.env["S3_SECRET_ACCESS_KEY"] || "your-secret-key"; +const minioBucketName = "silvester23"; + +const minioClient = new Client({ + endPoint: minioEndpoint, + accessKey: minioAccessKey, + secretKey: minioSecretKey, +}); + + +const objects = []; + +const objectStream = minioClient.listObjects(minioBucketName); + +for await (const obj of objectStream) { + objects.push(obj); +} + +async function compressObject(pngBuffer, fileName, format) { + + const newFilePath = `${fileName.slice(0, -4)}.${format}`; + + let buffer; + switch (format) { + case "webp": + buffer = await sharp(pngBuffer).webp({ quality: 80 }).toBuffer(); + break; + case "jpg": + buffer = await sharp(pngBuffer).jpeg({ quality: 80 }).toBuffer(); + break; + case "avif": + buffer = await sharp(pngBuffer).avif({ quality: 80 }).toBuffer(); + break; + default: + throw new Error(`Unknown format ${format}`); + } + + // Upload the JPG buffer back to the same MinIO bucket + await minioClient.putObject(minioBucketName, newFilePath, buffer, { + 'Content-Type': 'image/' + format, + }); + + console.log(`Uploaded ${newFilePath} to MinIO`); +} + +async function fetchBuffer(objectName) { + const chunks = []; + + return new Promise((res, rej) => { + minioClient.getObject(minioBucketName,objectName, function (err, dataStream) { + if (err) { + return console.log(err) + } + dataStream.on('data', function (chunk) { + chunks.push(chunk); + }) + dataStream.on('end', function () { + res(Buffer.concat(chunks)) + }) + dataStream.on('error', function (err) { + console.log(err) + rej(err) + }) + }) + }) +} + +const pngs = objects.filter((o) => o.name.endsWith(".png")); +console.log(`Found ${pngs.length} PNGs`); + +for (const obj of pngs) { + const pngFilePath = obj.name; + const jpgFilePath = pngFilePath.slice(0, -4) + ".jpg"; + const avifFilePath = pngFilePath.slice(0, -4) + ".avif"; + const webpFilePath = pngFilePath.slice(0, -4) + ".webp"; + + const hasJpg = objects.some((o) => o.name === jpgFilePath); + const hasAvif = objects.some((o) => o.name === avifFilePath); + const hasWebp = objects.some((o) => o.name === webpFilePath); + + if(hasAvif && hasJpg && hasWebp) { + continue; + } + + const pngBuffer = await fetchBuffer(pngFilePath); + + if(!hasJpg) { + await compressObject(pngBuffer, pngFilePath, "jpg"); + } + + if(!hasAvif) { + await compressObject(pngBuffer, pngFilePath, "avif"); + } + if(!hasWebp) { + await compressObject(pngBuffer, pngFilePath, "webp"); + } + +} diff --git a/bin/compress_s3.ts b/bin/compress_s3.ts deleted file mode 100644 index b16ba07..0000000 --- a/bin/compress_s3.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Client } from "npm:minio"; -import Jimp from 'npm:jimp'; -import { config } from "https://deno.land/x/dotenv/mod.ts"; -config({ export: true }); - -interface MinioObject { - name: string; -} - -// Retrieve MinIO details from environment variables -const minioEndpoint = Deno.env.get("S3_ENDPOINT_URL") || "your-minio-endpoint"; -const minioAccessKey = Deno.env.get("S3_ACCESS_KEY") || "your-access-key"; -const minioSecretKey = Deno.env.get("S3_SECRET_ACCESS_KEY") || "your-secret-key"; -const minioBucketName = "silvester23"; - -const minioClient = new Client({ - endPoint: minioEndpoint, - accessKey: minioAccessKey, - secretKey: minioSecretKey, -}); - - -const objects: MinioObject[] = []; - -const objectStream = minioClient.listObjects(minioBucketName); - -for await (const obj of objectStream) { - objects.push({ - name: obj.name, - }); -} - -// Process and upload images -for (const obj of objects) { - const pngFilePath = obj.name; - const jpgFilePath = `${pngFilePath.slice(0, -4)}.jpg`; - - // Check if the PNG file exists and there is no corresponding JPG file - if (!objects.some((o) => o.name === jpgFilePath)) { - // Download the PNG file from MinIO - const pngBuffer = await minioClient.getObject(minioBucketName, pngFilePath); - console.log(`Downloaded ${pngFilePath} from MinIO`); - - // Use Jimp to compress and convert the PNG to JPG - const image = await Jimp.read(`http://s3-api.app.max-richter.dev/silvester23/${pngFilePath}`); - const jpgBuffer = await image.quality(80).getBufferAsync(Jimp.MIME_JPEG); - - // Upload the JPG buffer back to the same MinIO bucket - await minioClient.putObject(minioBucketName, jpgFilePath, jpgBuffer, { - 'Content-Type': 'image/jpeg', - }); - - console.log(`Uploaded ${jpgFilePath} to MinIO`); - } -} diff --git a/package.json b/package.json index 443e18f..d9b00f1 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "@sveltejs/kit": "^1.27.5", "@typescript-eslint/eslint-plugin": "^6.10.0", "@typescript-eslint/parser": "^6.10.0", + "dotenv": "^16.3.1", "eslint": "^8.53.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-svelte": "^2.35.0", @@ -34,6 +35,7 @@ "jimp": "^0.22.10", "minio": "^7.1.3", "openai": "^4.17.4", - "pocketbase": "^0.19.0" + "pocketbase": "^0.19.0", + "sharp": "^0.32.6" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 37ee49c..ce3aa13 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ dependencies: pocketbase: specifier: ^0.19.0 version: 0.19.0 + sharp: + specifier: ^0.32.6 + version: 0.32.6 devDependencies: '@sveltejs/adapter-node': @@ -34,6 +37,9 @@ devDependencies: '@typescript-eslint/parser': specifier: ^6.10.0 version: 6.10.0(eslint@8.53.0)(typescript@5.2.2) + dotenv: + specifier: ^16.3.1 + version: 16.3.1 eslint: specifier: ^8.53.0 version: 8.53.0 @@ -1171,6 +1177,10 @@ packages: dequal: 2.0.3 dev: true + /b4a@1.6.4: + resolution: {integrity: sha512-fpWrvyVHEKyeEvbKZTVOeZF3VSKKWtJxFIxX/jaVPf+cLbGUSitjb49pHLqPV2BUNNZ0LcoeEGfE/YCpyDYHIw==} + dev: false + /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true @@ -1192,6 +1202,14 @@ packages: engines: {node: '>=8'} dev: true + /bl@4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + /block-stream2@2.1.0: resolution: {integrity: sha512-suhjmLI57Ewpmq00qaygS8UgEq2ly2PCItenIyhMqVjo4t4pGzqMvfgJuX8iWTeSDdfSSqS6j38fL4ToNL7Pfg==} dependencies: @@ -1290,6 +1308,10 @@ packages: fsevents: 2.3.3 dev: true + /chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + dev: false + /code-red@1.0.4: resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} dependencies: @@ -1305,11 +1327,24 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + + /color-string@1.9.1: + resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + dependencies: + color-name: 1.1.4 + simple-swizzle: 0.2.2 + dev: false + + /color@4.2.3: + resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} + engines: {node: '>=12.5.0'} + dependencies: + color-convert: 2.0.1 + color-string: 1.9.1 + dev: false /combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} @@ -1374,6 +1409,18 @@ packages: engines: {node: '>=0.10'} dev: false + /decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: false + + /deep-extend@0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: false + /deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true @@ -1407,6 +1454,11 @@ packages: engines: {node: '>=8'} dev: true + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + dev: false + /devalue@4.3.2: resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} dev: true @@ -1436,12 +1488,23 @@ packages: resolution: {integrity: sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==} dev: false + /dotenv@16.3.1: + resolution: {integrity: sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==} + engines: {node: '>=12'} + dev: true + /ecdsa-sig-formatter@1.0.11: resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} dependencies: safe-buffer: 5.2.1 dev: false + /end-of-stream@1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: false + /es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} dev: true @@ -1644,6 +1707,11 @@ packages: resolution: {integrity: sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==} dev: false + /expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + dev: false + /extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} dev: false @@ -1652,6 +1720,10 @@ packages: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true + /fast-fifo@1.3.2: + resolution: {integrity: sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==} + dev: false + /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} engines: {node: '>=8.6.0'} @@ -1760,6 +1832,10 @@ packages: web-streams-polyfill: 4.0.0-beta.3 dev: false + /fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: false + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -1815,6 +1891,10 @@ packages: omggif: 1.0.10 dev: false + /github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + dev: false + /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} @@ -2039,6 +2119,10 @@ packages: /inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + /ini@1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: false + /ipaddr.js@2.1.0: resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==} engines: {node: '>= 10'} @@ -2052,6 +2136,10 @@ packages: has-tostringtag: 1.0.0 dev: false + /is-arrayish@0.3.2: + resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + dev: false + /is-binary-path@2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} @@ -2279,7 +2367,6 @@ packages: engines: {node: '>=10'} dependencies: yallist: 4.0.0 - dev: true /magic-string@0.27.0: resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} @@ -2338,6 +2425,11 @@ packages: hasBin: true dev: false + /mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: false + /min-document@2.19.0: resolution: {integrity: sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==} dependencies: @@ -2364,7 +2456,6 @@ packages: /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true /minio@7.1.3: resolution: {integrity: sha512-xPrLjWkTT5E7H7VnzOjF//xBp9I40jYB4aWhb2xTFopXXfw+Wo82DDWngdUju7Doy3Wk7R8C4LAgwhLHHnf0wA==} @@ -2386,6 +2477,10 @@ packages: xml2js: 0.5.0 dev: false + /mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + dev: false + /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -2416,10 +2511,25 @@ packages: hasBin: true dev: true + /napi-build-utils@1.0.2: + resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} + dev: false + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /node-abi@3.51.0: + resolution: {integrity: sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==} + engines: {node: '>=10'} + dependencies: + semver: 7.5.4 + dev: false + + /node-addon-api@6.1.0: + resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==} + dev: false + /node-domexception@1.0.0: resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} engines: {node: '>=10.5.0'} @@ -2454,7 +2564,6 @@ packages: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: wrappy: 1.0.2 - dev: true /openai@4.17.4: resolution: {integrity: sha512-ThRFkl6snLbcAKS58St7N3CaKuI5WdYUvIjPvf4s+8SdymgNtOfzmZcZXVcCefx04oKFnvZJvIcTh3eAFUUhAQ==} @@ -2652,6 +2761,25 @@ packages: source-map-js: 1.0.2 dev: true + /prebuild-install@7.1.1: + resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} + engines: {node: '>=10'} + hasBin: true + dependencies: + detect-libc: 2.0.2 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 1.0.2 + node-abi: 3.51.0 + pump: 3.0.0 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.1 + tunnel-agent: 0.6.0 + dev: false + /prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -2678,6 +2806,13 @@ packages: engines: {node: '>= 0.6.0'} dev: false + /pump@3.0.0: + resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} + dependencies: + end-of-stream: 1.4.4 + once: 1.4.0 + dev: false + /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2704,6 +2839,20 @@ packages: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} dev: true + /queue-tick@1.0.1: + resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} + dev: false + + /rc@1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: false + /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} engines: {node: '>= 6'} @@ -2808,7 +2957,6 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 - dev: true /set-cookie-parser@2.6.0: resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} @@ -2824,6 +2972,21 @@ packages: has-property-descriptors: 1.0.1 dev: false + /sharp@0.32.6: + resolution: {integrity: sha512-KyLTWwgcR9Oe4d9HwCwNM2l7+J0dUQwn/yf7S0EnTtb0eVS4RxO0eUSvxPtzT4F3SY+C4K6fqdv/DO27sJ/v/w==} + engines: {node: '>=14.15.0'} + requiresBuild: true + dependencies: + color: 4.2.3 + detect-libc: 2.0.2 + node-addon-api: 6.1.0 + prebuild-install: 7.1.1 + semver: 7.5.4 + simple-get: 4.0.1 + tar-fs: 3.0.4 + tunnel-agent: 0.6.0 + dev: false + /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2844,6 +3007,24 @@ packages: object-inspect: 1.13.1 dev: false + /simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + dev: false + + /simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + dev: false + + /simple-swizzle@0.2.2: + resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + dependencies: + is-arrayish: 0.3.2 + dev: false + /sirv@2.0.3: resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} engines: {node: '>= 10'} @@ -2878,6 +3059,13 @@ packages: engines: {node: '>=6'} dev: false + /streamx@2.15.4: + resolution: {integrity: sha512-uSXKl88bibiUCQ1eMpItRljCzDENcDx18rsfDmV79r0e/ThfrAwxG4Y2FarQZ2G4/21xcOKmFFd1Hue+ZIDwHw==} + dependencies: + fast-fifo: 1.3.2 + queue-tick: 1.0.1 + dev: false + /strict-uri-encode@2.0.0: resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} engines: {node: '>=4'} @@ -2903,6 +3091,11 @@ packages: min-indent: 1.0.1 dev: true + /strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: false + /strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -3052,6 +3245,42 @@ packages: periscopic: 3.1.0 dev: true + /tar-fs@2.1.1: + resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 2.2.0 + dev: false + + /tar-fs@3.0.4: + resolution: {integrity: sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==} + dependencies: + mkdirp-classic: 0.5.3 + pump: 3.0.0 + tar-stream: 3.1.6 + dev: false + + /tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + dev: false + + /tar-stream@3.1.6: + resolution: {integrity: sha512-B/UyjYwPpMBv+PaFSWAmtYjwdrlEaZQEhMIBFNC5oEG8lpiW8XjcSdmEaClj28ArfKScKHs2nshz3k2le6crsg==} + dependencies: + b4a: 1.6.4 + fast-fifo: 1.3.2 + streamx: 2.15.4 + dev: false + /text-table@0.2.0: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true @@ -3114,6 +3343,12 @@ packages: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} dev: true + /tunnel-agent@0.6.0: + resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + dependencies: + safe-buffer: 5.2.1 + dev: false + /type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -3277,7 +3512,6 @@ packages: /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true /xhr@2.6.0: resolution: {integrity: sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==} @@ -3324,7 +3558,6 @@ packages: /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true /yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} diff --git a/src/lib/components/ImageFrame.svelte b/src/lib/components/ImageFrame.svelte index a005d00..089439c 100644 --- a/src/lib/components/ImageFrame.svelte +++ b/src/lib/components/ImageFrame.svelte @@ -1,20 +1,56 @@
- - + + + + + + + + + Painting Frame + + + painting hanging cord + + + - + handleError()} />