Skip to content

Instantly share code, notes, and snippets.

@setazer
Last active June 7, 2019 07:43
Show Gist options
  • Save setazer/4b19575615cd85559dee748cb2816022 to your computer and use it in GitHub Desktop.
Save setazer/4b19575615cd85559dee748cb2816022 to your computer and use it in GitHub Desktop.
Telebot paginator
from math import ceil
from random import randint
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
from telebot.apihelper import ApiException
class InlinePaginator():
def __init__(self, msg, data, items_per_row=5, max_rows=5):
self.data = data
self.current_page = 1
self.items_per_row = items_per_row
self.items_per_page = self.items_per_row * max_rows
self.max_pages = ceil(len(self.data) / self.items_per_page)
self.navigation_process = None
self.selector = None
self.finisher = None
self.msg = msg
self.bot = None
def __del__(self):
pass
def add_data_item(self, button_data, button_text):
self.data.append((button_data, button_text))
self.refresh()
def delete_data_item(self, button_data=None, button_text=None):
if not any([button_data, button_text]):
return
else:
found_buttons = [item for item in self.data if (
(item[0] == button_data and item[1] == button_text) if all([button_data, button_text]) else (
item[0] == button_data or item[1] == button_text))]
if found_buttons:
for item in found_buttons:
self.data.remove(item)
self.refresh()
return
else:
raise ValueError("Items not found")
def refresh(self):
self.max_pages = ceil(len(self.data) / self.items_per_page)
if self.current_page > self.max_pages:
self.current_page = self.max_pages
self.show_current_page()
def show_current_page(self):
markup = InlineKeyboardMarkup()
markup.row_width = self.items_per_row
buttons = []
for value, text in self.data[(self.current_page - 1) * self.items_per_page:
self.current_page * self.items_per_page]:
buttons.append(InlineKeyboardButton(text=text, callback_data=f'pag_item{value}'))
markup.add(*buttons)
nav_buttons = []
if self.current_page > 1:
nav_buttons.append(InlineKeyboardButton(text="⏪" + emojize_number(1), callback_data='pag_switch1'))
nav_buttons.append(InlineKeyboardButton(text="◀️" + emojize_number(self.current_page - 1),
callback_data=f'pag_switch{self.current_page - 1}'))
else:
nav_buttons += [InlineKeyboardButton(text="⏺", callback_data='pag_cur')] * 2
nav_buttons.append(InlineKeyboardButton(text=emojize_number(self.current_page),
# callback_data с произвольным числом чтобы телега не ругалась,
# что сообщение не изменилось, когда происходит перерисовка при удалении элемента
callback_data=f'pag_cur{randint(0,1000000000)}'))
if self.current_page < self.max_pages:
nav_buttons.append(InlineKeyboardButton(text="▶️" + emojize_number(self.current_page + 1),
callback_data=f'pag_switch{self.current_page + 1}'))
nav_buttons.append(InlineKeyboardButton(text="️⏩" + emojize_number(self.max_pages),
callback_data=f'pag_switch{self.max_pages}'))
else:
nav_buttons += [InlineKeyboardButton(text="⏺", callback_data='pag_cur')] * 2
markup.row(*nav_buttons)
markup.row(InlineKeyboardButton(text="✅ Завершить", callback_data='pag_finish'))
if self.bot:
try:
self.bot.edit_message_reply_markup(self.msg.chat.id, self.msg.message_id, reply_markup=markup)
except ApiException:
pass
def _navigation_process(self, call):
if 'pag_cur' in call.data:
self.refresh()
return
if 'pag_item' in call.data:
if self.selector:
self.selector(call, call.data[len('pag_item'):])
elif 'pag_finish' in call.data:
if self.bot:
# находим и удалям хендлер нажатий кнопок пагинатора (он ведь больше не нужен)
for index, callback_handler in enumerate(self.bot.callback_query_handlers):
if callback_handler['function'] == self._navigation_process:
del self.bot.callback_query_handlers[index]
break
self.bot.delete_message(call.message.chat.id, call.message.message_id)
self.finisher(call)
elif 'pag_switch' in call.data:
new_page = int(call.data.replace('pag_switch', ''))
if self.current_page != new_page:
self.current_page = new_page
self.show_current_page()
def hook_telebot(self, bot, func_item_selected, finisher=lambda f: None):
self.bot = bot
self.selector = func_item_selected
self.finisher = finisher
self.navigation_process = bot.callback_query_handler(func=lambda
call: 'pag_' in call.data and call.message.chat.id == self.msg.chat.id and call.message.message_id == self.msg.message_id)(
self._navigation_process) # регистрация нажатия на кнопки в пагинаторе с привязкой к конкретной мессаге,
# чтобы 2 пагинатора не влияли друг на друга
self.show_current_page()
def emojize_number(num):
digits = {'0':'0️⃣','1':'1️⃣','2':'2️⃣','3':'3️⃣','4':'4️⃣','5':'5️⃣','6':'6️⃣','7':'7️⃣','8':'8️⃣','9':'9️⃣'}
result = ''
for char in str(num):
result+=digits[char]
return result
import telebot
from paginator import InlinePaginator
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
TELEGRAM_PROXY = {
"http": "proxy.antizapret.prostovpn.org:3128",
"https": "proxy.antizapret.prostovpn.org:3128"
}
OWNER_ROOM_ID = ''
TELEGRAM_TOKEN = ''
telebot.apihelper.proxy=TELEGRAM_PROXY
bot = telebot.TeleBot(TELEGRAM_TOKEN)
paginators={}
buttons = [(str(item),str(item*1000)) for item in range(140)] # тестовый массив с данными вида [('1','1000'),('2','2000'),...]
def selected(data,call): # функция для обработки выбранного элемента
bot.send_message(call.message.chat.id,data)
def dead_paginator(call): # удаляем ненужный пагинатор
del paginators[(call.message.chat.id, call.message.message_id)]
sel=bot.send_message('@pyTelegramBotAPI_talks_ru',"Select item:") # мессага для подцепления
paginators[(sel.chat.id, sel.message_id)] = InlinePaginator(sel,buttons) # создаём навигацию, прицепляя её к мессаге и передавая массив с данными
paginators[(sel.chat.id, sel.message_id)].hook_telebot(bot,selected,dead_paginator) # подцепляем бота, функцию которая будет обрабатывать выбранный элемент
# и функцию которая будет выполнена при нажатии "Завершить"
# подцепление так же включает внутреннюю обработку нажатия на кнопки навигации
bot.polling()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment