mirror of https://github.com/Nofated095/Q2TG.git
feat: 支持翻页的群组选择器
This commit is contained in:
parent
10f4963131
commit
c6ba18123f
|
@ -6,8 +6,8 @@ generator client {
|
||||||
}
|
}
|
||||||
|
|
||||||
datasource db {
|
datasource db {
|
||||||
provider = "sqlite"
|
provider = "postgresql"
|
||||||
url = "file:../data/data.db"
|
url = env("DATABASE_URL")
|
||||||
}
|
}
|
||||||
|
|
||||||
model Message {
|
model Message {
|
||||||
|
|
|
@ -4,17 +4,22 @@ import { BotAuthParams, UserAuthParams } from 'telegram/client/auth';
|
||||||
import { NewMessage, NewMessageEvent } from 'telegram/events';
|
import { NewMessage, NewMessageEvent } from 'telegram/events';
|
||||||
import { EditedMessage, EditedMessageEvent } from 'telegram/events/EditedMessage';
|
import { EditedMessage, EditedMessageEvent } from 'telegram/events/EditedMessage';
|
||||||
import { DeletedMessage, DeletedMessageEvent } from 'telegram/events/DeletedMessage';
|
import { DeletedMessage, DeletedMessageEvent } from 'telegram/events/DeletedMessage';
|
||||||
import { Entity, EntityLike } from 'telegram/define';
|
import { ButtonLike, Entity, EntityLike } from 'telegram/define';
|
||||||
import { SendMessageParams } from 'telegram/client/messages';
|
import { SendMessageParams } from 'telegram/client/messages';
|
||||||
import { CustomFile } from 'telegram/client/uploads';
|
import { CustomFile } from 'telegram/client/uploads';
|
||||||
import WaitForMessageHelper from '../helpers/WaitForMessageHelper';
|
import WaitForMessageHelper from '../helpers/WaitForMessageHelper';
|
||||||
|
import createPaginatedInlineSelector from '../utils/paginatedInlineSelector';
|
||||||
|
import CallbackQueryHelper from '../helpers/CallbackQueryHelper';
|
||||||
|
import { CallbackQuery } from 'telegram/events/CallbackQuery';
|
||||||
|
|
||||||
type MessageHandler = (message: Api.Message) => Promise<boolean>;
|
type MessageHandler = (message: Api.Message) => Promise<boolean>;
|
||||||
|
|
||||||
export class Telegram {
|
export class Telegram {
|
||||||
private readonly client: TelegramClient;
|
private readonly client: TelegramClient;
|
||||||
private waitForMessageHelper: WaitForMessageHelper;
|
private waitForMessageHelper: WaitForMessageHelper;
|
||||||
|
private callbackQueryHelper: CallbackQueryHelper = new CallbackQueryHelper();
|
||||||
private readonly onMessageHandlers: Array<MessageHandler> = [];
|
private readonly onMessageHandlers: Array<MessageHandler> = [];
|
||||||
|
public me: Api.User;
|
||||||
|
|
||||||
private constructor(stringSession = '') {
|
private constructor(stringSession = '') {
|
||||||
this.client = new TelegramClient(
|
this.client = new TelegramClient(
|
||||||
|
@ -35,18 +40,25 @@ export class Telegram {
|
||||||
public static async create(startArgs: UserAuthParams | BotAuthParams, stringSession = '') {
|
public static async create(startArgs: UserAuthParams | BotAuthParams, stringSession = '') {
|
||||||
const bot = new this(stringSession);
|
const bot = new this(stringSession);
|
||||||
await bot.client.start(startArgs);
|
await bot.client.start(startArgs);
|
||||||
bot.client.setParseMode('html');
|
await bot.config();
|
||||||
bot.waitForMessageHelper = new WaitForMessageHelper(bot);
|
|
||||||
bot.client.addEventHandler(bot.onMessage, new NewMessage({}));
|
|
||||||
return bot;
|
return bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async connect(stringSession: string) {
|
public static async connect(stringSession: string) {
|
||||||
const bot = new this(stringSession);
|
const bot = new this(stringSession);
|
||||||
await bot.client.connect();
|
await bot.client.connect();
|
||||||
|
await bot.config();
|
||||||
return bot;
|
return bot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async config() {
|
||||||
|
this.client.setParseMode('html');
|
||||||
|
this.waitForMessageHelper = new WaitForMessageHelper(this);
|
||||||
|
this.client.addEventHandler(this.onMessage, new NewMessage({}));
|
||||||
|
this.client.addEventHandler(this.callbackQueryHelper.onCallbackQuery, new CallbackQuery());
|
||||||
|
this.me = await this.client.getMe() as Api.User;
|
||||||
|
}
|
||||||
|
|
||||||
private onMessage = async (event: NewMessageEvent) => {
|
private onMessage = async (event: NewMessageEvent) => {
|
||||||
// 能用的东西基本都在 message 里面,直接调用 event 里的会 undefined
|
// 能用的东西基本都在 message 里面,直接调用 event 里的会 undefined
|
||||||
for (const handler of this.onMessageHandlers) {
|
for (const handler of this.onMessageHandlers) {
|
||||||
|
@ -76,7 +88,7 @@ export class Telegram {
|
||||||
}
|
}
|
||||||
|
|
||||||
public async getChat(entity: EntityLike) {
|
public async getChat(entity: EntityLike) {
|
||||||
return new TelegramChat(this.client, await this.client.getEntity(entity), this.waitForMessageHelper);
|
return new TelegramChat(this, this.client, await this.client.getEntity(entity), this.waitForMessageHelper);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getStringSession() {
|
public getStringSession() {
|
||||||
|
@ -93,10 +105,15 @@ export class Telegram {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public registerCallback(cb: () => any) {
|
||||||
|
return this.callbackQueryHelper.registerCallback(cb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TelegramChat {
|
export class TelegramChat {
|
||||||
constructor(private readonly client: TelegramClient,
|
constructor(public readonly parent: Telegram,
|
||||||
|
private readonly client: TelegramClient,
|
||||||
private readonly entity: Entity,
|
private readonly entity: Entity,
|
||||||
private readonly waitForInputHelper: WaitForMessageHelper) {
|
private readonly waitForInputHelper: WaitForMessageHelper) {
|
||||||
}
|
}
|
||||||
|
@ -120,4 +137,12 @@ export class TelegramChat {
|
||||||
public async waitForInput() {
|
public async waitForInput() {
|
||||||
return this.waitForInputHelper.waitForMessage(this.entity.id);
|
return this.waitForInputHelper.waitForMessage(this.entity.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public cancelWait() {
|
||||||
|
this.waitForInputHelper.cancel(this.entity.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public createPaginatedInlineSelector(message: string, choices: ButtonLike[][]) {
|
||||||
|
return createPaginatedInlineSelector(this, message, choices);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import { Api } from 'telegram';
|
||||||
|
import { Telegram } from '../client/Telegram';
|
||||||
|
import { Client as OicqClient } from 'oicq';
|
||||||
|
import ConfigService from '../services/ConfigService';
|
||||||
|
import { config } from '../providers/userConfig';
|
||||||
|
|
||||||
|
export default class ConfigController {
|
||||||
|
private readonly configService: ConfigService;
|
||||||
|
|
||||||
|
constructor(private readonly tgBot: Telegram,
|
||||||
|
private readonly tgUser: Telegram,
|
||||||
|
private readonly oicq: OicqClient) {
|
||||||
|
this.configService = new ConfigService(tgBot, tgUser, oicq);
|
||||||
|
tgBot.addNewMessageEventHandler(this.handleMessage);
|
||||||
|
tgBot.setCommands([], new Api.BotCommandScopeUsers());
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleMessage = async (message: Api.Message) => {
|
||||||
|
if (!message.chat.id.eq(config.owner)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (message.message){
|
||||||
|
case '/add':
|
||||||
|
this.configService.add()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
|
@ -23,8 +23,8 @@ export default class SetupController {
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleMessage = async (message: Api.Message) => {
|
private handleMessage = async (message: Api.Message) => {
|
||||||
if (this.isInProgress) {
|
if (this.isInProgress || !message.isPrivate) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (message.text === '/setup') {
|
if (message.text === '/setup') {
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { CallbackQueryEvent } from 'telegram/events/CallbackQuery';
|
||||||
|
|
||||||
|
export default class CallbackQueryHelper {
|
||||||
|
private readonly queries: Array<() => any> = [];
|
||||||
|
|
||||||
|
public registerCallback(cb: () => any) {
|
||||||
|
const id = this.queries.push(cb) - 1;
|
||||||
|
const buf = Buffer.alloc(2);
|
||||||
|
buf.writeUInt16LE(id);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public onCallbackQuery = async (event: CallbackQueryEvent) => {
|
||||||
|
const id = event.query.data.readUint16LE();
|
||||||
|
if (this.queries[id]) {
|
||||||
|
this.queries[id]();
|
||||||
|
}
|
||||||
|
await event.answer();
|
||||||
|
};
|
||||||
|
}
|
10
src/index.ts
10
src/index.ts
|
@ -4,6 +4,7 @@ import { getLogger, configure } from 'log4js';
|
||||||
import SetupController from './controllers/SetupController';
|
import SetupController from './controllers/SetupController';
|
||||||
import { Client as OicqClient } from 'oicq';
|
import { Client as OicqClient } from 'oicq';
|
||||||
import createOicq from './client/oicq';
|
import createOicq from './client/oicq';
|
||||||
|
import ConfigController from './controllers/ConfigController';
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
configure({
|
configure({
|
||||||
|
@ -27,7 +28,12 @@ import createOicq from './client/oicq';
|
||||||
({ tgUser, oicq } = await setupController.waitForFinish());
|
({ tgUser, oicq } = await setupController.waitForFinish());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
config.userBotSession && (tgUser = await Telegram.connect(config.userBotSession));
|
if (config.userBotSession) {
|
||||||
|
log.debug('正在登录 TG UserBot');
|
||||||
|
tgUser = await Telegram.connect(config.userBotSession);
|
||||||
|
log.debug('TG UserBot 登录完成');
|
||||||
|
}
|
||||||
|
log.debug('正在登录 OICQ');
|
||||||
oicq = await createOicq({
|
oicq = await createOicq({
|
||||||
uin: config.qqUin,
|
uin: config.qqUin,
|
||||||
password: config.qqPassword,
|
password: config.qqPassword,
|
||||||
|
@ -36,5 +42,7 @@ import createOicq from './client/oicq';
|
||||||
onVerifySlider: () => null,
|
onVerifySlider: () => null,
|
||||||
onQrCode: () => null,
|
onQrCode: () => null,
|
||||||
});
|
});
|
||||||
|
log.debug('OICQ 登录完成');
|
||||||
}
|
}
|
||||||
|
new ConfigController(tgBot, tgUser, oicq);
|
||||||
})();
|
})();
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import { PrismaClient } from '@prisma/client';
|
||||||
|
|
||||||
|
const db = new PrismaClient();
|
||||||
|
|
||||||
|
export default db;
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { Telegram, TelegramChat } from '../client/Telegram';
|
||||||
|
import { Client as OicqClient } from 'oicq';
|
||||||
|
import { config } from '../providers/userConfig';
|
||||||
|
import { Button } from 'telegram/tl/custom/button';
|
||||||
|
|
||||||
|
export default class ConfigService {
|
||||||
|
private owner: TelegramChat;
|
||||||
|
|
||||||
|
constructor(private readonly tgBot: Telegram,
|
||||||
|
private readonly tgUser: Telegram,
|
||||||
|
private readonly oicq: OicqClient) {
|
||||||
|
tgBot.getChat(config.owner).then(e => this.owner = e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 开始添加转发群组流程
|
||||||
|
public async add() {
|
||||||
|
const qGroups = Array.from(this.oicq.gl).map(e => e[1]);
|
||||||
|
await this.owner.createPaginatedInlineSelector('选择 QQ 群组\n然后选择在 TG 中的群组',
|
||||||
|
qGroups.map(e => [Button.url(
|
||||||
|
`${e.group_name} (${e.group_id})`,
|
||||||
|
`https://t.me/${this.tgBot.me.username}?startgroup=${e.group_id}`,
|
||||||
|
)]));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
export default {
|
||||||
|
pagination<T>(arr: T[], pageSize: number, currentPage: number) {
|
||||||
|
const skipNum = currentPage * pageSize;
|
||||||
|
return (skipNum + pageSize >= arr.length) ? arr.slice(skipNum, arr.length) : arr.slice(skipNum, skipNum + pageSize);
|
||||||
|
},
|
||||||
|
};
|
|
@ -0,0 +1,37 @@
|
||||||
|
import { ButtonLike } from 'telegram/define';
|
||||||
|
import arrays from './arrays';
|
||||||
|
import { Button } from 'telegram/tl/custom/button';
|
||||||
|
import { TelegramChat } from '../client/Telegram';
|
||||||
|
import { Api } from 'telegram';
|
||||||
|
|
||||||
|
export default async function createPaginatedInlineSelector(chat: TelegramChat, message: string, choices: ButtonLike[][]) {
|
||||||
|
const PAGE_SIZE = 8;
|
||||||
|
let currentPage = 0;
|
||||||
|
const totalPages = Math.ceil(choices.length / PAGE_SIZE);
|
||||||
|
let sentMessage: Api.Message;
|
||||||
|
const getButtons = () => {
|
||||||
|
const buttons = arrays.pagination(choices, PAGE_SIZE, currentPage);
|
||||||
|
const paginateButtons: ButtonLike[] = [];
|
||||||
|
currentPage > 0 && paginateButtons.push(Button.inline('⏪ 上一页', chat.parent.registerCallback(() => {
|
||||||
|
currentPage = Math.max(0, currentPage - 1);
|
||||||
|
sentMessage.edit({
|
||||||
|
text: message + `\n\n第 ${currentPage + 1} 页,共 ${totalPages} 页`,
|
||||||
|
buttons: getButtons(),
|
||||||
|
});
|
||||||
|
})));
|
||||||
|
currentPage !== totalPages - 1 && paginateButtons.push(Button.inline('下一页 ⏩', chat.parent.registerCallback(() => {
|
||||||
|
currentPage = Math.min(totalPages - 1, currentPage + 1);
|
||||||
|
console.log(currentPage);
|
||||||
|
sentMessage.edit({
|
||||||
|
text: message + `\n\n第 ${currentPage + 1} 页,共 ${totalPages} 页`,
|
||||||
|
buttons: getButtons(),
|
||||||
|
});
|
||||||
|
})));
|
||||||
|
paginateButtons.length && buttons.push(paginateButtons);
|
||||||
|
return buttons;
|
||||||
|
};
|
||||||
|
sentMessage = await chat.sendMessage({
|
||||||
|
message: message + `\n\n第 ${currentPage + 1} 页,共 ${totalPages} 页`,
|
||||||
|
buttons: getButtons(),
|
||||||
|
});
|
||||||
|
}
|
Loading…
Reference in New Issue