169 lines
7.2 KiB
Python
169 lines
7.2 KiB
Python
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|текст] -> <a href="url">текст</a> (для Telegram)
|
|
"""
|
|
if not text:
|
|
return text
|
|
|
|
# Сначала обрабатываем ссылки формата [url|текст] и преобразуем их в HTML-ссылки
|
|
def replace_url_link(match):
|
|
url = match.group(1)
|
|
link_text = match.group(2)
|
|
return f'<a href="{url}">{link_text}</a>'
|
|
|
|
# Регулярное выражение для поиска ссылок формата [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-теги с учетом специальной обработки <p> и <a>"""
|
|
if not text:
|
|
return text
|
|
|
|
# Заменяем <p> и </p> на переносы строк
|
|
text = re.sub(r'</?p\s*/?>', '\n', text, flags=re.IGNORECASE)
|
|
|
|
# Обрабатываем ссылки <a href="URL">Текст</a> -> Текст (URL)
|
|
def replace_a_tag(match):
|
|
url = match.group(1)
|
|
link_text = match.group(2)
|
|
return f"{link_text} ({url})"
|
|
|
|
text = re.sub(
|
|
r'<a\s+href="([^"]*)"[^>]*>(.*?)</a>',
|
|
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'<a href="{vk_post_url}">Оригинал в ВК</a>' 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
|
|
}
|