diff --git a/.gitignore b/.gitignore index 3b9e8df..2228367 100644 --- a/.gitignore +++ b/.gitignore @@ -728,7 +728,7 @@ Network Trash Folder Temporary Items .apdisk -data/ +data config.yaml build .yarn/* diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/package.json b/package.json index ef6ba03..23bb370 100644 --- a/package.json +++ b/package.json @@ -18,20 +18,20 @@ "@types/dockerode": "^3.3.23", "@types/fluent-ffmpeg": "^2.1.24", "@types/lodash": "^4.14.202", - "@types/node": "^20.11.5", + "@types/node": "^20.11.17", "@types/prompts": "^2.4.9", "tsx": "^4.7.0", "typescript": "^5.3.3" }, "dependencies": { - "@prisma/client": "5.8.0", - "axios": "^1.6.5", + "@prisma/client": "5.9.1", + "axios": "^1.6.7", "baidu-aip-sdk": "^4.16.15", "big-integer": "^1.6.52", "cli-progress": "^3.11.2", "date-and-time": "^3.1.1", "dockerode": "^4.0.2", - "dotenv": "^16.4.0", + "dotenv": "^16.4.1", "eviltransform": "^0.2.2", "file-type": "^19.0.0", "fluent-ffmpeg": "^2.1.2", @@ -40,7 +40,7 @@ "lodash": "^4.17.21", "log4js": "^6.6.1", "nodejs-base64": "^2.0.0", - "prisma": "5.8.0", + "prisma": "5.9.1", "prompts": "^2.4.2", "quote-api": "https://github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz", "sharp": "^0.33.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index eb5f141..4b3b0fa 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -6,11 +6,11 @@ settings: dependencies: '@prisma/client': - specifier: 5.8.0 - version: 5.8.0(prisma@5.8.0) + specifier: 5.9.1 + version: 5.9.1(prisma@5.9.1) axios: - specifier: ^1.6.5 - version: 1.6.5 + specifier: ^1.6.7 + version: 1.6.7 baidu-aip-sdk: specifier: ^4.16.15 version: 4.16.15 @@ -27,8 +27,8 @@ dependencies: specifier: ^4.0.2 version: 4.0.2 dotenv: - specifier: ^16.4.0 - version: 16.4.0 + specifier: ^16.4.1 + version: 16.4.1 eviltransform: specifier: ^0.2.2 version: 0.2.2 @@ -54,8 +54,8 @@ dependencies: specifier: ^2.0.0 version: 2.0.0 prisma: - specifier: 5.8.0 - version: 5.8.0 + specifier: 5.9.1 + version: 5.9.1 prompts: specifier: ^2.4.2 version: 2.4.2 @@ -70,7 +70,7 @@ dependencies: version: 0.2.2 telegram: specifier: https://github.com/clansty/gramjs/releases/download/2.19.10%2Brevert_media/telegram-2.19.10.tgz - version: '@github.com/clansty/gramjs/releases/download/2.19.10%25252Brevert_media/telegram-2.19.10.tgz' + version: '@github.com/clansty/gramjs/releases/download/2.19.10%25252525252Brevert_media/telegram-2.19.10.tgz' tmp-promise: specifier: ^3.0.3 version: 3.0.3 @@ -101,8 +101,8 @@ devDependencies: specifier: ^4.14.202 version: 4.14.202 '@types/node': - specifier: ^20.11.5 - version: 20.11.5 + specifier: ^20.11.17 + version: 20.11.17 '@types/prompts': specifier: ^2.4.9 version: 2.4.9 @@ -895,8 +895,8 @@ packages: - supports-color dev: false - /@prisma/client@5.8.0(prisma@5.8.0): - resolution: {integrity: sha512-QxO6C4MaA/ysTIbC+EcAH1aX/YkpymhXtO6zPdk+FvA7+59tNibIYpd+7koPdViLg2iKES4ojsxWNUGNJaEcbA==} + /@prisma/client@5.9.1(prisma@5.9.1): + resolution: {integrity: sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==} engines: {node: '>=16.13'} requiresBuild: true peerDependencies: @@ -905,39 +905,39 @@ packages: prisma: optional: true dependencies: - prisma: 5.8.0 + prisma: 5.9.1 dev: false - /@prisma/debug@5.8.0: - resolution: {integrity: sha512-ZqPpkvbovu/kQJ1bvy57NO4dw97fpQGcbQSCtsqlwSE1UNKJP75R3BKxdznk8ZPMY+GJdMRetWNv4oAvSbWn8Q==} + /@prisma/debug@5.9.1: + resolution: {integrity: sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==} dev: false - /@prisma/engines-version@5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848: - resolution: {integrity: sha512-cXcoVweYbnv8xRfkWq9oj8BECOdzHUazrSpYCa0ehp5TNz4l5Spa8jbq/VROCTzj3ZncH5D9Q2TmySYTOUeKlw==} + /@prisma/engines-version@5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64: + resolution: {integrity: sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==} dev: false - /@prisma/engines@5.8.0: - resolution: {integrity: sha512-Qhqm9WWLujNEC13AuZlUO14SQ15tNLe5puaz+tOk7UqINqJ3PtqMmuSuzomiw2diGVqZ+HYiSQzlR3+pPucVHA==} + /@prisma/engines@5.9.1: + resolution: {integrity: sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==} requiresBuild: true dependencies: - '@prisma/debug': 5.8.0 - '@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 - '@prisma/fetch-engine': 5.8.0 - '@prisma/get-platform': 5.8.0 + '@prisma/debug': 5.9.1 + '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64 + '@prisma/fetch-engine': 5.9.1 + '@prisma/get-platform': 5.9.1 dev: false - /@prisma/fetch-engine@5.8.0: - resolution: {integrity: sha512-1CAuE+JoYsPNggMEn6qk0zos06Uc9bYZBJ0VBPHD6R7REL05614koAbOCmn52IaYz3nobb7f25hqW6AY7rLkIw==} + /@prisma/fetch-engine@5.9.1: + resolution: {integrity: sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==} dependencies: - '@prisma/debug': 5.8.0 - '@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 - '@prisma/get-platform': 5.8.0 + '@prisma/debug': 5.9.1 + '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64 + '@prisma/get-platform': 5.9.1 dev: false - /@prisma/get-platform@5.8.0: - resolution: {integrity: sha512-Nk3rhTFZ1LYkFZJnpSvQcLPCaBWgJQfteHII6UEENOOkYlmP0k3FuswND54tzzEr4qs39wOdV9pbXKX9U2lv7A==} + /@prisma/get-platform@5.9.1: + resolution: {integrity: sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==} dependencies: - '@prisma/debug': 5.8.0 + '@prisma/debug': 5.9.1 dev: false /@tokenizer/token@0.3.0: @@ -952,7 +952,7 @@ packages: /@types/cli-progress@3.11.5: resolution: {integrity: sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==} dependencies: - '@types/node': 20.11.5 + '@types/node': 20.11.17 dev: true /@types/date-and-time@3.0.3: @@ -965,7 +965,7 @@ packages: /@types/docker-modem@3.0.6: resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} dependencies: - '@types/node': 20.11.5 + '@types/node': 20.11.17 '@types/ssh2': 1.11.18 dev: true @@ -973,13 +973,13 @@ packages: resolution: {integrity: sha512-Lz5J+NFgZS4cEVhquwjIGH4oQwlVn2h7LXD3boitujBnzOE5o7s9H8hchEjoDK2SlRsJTogdKnQeiJgPPKLIEw==} dependencies: '@types/docker-modem': 3.0.6 - '@types/node': 20.11.5 + '@types/node': 20.11.17 dev: true /@types/fluent-ffmpeg@2.1.24: resolution: {integrity: sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==} dependencies: - '@types/node': 20.11.5 + '@types/node': 20.11.17 dev: true /@types/lodash@4.14.202: @@ -996,8 +996,8 @@ packages: undici-types: 5.26.5 dev: true - /@types/node@20.11.5: - resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==} + /@types/node@20.11.17: + resolution: {integrity: sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==} dependencies: undici-types: 5.26.5 dev: true @@ -1005,7 +1005,7 @@ packages: /@types/prompts@2.4.9: resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} dependencies: - '@types/node': 20.11.5 + '@types/node': 20.11.17 kleur: 3.0.3 dev: true @@ -1139,8 +1139,8 @@ packages: resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} dev: false - /axios@1.6.5: - resolution: {integrity: sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==} + /axios@1.6.7: + resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} dependencies: follow-redirects: 1.15.4 form-data: 4.0.0 @@ -1652,8 +1652,8 @@ packages: domhandler: 4.3.1 dev: false - /dotenv@16.4.0: - resolution: {integrity: sha512-WvImr5kpN5NGNn7KaDjJnLTh5rDVLZiDf/YLA8T1ZEZEBZNEDOE+mnkS0PVjPax8ZxBP5zC5SLMB3/9VV5de9g==} + /dotenv@16.4.1: + resolution: {integrity: sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==} engines: {node: '>=12'} dev: false @@ -2185,7 +2185,7 @@ packages: resolution: {integrity: sha512-+Whg6gcxomNshRhij3vuEnjaO/8ODAzl3ZVda6KKwZtWTwuD23iX4pR57Kv7+VGw6Lp5fEGF6hjSxPHw9Rvqcg==} engines: {node: '>= v14'} dependencies: - axios: 1.6.5 + axios: 1.6.7 log4js: 6.9.1 long: 4.0.0 pngjs: 6.0.0 @@ -2908,13 +2908,13 @@ packages: engines: {node: '>=12.13.0'} dev: false - /prisma@5.8.0: - resolution: {integrity: sha512-hDKoEqPt2qEUTH5yGO3l27CBnPtwvte0CGMKrpCr9+/A919JghfqJ3qgCGgMbOwdkXUOzdho0RH9tyUF3UhpMw==} + /prisma@5.9.1: + resolution: {integrity: sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==} engines: {node: '>=16.13'} hasBin: true requiresBuild: true dependencies: - '@prisma/engines': 5.8.0 + '@prisma/engines': 5.9.1 dev: false /probe-image-size@7.2.3: @@ -3903,7 +3903,7 @@ packages: - utf-8-validate dev: false - '@github.com/clansty/gramjs/releases/download/2.19.10%25252Brevert_media/telegram-2.19.10.tgz': + '@github.com/clansty/gramjs/releases/download/2.19.10%25252525252Brevert_media/telegram-2.19.10.tgz': resolution: {tarball: https://github.com/clansty/gramjs/releases/download/2.19.10%2Brevert_media/telegram-2.19.10.tgz} name: telegram version: 2.19.10 diff --git a/src/client/TelegramChat.ts b/src/client/TelegramChat.ts index 90fd6a5..a9e6281 100644 --- a/src/client/TelegramChat.ts +++ b/src/client/TelegramChat.ts @@ -31,6 +31,11 @@ export default class TelegramChat { return await this.client.sendMessage(this.entity, params); } + public async getMessage(params: Parameters[1]) { + const messages = await this.client.getMessages(this.entity, params); + return messages[0]; + } + public async sendSelfDestructingPhoto(params: SendMessageParams, photo: CustomFile, ttlSeconds: number) { // @ts-ignore 定义不好好写的?你家 `FileLike` 明明可以是 `TypeInputMedia` params.file = new Api.InputMediaUploadedPhoto({ diff --git a/src/constants/flags.ts b/src/constants/flags.ts index 4d52af4..3b665cc 100644 --- a/src/constants/flags.ts +++ b/src/constants/flags.ts @@ -7,6 +7,8 @@ enum flags { NO_AUTO_CREATE_PM = 1 << 5, COLOR_EMOJI_PREFIX = 1 << 6, RICH_HEADER = 1 << 7, + NO_QUOTE_PIN = 1 << 8, + NO_FORWARD_OTHER_BOT = 1 << 9, } export default flags; diff --git a/src/controllers/ForwardController.ts b/src/controllers/ForwardController.ts index c176c6c..bfbb9b3 100644 --- a/src/controllers/ForwardController.ts +++ b/src/controllers/ForwardController.ts @@ -17,7 +17,6 @@ import { getAvatar } from '../utils/urls'; import { CustomFile } from 'telegram/client/uploads'; import forwardHelper from '../helpers/forwardHelper'; import helper from '../helpers/forwardHelper'; -import ZincSearch from 'zincsearch-node'; import flags from '../constants/flags'; export default class ForwardController { @@ -36,6 +35,7 @@ export default class ForwardController { oicq.on('notice.friend.poke', this.onQqPoke); oicq.on('notice.group.poke', this.onQqPoke); tgBot.addNewMessageEventHandler(this.onTelegramMessage); + tgUser.addNewMessageEventHandler(this.onTelegramUserMessage); tgBot.addEditedMessageEventHandler(this.onTelegramMessage); instance.workMode === 'group' && tgBot.addChannelParticipantEventHandler(this.onTelegramParticipant); } @@ -92,10 +92,17 @@ export default class ForwardController { } }; - private onTelegramMessage = async (message: Api.Message) => { + private onTelegramUserMessage = async (message: Api.Message) => { + if (!('bot' in message.sender) || !message.sender.bot) return; + const pair = this.instance.forwardPairs.find(message.chat); + if (!pair) return; + if ((pair.flags | this.instance.flags) & flags.NO_FORWARD_OTHER_BOT) return; + await this.onTelegramMessage(message, pair); + }; + + private onTelegramMessage = async (message: Api.Message, pair = this.instance.forwardPairs.find(message.chat)) => { try { if (message.senderId?.eq(this.instance.botMe.id)) return true; - const pair = this.instance.forwardPairs.find(message.chat); if (!pair) return false; if ((pair.flags | this.instance.flags) & flags.DISABLE_TG2Q) return; const qqMessagesSent = await this.forwardService.forwardFromTelegram(message, pair); diff --git a/src/controllers/QuotLyController.ts b/src/controllers/QuotLyController.ts index 5a5a836..99efbe6 100644 --- a/src/controllers/QuotLyController.ts +++ b/src/controllers/QuotLyController.ts @@ -2,7 +2,7 @@ import Instance from '../models/Instance'; import Telegram from '../client/Telegram'; import OicqClient from '../client/OicqClient'; import { getLogger, Logger } from 'log4js'; -import { GroupMessageEvent, PrivateMessageEvent } from 'icqq'; +import { Group, GroupMessageEvent, PrivateMessageEvent } from 'icqq'; import { Api } from 'telegram'; import quotly from 'quote-api/methods/generate.js'; import { CustomFile } from 'telegram/client/uploads'; @@ -13,6 +13,7 @@ import { getAvatarUrl } from '../utils/urls'; import convert from '../helpers/convert'; import { Pair } from '../models/Pair'; import env from '../models/env'; +import flags from '../constants/flags'; export default class { private readonly log: Logger; @@ -55,16 +56,14 @@ export default class { this.log.error('找不到 sourceMessage'); return true; } - setTimeout(async () => { - // 异步发送,为了让 /q 先到达 - try { - await this.sendQuote(pair, sourceMessage); - } - catch (e) { - this.log.error(e); - await event.reply(e.toString(), true); - } - }, 50); + if (!((pair.flags | this.instance.flags) & flags.NO_QUOTE_PIN)) { + this.pinMessageOnBothSide(pair, sourceMessage).then(); + } + // 异步发送,为了让 /q 先到达 + this.sendQuote(pair, sourceMessage).catch(async e => { + this.log.error(e); + await event.reply(e.toString(), true); + }); }; private onTelegramMessage = async (message: Api.Message) => { @@ -91,22 +90,39 @@ export default class { this.log.error('找不到 sourceMessage'); return true; } - setTimeout(async () => { - try { - await this.sendQuote(pair, sourceMessage); - } - catch (e) { - this.log.error(e); - await message.reply({ - message: e.toString(), - }); - } - }, 50); + if (!((pair.flags | this.instance.flags) & flags.NO_QUOTE_PIN)) { + this.pinMessageOnBothSide(pair, sourceMessage).then(); + } + // 异步发送,为了让 /q 先到达 + this.sendQuote(pair, sourceMessage).catch(async e => { + this.log.error(e); + await message.reply({ + message: e.toString(), + }); + }); // 个人模式下,/q 这条消息不转发到 QQ,怪话图只有自己可见 if (this.instance.workMode === 'personal') return true; }; + private async pinMessageOnBothSide(pair: Pair, sourceMessage: Awaited>) { + if (pair.qq instanceof Group) { + try { + await pair.qq.addEssence(sourceMessage.seq, Number(sourceMessage.rand)); + } + catch (e) { + this.log.warn('无法添加精华消息,群:', pair.qqRoomId, e); + } + } + try { + const tgMessage = await pair.tg.getMessage({ ids: sourceMessage.tgMsgId }); + await tgMessage.pin({ notify: false, pmOneSide: false }); + } + catch (e) { + this.log.warn('无法置顶消息,群:', pair.tgId, '消息 ID:', sourceMessage.tgMsgId, e); + } + } + private async genQuote(message: Message) { const GROUP_ANONYMOUS_BOT = 1087968824n; diff --git a/src/controllers/RequestController.ts b/src/controllers/RequestController.ts index 0084fad..e01c121 100644 --- a/src/controllers/RequestController.ts +++ b/src/controllers/RequestController.ts @@ -20,9 +20,10 @@ export default class RequestController { private handleRequest = async (event: FriendRequestEvent | GroupInviteEvent) => { this.log.info(`收到申请:${event.nickname} (${event.user_id})`); - const avatar = await getAvatar(event.user_id); + let avatar: Buffer; let messageText = ''; if (event.request_type === 'friend') { + avatar = await getAvatar(event.user_id); messageText = `收到好友申请\n` + `昵称:${event.nickname}\n` + `账号:${event.user_id}\n` + @@ -32,6 +33,7 @@ export default class RequestController { `附言:${event.comment}`; } else { + avatar = await getAvatar(-event.group_id); messageText = `收到加群邀请\n` + `邀请人:${event.nickname} (${event.user_id})\n` + `群名称:${event.group_name}\n` + diff --git a/src/models/ForwardPairs.ts b/src/models/ForwardPairs.ts index 706b0f2..06589e4 100644 --- a/src/models/ForwardPairs.ts +++ b/src/models/ForwardPairs.ts @@ -18,7 +18,7 @@ export default class ForwardPairs { } // 在 forwardController 创建时初始化 - private async init(oicq: OicqClient, tgBot: Telegram) { + private async init(oicq: OicqClient, tgBot: Telegram, tgUser: Telegram) { const dbValues = await db.forwardPair.findMany({ where: { instanceId: this.instanceId }, }); @@ -26,8 +26,9 @@ export default class ForwardPairs { try { const qq = oicq.getChat(Number(i.qqRoomId)); const tg = await tgBot.getChat(Number(i.tgChatId)); - if (qq && tg) { - this.pairs.push(new Pair(qq, tg, i.id, i.flags)); + const tgUserChat = await tgUser.getChat(Number(i.tgChatId)); + if (qq && tg && tgUserChat) { + this.pairs.push(new Pair(qq, tg, tgUserChat, i.id, i.flags)); } } catch (e) { @@ -36,13 +37,13 @@ export default class ForwardPairs { } } - public static async load(instanceId: number, oicq: OicqClient, tgBot: Telegram) { + public static async load(instanceId: number, oicq: OicqClient, tgBot: Telegram, tgUser: Telegram) { const instance = new this(instanceId); - await instance.init(oicq, tgBot); + await instance.init(oicq, tgBot, tgUser); return instance; } - public async add(qq: Friend | Group, tg: TelegramChat) { + public async add(qq: Friend | Group, tg: TelegramChat, tgUser: TelegramChat) { const dbEntry = await db.forwardPair.create({ data: { qqRoomId: qq instanceof Friend ? qq.user_id : -qq.group_id, @@ -50,7 +51,7 @@ export default class ForwardPairs { instanceId: this.instanceId, }, }); - this.pairs.push(new Pair(qq, tg, dbEntry.id, dbEntry.flags)); + this.pairs.push(new Pair(qq, tg, tgUser, dbEntry.id, dbEntry.flags)); return dbEntry; } diff --git a/src/models/Pair.ts b/src/models/Pair.ts index 47f1362..c6de07f 100644 --- a/src/models/Pair.ts +++ b/src/models/Pair.ts @@ -16,6 +16,7 @@ export class Pair { constructor( public readonly qq: Friend | Group, private _tg: TelegramChat, + public readonly tgUser: TelegramChat, public dbId: number, private _flags: number, ) { diff --git a/src/services/ConfigService.ts b/src/services/ConfigService.ts index efaaf14..fb8e6c6 100644 --- a/src/services/ConfigService.ts +++ b/src/services/ConfigService.ts @@ -199,7 +199,7 @@ export default class ConfigService { // 关联写入数据库 const chatForBot = await this.tgBot.getChat(chat.id); status && await status.edit({ text: '正在写数据库…' }); - const dbPair = await this.instance.forwardPairs.add(room, chatForBot); + const dbPair = await this.instance.forwardPairs.add(room, chatForBot, chat); isFinish = true; // 更新头像 @@ -252,7 +252,8 @@ export default class ConfigService { try { const qGroup = this.oicq.getChat(qqRoomId) as Group; const tgChat = await this.tgBot.getChat(tgChatId); - await this.instance.forwardPairs.add(qGroup, tgChat); + const tgUserChat = await this.tgUser.getChat(tgChatId); + await this.instance.forwardPairs.add(qGroup, tgChat, tgUserChat); await tgChat.sendMessage(`QQ群:${qGroup.name} (${qGroup.group_id})已与 ` + `Telegram 群 ${(tgChat.entity as Api.Channel).title} (${tgChatId})关联`); if (!(tgChat.entity instanceof Api.Channel)) { diff --git a/src/services/ForwardService.ts b/src/services/ForwardService.ts index f508c23..5317d78 100644 --- a/src/services/ForwardService.ts +++ b/src/services/ForwardService.ts @@ -377,7 +377,7 @@ export default class ForwardService { else if (files.length) { messageToSend.file = files; } - else if ((pair.flags | this.instance.flags) & flags.RICH_HEADER) { + else if (event.message_type === 'group' && (pair.flags | this.instance.flags) & flags.RICH_HEADER) { // 没有文件时才能显示链接预览 richHeaderUsed = true; const url = new URL('https://q2tg-header.clansty.workers.dev'); @@ -410,6 +410,7 @@ export default class ForwardService { } catch (e) { if (richHeaderUsed) { + richHeaderUsed = false; this.log.warn('Rich Header 发送错误', messageToSend.file, e); delete messageToSend.file; delete messageToSend.linkPreview; @@ -420,6 +421,23 @@ export default class ForwardService { else throw e; } + if (richHeaderUsed) { + // 测试 Web Preview 内容是否被正确获取 + setTimeout(async () => { + // Telegram Bot 账号无法获取 Web 预览内容,只能用 User 账号获取 + const userMessage = await pair.tgUser.getMessage({ + ids: tgMessage.id, + }); + if (['WebPage', 'WebPageNotModified'].includes((userMessage.media as Api.MessageMediaWebPage)?.webpage?.className)) + return; + // 没有正常获取的话,就加上原先的头部 + this.log.warn('Rich Header 回测错误', messageToSend.file); + await tgMessage.edit({ + text: messageHeader + (message && messageHeader ? '\n' : '') + message, + }); + }, 3000); + } + if (this.instance.workMode === 'personal' && event.message_type === 'group' && event.atall) { await tgMessage.pin({ notify: false }); }