diff --git a/package-lock.json b/package-lock.json index cc9ec66..c34b62b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "axios": "^1.5.0", "dotenv": "^16.3.1", "n-readlines": "^1.0.1", + "node-emoji": "^2.1.0", "reflect-metadata": "^0.1.13", "sqlite3": "^5.1.6", "typeorm": "^0.3.17", @@ -1405,6 +1406,17 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@sindresorhus/is": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-3.1.2.tgz", + "integrity": "sha512-JiX9vxoKMmu8Y3Zr2RVathBL1Cdu4Nt4MuNWemt1Nc06A0RAin9c5FArkhGsyMBWfCu4zj+9b+GxtjAnE4qqLQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, "node_modules/@sinonjs/commons": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", @@ -2498,8 +2510,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", - "dev": true, - "peer": true, "engines": { "node": ">=10" } @@ -3204,6 +3214,11 @@ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", "dev": true }, + "node_modules/emojilib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/emojilib/-/emojilib-2.4.0.tgz", + "integrity": "sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw==" + }, "node_modules/enabled": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", @@ -6317,6 +6332,17 @@ "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==" }, + "node_modules/node-emoji": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-2.1.0.tgz", + "integrity": "sha512-tcsBm9C6FmPN5Wo7OjFi9lgMyJjvkAeirmjR/ax8Ttfqy4N8PoFic26uqFTIgayHPNI5FH4ltUvfh9kHzwcK9A==", + "dependencies": { + "@sindresorhus/is": "^3.1.2", + "char-regex": "^1.0.2", + "emojilib": "^2.4.0", + "skin-tone": "^2.0.0" + } + }, "node_modules/node-fetch": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", @@ -7426,6 +7452,17 @@ "dev": true, "peer": true }, + "node_modules/skin-tone": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/skin-tone/-/skin-tone-2.0.0.tgz", + "integrity": "sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA==", + "dependencies": { + "unicode-emoji-modifier-base": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -8292,6 +8329,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/unicode-emoji-modifier-base": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz", + "integrity": "sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g==", + "engines": { + "node": ">=4" + } + }, "node_modules/unique-filename": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", diff --git a/package.json b/package.json index 6526bbb..4b1d870 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "axios": "^1.5.0", "dotenv": "^16.3.1", "n-readlines": "^1.0.1", + "node-emoji": "^2.1.0", "reflect-metadata": "^0.1.13", "sqlite3": "^5.1.6", "typeorm": "^0.3.17", diff --git a/src/handlers/messages.ts b/src/handlers/messages.ts index 0f2e867..1be5ede 100644 --- a/src/handlers/messages.ts +++ b/src/handlers/messages.ts @@ -1,4 +1,5 @@ import { AxiosError } from 'axios' +import * as emoji from 'node-emoji' import { Entity, entities } from '../Entities' import { IdMapping } from '../entity/IdMapping' import log from '../helpers/logger' @@ -106,43 +107,55 @@ export async function handleReactions( ): Promise { for (const [reaction, value] of Object.entries(reactions)) { // Lookup key/emoji - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const reactionKey = (reactionKeys as any)[reaction] - value.usernames.map(async (rcUsername: string) => { - // generate transaction id - const transactionId = Buffer.from( - [matrixMessageId, reaction, rcUsername].join('\0') - ).toString('base64') - // lookup user access token - const userMapping = await getUserMappingByName(rcUsername) - if (!userMapping) { - throw new Error(`Could not find user mapping for name: ${rcUsername}`) - } - if (!userMapping.accessToken) { - throw new Error( - `User mapping for name ${rcUsername} has no access token` - ) - } + const reactionKey: string = + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (reactionKeys as any)[reaction] || emoji.get(reaction.replaceAll(':', '')) + if (!reactionKey) { + log.warn( + `Could not find an emoji for ${reaction} for message ${matrixMessageId}, skipping` + ) + return + } + await Promise.all( + value.usernames.map(async (rcUsername: string) => { + // generate transaction id + const transactionId = Buffer.from( + [matrixMessageId, reaction, rcUsername].join('\0') + ).toString('base64') + // lookup user access token + const userMapping = await getUserMappingByName(rcUsername) + if (!userMapping) { + log.warn( + `Could not find user mapping for name: ${rcUsername}, skipping reaction ${reaction} for message ${matrixMessageId}` + ) + return + } + if (!userMapping.accessToken) { + throw new Error( + `User mapping for name ${rcUsername} has no access token` + ) + } - const userSessionOptions = formatUserSessionOptions( - userMapping.accessToken - ) - log.http( - `Adding reaction to message ${matrixMessageId} with symbol ${reactionKey} for user ${rcUsername}` - ) - // put reaction - await axios.put( - `/_matrix/client/v3/rooms/${matrixRoomId}/send/m.reaction/${transactionId}`, - { - 'm.relates_to': { - rel_type: 'm.annotation', - event_id: matrixMessageId, - key: reactionKey, + const userSessionOptions = formatUserSessionOptions( + userMapping.accessToken + ) + log.http( + `Adding reaction to message ${matrixMessageId} with symbol ${reactionKey} for user ${rcUsername}` + ) + // put reaction + await axios.put( + `/_matrix/client/v3/rooms/${matrixRoomId}/send/m.reaction/${transactionId}`, + { + 'm.relates_to': { + rel_type: 'm.annotation', + event_id: matrixMessageId, + key: reactionKey, + }, }, - }, - userSessionOptions - ) - }) + userSessionOptions + ) + }) + ) } }