From e10e107a7421fa3ffb020a918a8cfc9e22ad01b7 Mon Sep 17 00:00:00 2001 From: Nanako <469449812@qq.com> Date: Mon, 9 Dec 2024 23:12:07 +0800 Subject: [PATCH] Init --- .editorconfig | 16 + .gitignore | 28 + .rcappsconfig | 19 + .vscode/extensions.json | 11 + PicSearcherApp.js | 233 ++++++ PicSearcherApp.ts | 367 +++++++++ app.json | 18 + favicon.png | Bin 0 -> 352 bytes package-lock.json | 1610 +++++++++++++++++++++++++++++++++++++++ package.json | 12 + tsconfig.json | 18 + tslint.json | 15 + 12 files changed, 2347 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 .rcappsconfig create mode 100644 .vscode/extensions.json create mode 100644 PicSearcherApp.js create mode 100644 PicSearcherApp.ts create mode 100644 app.json create mode 100644 favicon.png create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..a1166f2 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# EditorConfig is awesome: http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +indent_style = space +indent_size = 4 +charset = utf-8 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a461715 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# ignore modules pulled in from npm +node_modules/ + +# rc-apps package output +dist/ + +# JetBrains IDEs +out/ +.idea/ +.idea_modules/ + +# macOS +.DS_Store +.AppleDouble +.LSOverride +._* +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk diff --git a/.rcappsconfig b/.rcappsconfig new file mode 100644 index 0000000..bf8a0d6 --- /dev/null +++ b/.rcappsconfig @@ -0,0 +1,19 @@ +{ + "url": "http://192.168.1.104:3010", + "username": "Nanako", + "password": "Nasiko@90", + "ignoredFiles": [ + "**/README.md", + "**/package-lock.json", + "**/package.json", + "**/tslint.json", + "**/tsconfig.json", + "**/*.js", + "**/*.js.map", + "**/*.d.ts", + "**/*.spec.ts", + "**/*.test.ts", + "**/dist/**", + "**/.*" + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..b1e1592 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,11 @@ + { + "recommendations": [ + "EditorConfig.editorconfig", + "eamodio.gitlens", + "eg2.vscode-npm-script", + "wayou.vscode-todo-highlight", + "minhthai.vscode-todo-parser", + "ms-vscode.vscode-typescript-tslint-plugin", + "rbbit.typescript-hero" + ] +} diff --git a/PicSearcherApp.js b/PicSearcherApp.js new file mode 100644 index 0000000..15986f6 --- /dev/null +++ b/PicSearcherApp.js @@ -0,0 +1,233 @@ +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.PicSearcherApp = void 0; +exports.processMessageImages = processMessageImages; +exports.getFileBlob = getFileBlob; +const App_1 = require("@rocket.chat/apps-engine/definition/App"); +const defaultSauceNAOResponse = { + header: { + user_id: '', + account_type: '', + short_limit: '', + long_limit: '', + long_remaining: 0, + short_remaining: 0, + status: 0, + results_requested: 0, + index: {}, + search_depth: '', + minimum_similarity: 0, + query_image_display: '', + query_image: '', + results_returned: 0, + }, + results: [], +}; +let myLogger; +class PicSearcherApp extends App_1.App { + constructor(info, logger, accessors) { + super(info, logger, accessors); + this.rootUrl = ''; + myLogger = logger; + } + async initialize(configurationExtend, environmentRead) { + this.rootUrl = await environmentRead.getEnvironmentVariables().getValueByName('ROOT_URL'); + myLogger.log('rootUrl:', this.rootUrl); + return super.initialize(configurationExtend, environmentRead); + } + checkPostMessageSent(message, read, http) { + return Promise.resolve(true); + } + async executePostMessageSent(message, read, http, persistence, modify) { + const author = await read.getUserReader().getAppUser(); + if (!message.attachments || message.attachments.length <= 0) { + return Promise.resolve(); + } + myLogger.info('message.attachments:', message.attachments); + const imageBlobs = await processMessageImages(message, http, read); + const result = await searchImageOnSauceNAO(imageBlobs[0].blob, imageBlobs[0].suffix); + await sendSearchResults(modify, message.room, result, author); + } + async sendMessage(textMessage, room, author, modify) { + const messageBuilder = modify.getCreator().startMessage({ + text: textMessage, + }); + messageBuilder.setSender(author); + messageBuilder.setRoom(room); + return modify.getCreator().finish(messageBuilder); + } +} +exports.PicSearcherApp = PicSearcherApp; +async function processMessageImages(message, http, context) { + const blobs = []; + if (!message.attachments || message.attachments.length === 0) { + throw new Error('No attachments found in the message.'); + } + for (const attachment of message.attachments) { + if (attachment.imageUrl) { + try { + const fileId = attachment.imageUrl.split('/')[2]; + const r = { + blob: await getFileBlob(fileId, context), + suffix: attachment.imageUrl.split('.').pop() || '', + }; + blobs.push(r); + } + catch (error) { + throw new Error(`Error fetching image content: ${error.message}`); + } + } + } + return blobs; +} +async function getFileBlob(fileId, read) { + try { + const buffer = await read.getUploadReader().getBufferById(fileId); + return new Blob([buffer]); + } + catch (error) { + myLogger.error(`Error fetching file content: ${error.message}`); + } + return new Blob(); +} +async function searchImageOnSauceNAO(image, suffix) { + const formData = new FormData(); + formData.append('file', image, 'image.' + suffix); + try { + const response = await fetch('https://saucenao.com/search.php', { + method: 'POST', + body: formData, + }); + if (response.ok) { + const results = []; + const html = await response.text(); + myLogger.info('HTML:', html); + const resultBlocks = html.match(/