mirror of https://github.com/Nofated095/Q2TG.git
feat: 新的好友发送消息时自动创建新的 tg 群组
This commit is contained in:
parent
334aa46375
commit
ffdfc90b96
|
@ -1,5 +1,5 @@
|
||||||
import { Client, LogLevel, Platform } from 'oicq';
|
import { Client, DiscussMessageEvent, GroupMessageEvent, LogLevel, Platform, PrivateMessageEvent } from 'oicq';
|
||||||
import * as Buffer from 'buffer';
|
import Buffer from 'buffer';
|
||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import random from '../utils/random';
|
import random from '../utils/random';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
|
@ -9,6 +9,8 @@ import { Config } from 'oicq/lib/client';
|
||||||
|
|
||||||
const LOG_LEVEL: LogLevel = 'warn';
|
const LOG_LEVEL: LogLevel = 'warn';
|
||||||
|
|
||||||
|
type MessageHandler = (event: PrivateMessageEvent | GroupMessageEvent) => Promise<boolean | void>
|
||||||
|
|
||||||
interface CreateOicqParams {
|
interface CreateOicqParams {
|
||||||
uin: number;
|
uin: number;
|
||||||
password: string;
|
password: string;
|
||||||
|
@ -23,6 +25,8 @@ interface CreateOicqParams {
|
||||||
|
|
||||||
// OicqExtended??
|
// OicqExtended??
|
||||||
export default class OicqClient extends Client {
|
export default class OicqClient extends Client {
|
||||||
|
private readonly onMessageHandlers: Array<MessageHandler> = [];
|
||||||
|
|
||||||
private constructor(uin: number, conf?: Config) {
|
private constructor(uin: number, conf?: Config) {
|
||||||
super(uin, conf);
|
super(uin, conf);
|
||||||
}
|
}
|
||||||
|
@ -59,7 +63,8 @@ export default class OicqClient extends Client {
|
||||||
.off('system.login.slider', loginSliderHandler)
|
.off('system.login.slider', loginSliderHandler)
|
||||||
.off('system.login.qrcode', loginQrCodeHandler)
|
.off('system.login.qrcode', loginQrCodeHandler)
|
||||||
.off('system.login.error', loginErrorHandler)
|
.off('system.login.error', loginErrorHandler)
|
||||||
.off('system.online', successLoginHandler);
|
.off('system.online', successLoginHandler)
|
||||||
|
.on('message', client.onMessage);
|
||||||
resolve(client);
|
resolve(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,8 +78,8 @@ export default class OicqClient extends Client {
|
||||||
board: 'raincandy',
|
board: 'raincandy',
|
||||||
brand: random.pick('GOOGLE', 'XIAOMI', 'HUAWEI', 'SAMSUNG', 'SONY'),
|
brand: random.pick('GOOGLE', 'XIAOMI', 'HUAWEI', 'SAMSUNG', 'SONY'),
|
||||||
model: 'raincandy',
|
model: 'raincandy',
|
||||||
wifi_ssid: random.pick('OpenWrt', `Redmi-${random.hex(4)}`,
|
wifi_ssid: random.pick('OpenWrt', `Redmi-${random.hex(4).toUpperCase()}`,
|
||||||
`MiWifi-${random.hex(4)}`, `TP-LINK-${random.hex(6)}`),
|
`MiWifi-${random.hex(4).toUpperCase()}`, `TP-LINK-${random.hex(6).toUpperCase()}`),
|
||||||
bootloader: random.pick('U-Boot', 'GRUB', 'gummiboot'),
|
bootloader: random.pick('U-Boot', 'GRUB', 'gummiboot'),
|
||||||
android_id: random.hex(16),
|
android_id: random.hex(16),
|
||||||
proc_version: `${execSync('uname -s').toString().replace('\n', '')} version ${execSync('uname -r').toString().replace('\n', '')}`,
|
proc_version: `${execSync('uname -s').toString().replace('\n', '')} version ${execSync('uname -r').toString().replace('\n', '')}`,
|
||||||
|
@ -90,7 +95,7 @@ export default class OicqClient extends Client {
|
||||||
const client = new this(params.uin, {
|
const client = new this(params.uin, {
|
||||||
platform: params.platform,
|
platform: params.platform,
|
||||||
data_dir: path.resolve('./data'),
|
data_dir: path.resolve('./data'),
|
||||||
log_level: 'warn',
|
log_level: LOG_LEVEL,
|
||||||
})
|
})
|
||||||
.on('system.login.device', loginDeviceHandler)
|
.on('system.login.device', loginDeviceHandler)
|
||||||
.on('system.login.slider', loginSliderHandler)
|
.on('system.login.slider', loginSliderHandler)
|
||||||
|
@ -101,6 +106,23 @@ export default class OicqClient extends Client {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private onMessage = async (event: PrivateMessageEvent | GroupMessageEvent | DiscussMessageEvent) => {
|
||||||
|
if (event.message_type === 'discuss') return;
|
||||||
|
for (const handler of this.onMessageHandlers) {
|
||||||
|
const res = await handler(event);
|
||||||
|
if (res) return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public addNewMessageEventHandler(handler: MessageHandler) {
|
||||||
|
this.onMessageHandlers.push(handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeNewMessageEventHandler(handler: MessageHandler) {
|
||||||
|
this.onMessageHandlers.includes(handler) &&
|
||||||
|
this.onMessageHandlers.splice(this.onMessageHandlers.indexOf(handler), 1);
|
||||||
|
}
|
||||||
|
|
||||||
public getChat(roomId: number) {
|
public getChat(roomId: number) {
|
||||||
if (roomId > 0) {
|
if (roomId > 0) {
|
||||||
return this.pickFriend(roomId);
|
return this.pickFriend(roomId);
|
||||||
|
|
|
@ -5,9 +5,11 @@ import ConfigService from '../services/ConfigService';
|
||||||
import { config } from '../providers/userConfig';
|
import { config } from '../providers/userConfig';
|
||||||
import regExps from '../constants/regExps';
|
import regExps from '../constants/regExps';
|
||||||
import forwardPairs from '../providers/forwardPairs';
|
import forwardPairs from '../providers/forwardPairs';
|
||||||
|
import { GroupMessageEvent, PrivateMessageEvent } from 'oicq';
|
||||||
|
|
||||||
export default class ConfigController {
|
export default class ConfigController {
|
||||||
private readonly configService: ConfigService;
|
private readonly configService: ConfigService;
|
||||||
|
private readonly createPrivateMessageGroupBlockList = new Map<number, Promise<void>>();
|
||||||
|
|
||||||
constructor(private readonly tgBot: Telegram,
|
constructor(private readonly tgBot: Telegram,
|
||||||
private readonly tgUser: Telegram,
|
private readonly tgUser: Telegram,
|
||||||
|
@ -15,6 +17,7 @@ export default class ConfigController {
|
||||||
this.configService = new ConfigService(tgBot, tgUser, oicq);
|
this.configService = new ConfigService(tgBot, tgUser, oicq);
|
||||||
tgBot.addNewMessageEventHandler(this.handleMessage);
|
tgBot.addNewMessageEventHandler(this.handleMessage);
|
||||||
tgBot.addNewServiceMessageEventHandler(this.handleServiceMessage);
|
tgBot.addNewServiceMessageEventHandler(this.handleServiceMessage);
|
||||||
|
oicq.addNewMessageEventHandler(this.handleQqMessage);
|
||||||
this.configService.configCommands();
|
this.configService.configCommands();
|
||||||
config.workMode === 'personal' && this.configService.setupFilter();
|
config.workMode === 'personal' && this.configService.setupFilter();
|
||||||
}
|
}
|
||||||
|
@ -69,4 +72,21 @@ export default class ConfigController {
|
||||||
pair.tg = await this.tgBot.getChat(message.action.channelId);
|
pair.tg = await this.tgBot.getChat(message.action.channelId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private handleQqMessage = async (message: GroupMessageEvent | PrivateMessageEvent) => {
|
||||||
|
if (message.message_type !== 'private') return false;
|
||||||
|
const pair = forwardPairs.find(message.friend);
|
||||||
|
if (pair) return false;
|
||||||
|
// 如果正在创建中,应该阻塞
|
||||||
|
let promise = this.createPrivateMessageGroupBlockList.get(message.from_id);
|
||||||
|
if (promise) {
|
||||||
|
await promise;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 有未创建转发群的新私聊消息时自动创建
|
||||||
|
promise = this.configService.createGroupAndLink(message.from_id, message.friend.remark || message.friend.nickname, true);
|
||||||
|
this.createPrivateMessageGroupBlockList.set(message.from_id, promise);
|
||||||
|
await promise;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Telegram from '../client/Telegram';
|
||||||
import OicqClient from '../client/OicqClient';
|
import OicqClient from '../client/OicqClient';
|
||||||
import ForwardService from '../services/ForwardService';
|
import ForwardService from '../services/ForwardService';
|
||||||
import forwardPairs from '../providers/forwardPairs';
|
import forwardPairs from '../providers/forwardPairs';
|
||||||
import { DiscussMessageEvent, Friend, Group, GroupMessageEvent, PrivateMessageEvent } from 'oicq';
|
import { Friend, Group, GroupMessageEvent, PrivateMessageEvent } from 'oicq';
|
||||||
import db from '../providers/db';
|
import db from '../providers/db';
|
||||||
import helper from '../helpers/forwardHelper';
|
import helper from '../helpers/forwardHelper';
|
||||||
import { Api } from 'telegram';
|
import { Api } from 'telegram';
|
||||||
|
@ -15,19 +15,18 @@ export default class ForwardController {
|
||||||
private readonly oicq: OicqClient) {
|
private readonly oicq: OicqClient) {
|
||||||
this.forwardService = new ForwardService(tgBot, oicq);
|
this.forwardService = new ForwardService(tgBot, oicq);
|
||||||
forwardPairs.init(oicq, tgBot)
|
forwardPairs.init(oicq, tgBot)
|
||||||
.then(() => oicq.on('message', this.onQqMessage))
|
.then(() => oicq.addNewMessageEventHandler(this.onQqMessage))
|
||||||
.then(() => tgBot.addNewMessageEventHandler(this.onTelegramMessage));
|
.then(() => tgBot.addNewMessageEventHandler(this.onTelegramMessage));
|
||||||
}
|
}
|
||||||
|
|
||||||
private onQqMessage = async (event: PrivateMessageEvent | GroupMessageEvent | DiscussMessageEvent) => {
|
private onQqMessage = async (event: PrivateMessageEvent | GroupMessageEvent) => {
|
||||||
let target: Friend | Group;
|
let target: Friend | Group;
|
||||||
if (event.message_type === 'private') {
|
if (event.message_type === 'private') {
|
||||||
target = event.friend;
|
target = event.friend;
|
||||||
}
|
}
|
||||||
else if (event.message_type === 'group') {
|
else {
|
||||||
target = event.group;
|
target = event.group;
|
||||||
}
|
}
|
||||||
else return;
|
|
||||||
const pair = forwardPairs.find(target);
|
const pair = forwardPairs.find(target);
|
||||||
if (!pair) return;
|
if (!pair) return;
|
||||||
const tgMessage = await this.forwardService.forwardFromQq(event, pair);
|
const tgMessage = await this.forwardService.forwardFromQq(event, pair);
|
||||||
|
|
|
@ -109,7 +109,7 @@ export default class ConfigService {
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
private async createGroupAndLink(roomId: number, title?: string) {
|
public async createGroupAndLink(roomId: number, title?: string, silent = false) {
|
||||||
this.log.info(`创建群组并关联:${roomId}`);
|
this.log.info(`创建群组并关联:${roomId}`);
|
||||||
const qEntity = this.oicq.getChat(roomId);
|
const qEntity = this.oicq.getChat(roomId);
|
||||||
if (!title) {
|
if (!title) {
|
||||||
|
@ -124,7 +124,7 @@ export default class ConfigService {
|
||||||
let isFinish = false;
|
let isFinish = false;
|
||||||
try {
|
try {
|
||||||
// 状态信息
|
// 状态信息
|
||||||
const status = await (await this.owner).sendMessage('正在创建 Telegram 群…');
|
const status = !silent && await (await this.owner).sendMessage('正在创建 Telegram 群…');
|
||||||
|
|
||||||
// 创建群聊,拿到的是 user 的 chat
|
// 创建群聊,拿到的是 user 的 chat
|
||||||
const chat = await this.tgUser.createChat({
|
const chat = await this.tgUser.createChat({
|
||||||
|
@ -133,12 +133,12 @@ export default class ConfigService {
|
||||||
});
|
});
|
||||||
|
|
||||||
// 设置管理员
|
// 设置管理员
|
||||||
await status.edit({ text: '正在设置管理员…' });
|
status && await status.edit({ text: '正在设置管理员…' });
|
||||||
await chat.editAdmin(this.tgBot.me.username, true);
|
await chat.editAdmin(this.tgBot.me.username, true);
|
||||||
const chatForBot = await this.tgBot.getChat(chat.id);
|
const chatForBot = await this.tgBot.getChat(chat.id);
|
||||||
|
|
||||||
// 添加到 Filter
|
// 添加到 Filter
|
||||||
await status.edit({ text: '正在将群添加到文件夹…' });
|
status && await status.edit({ text: '正在将群添加到文件夹…' });
|
||||||
this.filter.includePeers.push(utils.getInputPeer(chat));
|
this.filter.includePeers.push(utils.getInputPeer(chat));
|
||||||
await this.tgUser.updateDialogFilter({
|
await this.tgUser.updateDialogFilter({
|
||||||
id: this.filter.id,
|
id: this.filter.id,
|
||||||
|
@ -146,16 +146,16 @@ export default class ConfigService {
|
||||||
});
|
});
|
||||||
|
|
||||||
// 关闭【添加成员】快捷条
|
// 关闭【添加成员】快捷条
|
||||||
await status.edit({ text: '正在关闭【添加成员】快捷条…' });
|
status && await status.edit({ text: '正在关闭【添加成员】快捷条…' });
|
||||||
await chat.hidePeerSettingsBar();
|
await chat.hidePeerSettingsBar();
|
||||||
|
|
||||||
// 关联写入数据库
|
// 关联写入数据库
|
||||||
await status.edit({ text: '正在写数据库…' });
|
status && await status.edit({ text: '正在写数据库…' });
|
||||||
const dbPair = await forwardPairs.add(qEntity, chatForBot);
|
const dbPair = await forwardPairs.add(qEntity, chatForBot);
|
||||||
isFinish = true;
|
isFinish = true;
|
||||||
|
|
||||||
// 更新头像
|
// 更新头像
|
||||||
await status.edit({ text: '正在更新头像…' });
|
status && await status.edit({ text: '正在更新头像…' });
|
||||||
const avatar = await getAvatar(roomId);
|
const avatar = await getAvatar(roomId);
|
||||||
const avatarHash = md5B64(avatar);
|
const avatarHash = md5B64(avatar);
|
||||||
await chatForBot.setProfilePhoto(avatar);
|
await chatForBot.setProfilePhoto(avatar);
|
||||||
|
@ -164,16 +164,18 @@ export default class ConfigService {
|
||||||
});
|
});
|
||||||
|
|
||||||
// 更新关于文本
|
// 更新关于文本
|
||||||
await status.edit({ text: '正在更新关于文本…' });
|
status && await status.edit({ text: '正在更新关于文本…' });
|
||||||
await chatForBot.editAbout(await this.getAboutText(qEntity));
|
await chatForBot.editAbout(await this.getAboutText(qEntity));
|
||||||
|
|
||||||
// 完成
|
// 完成
|
||||||
await status.edit({ text: '正在获取链接…' });
|
if (status) {
|
||||||
const { link } = await chat.getInviteLink();
|
await status.edit({ text: '正在获取链接…' });
|
||||||
await status.edit({
|
const { link } = await chat.getInviteLink();
|
||||||
text: '创建完成!',
|
await status.edit({
|
||||||
buttons: Button.url('打开', link),
|
text: '创建完成!',
|
||||||
});
|
buttons: Button.url('打开', link),
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
this.log.error('创建群组并关联失败', e);
|
this.log.error('创建群组并关联失败', e);
|
||||||
|
|
Loading…
Reference in New Issue