|
from __future__ import annotations |
|
|
|
from typing import TYPE_CHECKING |
|
|
|
from aiogram.enums import MessageEntityType |
|
from aiogram.types import InlineKeyboardButton, InlineKeyboardMarkup |
|
|
|
|
|
if TYPE_CHECKING: |
|
from aiogram.types import Message, MessageEntity |
|
|
|
|
|
MAX_BUTTONS_PER_ROW = 8 |
|
MAX_ROWS = 100 |
|
|
|
|
|
class TooManyButtonsInRowError(Exception): |
|
pass |
|
|
|
|
|
class TooManyRowsError(Exception): |
|
pass |
|
|
|
|
|
class NoTextLinkEntitiesError(Exception): |
|
pass |
|
|
|
|
|
def parse_buttons(message: Message) -> InlineKeyboardMarkup: |
|
if not message.text: |
|
raise ValueError |
|
if not message.entities: |
|
raise NoTextLinkEntitiesError |
|
entities = filter_text_link_entities(entities=message.entities) |
|
if not entities: |
|
raise NoTextLinkEntitiesError |
|
return parse_rows(entities=entities, text=message.text) |
|
|
|
|
|
def filter_text_link_entities(entities: list[MessageEntity]) -> list[MessageEntity]: |
|
return [entity for entity in entities if entity.type == MessageEntityType.TEXT_LINK] |
|
|
|
|
|
def parse_rows(entities: list[MessageEntity], text: str) -> InlineKeyboardMarkup: |
|
rows = [] |
|
lines = text.splitlines() |
|
for line in lines: |
|
row = parse_row(entities=entities, text=text, line=line) |
|
if len(row) > MAX_BUTTONS_PER_ROW: |
|
raise TooManyButtonsInRowError |
|
if row: |
|
rows.append(row) |
|
if len(rows) > MAX_ROWS: |
|
raise TooManyRowsError |
|
return InlineKeyboardMarkup(inline_keyboard=rows) |
|
|
|
|
|
def parse_row(entities: list[MessageEntity], text: str, line: str) -> list[InlineKeyboardButton]: |
|
return [ |
|
create_button(entity=entity, text=text) |
|
for entity in entities |
|
if is_entity_in_line(entity=entity, text=text, line=line) |
|
] |
|
|
|
|
|
def is_entity_in_line(entity: MessageEntity, text: str, line: str) -> bool: |
|
entity_start = entity.offset |
|
entity_end = entity_start + entity.length |
|
line_start = text.index(line) |
|
line_end = line_start + len(line) |
|
return entity_start >= line_start and entity_end <= line_end |
|
|
|
|
|
def create_button(entity: MessageEntity, text: str) -> InlineKeyboardButton: |
|
text = text[entity.offset : entity.offset + entity.length] |
|
return InlineKeyboardButton(text=text, url=entity.url) |