2022-02-24 10:27:06 +00:00
|
|
|
|
import Telegram from '../client/Telegram';
|
2022-03-06 12:33:49 +00:00
|
|
|
|
import { Group, GroupMessageEvent, PrivateMessageEvent, Quotable, segment, Sendable } from 'oicq';
|
2022-02-24 10:27:06 +00:00
|
|
|
|
import { fetchFile, getBigFaceUrl, getImageUrlByMd5 } from '../utils/urls';
|
|
|
|
|
import { FileLike, MarkupLike } from 'telegram/define';
|
|
|
|
|
import { CustomFile } from 'telegram/client/uploads';
|
2022-03-07 10:14:45 +00:00
|
|
|
|
import { getLogger, Logger } from 'log4js';
|
2022-02-24 10:27:06 +00:00
|
|
|
|
import path from 'path';
|
|
|
|
|
import exts from '../constants/exts';
|
|
|
|
|
import helper from '../helpers/forwardHelper';
|
2022-03-07 08:36:13 +00:00
|
|
|
|
import db from '../models/db';
|
2022-02-24 10:27:06 +00:00
|
|
|
|
import { Button } from 'telegram/tl/custom/button';
|
|
|
|
|
import { SendMessageParams } from 'telegram/client/messages';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
import { Api } from 'telegram';
|
|
|
|
|
import { file as createTempFile, FileResult } from 'tmp-promise';
|
|
|
|
|
import fsP from 'fs/promises';
|
2022-03-01 06:49:57 +00:00
|
|
|
|
import eviltransform from 'eviltransform';
|
2022-03-06 12:26:48 +00:00
|
|
|
|
import silk from '../encoding/silk';
|
2022-03-02 10:29:14 +00:00
|
|
|
|
import fs from 'fs';
|
2022-03-06 12:26:48 +00:00
|
|
|
|
import tgsToGif from '../encoding/tgsToGif';
|
2022-03-07 06:14:57 +00:00
|
|
|
|
import axios from 'axios';
|
|
|
|
|
import { md5Hex } from '../utils/hashing';
|
2022-03-07 08:36:13 +00:00
|
|
|
|
import Instance from '../models/Instance';
|
2022-03-07 10:05:14 +00:00
|
|
|
|
import { Pair } from '../models/Pair';
|
2022-02-24 10:27:06 +00:00
|
|
|
|
|
|
|
|
|
// noinspection FallThroughInSwitchStatementJS
|
|
|
|
|
export default class ForwardService {
|
2022-03-07 10:14:45 +00:00
|
|
|
|
private readonly log: Logger;
|
2022-02-24 10:27:06 +00:00
|
|
|
|
|
2022-03-07 08:36:13 +00:00
|
|
|
|
constructor(private readonly instance: Instance,
|
2022-03-07 10:14:45 +00:00
|
|
|
|
private readonly tgBot: Telegram) {
|
|
|
|
|
this.log = getLogger(`ForwardService - ${instance.id}`);
|
2022-02-24 10:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public async forwardFromQq(event: PrivateMessageEvent | GroupMessageEvent, pair: Pair) {
|
|
|
|
|
try {
|
2022-03-02 07:38:52 +00:00
|
|
|
|
const tempFiles: FileResult[] = [];
|
2022-03-07 06:14:57 +00:00
|
|
|
|
let message = '', files: FileLike[] = [], button: MarkupLike, replyTo = 0, noEscape = false;
|
2022-02-24 10:27:06 +00:00
|
|
|
|
let messageHeader = '';
|
|
|
|
|
if (event.message_type === 'group') {
|
|
|
|
|
// 产生头部,这和工作模式没有关系
|
2022-03-02 13:51:59 +00:00
|
|
|
|
let sender = event.sender.card || event.sender.nickname;
|
2022-03-02 15:38:16 +00:00
|
|
|
|
if (event.anonymous) {
|
|
|
|
|
sender = `[${sender}]${event.anonymous.name}`;
|
2022-03-02 13:51:59 +00:00
|
|
|
|
}
|
2022-02-24 10:27:06 +00:00
|
|
|
|
messageHeader = `<b>${helper.htmlEscape(sender)}</b>: `;
|
|
|
|
|
}
|
|
|
|
|
for (const elem of event.message) {
|
|
|
|
|
let url: string;
|
|
|
|
|
switch (elem.type) {
|
|
|
|
|
case 'text': {
|
|
|
|
|
message += elem.text;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'at': {
|
|
|
|
|
if (event.source?.user_id === elem.qq)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'face':
|
|
|
|
|
case 'sface': {
|
|
|
|
|
message += `[${elem.text}]`;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'bface': {
|
|
|
|
|
const file = await fetchFile(getBigFaceUrl(elem.file));
|
|
|
|
|
files.push(new CustomFile('face.png', file.length, '', file));
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'video':
|
|
|
|
|
// 先获取 URL,要传给下面
|
|
|
|
|
url = await pair.qq.getVideoUrl(elem.fid, elem.md5);
|
|
|
|
|
case 'image':
|
|
|
|
|
if ('url' in elem)
|
|
|
|
|
url = elem.url;
|
|
|
|
|
try {
|
2022-03-06 12:33:49 +00:00
|
|
|
|
files.push(await helper.downloadToCustomFile(url, !(message || messageHeader)));
|
2022-02-24 10:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
this.log.error('下载媒体失败', e);
|
|
|
|
|
// 下载失败让 Telegram 服务器下载
|
|
|
|
|
files.push(url);
|
|
|
|
|
}
|
|
|
|
|
break;
|
2022-03-04 10:50:11 +00:00
|
|
|
|
case 'flash': {
|
2022-03-07 08:36:13 +00:00
|
|
|
|
message += `[闪照]\n${this.instance.workMode === 'group' ? '每人' : ''}只能查看一次`;
|
2022-03-04 10:50:11 +00:00
|
|
|
|
const dbEntry = await db.flashPhoto.create({
|
|
|
|
|
data: { photoMd5: (elem.file as string).substring(0, 32) },
|
|
|
|
|
});
|
|
|
|
|
button = Button.url('📸查看', `https://t.me/${this.tgBot.me.username}?start=flash-${dbEntry.id}`);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-02-24 10:27:06 +00:00
|
|
|
|
case 'file': {
|
|
|
|
|
const extName = path.extname(elem.name);
|
|
|
|
|
if (exts.images.includes(extName.toLowerCase())) {
|
|
|
|
|
// 是图片
|
|
|
|
|
const url = await pair.qq.getFileUrl(elem.fid);
|
|
|
|
|
try {
|
2022-03-06 12:33:49 +00:00
|
|
|
|
files.push(await helper.downloadToCustomFile(url, !(message || messageHeader)));
|
2022-02-24 10:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
this.log.error('下载媒体失败', e);
|
|
|
|
|
// 下载失败让 Telegram 服务器下载
|
|
|
|
|
files.push(url);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
message = `文件: ${elem.name}\n` +
|
|
|
|
|
`大小: ${helper.hSize(elem.size)}`;
|
|
|
|
|
const dbEntry = await db.file.create({
|
2022-03-02 13:06:15 +00:00
|
|
|
|
data: { fileId: elem.fid, roomId: pair.qqRoomId, info: message },
|
2022-02-24 10:27:06 +00:00
|
|
|
|
});
|
2022-03-04 09:47:28 +00:00
|
|
|
|
button = Button.url('⏬获取下载地址',
|
2022-02-24 10:27:06 +00:00
|
|
|
|
`https://t.me/${this.tgBot.me.username}?start=file-${dbEntry.id}`);
|
|
|
|
|
}
|
2022-03-02 07:38:52 +00:00
|
|
|
|
break;
|
2022-02-24 10:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
case 'record': {
|
2022-03-02 07:38:52 +00:00
|
|
|
|
const temp = await createTempFile({ postfix: '.ogg' });
|
|
|
|
|
tempFiles.push(temp);
|
|
|
|
|
await silk.decode(await fetchFile(elem.url), temp.path);
|
|
|
|
|
files.push(temp.path);
|
2022-02-24 10:27:06 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'share': {
|
|
|
|
|
message = elem.url;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'json': {
|
|
|
|
|
message = helper.processJson(elem.data);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'xml': {
|
|
|
|
|
const result = helper.processXml(elem.data);
|
|
|
|
|
switch (result.type) {
|
|
|
|
|
case 'text':
|
|
|
|
|
message = result.text;
|
|
|
|
|
break;
|
|
|
|
|
case 'image':
|
|
|
|
|
try {
|
|
|
|
|
files.push(await helper.downloadToCustomFile(getImageUrlByMd5(result.md5)));
|
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
this.log.error('下载媒体失败', e);
|
|
|
|
|
// 下载失败让 Telegram 服务器下载
|
|
|
|
|
files.push(getImageUrlByMd5(result.md5));
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case 'forward':
|
2022-03-07 06:14:57 +00:00
|
|
|
|
try {
|
|
|
|
|
const messages = await pair.qq.getForwardMsg(result.resId);
|
|
|
|
|
message = helper.generateForwardBrief(messages);
|
|
|
|
|
noEscape = true;
|
|
|
|
|
const hash = md5Hex(result.resId);
|
|
|
|
|
button = Button.url('📃查看', `${process.env.CRV_API}/?hash=${hash}`);
|
|
|
|
|
// 传到 Cloudflare
|
|
|
|
|
axios.post(`${process.env.CRV_API}/add`, {
|
|
|
|
|
auth: process.env.CRV_KEY,
|
|
|
|
|
key: hash,
|
|
|
|
|
data: messages,
|
|
|
|
|
})
|
|
|
|
|
.then(data => this.log.trace('上传消息记录到 Cloudflare', data.data))
|
|
|
|
|
.catch(e => this.log.error('上传消息记录到 Cloudflare 失败', e));
|
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
message = '[转发多条消息(无法获取)]';
|
|
|
|
|
}
|
2022-02-24 10:27:06 +00:00
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case 'rps':
|
|
|
|
|
case 'dice':
|
|
|
|
|
message = `[${elem.type === 'rps' ? '猜拳' : '骰子'}] ${elem.id}`;
|
|
|
|
|
break;
|
|
|
|
|
case 'poke':
|
|
|
|
|
message = `[戳一戳] ${elem.text}`;
|
|
|
|
|
break;
|
|
|
|
|
case 'location':
|
|
|
|
|
message = `[位置] ${elem.name}\n${elem.address}`;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-07 06:14:57 +00:00
|
|
|
|
!noEscape && (message = helper.htmlEscape(message.trim()));
|
2022-02-24 10:27:06 +00:00
|
|
|
|
message = messageHeader + (message && messageHeader ? '\n' : '') + message;
|
|
|
|
|
|
|
|
|
|
// 处理回复
|
|
|
|
|
if (event.source) {
|
|
|
|
|
try {
|
|
|
|
|
const quote = await db.message.findFirst({
|
|
|
|
|
where: {
|
2022-03-02 13:06:15 +00:00
|
|
|
|
qqRoomId: pair.qqRoomId,
|
2022-02-24 10:27:06 +00:00
|
|
|
|
seq: event.source.seq,
|
|
|
|
|
rand: event.source.rand,
|
2022-03-07 11:41:59 +00:00
|
|
|
|
instanceId: this.instance.id,
|
2022-02-24 10:27:06 +00:00
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (quote) {
|
|
|
|
|
replyTo = quote.tgMsgId;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
this.log.error('查找回复消息失败', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 发送消息
|
|
|
|
|
const messageToSend: SendMessageParams = {};
|
|
|
|
|
message && (messageToSend.message = message);
|
|
|
|
|
if (files.length === 1) {
|
|
|
|
|
messageToSend.file = files[0];
|
|
|
|
|
}
|
|
|
|
|
else if (files.length) {
|
|
|
|
|
messageToSend.file = files;
|
|
|
|
|
}
|
|
|
|
|
button && (messageToSend.buttons = button);
|
|
|
|
|
replyTo && (messageToSend.replyTo = replyTo);
|
|
|
|
|
|
2022-03-02 07:38:52 +00:00
|
|
|
|
const messageSent = await pair.tg.sendMessage(messageToSend);
|
|
|
|
|
tempFiles.forEach(it => it.cleanup());
|
|
|
|
|
return messageSent;
|
2022-02-24 10:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
2022-02-26 10:15:40 +00:00
|
|
|
|
this.log.error('从 QQ 到 TG 的消息转发失败', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async forwardFromTelegram(message: Api.Message, pair: Pair) {
|
|
|
|
|
try {
|
|
|
|
|
const tempFiles: FileResult[] = [];
|
|
|
|
|
const chain: Sendable = [];
|
2022-03-02 15:38:16 +00:00
|
|
|
|
// 这条消息在 tg 中被回复的时候显示的
|
|
|
|
|
let brief = '';
|
2022-03-07 08:36:13 +00:00
|
|
|
|
this.instance.workMode === 'group' && chain.push(helper.getUserDisplayName(message.sender) +
|
2022-02-26 10:15:40 +00:00
|
|
|
|
(message.forward ? ' Forwarded from ' + helper.getUserDisplayName(message.forward.chat || message.forward.sender) : '') +
|
|
|
|
|
': \n');
|
|
|
|
|
if (message.photo instanceof Api.Photo ||
|
|
|
|
|
// stickers 和以文件发送的图片都是这个
|
|
|
|
|
message.document?.mimeType?.startsWith('image/')) {
|
2022-03-02 10:29:14 +00:00
|
|
|
|
chain.push({
|
|
|
|
|
type: 'image',
|
|
|
|
|
file: await message.downloadMedia({}),
|
|
|
|
|
asface: !!message.sticker,
|
|
|
|
|
});
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[图片]';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
else if (message.video || message.videoNote || message.gif) {
|
|
|
|
|
const file = message.video || message.videoNote || message.gif;
|
|
|
|
|
if (file.size > 20 * 1024 * 1024) {
|
|
|
|
|
chain.push('[视频大于 20MB]');
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
const temp = await createTempFile();
|
|
|
|
|
tempFiles.push(temp);
|
|
|
|
|
await fsP.writeFile(temp.path, await message.downloadMedia({}));
|
|
|
|
|
chain.push(segment.video(temp.path));
|
|
|
|
|
}
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[视频]';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
2022-03-02 08:02:08 +00:00
|
|
|
|
else if (message.sticker) {
|
|
|
|
|
// 一定是 tgs
|
2022-03-02 10:29:14 +00:00
|
|
|
|
let gifPath: string;
|
|
|
|
|
const tempTgsPath = path.resolve(path.join('./data/cache/tgs', message.sticker.id.toString(16)));
|
|
|
|
|
// 先从缓存中找
|
|
|
|
|
if (fs.existsSync(tempTgsPath + '.gif')) {
|
|
|
|
|
gifPath = tempTgsPath + '.gif';
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
await fsP.mkdir('./data/cache/tgs', { recursive: true });
|
|
|
|
|
await fsP.writeFile(tempTgsPath, await message.downloadMedia({}));
|
|
|
|
|
await tgsToGif(tempTgsPath);
|
|
|
|
|
await fsP.rm(tempTgsPath);
|
|
|
|
|
gifPath = tempTgsPath + '.gif';
|
|
|
|
|
}
|
|
|
|
|
chain.push({
|
|
|
|
|
type: 'image',
|
|
|
|
|
file: gifPath,
|
|
|
|
|
asface: true,
|
|
|
|
|
});
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[贴纸]';
|
2022-03-02 08:02:08 +00:00
|
|
|
|
}
|
2022-02-26 10:15:40 +00:00
|
|
|
|
else if (message.voice) {
|
2022-03-02 07:38:52 +00:00
|
|
|
|
const temp = await createTempFile();
|
|
|
|
|
tempFiles.push(temp);
|
|
|
|
|
await fsP.writeFile(temp.path, await message.downloadMedia({}));
|
|
|
|
|
const bufSilk = await silk.encode(temp.path);
|
|
|
|
|
chain.push(segment.record(bufSilk));
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[语音]';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
else if (message.poll) {
|
|
|
|
|
const poll = message.poll.poll;
|
|
|
|
|
chain.push(`${poll.multipleChoice ? '多' : '单'}选投票:\n${poll.question}`);
|
|
|
|
|
chain.push(...poll.answers.map(answer => `\n - ${answer.text}`));
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[投票]';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
else if (message.contact) {
|
|
|
|
|
const contact = message.contact;
|
|
|
|
|
chain.push(`名片:\n` +
|
|
|
|
|
contact.firstName + (contact.lastName ? ' ' + contact.lastName : '') +
|
|
|
|
|
(contact.phoneNumber ? `\n电话:${contact.phoneNumber}` : ''));
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[名片]';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
2022-03-01 06:49:57 +00:00
|
|
|
|
else if (message.venue && message.venue.geo instanceof Api.GeoPoint) {
|
2022-02-26 10:15:40 +00:00
|
|
|
|
// 地标
|
2022-03-01 06:49:57 +00:00
|
|
|
|
const geo: { lat: number, lng: number } = eviltransform.wgs2gcj(message.venue.geo.lat, message.venue.geo.long);
|
|
|
|
|
chain.push(segment.location(geo.lat, geo.lng, `${message.venue.title} (${message.venue.address})`));
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += `[位置:${message.venue.title}]`;
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
2022-03-01 06:49:57 +00:00
|
|
|
|
else if (message.geo instanceof Api.GeoPoint) {
|
2022-02-26 10:15:40 +00:00
|
|
|
|
// 普通的位置,没有名字
|
2022-03-01 06:49:57 +00:00
|
|
|
|
const geo: { lat: number, lng: number } = eviltransform.wgs2gcj(message.geo.lat, message.geo.long);
|
|
|
|
|
chain.push(segment.location(geo.lat, geo.lng, '选中的位置'));
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[位置]';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
else if (message.media instanceof Api.MessageMediaDocument && message.media.document instanceof Api.Document) {
|
|
|
|
|
const file = message.media.document;
|
|
|
|
|
const fileNameAttribute =
|
|
|
|
|
file.attributes.find(attribute => attribute instanceof Api.DocumentAttributeFilename) as Api.DocumentAttributeFilename;
|
|
|
|
|
chain.push(`文件:${fileNameAttribute ? fileNameAttribute.fileName : ''}\n` +
|
|
|
|
|
`类型:${file.mimeType}\n` +
|
|
|
|
|
`大小:${file.size}`);
|
2022-03-02 08:02:08 +00:00
|
|
|
|
if (file.size <= 20 * 1024 * 1024 && pair.qq instanceof Group) {
|
|
|
|
|
chain.push('\n文件正在上传中…');
|
|
|
|
|
pair.qq.fs.upload(await message.downloadMedia({}), '/',
|
|
|
|
|
fileNameAttribute ? fileNameAttribute.fileName : 'file')
|
|
|
|
|
.catch(err => pair.qq.sendMsg(`上传失败:\n${err.message}`));
|
|
|
|
|
}
|
2022-03-02 15:38:16 +00:00
|
|
|
|
brief += '[文件]';
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-07 11:46:03 +00:00
|
|
|
|
if (message.message) {
|
|
|
|
|
chain.push(message.message);
|
|
|
|
|
brief += message.message;
|
|
|
|
|
}
|
2022-02-26 10:15:40 +00:00
|
|
|
|
|
|
|
|
|
// 处理回复
|
|
|
|
|
let source: Quotable;
|
|
|
|
|
if (message.replyToMsgId) {
|
|
|
|
|
try {
|
|
|
|
|
const quote = await db.message.findFirst({
|
|
|
|
|
where: {
|
|
|
|
|
tgChatId: Number(pair.tg.id),
|
|
|
|
|
tgMsgId: message.replyToMsgId,
|
2022-03-07 11:41:59 +00:00
|
|
|
|
instanceId: this.instance.id,
|
2022-02-26 10:15:40 +00:00
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
if (quote) {
|
|
|
|
|
source = {
|
2022-03-07 11:46:03 +00:00
|
|
|
|
message: quote.brief || ' ',
|
2022-02-26 10:15:40 +00:00
|
|
|
|
seq: quote.seq,
|
|
|
|
|
rand: quote.rand,
|
2022-03-02 13:23:00 +00:00
|
|
|
|
user_id: Number(quote.qqSenderId),
|
2022-02-26 10:15:40 +00:00
|
|
|
|
time: quote.time,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
this.log.error('查找回复消息失败', e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-02 07:38:52 +00:00
|
|
|
|
const qqMessage = await pair.qq.sendMsg(chain, source);
|
2022-02-26 10:15:40 +00:00
|
|
|
|
tempFiles.forEach(it => it.cleanup());
|
2022-03-02 15:38:16 +00:00
|
|
|
|
return {
|
|
|
|
|
...qqMessage,
|
|
|
|
|
brief,
|
|
|
|
|
};
|
2022-02-26 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
catch (e) {
|
|
|
|
|
this.log.error('从 TG 到 QQ 的消息转发失败', e);
|
2022-03-07 11:46:03 +00:00
|
|
|
|
await message.reply({
|
2022-03-02 08:02:08 +00:00
|
|
|
|
message: `转发失败:${e.message}\n${e}`,
|
|
|
|
|
});
|
2022-02-24 10:27:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|