Merge branch 'clansty:rainbowcat' into rainbowcat

This commit is contained in:
谷風 天音 たにかぜ あまね 2024-02-03 22:49:13 +08:00 committed by GitHub
commit cd3e2e1f2c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 137 additions and 90 deletions

View File

@ -42,10 +42,10 @@
"nodejs-base64": "^2.0.0",
"prisma": "5.8.0",
"prompts": "^2.4.2",
"quote-api": "https://github.com/Clansty/quote-api/archive/37a0e48a434b94bb04c04c7d86d9f0d2295df869.tar.gz",
"quote-api": "https://github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz",
"sharp": "^0.33.2",
"silk-sdk": "^0.2.2",
"telegram": "^2.19.10",
"telegram": "https://github.com/clansty/gramjs/releases/download/2.19.10%2Brevert_media/telegram-2.19.10.tgz",
"tmp-promise": "^3.0.3",
"undici": "^6.4.0",
"zincsearch-node": "^2.1.0",

View File

@ -60,8 +60,8 @@ dependencies:
specifier: ^2.4.2
version: 2.4.2
quote-api:
specifier: https://github.com/Clansty/quote-api/archive/37a0e48a434b94bb04c04c7d86d9f0d2295df869.tar.gz
version: '@github.com/Clansty/quote-api/archive/37a0e48a434b94bb04c04c7d86d9f0d2295df869.tar.gz'
specifier: https://github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz
version: '@github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz'
sharp:
specifier: ^0.33.2
version: 0.33.2
@ -69,8 +69,8 @@ dependencies:
specifier: ^0.2.2
version: 0.2.2
telegram:
specifier: ^2.19.10
version: 2.19.10
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'
tmp-promise:
specifier: ^3.0.3
version: 3.0.3
@ -1243,7 +1243,7 @@ packages:
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.6.1
node-gyp-build: 4.8.0
dev: false
/buildcheck@0.0.6:
@ -2740,8 +2740,8 @@ packages:
whatwg-url: 5.0.0
dev: false
/node-gyp-build@4.6.1:
resolution: {integrity: sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==}
/node-gyp-build@4.8.0:
resolution: {integrity: sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==}
hasBin: true
requiresBuild: true
dev: false
@ -3457,30 +3457,6 @@ packages:
- supports-color
dev: false
/telegram@2.19.10:
resolution: {integrity: sha512-5Brrn+BcYSjDUmT1/9T4Nq2tYlR1/TreRvpim1UGeuwfnIgFOiTXwDwXBOy6hbn9yssvmtk/dQJU9pBColM7ag==}
dependencies:
'@cryptography/aes': 0.1.1
async-mutex: 0.3.2
big-integer: 1.6.52
buffer: 6.0.3
htmlparser2: 6.1.0
mime: 3.0.0
node-localstorage: 2.2.1
pako: 2.1.0
path-browserify: 1.0.1
real-cancellable-promise: 1.2.0
socks: 2.7.1
store2: 2.14.2
ts-custom-error: 3.3.1
websocket: 1.0.34
optionalDependencies:
bufferutil: 4.0.8
utf-8-validate: 5.0.10
transitivePeerDependencies:
- supports-color
dev: false
/timm@1.7.1:
resolution: {integrity: sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==}
dev: false
@ -3563,6 +3539,7 @@ packages:
/tslib@2.6.2:
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
requiresBuild: true
dev: false
/tsscmp@1.0.6:
@ -3681,7 +3658,7 @@ packages:
engines: {node: '>=6.14.2'}
requiresBuild: true
dependencies:
node-gyp-build: 4.6.1
node-gyp-build: 4.8.0
dev: false
/utif2@4.1.0:
@ -3895,10 +3872,10 @@ packages:
resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==}
dev: false
'@github.com/Clansty/quote-api/archive/37a0e48a434b94bb04c04c7d86d9f0d2295df869.tar.gz':
resolution: {tarball: https://github.com/Clansty/quote-api/archive/37a0e48a434b94bb04c04c7d86d9f0d2295df869.tar.gz}
'@github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz':
resolution: {tarball: https://github.com/Clansty/quote-api/archive/014b21138afbbe0e12c91b00561414b1e851fc0f.tar.gz}
name: quote-api
version: 0.12.2
version: 0.14.0
dependencies:
canvas: 2.11.2
dotenv: 7.0.0
@ -3925,3 +3902,29 @@ packages:
- supports-color
- utf-8-validate
dev: false
'@github.com/clansty/gramjs/releases/download/2.19.10%25252Brevert_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
dependencies:
'@cryptography/aes': 0.1.1
async-mutex: 0.3.2
big-integer: 1.6.52
buffer: 6.0.3
htmlparser2: 6.1.0
mime: 3.0.0
node-localstorage: 2.2.1
pako: 2.1.0
path-browserify: 1.0.1
real-cancellable-promise: 1.2.0
socks: 2.7.1
store2: 2.14.2
ts-custom-error: 3.3.1
websocket: 1.0.34
optionalDependencies:
bufferutil: 4.0.8
utf-8-validate: 5.0.10
transitivePeerDependencies:
- supports-color
dev: false

View File

@ -60,22 +60,23 @@ model QqBot {
}
model Message {
id Int @id @default(autoincrement())
qqRoomId BigInt @db.BigInt
qqSenderId BigInt @db.BigInt
time Int
brief String?
seq Int
rand BigInt @db.BigInt
pktnum Int
tgChatId BigInt @db.BigInt
tgMsgId Int
instanceId Int @default(0)
instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
tgFileId BigInt? @db.BigInt
tgMessageText String?
nick String? // /抱 的时候会用到
tgSenderId BigInt? @db.BigInt
id Int @id @default(autoincrement())
qqRoomId BigInt @db.BigInt
qqSenderId BigInt @db.BigInt
time Int
brief String?
seq Int
rand BigInt @db.BigInt
pktnum Int
tgChatId BigInt @db.BigInt
tgMsgId Int
instanceId Int @default(0)
instance Instance @relation(fields: [instanceId], references: [id], onDelete: Cascade)
tgFileId BigInt? @db.BigInt
tgMessageText String?
nick String? // /抱 的时候会用到
tgSenderId BigInt? @db.BigInt
richHeaderUsed Boolean @default(false)
@@index([qqRoomId, qqSenderId, seq, rand, pktnum, time, instanceId])
@@index([tgChatId, tgMsgId, instanceId])

View File

@ -7,4 +7,11 @@ export default {
index = index % arr.length;
return arr[index];
},
tgColor(index: number) {
// https://github.com/telegramdesktop/tdesktop/blob/7049929a59176a996c4257d5a09df08b04ac3b22/Telegram/SourceFiles/ui/chat/chat_style.cpp#L1043
// https://github.com/LyoSU/quote-api/blob/master/utils/quote-generate.js#L163
const arr = [...new Intl.Segmenter().segment('❤️🧡💜💚🩵💙🩷')].map(x => x.segment);
index = index % arr.length;
return arr[index];
},
};

View File

@ -6,6 +6,7 @@ enum flags {
NO_DELETE_MESSAGE = 1 << 4,
NO_AUTO_CREATE_PM = 1 << 5,
COLOR_EMOJI_PREFIX = 1 << 6,
RICH_HEADER = 1 << 7,
}
export default flags;

View File

@ -60,36 +60,32 @@ export default class ForwardController {
});
if (existed) return;
// 开始转发过程
let tgMessages: Api.Message | Api.Message[] = await this.forwardService.forwardFromQq(event, pair);
if (!tgMessages) return;
if (!Array.isArray(tgMessages)) {
tgMessages = [tgMessages];
}
for (const tgMessage of tgMessages) {
// 更新数据库
await db.message.create({
data: {
qqRoomId: pair.qqRoomId,
qqSenderId: event.sender.user_id,
time: event.time,
brief: event.raw_message,
seq: event.seq,
rand: event.rand,
pktnum: event.pktnum,
tgChatId: pair.tgId,
tgMsgId: tgMessage.id,
instanceId: this.instance.id,
tgMessageText: tgMessage.message,
tgFileId: forwardHelper.getMessageDocumentId(tgMessage),
nick: event.nickname,
tgSenderId: BigInt(this.tgBot.me.id.toString()),
},
});
await this.forwardService.addToZinc(pair.dbId, tgMessage.id, {
text: event.raw_message,
let { tgMessage, richHeaderUsed } = await this.forwardService.forwardFromQq(event, pair);
if (!tgMessage) return;
// 更新数据库
await db.message.create({
data: {
qqRoomId: pair.qqRoomId,
qqSenderId: event.sender.user_id,
time: event.time,
brief: event.raw_message,
seq: event.seq,
rand: event.rand,
pktnum: event.pktnum,
tgChatId: pair.tgId,
tgMsgId: tgMessage.id,
instanceId: this.instance.id,
tgMessageText: tgMessage.message,
tgFileId: forwardHelper.getMessageDocumentId(tgMessage),
nick: event.nickname,
});
}
tgSenderId: BigInt(this.tgBot.me.id.toString()),
richHeaderUsed,
},
});
await this.forwardService.addToZinc(pair.dbId, tgMessage.id, {
text: event.raw_message,
nick: event.nickname,
});
}
catch (e) {
this.log.error('处理 QQ 消息时遇到问题', e);

View File

@ -163,7 +163,7 @@ export default class {
title: message.nick,
photo: { url: getAvatarUrl(message.qqSenderId) },
};
if (message.qqRoomId > 0) {
if (message.qqRoomId > 0 || message.richHeaderUsed) {
quoteMessage.text = message.tgMessageText;
}
else if (message.tgMessageText.includes('\n')) {
@ -195,7 +195,7 @@ export default class {
photo = await convert.cachedBuffer(`${sender.photo.photoId.toString(16)}.jpg`, () => this.tgBot.downloadEntityPhoto(sender));
}
messageFrom = {
id: Number(message.tgSenderId),
id: sender.color || Number(message.tgSenderId),
name: message.nick,
title: message.nick,
username: sender.username,

View File

@ -44,6 +44,7 @@ import ReplyKeyboardHide = Api.ReplyKeyboardHide;
import env from '../models/env';
import { CustomFile } from 'telegram/client/uploads';
import flags from '../constants/flags';
import BigInteger from 'big-integer';
const NOT_CHAINABLE_ELEMENTS = ['flash', 'record', 'video', 'location', 'share', 'json', 'xml', 'poke'];
@ -331,7 +332,6 @@ export default class ForwardService {
}
}
message = message.trim();
message = messageHeader + (message && messageHeader ? '\n' : '') + message;
// 处理回复
if (event.source) {
@ -366,28 +366,66 @@ export default class ForwardService {
}
let richHeaderUsed = false;
// 发送消息
const messageToSend: SendMessageParams = {
forceDocument: forceDocument as any, // 恼
};
message && (messageToSend.message = message);
if (files.length === 1) {
messageToSend.file = files[0];
}
else if (files.length) {
messageToSend.file = files;
}
else if ((pair.flags | this.instance.flags) & flags.RICH_HEADER) {
// 没有文件时才能显示链接预览
richHeaderUsed = true;
const url = new URL('https://q2tg-header.clansty.workers.dev');
url.searchParams.set('name', sender);
url.searchParams.set('title', 'title' in event.sender ? event.sender.title : '');
url.searchParams.set('role', 'role' in event.sender ? event.sender.role : '');
url.searchParams.set('id', event.sender.user_id.toString());
// https://github.com/tdlib/td/blob/437c2d0c6e0ad104022d5ad86ddc8aedc41cb7a8/td/telegram/MessageContent.cpp#L2575
// https://github.com/tdlib/td/blob/437c2d0c6e0ad104022d5ad86ddc8aedc41cb7a8/td/generate/scheme/telegram_api.tl#L1841
// https://github.com/gram-js/gramjs/pull/633
messageToSend.file = new Api.InputMediaWebPage({
url: url.toString(),
forceSmallMedia: true,
optional: true,
});
messageToSend.linkPreview = { showAboveText: true };
}
if (!richHeaderUsed) {
message = messageHeader + (message && messageHeader ? '\n' : '') + message;
}
message && (messageToSend.message = message);
buttons.length && (messageToSend.buttons = _.chunk(buttons, 3));
replyTo && (messageToSend.replyTo = replyTo);
const tgMessage = await pair.tg.sendMessage(messageToSend);
let tgMessage: Api.Message;
try {
tgMessage = await pair.tg.sendMessage(messageToSend);
}
catch (e) {
if (richHeaderUsed) {
this.log.warn('Rich Header 发送错误', messageToSend.file, e);
delete messageToSend.file;
delete messageToSend.linkPreview;
message = messageHeader + (message && messageHeader ? '\n' : '') + message;
message && (messageToSend.message = message);
tgMessage = await pair.tg.sendMessage(messageToSend);
}
else throw e;
}
if (this.instance.workMode === 'personal' && event.message_type === 'group' && event.atall) {
await tgMessage.pin({ notify: false });
}
tempFiles.forEach(it => it.cleanup());
return tgMessage;
return { tgMessage, richHeaderUsed };
}
catch (e) {
this.log.error('从 QQ 到 TG 的消息转发失败', e);
@ -396,11 +434,12 @@ export default class ForwardService {
}
catch {
}
return null;
return {};
}
}
public async forwardFromTelegram(message: Api.Message, pair: Pair): Promise<Array<QQMessageSent>> {
// console.log(message);
try {
const tempFiles: FileResult[] = [];
let chain: Sendable = [];
@ -415,7 +454,7 @@ export default class ForwardService {
'') +
': \n';
if ((pair.flags | this.instance.flags) & flags.COLOR_EMOJI_PREFIX) {
messageHeader = emoji.color(message.senderId.toJSNumber()) + messageHeader;
messageHeader = emoji.tgColor((message.sender as Api.User)?.color || message.senderId.toJSNumber()) + messageHeader;
}
if (message.photo instanceof Api.Photo ||
// stickers 和以文件发送的图片都是这个