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 {
|
||||
provider = "sqlite"
|
||||
url = "file:../data/data.db"
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model Message {
|
||||
|
|
|
@ -4,17 +4,22 @@ import { BotAuthParams, UserAuthParams } from 'telegram/client/auth';
|
|||
import { NewMessage, NewMessageEvent } from 'telegram/events';
|
||||
import { EditedMessage, EditedMessageEvent } from 'telegram/events/EditedMessage';
|
||||
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 { CustomFile } from 'telegram/client/uploads';
|
||||
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>;
|
||||
|
||||
export class Telegram {
|
||||
private readonly client: TelegramClient;
|
||||
private waitForMessageHelper: WaitForMessageHelper;
|
||||
private callbackQueryHelper: CallbackQueryHelper = new CallbackQueryHelper();
|
||||
private readonly onMessageHandlers: Array<MessageHandler> = [];
|
||||
public me: Api.User;
|
||||
|
||||
private constructor(stringSession = '') {
|
||||
this.client = new TelegramClient(
|
||||
|
@ -35,18 +40,25 @@ export class Telegram {
|
|||
public static async create(startArgs: UserAuthParams | BotAuthParams, stringSession = '') {
|
||||
const bot = new this(stringSession);
|
||||
await bot.client.start(startArgs);
|
||||
bot.client.setParseMode('html');
|
||||
bot.waitForMessageHelper = new WaitForMessageHelper(bot);
|
||||
bot.client.addEventHandler(bot.onMessage, new NewMessage({}));
|
||||
await bot.config();
|
||||
return bot;
|
||||
}
|
||||
|
||||
public static async connect(stringSession: string) {
|
||||
const bot = new this(stringSession);
|
||||
await bot.client.connect();
|
||||
await bot.config();
|
||||
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) => {
|
||||
// 能用的东西基本都在 message 里面,直接调用 event 里的会 undefined
|
||||
for (const handler of this.onMessageHandlers) {
|
||||
|
@ -76,7 +88,7 @@ export class Telegram {
|
|||
}
|
||||
|
||||
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() {
|
||||
|
@ -93,10 +105,15 @@ export class Telegram {
|
|||
}),
|
||||
);
|
||||
}
|
||||
|
||||
public registerCallback(cb: () => any) {
|
||||
return this.callbackQueryHelper.registerCallback(cb);
|
||||
}
|
||||
}
|
||||
|
||||
export class TelegramChat {
|
||||
constructor(private readonly client: TelegramClient,
|
||||
constructor(public readonly parent: Telegram,
|
||||
private readonly client: TelegramClient,
|
||||
private readonly entity: Entity,
|
||||
private readonly waitForInputHelper: WaitForMessageHelper) {
|
||||
}
|
||||
|
@ -120,4 +137,12 @@ export class TelegramChat {
|
|||
public async waitForInput() {
|
||||
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) => {
|
||||
if (this.isInProgress) {
|
||||
return true;
|
||||
if (this.isInProgress || !message.isPrivate) {
|
||||
return false;
|
||||
}
|
||||
|
||||
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 { Client as OicqClient } from 'oicq';
|
||||
import createOicq from './client/oicq';
|
||||
import ConfigController from './controllers/ConfigController';
|
||||
|
||||
(async () => {
|
||||
configure({
|
||||
|
@ -27,7 +28,12 @@ import createOicq from './client/oicq';
|
|||
({ tgUser, oicq } = await setupController.waitForFinish());
|
||||
}
|
||||
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({
|
||||
uin: config.qqUin,
|
||||
password: config.qqPassword,
|
||||
|
@ -36,5 +42,7 @@ import createOicq from './client/oicq';
|
|||
onVerifySlider: () => 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