import re
def truncate_text(text, max_length):
"""Обрезает текст до максимальной длины с учетом границ слов"""
if text is None or not text:
return ""
if len(text) <= max_length:
return text
# Ищем последний пробел перед максимальной длиной
truncated = text[:max_length]
last_space = truncated.rfind(' ')
if last_space > 0:
return truncated[:last_space] + "..."
return truncated[:max_length-3] + "..."
def safe_text(text):
"""Обеспечивает безопасное использование текста (заменяет None на пустую строку)"""
return text if text is not None else ""
def replace_vk_links(text):
"""
Заменяет ссылки на сообщества ВК в форматах:
[club123|Название сообщества] -> Название сообщества
[id456|Имя пользователя] -> Имя пользователя
[url|текст] -> текст (для Telegram)
"""
if not text:
return text
# Сначала обрабатываем ссылки формата [url|текст] и преобразуем их в HTML-ссылки
def replace_url_link(match):
url = match.group(1)
link_text = match.group(2)
return f'{link_text}'
# Регулярное выражение для поиска ссылок формата [url|текст]
# Исключаем случаи, когда url начинается с club или id и цифр, за которыми сразу следует | (это обрабатывается отдельно)
url_pattern = r'\[(?!club\d+\||id\d+\|)([^\|]+)\|([^\]]+)\]'
text = re.sub(url_pattern, replace_url_link, text)
# Регулярное выражение для поиска ссылок формата [типID|Текст] (ВК-специфичные)
vk_pattern = r'\[(?:club|id)\d+\|([^\]]+)\]'
# Заменяем все вхождения на текст внутри ссылки
return re.sub(vk_pattern, r'\1', text)
def remove_html_tags(text):
"""Удаляет HTML-теги с учетом специальной обработки
и """
if not text:
return text
# Заменяем и
на переносы строк
text = re.sub(r'?p\s*/?>', '\n', text, flags=re.IGNORECASE)
# Обрабатываем ссылки Текст -> Текст (URL)
def replace_a_tag(match):
url = match.group(1)
link_text = match.group(2)
return f"{link_text} ({url})"
text = re.sub(
r']*>(.*?)',
replace_a_tag,
text,
flags=re.IGNORECASE | re.DOTALL
)
# Удаляем все оставшиеся HTML-теги
text = re.sub(r'<[^>]+>', '', text)
# Схлопываем множественные переносы строк
text = re.sub(r'\n+', '\n', text)
return text.strip()
def get_event_text(text, limit=950):
"""
Обрабатывает текст: удаляет HTML-теги и VK-ссылки, обрезает до указанной длины
:param text: исходный текст
:param limit: максимальная длина текста (по умолчанию 950)
:return: обработанный текст
"""
if not text:
return ""
# Удаляем HTML-теги
cleaned_text = remove_html_tags(text)
# Обрабатываем VK-ссылки
cleaned_text = replace_vk_links(cleaned_text)
# Обрезаем текст до указанной длины
return truncate_text(cleaned_text, limit)
def get_post_text(post_data, max_caption_length=1000, max_text_length=4000):
"""
Форматирует пост для публикации в Telegram
Возвращает словарь с элементами:
{
'base_text': основной текст поста,
'image_url': URL изображения (или None),
'vk_link': HTML-ссылка на оригинал в ВК,
'caption': подпись для изображения (с учетом ограничений длины),
'text_message': текстовое сообщение (с учетом ограничений длины),
'has_poll': есть ли опрос,
'is_event': является ли пост событием,
'poll_question': вопрос опроса,
'poll_options': варианты ответов опроса,
'poll_multiple': разрешен ли множественный выбор
}
"""
# Извлекаем данные из кортежа
vk_post_id = post_data[0]
text_content = safe_text(post_data[1])
image_url = safe_text(post_data[2])
vk_post_url = safe_text(post_data[3])
poll_question = safe_text(post_data[4])
poll_options = safe_text(post_data[5])
poll_multiple = post_data[6]
is_event = post_data[7]
has_poll = post_data[8] # Извлекаем значение is_poll
# Обрабатываем текст: заменяем ссылки на сообщества ВК
text_content = replace_vk_links(text_content)
# Базовый текст - только содержимое поста
base_text = text_content
vk_link = f'Оригинал в ВК' if vk_post_url else ""
# Формируем подпись для изображения
caption = None
if image_url:
full_caption = f"{base_text}\n\n{vk_link}" if vk_link else base_text
if len(full_caption) > max_caption_length:
available_length = max_caption_length - (len(vk_link) + 10) if vk_link else 0
truncated_text = truncate_text(base_text, available_length)
caption = f"{truncated_text}\n\n{vk_link}" if vk_link else truncated_text
else:
caption = full_caption
# Формируем текстовое сообщение (для постов без изображения)
text_message = None
if not image_url:
full_message = f"{base_text}\n\n{vk_link}" if vk_link else base_text
if len(full_message) > max_text_length:
available_length = max_text_length - (len(vk_link) + 10) if vk_link else 0
truncated_text = truncate_text(base_text, available_length)
text_message = f"{truncated_text}\n\n{vk_link}" if vk_link else truncated_text
else:
text_message = full_message
return {
'vk_post_id': vk_post_id,
'base_text': base_text,
'image_url': image_url if image_url else None,
'vk_link': vk_link,
'caption': caption,
'text_message': text_message,
'has_poll': has_poll, # Используем прямое значение из кортежа
'is_event': is_event,
'poll_question': poll_question,
'poll_options': poll_options,
'poll_multiple': poll_multiple
}