Merge branch 'rainbowcat' of github.com:clansty/Q2TG into rainbowcat

This commit is contained in:
Nofated095 2024-02-17 07:58:08 +08:00
commit 7a3ddc4309
13 changed files with 148 additions and 90 deletions

2
.gitignore vendored
View File

@ -728,7 +728,7 @@ Network Trash Folder
Temporary Items Temporary Items
.apdisk .apdisk
data/ data
config.yaml config.yaml
build build
.yarn/* .yarn/*

View File

@ -0,0 +1,5 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
</state>
</component>

View File

@ -18,20 +18,20 @@
"@types/dockerode": "^3.3.23", "@types/dockerode": "^3.3.23",
"@types/fluent-ffmpeg": "^2.1.24", "@types/fluent-ffmpeg": "^2.1.24",
"@types/lodash": "^4.14.202", "@types/lodash": "^4.14.202",
"@types/node": "^20.11.5", "@types/node": "^20.11.17",
"@types/prompts": "^2.4.9", "@types/prompts": "^2.4.9",
"tsx": "^4.7.0", "tsx": "^4.7.0",
"typescript": "^5.3.3" "typescript": "^5.3.3"
}, },
"dependencies": { "dependencies": {
"@prisma/client": "5.8.0", "@prisma/client": "5.9.1",
"axios": "^1.6.5", "axios": "^1.6.7",
"baidu-aip-sdk": "^4.16.15", "baidu-aip-sdk": "^4.16.15",
"big-integer": "^1.6.52", "big-integer": "^1.6.52",
"cli-progress": "^3.11.2", "cli-progress": "^3.11.2",
"date-and-time": "^3.1.1", "date-and-time": "^3.1.1",
"dockerode": "^4.0.2", "dockerode": "^4.0.2",
"dotenv": "^16.4.0", "dotenv": "^16.4.1",
"eviltransform": "^0.2.2", "eviltransform": "^0.2.2",
"file-type": "^19.0.0", "file-type": "^19.0.0",
"fluent-ffmpeg": "^2.1.2", "fluent-ffmpeg": "^2.1.2",
@ -40,7 +40,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"log4js": "^6.6.1", "log4js": "^6.6.1",
"nodejs-base64": "^2.0.0", "nodejs-base64": "^2.0.0",
"prisma": "5.8.0", "prisma": "5.9.1",
"prompts": "^2.4.2", "prompts": "^2.4.2",
"quote-api": "https://github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz", "quote-api": "https://github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz",
"sharp": "^0.33.2", "sharp": "^0.33.2",

View File

@ -6,11 +6,11 @@ settings:
dependencies: dependencies:
'@prisma/client': '@prisma/client':
specifier: 5.8.0 specifier: 5.9.1
version: 5.8.0(prisma@5.8.0) version: 5.9.1(prisma@5.9.1)
axios: axios:
specifier: ^1.6.5 specifier: ^1.6.7
version: 1.6.5 version: 1.6.7
baidu-aip-sdk: baidu-aip-sdk:
specifier: ^4.16.15 specifier: ^4.16.15
version: 4.16.15 version: 4.16.15
@ -27,8 +27,8 @@ dependencies:
specifier: ^4.0.2 specifier: ^4.0.2
version: 4.0.2 version: 4.0.2
dotenv: dotenv:
specifier: ^16.4.0 specifier: ^16.4.1
version: 16.4.0 version: 16.4.1
eviltransform: eviltransform:
specifier: ^0.2.2 specifier: ^0.2.2
version: 0.2.2 version: 0.2.2
@ -54,8 +54,8 @@ dependencies:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.0.0 version: 2.0.0
prisma: prisma:
specifier: 5.8.0 specifier: 5.9.1
version: 5.8.0 version: 5.9.1
prompts: prompts:
specifier: ^2.4.2 specifier: ^2.4.2
version: 2.4.2 version: 2.4.2
@ -70,7 +70,7 @@ dependencies:
version: 0.2.2 version: 0.2.2
telegram: telegram:
specifier: https://github.com/clansty/gramjs/releases/download/2.19.10%2Brevert_media/telegram-2.19.10.tgz 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: tmp-promise:
specifier: ^3.0.3 specifier: ^3.0.3
version: 3.0.3 version: 3.0.3
@ -101,8 +101,8 @@ devDependencies:
specifier: ^4.14.202 specifier: ^4.14.202
version: 4.14.202 version: 4.14.202
'@types/node': '@types/node':
specifier: ^20.11.5 specifier: ^20.11.17
version: 20.11.5 version: 20.11.17
'@types/prompts': '@types/prompts':
specifier: ^2.4.9 specifier: ^2.4.9
version: 2.4.9 version: 2.4.9
@ -895,8 +895,8 @@ packages:
- supports-color - supports-color
dev: false dev: false
/@prisma/client@5.8.0(prisma@5.8.0): /@prisma/client@5.9.1(prisma@5.9.1):
resolution: {integrity: sha512-QxO6C4MaA/ysTIbC+EcAH1aX/YkpymhXtO6zPdk+FvA7+59tNibIYpd+7koPdViLg2iKES4ojsxWNUGNJaEcbA==} resolution: {integrity: sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ==}
engines: {node: '>=16.13'} engines: {node: '>=16.13'}
requiresBuild: true requiresBuild: true
peerDependencies: peerDependencies:
@ -905,39 +905,39 @@ packages:
prisma: prisma:
optional: true optional: true
dependencies: dependencies:
prisma: 5.8.0 prisma: 5.9.1
dev: false dev: false
/@prisma/debug@5.8.0: /@prisma/debug@5.9.1:
resolution: {integrity: sha512-ZqPpkvbovu/kQJ1bvy57NO4dw97fpQGcbQSCtsqlwSE1UNKJP75R3BKxdznk8ZPMY+GJdMRetWNv4oAvSbWn8Q==} resolution: {integrity: sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA==}
dev: false dev: false
/@prisma/engines-version@5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848: /@prisma/engines-version@5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64:
resolution: {integrity: sha512-cXcoVweYbnv8xRfkWq9oj8BECOdzHUazrSpYCa0ehp5TNz4l5Spa8jbq/VROCTzj3ZncH5D9Q2TmySYTOUeKlw==} resolution: {integrity: sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ==}
dev: false dev: false
/@prisma/engines@5.8.0: /@prisma/engines@5.9.1:
resolution: {integrity: sha512-Qhqm9WWLujNEC13AuZlUO14SQ15tNLe5puaz+tOk7UqINqJ3PtqMmuSuzomiw2diGVqZ+HYiSQzlR3+pPucVHA==} resolution: {integrity: sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ==}
requiresBuild: true requiresBuild: true
dependencies: dependencies:
'@prisma/debug': 5.8.0 '@prisma/debug': 5.9.1
'@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64
'@prisma/fetch-engine': 5.8.0 '@prisma/fetch-engine': 5.9.1
'@prisma/get-platform': 5.8.0 '@prisma/get-platform': 5.9.1
dev: false dev: false
/@prisma/fetch-engine@5.8.0: /@prisma/fetch-engine@5.9.1:
resolution: {integrity: sha512-1CAuE+JoYsPNggMEn6qk0zos06Uc9bYZBJ0VBPHD6R7REL05614koAbOCmn52IaYz3nobb7f25hqW6AY7rLkIw==} resolution: {integrity: sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA==}
dependencies: dependencies:
'@prisma/debug': 5.8.0 '@prisma/debug': 5.9.1
'@prisma/engines-version': 5.8.0-37.0a83d8541752d7582de2ebc1ece46519ce72a848 '@prisma/engines-version': 5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64
'@prisma/get-platform': 5.8.0 '@prisma/get-platform': 5.9.1
dev: false dev: false
/@prisma/get-platform@5.8.0: /@prisma/get-platform@5.9.1:
resolution: {integrity: sha512-Nk3rhTFZ1LYkFZJnpSvQcLPCaBWgJQfteHII6UEENOOkYlmP0k3FuswND54tzzEr4qs39wOdV9pbXKX9U2lv7A==} resolution: {integrity: sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg==}
dependencies: dependencies:
'@prisma/debug': 5.8.0 '@prisma/debug': 5.9.1
dev: false dev: false
/@tokenizer/token@0.3.0: /@tokenizer/token@0.3.0:
@ -952,7 +952,7 @@ packages:
/@types/cli-progress@3.11.5: /@types/cli-progress@3.11.5:
resolution: {integrity: sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==} resolution: {integrity: sha512-D4PbNRbviKyppS5ivBGyFO29POlySLmA2HyUFE4p5QGazAMM3CwkKWcvTl8gvElSuxRh6FPKL8XmidX873ou4g==}
dependencies: dependencies:
'@types/node': 20.11.5 '@types/node': 20.11.17
dev: true dev: true
/@types/date-and-time@3.0.3: /@types/date-and-time@3.0.3:
@ -965,7 +965,7 @@ packages:
/@types/docker-modem@3.0.6: /@types/docker-modem@3.0.6:
resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==} resolution: {integrity: sha512-yKpAGEuKRSS8wwx0joknWxsmLha78wNMe9R2S3UNsVOkZded8UqOrV8KoeDXoXsjndxwyF3eIhyClGbO1SEhEg==}
dependencies: dependencies:
'@types/node': 20.11.5 '@types/node': 20.11.17
'@types/ssh2': 1.11.18 '@types/ssh2': 1.11.18
dev: true dev: true
@ -973,13 +973,13 @@ packages:
resolution: {integrity: sha512-Lz5J+NFgZS4cEVhquwjIGH4oQwlVn2h7LXD3boitujBnzOE5o7s9H8hchEjoDK2SlRsJTogdKnQeiJgPPKLIEw==} resolution: {integrity: sha512-Lz5J+NFgZS4cEVhquwjIGH4oQwlVn2h7LXD3boitujBnzOE5o7s9H8hchEjoDK2SlRsJTogdKnQeiJgPPKLIEw==}
dependencies: dependencies:
'@types/docker-modem': 3.0.6 '@types/docker-modem': 3.0.6
'@types/node': 20.11.5 '@types/node': 20.11.17
dev: true dev: true
/@types/fluent-ffmpeg@2.1.24: /@types/fluent-ffmpeg@2.1.24:
resolution: {integrity: sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==} resolution: {integrity: sha512-g5oQO8Jgi2kFS3tTub7wLvfLztr1s8tdXmRd8PiL/hLMLzTIAyMR2sANkTggM/rdEDAg3d63nYRRVepwBiCw5A==}
dependencies: dependencies:
'@types/node': 20.11.5 '@types/node': 20.11.17
dev: true dev: true
/@types/lodash@4.14.202: /@types/lodash@4.14.202:
@ -996,8 +996,8 @@ packages:
undici-types: 5.26.5 undici-types: 5.26.5
dev: true dev: true
/@types/node@20.11.5: /@types/node@20.11.17:
resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==} resolution: {integrity: sha512-QmgQZGWu1Yw9TDyAP9ZzpFJKynYNeOvwMJmaxABfieQoVoiVOS6MN1WSpqpRcbeA5+RW82kraAVxCCJg+780Qw==}
dependencies: dependencies:
undici-types: 5.26.5 undici-types: 5.26.5
dev: true dev: true
@ -1005,7 +1005,7 @@ packages:
/@types/prompts@2.4.9: /@types/prompts@2.4.9:
resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==}
dependencies: dependencies:
'@types/node': 20.11.5 '@types/node': 20.11.17
kleur: 3.0.3 kleur: 3.0.3
dev: true dev: true
@ -1139,8 +1139,8 @@ packages:
resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==} resolution: {integrity: sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==}
dev: false dev: false
/axios@1.6.5: /axios@1.6.7:
resolution: {integrity: sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==} resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==}
dependencies: dependencies:
follow-redirects: 1.15.4 follow-redirects: 1.15.4
form-data: 4.0.0 form-data: 4.0.0
@ -1652,8 +1652,8 @@ packages:
domhandler: 4.3.1 domhandler: 4.3.1
dev: false dev: false
/dotenv@16.4.0: /dotenv@16.4.1:
resolution: {integrity: sha512-WvImr5kpN5NGNn7KaDjJnLTh5rDVLZiDf/YLA8T1ZEZEBZNEDOE+mnkS0PVjPax8ZxBP5zC5SLMB3/9VV5de9g==} resolution: {integrity: sha512-CjA3y+Dr3FyFDOAMnxZEGtnW9KBR2M0JvvUtXNW+dYJL5ROWxP9DUHCwgFqpMk0OXCc0ljhaNTr2w/kutYIcHQ==}
engines: {node: '>=12'} engines: {node: '>=12'}
dev: false dev: false
@ -2185,7 +2185,7 @@ packages:
resolution: {integrity: sha512-+Whg6gcxomNshRhij3vuEnjaO/8ODAzl3ZVda6KKwZtWTwuD23iX4pR57Kv7+VGw6Lp5fEGF6hjSxPHw9Rvqcg==} resolution: {integrity: sha512-+Whg6gcxomNshRhij3vuEnjaO/8ODAzl3ZVda6KKwZtWTwuD23iX4pR57Kv7+VGw6Lp5fEGF6hjSxPHw9Rvqcg==}
engines: {node: '>= v14'} engines: {node: '>= v14'}
dependencies: dependencies:
axios: 1.6.5 axios: 1.6.7
log4js: 6.9.1 log4js: 6.9.1
long: 4.0.0 long: 4.0.0
pngjs: 6.0.0 pngjs: 6.0.0
@ -2908,13 +2908,13 @@ packages:
engines: {node: '>=12.13.0'} engines: {node: '>=12.13.0'}
dev: false dev: false
/prisma@5.8.0: /prisma@5.9.1:
resolution: {integrity: sha512-hDKoEqPt2qEUTH5yGO3l27CBnPtwvte0CGMKrpCr9+/A919JghfqJ3qgCGgMbOwdkXUOzdho0RH9tyUF3UhpMw==} resolution: {integrity: sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ==}
engines: {node: '>=16.13'} engines: {node: '>=16.13'}
hasBin: true hasBin: true
requiresBuild: true requiresBuild: true
dependencies: dependencies:
'@prisma/engines': 5.8.0 '@prisma/engines': 5.9.1
dev: false dev: false
/probe-image-size@7.2.3: /probe-image-size@7.2.3:
@ -3903,7 +3903,7 @@ packages:
- utf-8-validate - utf-8-validate
dev: false 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} resolution: {tarball: https://github.com/clansty/gramjs/releases/download/2.19.10%2Brevert_media/telegram-2.19.10.tgz}
name: telegram name: telegram
version: 2.19.10 version: 2.19.10

View File

@ -31,6 +31,11 @@ export default class TelegramChat {
return await this.client.sendMessage(this.entity, params); return await this.client.sendMessage(this.entity, params);
} }
public async getMessage(params: Parameters<typeof this.client.getMessages>[1]) {
const messages = await this.client.getMessages(this.entity, params);
return messages[0];
}
public async sendSelfDestructingPhoto(params: SendMessageParams, photo: CustomFile, ttlSeconds: number) { public async sendSelfDestructingPhoto(params: SendMessageParams, photo: CustomFile, ttlSeconds: number) {
// @ts-ignore 定义不好好写的?你家 `FileLike` 明明可以是 `TypeInputMedia` // @ts-ignore 定义不好好写的?你家 `FileLike` 明明可以是 `TypeInputMedia`
params.file = new Api.InputMediaUploadedPhoto({ params.file = new Api.InputMediaUploadedPhoto({

View File

@ -7,6 +7,8 @@ enum flags {
NO_AUTO_CREATE_PM = 1 << 5, NO_AUTO_CREATE_PM = 1 << 5,
COLOR_EMOJI_PREFIX = 1 << 6, COLOR_EMOJI_PREFIX = 1 << 6,
RICH_HEADER = 1 << 7, RICH_HEADER = 1 << 7,
NO_QUOTE_PIN = 1 << 8,
NO_FORWARD_OTHER_BOT = 1 << 9,
} }
export default flags; export default flags;

View File

@ -17,7 +17,6 @@ import { getAvatar } from '../utils/urls';
import { CustomFile } from 'telegram/client/uploads'; import { CustomFile } from 'telegram/client/uploads';
import forwardHelper from '../helpers/forwardHelper'; import forwardHelper from '../helpers/forwardHelper';
import helper from '../helpers/forwardHelper'; import helper from '../helpers/forwardHelper';
import ZincSearch from 'zincsearch-node';
import flags from '../constants/flags'; import flags from '../constants/flags';
export default class ForwardController { export default class ForwardController {
@ -36,6 +35,7 @@ export default class ForwardController {
oicq.on('notice.friend.poke', this.onQqPoke); oicq.on('notice.friend.poke', this.onQqPoke);
oicq.on('notice.group.poke', this.onQqPoke); oicq.on('notice.group.poke', this.onQqPoke);
tgBot.addNewMessageEventHandler(this.onTelegramMessage); tgBot.addNewMessageEventHandler(this.onTelegramMessage);
tgUser.addNewMessageEventHandler(this.onTelegramUserMessage);
tgBot.addEditedMessageEventHandler(this.onTelegramMessage); tgBot.addEditedMessageEventHandler(this.onTelegramMessage);
instance.workMode === 'group' && tgBot.addChannelParticipantEventHandler(this.onTelegramParticipant); 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 { try {
if (message.senderId?.eq(this.instance.botMe.id)) return true; if (message.senderId?.eq(this.instance.botMe.id)) return true;
const pair = this.instance.forwardPairs.find(message.chat);
if (!pair) return false; if (!pair) return false;
if ((pair.flags | this.instance.flags) & flags.DISABLE_TG2Q) return; if ((pair.flags | this.instance.flags) & flags.DISABLE_TG2Q) return;
const qqMessagesSent = await this.forwardService.forwardFromTelegram(message, pair); const qqMessagesSent = await this.forwardService.forwardFromTelegram(message, pair);

View File

@ -2,7 +2,7 @@ import Instance from '../models/Instance';
import Telegram from '../client/Telegram'; import Telegram from '../client/Telegram';
import OicqClient from '../client/OicqClient'; import OicqClient from '../client/OicqClient';
import { getLogger, Logger } from 'log4js'; import { getLogger, Logger } from 'log4js';
import { GroupMessageEvent, PrivateMessageEvent } from 'icqq'; import { Group, GroupMessageEvent, PrivateMessageEvent } from 'icqq';
import { Api } from 'telegram'; import { Api } from 'telegram';
import quotly from 'quote-api/methods/generate.js'; import quotly from 'quote-api/methods/generate.js';
import { CustomFile } from 'telegram/client/uploads'; import { CustomFile } from 'telegram/client/uploads';
@ -13,6 +13,7 @@ import { getAvatarUrl } from '../utils/urls';
import convert from '../helpers/convert'; import convert from '../helpers/convert';
import { Pair } from '../models/Pair'; import { Pair } from '../models/Pair';
import env from '../models/env'; import env from '../models/env';
import flags from '../constants/flags';
export default class { export default class {
private readonly log: Logger; private readonly log: Logger;
@ -55,16 +56,14 @@ export default class {
this.log.error('找不到 sourceMessage'); this.log.error('找不到 sourceMessage');
return true; return true;
} }
setTimeout(async () => { if (!((pair.flags | this.instance.flags) & flags.NO_QUOTE_PIN)) {
// 异步发送,为了让 /q 先到达 this.pinMessageOnBothSide(pair, sourceMessage).then();
try { }
await this.sendQuote(pair, sourceMessage); // 异步发送,为了让 /q 先到达
} this.sendQuote(pair, sourceMessage).catch(async e => {
catch (e) { this.log.error(e);
this.log.error(e); await event.reply(e.toString(), true);
await event.reply(e.toString(), true); });
}
}, 50);
}; };
private onTelegramMessage = async (message: Api.Message) => { private onTelegramMessage = async (message: Api.Message) => {
@ -91,22 +90,39 @@ export default class {
this.log.error('找不到 sourceMessage'); this.log.error('找不到 sourceMessage');
return true; return true;
} }
setTimeout(async () => { if (!((pair.flags | this.instance.flags) & flags.NO_QUOTE_PIN)) {
try { this.pinMessageOnBothSide(pair, sourceMessage).then();
await this.sendQuote(pair, sourceMessage); }
} // 异步发送,为了让 /q 先到达
catch (e) { this.sendQuote(pair, sourceMessage).catch(async e => {
this.log.error(e); this.log.error(e);
await message.reply({ await message.reply({
message: e.toString(), message: e.toString(),
}); });
} });
}, 50);
// 个人模式下,/q 这条消息不转发到 QQ怪话图只有自己可见 // 个人模式下,/q 这条消息不转发到 QQ怪话图只有自己可见
if (this.instance.workMode === 'personal') return true; if (this.instance.workMode === 'personal') return true;
}; };
private async pinMessageOnBothSide(pair: Pair, sourceMessage: Awaited<ReturnType<typeof db.message.findFirst>>) {
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) { private async genQuote(message: Message) {
const GROUP_ANONYMOUS_BOT = 1087968824n; const GROUP_ANONYMOUS_BOT = 1087968824n;

View File

@ -20,9 +20,10 @@ export default class RequestController {
private handleRequest = async (event: FriendRequestEvent | GroupInviteEvent) => { private handleRequest = async (event: FriendRequestEvent | GroupInviteEvent) => {
this.log.info(`收到申请:${event.nickname} (${event.user_id})`); this.log.info(`收到申请:${event.nickname} (${event.user_id})`);
const avatar = await getAvatar(event.user_id); let avatar: Buffer;
let messageText = ''; let messageText = '';
if (event.request_type === 'friend') { if (event.request_type === 'friend') {
avatar = await getAvatar(event.user_id);
messageText = `收到好友申请\n` + messageText = `收到好友申请\n` +
`<b>昵称:</b>${event.nickname}\n` + `<b>昵称:</b>${event.nickname}\n` +
`<b>账号:</b><code>${event.user_id}</code>\n` + `<b>账号:</b><code>${event.user_id}</code>\n` +
@ -32,6 +33,7 @@ export default class RequestController {
`<b>附言:</b>${event.comment}`; `<b>附言:</b>${event.comment}`;
} }
else { else {
avatar = await getAvatar(-event.group_id);
messageText = `收到加群邀请\n` + messageText = `收到加群邀请\n` +
`<b>邀请人:</b>${event.nickname} (<code>${event.user_id}</code>)\n` + `<b>邀请人:</b>${event.nickname} (<code>${event.user_id}</code>)\n` +
`<b>群名称:</b>${event.group_name}\n` + `<b>群名称:</b>${event.group_name}\n` +

View File

@ -18,7 +18,7 @@ export default class ForwardPairs {
} }
// 在 forwardController 创建时初始化 // 在 forwardController 创建时初始化
private async init(oicq: OicqClient, tgBot: Telegram) { private async init(oicq: OicqClient, tgBot: Telegram, tgUser: Telegram) {
const dbValues = await db.forwardPair.findMany({ const dbValues = await db.forwardPair.findMany({
where: { instanceId: this.instanceId }, where: { instanceId: this.instanceId },
}); });
@ -26,8 +26,9 @@ export default class ForwardPairs {
try { try {
const qq = oicq.getChat(Number(i.qqRoomId)); const qq = oicq.getChat(Number(i.qqRoomId));
const tg = await tgBot.getChat(Number(i.tgChatId)); const tg = await tgBot.getChat(Number(i.tgChatId));
if (qq && tg) { const tgUserChat = await tgUser.getChat(Number(i.tgChatId));
this.pairs.push(new Pair(qq, tg, i.id, i.flags)); if (qq && tg && tgUserChat) {
this.pairs.push(new Pair(qq, tg, tgUserChat, i.id, i.flags));
} }
} }
catch (e) { 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); const instance = new this(instanceId);
await instance.init(oicq, tgBot); await instance.init(oicq, tgBot, tgUser);
return instance; 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({ const dbEntry = await db.forwardPair.create({
data: { data: {
qqRoomId: qq instanceof Friend ? qq.user_id : -qq.group_id, qqRoomId: qq instanceof Friend ? qq.user_id : -qq.group_id,
@ -50,7 +51,7 @@ export default class ForwardPairs {
instanceId: this.instanceId, 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; return dbEntry;
} }

View File

@ -16,6 +16,7 @@ export class Pair {
constructor( constructor(
public readonly qq: Friend | Group, public readonly qq: Friend | Group,
private _tg: TelegramChat, private _tg: TelegramChat,
public readonly tgUser: TelegramChat,
public dbId: number, public dbId: number,
private _flags: number, private _flags: number,
) { ) {

View File

@ -199,7 +199,7 @@ export default class ConfigService {
// 关联写入数据库 // 关联写入数据库
const chatForBot = await this.tgBot.getChat(chat.id); const chatForBot = await this.tgBot.getChat(chat.id);
status && await status.edit({ text: '正在写数据库…' }); 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; isFinish = true;
// 更新头像 // 更新头像
@ -252,7 +252,8 @@ export default class ConfigService {
try { try {
const qGroup = this.oicq.getChat(qqRoomId) as Group; const qGroup = this.oicq.getChat(qqRoomId) as Group;
const tgChat = await this.tgBot.getChat(tgChatId); 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} (<code>${qGroup.group_id}</code>)已与 ` + await tgChat.sendMessage(`QQ群${qGroup.name} (<code>${qGroup.group_id}</code>)已与 ` +
`Telegram 群 ${(tgChat.entity as Api.Channel).title} (<code>${tgChatId}</code>)关联`); `Telegram 群 ${(tgChat.entity as Api.Channel).title} (<code>${tgChatId}</code>)关联`);
if (!(tgChat.entity instanceof Api.Channel)) { if (!(tgChat.entity instanceof Api.Channel)) {

View File

@ -377,7 +377,7 @@ export default class ForwardService {
else if (files.length) { else if (files.length) {
messageToSend.file = files; 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; richHeaderUsed = true;
const url = new URL('https://q2tg-header.clansty.workers.dev'); const url = new URL('https://q2tg-header.clansty.workers.dev');
@ -410,6 +410,7 @@ export default class ForwardService {
} }
catch (e) { catch (e) {
if (richHeaderUsed) { if (richHeaderUsed) {
richHeaderUsed = false;
this.log.warn('Rich Header 发送错误', messageToSend.file, e); this.log.warn('Rich Header 发送错误', messageToSend.file, e);
delete messageToSend.file; delete messageToSend.file;
delete messageToSend.linkPreview; delete messageToSend.linkPreview;
@ -420,6 +421,23 @@ export default class ForwardService {
else throw e; 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) { if (this.instance.workMode === 'personal' && event.message_type === 'group' && event.atall) {
await tgMessage.pin({ notify: false }); await tgMessage.pin({ notify: false });
} }