Q2TG/src/helpers/forwardHelper.ts

170 lines
5.2 KiB
TypeScript

import { fetchFile } from '../utils/urls';
import { CustomFile } from 'telegram/client/uploads';
import { base64decode } from 'nodejs-base64';
import { getLogger } from 'log4js';
import { Entity } from 'telegram/define';
import { ForwardMessage } from 'oicq';
import { Api } from 'telegram';
const log = getLogger('ForwardHelper');
const htmlEscape = (text: string) =>
text.replace(/&/g, '&')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
export default {
async downloadToCustomFile(url: string, allowWebp = false, filename?: string) {
const { fileTypeFromBuffer } = await (Function('return import("file-type")')() as Promise<typeof import('file-type')>);
const file = await fetchFile(url);
if (filename) {
return new CustomFile(filename, file.length, '', file);
}
const type = await fileTypeFromBuffer(file);
if (allowWebp) {
return new CustomFile(`image.${type.ext}`, file.length, '', file);
}
else {
// 防止 webp 作为贴纸发送时丢失发送者信息
return new CustomFile(`image.${type.ext === 'webp' ? 'png' : type.ext}`, file.length, '', file);
}
},
hSize(size: number) {
const BYTE = 1024;
if (size < BYTE)
return size + 'B';
if (size < Math.pow(BYTE, 2))
return (size / BYTE).toFixed(1) + 'KB';
if (size < Math.pow(BYTE, 3))
return (size / Math.pow(BYTE, 2)).toFixed(1) + 'MB';
if (size < Math.pow(BYTE, 4))
return (size / Math.pow(BYTE, 3)).toFixed(1) + 'GB';
return (size / Math.pow(BYTE, 4)).toFixed(1) + 'TB';
},
htmlEscape,
processJson(json: string) {
const jsonObj = JSON.parse(json);
if (jsonObj.app === 'com.tencent.mannounce') {
try {
const title = base64decode(jsonObj.meta.mannounce.title);
const content = base64decode(jsonObj.meta.mannounce.text);
return title + '\n\n' + content;
}
catch (err) {
log.error('解析群公告时出错', err);
return '[群公告]';
}
}
let appurl: string;
const biliRegex = /(https?:\\?\/\\?\/b23\.tv\\?\/\w*)\??/;
const zhihuRegex = /(https?:\\?\/\\?\/\w*\.?zhihu\.com\\?\/[^?"=]*)\??/;
const biliRegex2 = /(https?:\\?\/\\?\/\w*\.?bilibili\.com\\?\/[^?"=]*)\??/;
const jsonLinkRegex = /{.*"app":"com.tencent.structmsg".*"jumpUrl":"(https?:\\?\/\\?\/[^",]*)".*}/;
const jsonAppLinkRegex = /"contentJumpUrl": ?"(https?:\\?\/\\?\/[^",]*)"/;
if (biliRegex.test(json))
appurl = json.match(biliRegex)[1].replace(/\\\//g, '/');
else if (biliRegex2.test(json))
appurl = json.match(biliRegex2)[1].replace(/\\\//g, '/');
else if (zhihuRegex.test(json))
appurl = json.match(zhihuRegex)[1].replace(/\\\//g, '/');
else if (jsonLinkRegex.test(json))
appurl = json.match(jsonLinkRegex)[1].replace(/\\\//g, '/');
else if (jsonAppLinkRegex.test(json))
appurl = json.match(jsonAppLinkRegex)[1].replace(/\\\//g, '/');
if (appurl) {
return appurl;
}
else {
// TODO 记录无法解析的 JSON
return '[JSON]';
}
},
processXml(xml: string):
{ type: 'forward', resId: string } | { type: 'text', text: string } | { type: 'image', md5: string } {
const urlRegex = /url="([^"]+)"/;
const md5ImageRegex = /image md5="([A-F\d]{32})"/;
let text: string;
if (urlRegex.test(xml))
text = xml.match(urlRegex)[1].replace(/\\\//g, '/');
if (xml.includes('action="viewMultiMsg"')) {
text = '[Forward multiple messages]';
const resIdRegex = /m_resid="([\w+=/]+)"/;
if (resIdRegex.test(xml)) {
const resId = xml.match(resIdRegex)![1];
return {
type: 'forward',
resId,
};
}
}
else if (text) {
text = text.replace(/&amp;/g, '&');
return {
type: 'text',
text,
};
}
else if (md5ImageRegex.test(xml)) {
const imgMd5 = xml.match(md5ImageRegex)![1];
return {
type: 'image',
md5: imgMd5,
};
}
else {
return {
type: 'text',
text: '[XML]',
};
}
},
getUserDisplayName(user: Entity) {
if (!user) {
return '未知';
}
if ('firstName' in user) {
return user.firstName +
(user.lastName ? ' ' + user.lastName : '');
}
else if ('title' in user) {
return user.title;
}
else if ('id' in user) {
return user.id.toString();
}
return '未知';
},
generateForwardBrief(messages: ForwardMessage[]) {
const count = messages.length;
// 取前四条
messages = messages.slice(0, 4);
let result = '<b>转发的消息记录</b>';
for (const message of messages) {
result += `\n<b>${message.nickname}: </b>` +
`${htmlEscape(message.raw_message.length > 10 ? message.raw_message.substring(0, 10) + '…' : message.raw_message)}`;
}
if (count > messages.length) {
result += `\n<b>共 ${count} 条消息记录</b>`;
}
return result;
},
getMessageDocumentId(message: Api.Message) {
if (message.document) {
return BigInt(message.document.id.toString());
}
if (message.file) {
const media = Reflect.get(message.file, 'media');
return BigInt(media.id.toString());
}
return null;
},
};