diff options
author | bobzel <zzzman@gmail.com> | 2024-12-14 14:39:56 -0500 |
---|---|---|
committer | bobzel <zzzman@gmail.com> | 2024-12-14 14:39:56 -0500 |
commit | 4826ac1b3223376493ea22c0f23095bc0797cd9c (patch) | |
tree | eca3924148c9baedf8f2d0734627d45fe32d1354 | |
parent | 38b8c63d374415142acefcf6b6f736646f78de44 (diff) | |
parent | f7c7f5f77f1170a84a22eb8b337db7c37a52a5da (diff) |
Merge branch 'master' into eleanor-gptdraw
-rw-r--r-- | .env2 | 4 | ||||
-rw-r--r-- | package-lock.json | 29 | ||||
-rw-r--r-- | package.json | 4 | ||||
-rw-r--r-- | src/.DS_Store | bin | 10244 -> 10244 bytes | |||
-rw-r--r-- | src/client/views/nodes/ImageBox.tsx | 31 | ||||
-rw-r--r-- | src/server/ApiManagers/FireflyManager.ts | 6 | ||||
-rw-r--r-- | src/server/ApiManagers/UploadManager.ts | 13 | ||||
-rw-r--r-- | src/server/DashUploadUtils.ts | 41 |
8 files changed, 98 insertions, 30 deletions
@@ -0,0 +1,4 @@ + +export _CLIENT_FIREFLY_CLIENT_ID='62eb3cc56d8d47c88ff67103ded0003f' +export _CLIENT_FIREFLY_SECRET='p8e-4JxcVXG6izNEnf0ceEPO1zSZ7U13TMUQ' +export _CLIENT_FIREFLY_TOKEN='eyJhbGciOiJSUzI1NiIsIng1dSI6Imltc19uYTEta2V5LWF0LTEuY2VyIiwia2lkIjoiaW1zX25hMS1rZXktYXQtMSIsIml0dCI6ImF0In0.eyJpZCI6IjE3MzMyMzgwMjg3NDVfNDg0ODM3ZTAtMmU3Zi00NWFkLTkzZjEtZjM0NWRkNDM3MzAwX3VlMSIsIm9yZyI6IjVEOEUxREMzNjcyNTQ2MDIwQTQ5NUZGMEBBZG9iZU9yZyIsInR5cGUiOiJhY2Nlc3NfdG9rZW4iLCJjbGllbnRfaWQiOiI2MmViM2NjNTZkOGQ0N2M4OGZmNjcxMDNkZWQwMDAzZiIsInVzZXJfaWQiOiI2MzQ1MUQ5RTY3MjU1MEQ4MEE0OTVFQ0FAdGVjaGFjY3QuYWRvYmUuY29tIiwiYXMiOiJpbXMtbmExIiwiYWFfaWQiOiI2MzQ1MUQ5RTY3MjU1MEQ4MEE0OTVFQ0FAdGVjaGFjY3QuYWRvYmUuY29tIiwiY3RwIjozLCJtb2kiOiI3NDc2MDZiZCIsImV4cGlyZXNfaW4iOiI4NjQwMDAwMCIsInNjb3BlIjoiZmlyZWZseV9hcGksYWRkaXRpb25hbF9pbmZvLG9wZW5pZCxzZXNzaW9uLEFkb2JlSUQsZmZfYXBpcyxyZWFkX29yZ2FuaXphdGlvbnMiLCJjcmVhdGVkX2F0IjoiMTczMzIzODAyODc0NSJ9.O-HGx7ji_-RZJXmCnsPVzdTmJA4s_fA0Gj0s7z1FZ6MPtzdXa9MSYkMYdo4ImfiYZGf73SeJACEpfTdgyd7shG3qXBydeZV2exGQcN6eve88zXMBsc98aCi0mPz2eql4MomJk9xGXuk3ZuZmVAbsAVfwScPU_uyl75DZAq4_4e6lyXakEti9ACYnEl-7TQQeEgK6Mr4R8giUWvYVAdmSK4xOq67yjBToj6S-fv_s2dBRY58x_fMkORCrJnDLEnSdXS2LXHXAyM_Up9EaezIovlVhwz04BuwrH0vVOJN7uHgFOeWbjULaGGYy2Wzb1hPeRVd7VIRiw3sHavthTSJ3KA' diff --git a/package-lock.json b/package-lock.json index 8c2cf0694..46057f615 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,6 +100,7 @@ "depcheck": "^1.4.7", "dompurify": "^3.1.7", "dotenv": "^16.4.5", + "dropbox": "^10.34.0", "eslint-webpack-plugin": "^4.1.0", "exif": "^0.6.0", "exifr": "^7.1.3", @@ -128,7 +129,7 @@ "google-auth-library": "^9.4.1", "googleapis": "^144.0.0", "googlephotos": "^0.3.5", - "got": "^14.0.0", + "got": "^14.4.5", "howler": "^2.2.4", "html-to-image": "^1.11.11", "html-to-text": "^9.0.5", @@ -171,6 +172,7 @@ "npm": "^10.8.1", "openai": "^4.26.0", "p-limit": "^6.1.0", + "parse-multipart-data": "^1.5.0", "passport": "^0.7.0", "passport-google-oauth20": "^2.0.0", "passport-local": "^1.0.0", @@ -19700,6 +19702,20 @@ "resolved": "https://registry.npmjs.org/double-bits/-/double-bits-1.1.1.tgz", "integrity": "sha512-BCLEIBq0O/DWoA7BsCu/R+RP0ZXiowP8BhtJT3qeuuQEBpnS8LK/Wo6UTJQv6v8mK1fj8n90YziHLwGdM5whSg==" }, + "node_modules/dropbox": { + "version": "10.34.0", + "resolved": "https://registry.npmjs.org/dropbox/-/dropbox-10.34.0.tgz", + "integrity": "sha512-5jb5/XzU0fSnq36/hEpwT5/QIep7MgqKuxghEG44xCu7HruOAjPdOb3x0geXv5O/hd0nHpQpWO+r5MjYTpMvJg==", + "dependencies": { + "node-fetch": "^2.6.1" + }, + "engines": { + "node": ">=0.10.3" + }, + "peerDependencies": { + "@types/node-fetch": "^2.5.7" + } + }, "node_modules/dynamic-dedupe": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", @@ -22148,9 +22164,9 @@ } }, "node_modules/got": { - "version": "14.4.4", - "resolved": "https://registry.npmjs.org/got/-/got-14.4.4.tgz", - "integrity": "sha512-tqiF7eSgTBwQkxb1LxsEpva8TaMYVisbhplrFVmw9GQE3855Z+MH/mnsXLLOkDxR6hZJRFMj5VTAZ8lmTF8ZOA==", + "version": "14.4.5", + "resolved": "https://registry.npmjs.org/got/-/got-14.4.5.tgz", + "integrity": "sha512-sq+uET8TnNKRNnjEOPJzMcxeI0irT8BBNmf+GtZcJpmhYsQM1DSKmCROUjPWKsXZ5HzwD5Cf5/RV+QD9BSTxJg==", "dependencies": { "@sindresorhus/is": "^7.0.1", "@szmarczak/http-timer": "^5.0.1", @@ -30590,6 +30606,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/parse-multipart-data": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/parse-multipart-data/-/parse-multipart-data-1.5.0.tgz", + "integrity": "sha512-ck5zaMF0ydjGfejNMnlo5YU2oJ+pT+80Jb1y4ybanT27j+zbVP/jkYmCrUGsEln0Ox/hZmuvgy8Ra7AxbXP2Mw==" + }, "node_modules/parse-passwd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", diff --git a/package.json b/package.json index 7c2730245..7ca0c8b38 100644 --- a/package.json +++ b/package.json @@ -183,6 +183,7 @@ "depcheck": "^1.4.7", "dompurify": "^3.1.7", "dotenv": "^16.4.5", + "dropbox": "^10.34.0", "eslint-webpack-plugin": "^4.1.0", "exif": "^0.6.0", "exifr": "^7.1.3", @@ -211,7 +212,7 @@ "google-auth-library": "^9.4.1", "googleapis": "^144.0.0", "googlephotos": "^0.3.5", - "got": "^14.0.0", + "got": "^14.4.5", "howler": "^2.2.4", "html-to-image": "^1.11.11", "html-to-text": "^9.0.5", @@ -254,6 +255,7 @@ "npm": "^10.8.1", "openai": "^4.26.0", "p-limit": "^6.1.0", + "parse-multipart-data": "^1.5.0", "passport": "^0.7.0", "passport-google-oauth20": "^2.0.0", "passport-local": "^1.0.0", diff --git a/src/.DS_Store b/src/.DS_Store Binary files differindex 9b66f8d8e..1ef749033 100644 --- a/src/.DS_Store +++ b/src/.DS_Store diff --git a/src/client/views/nodes/ImageBox.tsx b/src/client/views/nodes/ImageBox.tsx index 4d35068ee..d847b7940 100644 --- a/src/client/views/nodes/ImageBox.tsx +++ b/src/client/views/nodes/ImageBox.tsx @@ -39,6 +39,8 @@ import { FieldView, FieldViewProps } from './FieldView'; import { FocusViewOptions } from './FocusViewOptions'; import './ImageBox.scss'; import { OpenWhere } from './OpenWhere'; +import { Upload } from '../../../server/SharedMediaTypes'; +import { ImageUtils } from '../../util/Import & Export/ImageUtils'; export class ImageEditorData { // eslint-disable-next-line no-use-before-define @@ -310,6 +312,35 @@ export class ImageBox extends ViewBoxAnnotatableComponent<FieldViewProps>() { funcs.push({ description: 'Rotate Clockwise 90', event: this.rotate, icon: 'redo-alt' }); funcs.push({ description: `Show ${this.layoutDoc._showFullRes ? 'Dynamic Res' : 'Full Res'}`, event: this.resolution, icon: 'expand' }); funcs.push({ description: 'Set Native Pixel Size', event: this.setNativeSize, icon: 'expand-arrows-alt' }); + funcs.push({ + description: 'GetImageText', + event: () => { + Networking.PostToServer('/queryFireflyImageText', { + file: (file => { + const ext = extname(file); + return file.replace(ext, (this._error ? '_o' : this._curSuffix) + ext); + })(ImageCast(this.Document[Doc.LayoutFieldKey(this.Document)])?.url.href), + }).then(text => alert(text)); + }, + icon: 'expand-arrows-alt', + }); + funcs.push({ + description: 'Expand Image', + event: () => { + Networking.PostToServer('/expandImage', { + prompt: 'sunny skies', + file: (file => { + const ext = extname(file); + return file.replace(ext, (this._error ? '_o' : this._curSuffix) + ext); + })(ImageCast(this.Document[Doc.LayoutFieldKey(this.Document)])?.url.href), + }).then((info: Upload.ImageInformation) => { + const img = Docs.Create.ImageDocument(info.accessPaths.agnostic.client, { title: 'expand:' + this.Document.title }); + DocUtils.assignImageInfo(info, img); + this._props.addDocTab(img, OpenWhere.addRight); + }); + }, + icon: 'expand-arrows-alt', + }); funcs.push({ description: 'Copy path', event: () => ClientUtils.CopyText(this.choosePath(field.url)), icon: 'copy' }); funcs.push({ description: 'Open Image Editor', diff --git a/src/server/ApiManagers/FireflyManager.ts b/src/server/ApiManagers/FireflyManager.ts index 4425aff43..73cf94206 100644 --- a/src/server/ApiManagers/FireflyManager.ts +++ b/src/server/ApiManagers/FireflyManager.ts @@ -1,4 +1,4 @@ -import { Dropbox, files } from 'dropbox'; +import { Dropbox } from 'dropbox'; import * as fs from 'fs'; import * as multipart from 'parse-multipart-data'; import * as path from 'path'; @@ -227,9 +227,9 @@ export default class FireflyManager extends ApiManager { const { prompt, imageBlob, strength = 0.5 } = req.body; const uploadId = imageBlob ? await this.uploadImageToFirefly(imageBlob) : null; this.askFireflyOld(prompt, uploadId, strength).then(fire => - DashUploadUtils.UploadImage(JSON.parse(fire).url).then(info => { + DashUploadUtils.UploadImage(JSON.parse(fire ?? '').url).then(info => { if (info instanceof Error) _invalid(res, info.message); - else _success(res, info.accessPaths.agnostic.client); + else _success(res, info); }) ); }, diff --git a/src/server/ApiManagers/UploadManager.ts b/src/server/ApiManagers/UploadManager.ts index 868373474..5a880901b 100644 --- a/src/server/ApiManagers/UploadManager.ts +++ b/src/server/ApiManagers/UploadManager.ts @@ -70,10 +70,16 @@ export default class UploadManager extends ApiManager { ]); } else { fileguids.split(';').map(guid => DashUploadUtils.uploadProgress.set(guid, `resampling images`)); + // original filenames with '.'s, such as a Macbook screenshot, can be a problem - their extension is not kept in formidable's newFilename. + // This makes sure that the extension is preserved in the newFilename. + const fixNewFilename = (f: formidable.File) => { + if (path.extname(f.originalFilename ?? '') !== path.extname(f.newFilename)) f.newFilename = f.newFilename + path.extname(f.originalFilename ?? ''); + return f; + }; const results = ( await Promise.all( Array.from(Object.keys(files)).map( - async key => (!files[key] ? undefined : DashUploadUtils.upload(files[key]![0] /* , key */)) // key is the guid used by the client to track upload progress. + async key => (!files[key] ? undefined : DashUploadUtils.upload(fixNewFilename(files[key][0]) /* , key */)) // key is the guid used by the client to track upload progress. ) ) ).filter(result => result && !(result.result instanceof Error)); @@ -147,13 +153,10 @@ export default class UploadManager extends ApiManager { if (doc.id) { doc.id = getId(doc.id); } - // eslint-disable-next-line no-restricted-syntax for (const key in doc.fields) { - // eslint-disable-next-line no-continue if (!Object.prototype.hasOwnProperty.call(doc.fields, key)) continue; const field = doc.fields[key]; - // eslint-disable-next-line no-continue if (field === undefined || field === null) continue; if (field.__type === 'Doc') { @@ -182,11 +185,9 @@ export default class UploadManager extends ApiManager { let docids: string[] = []; let linkids: string[] = []; try { - // eslint-disable-next-line no-restricted-syntax for (const name in files) { if (Object.prototype.hasOwnProperty.call(files, name)) { const f = files[name]; - // eslint-disable-next-line no-continue if (!f) continue; const path2 = f[0]; // what about the rest of the array? are we guaranteed only one value is set? const zip = new AdmZip(path2.filepath); diff --git a/src/server/DashUploadUtils.ts b/src/server/DashUploadUtils.ts index 351351ca5..a06fa3b6e 100644 --- a/src/server/DashUploadUtils.ts +++ b/src/server/DashUploadUtils.ts @@ -22,7 +22,6 @@ import { AzureManager } from './ApiManagers/AzureManager'; import { AcceptableMedia, Upload } from './SharedMediaTypes'; import { Directory, clientPathToFile, filesDirectory, pathToDirectory, publicDirectory, serverPathToFile } from './SocketData'; import { resolvedServerUrl } from './server_Initialization'; - import { Worker, isMainThread, parentPort } from 'worker_threads'; // Create an array to store worker threads @@ -55,7 +54,8 @@ if (isMainThread) { .then(img => sizes.forEach(({ width, suffix }) => img.resize({ w: width || img.bitmap.width }) - .write(InjectSize(outputPath, suffix) as `${string}.${string}`) + .write(InjectSize(outputPath, suffix) as `${string}.${string}`) + .catch(e => console.log("Jimp error:", e)) )) .catch(e => console.log('Error Jimp:', e)) .finally(() => unlinkSource && unlinkSync(imgSourcePath)); @@ -223,7 +223,6 @@ export namespace DashUploadUtils { const parseExifData = async (source: string) => { const image = await request.get(source, { encoding: null }); const { /* data, */ error } = await new Promise<{ data: ExifData; error: string | undefined }>(resolve => { - // eslint-disable-next-line no-new new ExifImage({ image }, (exifError, data) => { resolve({ data, error: exifError?.message }); }); @@ -302,7 +301,6 @@ export namespace DashUploadUtils { // Bundle up the information into an object return { source, - // eslint-disable-next-line radix contentSize: parseInt(headers[size]), contentType: headers[type], nativeWidth, @@ -345,15 +343,24 @@ export namespace DashUploadUtils { const outputPath = path.resolve(pathToDirectory(Directory.images), outputFileName); const sizes = imageResampleSizes(path.extname(outputFileName)); - const imgReadStream = new Duplex(); - imgReadStream.push(fs.readFileSync(imgSourcePath)); - imgReadStream.push(null); - await Promise.all( - sizes.map(({ suffix }) => - new Promise<unknown>(res => - imgReadStream.pipe(createWriteStream(writtenFiles[suffix] = InjectSize(outputPath, suffix))).on('close', res) - ) - )); // prettier-ignore + if (unlinkSource) { + const imgReadStream = new Duplex(); + imgReadStream.push(fs.readFileSync(imgSourcePath)); + imgReadStream.push(null); + await Promise.all( + sizes.map(({ suffix }) => + new Promise<unknown>(res => + imgReadStream.pipe(createWriteStream(writtenFiles[suffix] = InjectSize(outputPath, suffix))).on('close', res) + ) + )); // prettier-ignore + } else { + await Promise.all( + sizes.map(({ suffix }) => + new Promise<unknown>(res => + request.get(imgSourcePath).pipe(createWriteStream(writtenFiles[suffix] = InjectSize(outputPath, suffix))).on('close', res) + ) + )); // prettier-ignore + } workerResample(imgSourcePath, outputPath, SizeSuffix.Original, unlinkSource); return writtenFiles; @@ -370,7 +377,7 @@ export namespace DashUploadUtils { * @returns the accessPaths for the resized files. */ export const UploadInspectedImage = async (metadata: Upload.InspectionResults, filename: string, prefix = '', cleanUp = true): Promise<Upload.ImageInformation> => { - const { requestable, source, ...remaining } = metadata; + const { requestable, ...remaining } = metadata; const dfltSuffix = remaining.contentType.split('/')[1].toLowerCase(); const resolved = filename || `${prefix}upload_${Utils.GenerateGuid()}.${dfltSuffix === 'xml' ? 'jpg' : dfltSuffix}`; const { images } = Directory; @@ -452,7 +459,7 @@ export namespace DashUploadUtils { } const outputFile = filename || result.filename || ''; - return UploadInspectedImage(result, outputFile, prefix); + return UploadInspectedImage(result, outputFile, prefix, isLocal().exec(source) ? true : false); }; type md5 = 'md5'; @@ -570,7 +577,9 @@ export namespace DashUploadUtils { switch (category) { case 'image': if (imageFormats.includes(format)) { - const result = await UploadImage(filepath, basename(filepath)); + const outputName = basename(filepath); + const extname = path.extname(originalFilename ?? ''); + const result = await UploadImage(filepath, outputName.endsWith(extname) ? outputName : outputName + extname, undefined); return { source: file, result }; } fs.unlink(filepath, () => {}); |