From 4f1b99fd8cb31a2ea1cc2b3285c133bcd7e02168 Mon Sep 17 00:00:00 2001 From: f0x Date: Sun, 19 May 2024 23:27:24 +0200 Subject: [PATCH] untested heic conversion patch --- package.json | 1 + server/plugins/uploader.ts | 31 +++++++++++++++++++-- yarn.lock | 56 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 11f40222a..75a1b280d 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "file-type": "16.5.4", "filenamify": "4.3.0", "got": "11.8.5", + "heic-jpg-exif": "0.3.5", "irc-framework": "4.13.1", "is-utf8": "0.2.1", "ldapjs": "2.3.1", diff --git a/server/plugins/uploader.ts b/server/plugins/uploader.ts index 0a5e53a88..65c70751a 100644 --- a/server/plugins/uploader.ts +++ b/server/plugins/uploader.ts @@ -11,6 +11,7 @@ import log from "../log"; import contentDisposition from "content-disposition"; import type {Socket} from "socket.io"; import {Request, Response} from "express"; +import convert from "heic-jpg-exif"; // Map of allowed mime types to their respecive default filenames // that will be rendered in browser without forcing them to be downloaded @@ -248,6 +249,13 @@ class Uploader { }, filename: string | number | boolean ) => { + let convertToJpeg = false; + + if (typeof filename === "string" && filename.endsWith(".heic")) { + convertToJpeg = true; + filename.replace(/\.heic$/, ".jpg"); + } + uploadUrl = `${randomName}/${encodeURIComponent(filename)}`; if (Config.values.fileUpload.baseUrl) { @@ -267,8 +275,27 @@ class Uploader { return abortWithError(Error("File size limit reached")); }); - // Attempt to write the stream to file - fileStream.pipe(streamWriter); + // Attempt to write the stream to file, converting to jpeg first if needed (HEIC) + + // Little race-condition where busboyInstance.on("finish") handler might fire as soon + // as buffers are concatinated, while conversion is still happening. + // might be fine, as it'll take a bit before the url actually needs to be available anyways, + // but might have worse error-handling.. + if (convertToJpeg && streamWriter) { + const bufs: Buffer[] = []; + streamWriter.on("data", (d: Buffer) => bufs.push(d)); + streamWriter.on("error", abortWithError); + streamWriter.on("end", () => { + const buf = Buffer.concat(bufs); + convert(buf).then((c) => { + fileStream.pipe(c); + }).catch((e) => { + abortWithError(e); + }); + }); + } else { + fileStream.pipe(streamWriter); + } } ); diff --git a/yarn.lock b/yarn.lock index 892191960..270beb86c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3826,6 +3826,11 @@ execall@^2.0.0: dependencies: clone-regexp "^2.1.0" +exifr@^7.1.3: + version "7.1.3" + resolved "https://registry.yarnpkg.com/exifr/-/exifr-7.1.3.tgz#f6218012c36dbb7d843222011b27f065fddbab6f" + integrity sha512-g/aje2noHivrRSLbAUtBPWFbxKdKhgj/xr1vATDdUXPOFYJlQ62Ft0oy+72V6XLIpDJfHs6gXLbBLAolqOXYRw== + expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" @@ -4057,6 +4062,11 @@ fraction.js@^4.2.0: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.2.0.tgz#448e5109a313a3527f5a3ab2119ec4cf0e0e2950" integrity sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA== +fraction.js@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.3.7.tgz#06ca0085157e42fda7f9e726e79fefc4068840f7" + integrity sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew== + fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -4418,6 +4428,32 @@ he@1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +heic-convert@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/heic-convert/-/heic-convert-2.1.0.tgz#7f764529e37591ae263ef49582d1d0c13491526e" + integrity sha512-1qDuRvEHifTVAj3pFIgkqGgJIr0M3X7cxEPjEp0oG4mo8GFjq99DpCo8Eg3kg17Cy0MTjxpFdoBHOatj7ZVKtg== + dependencies: + heic-decode "^2.0.0" + jpeg-js "^0.4.4" + pngjs "^6.0.0" + +heic-decode@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/heic-decode/-/heic-decode-2.0.0.tgz#77ab96ee1a255f0a9952d0e88d584bca30577114" + integrity sha512-NU+zsiDvdL+EebyTjrEqjkO2XYI7FgLhQzsbmO8dnnYce3S0PBSDm/ZyI4KpcGPXYEdb5W72vp/AQFuc4F8ASg== + dependencies: + libheif-js "^1.17.1" + +heic-jpg-exif@0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/heic-jpg-exif/-/heic-jpg-exif-0.3.5.tgz#f1f9041a1cfee2a151999ab6e9ffcaeb98299d6c" + integrity sha512-YrXUw4ea13bJsr1vobvFbZWeewdsaSx33JzUs6e2aj169Q3q/tW/rNIByv/TJ0Bb5Ksjc+8KmHE/7kDLxlwxfw== + dependencies: + exifr "^7.1.3" + fraction.js "^4.3.7" + heic-convert "^2.1.0" + piexif-ts "^2.1.0" + hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" @@ -4946,6 +4982,11 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" +jpeg-js@^0.4.4: + version "0.4.4" + resolved "https://registry.yarnpkg.com/jpeg-js/-/jpeg-js-0.4.4.tgz#a9f1c6f1f9f0fa80cdb3484ed9635054d28936aa" + integrity sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg== + js-beautify@1.14.6: version "1.14.6" resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.14.6.tgz#b23ca5d74a462c282c7711bb51150bcc97f2b507" @@ -5104,6 +5145,11 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +libheif-js@^1.17.1: + version "1.17.1" + resolved "https://registry.yarnpkg.com/libheif-js/-/libheif-js-1.17.1.tgz#7772cc5a31098df0354f0fadb49a939030765acd" + integrity sha512-g9wBm/CasGZMjmH3B2sD9+AO7Y5+79F0oPS+sdAulSxQeYeCeiTIP+lDqvlPofD+y76wvfVtotKZ8AuvZQnWgg== + lilconfig@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4" @@ -6103,6 +6149,11 @@ pidtree@^0.3.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.1.tgz#ef09ac2cc0533df1f3250ccf2c4d366b0d12114a" integrity sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA== +piexif-ts@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/piexif-ts/-/piexif-ts-2.1.0.tgz#d8da5a7d9113035f615e48cc8e12d5d45e924632" + integrity sha512-Fk1T7NbZnmiI4IPHrxz8y3dpzMAywDk1+9g0iGwHf+UPYPZJ1/CKALzhPPRPqAxwalwNz2t0NB4krY/PkAI93A== + pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -6125,6 +6176,11 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" +pngjs@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-6.0.0.tgz#ca9e5d2aa48db0228a52c419c3308e87720da821" + integrity sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg== + postcss-attribute-case-insensitive@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/postcss-attribute-case-insensitive/-/postcss-attribute-case-insensitive-5.0.2.tgz#03d761b24afc04c09e757e92ff53716ae8ea2741"