Files
bot-news-linux-gaming/content_processor.py

236 lines
11 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
import re
import logging
import html2text
import urllib.parse
from bs4 import BeautifulSoup
class ContentProcessor:
def __init__(self):
self.logger = logging.getLogger(__name__)
def make_soup(self, response):
self.logger.debug("Создаем объект BeautifulSoup")
return BeautifulSoup(response.text, 'html.parser')
def html_to_text(self, html_content):
self.logger.debug(f"Конвертируем HTML в текст")
self.logger.debug(f"HTML на входе: {html_content}")
h = html2text.HTML2Text()
h.ignore_links = False
h.ignore_images = True
h.bypass_tables = True
h.reference_links = True
markdown_text = h.handle(html_content)
self.logger.debug(f"Текст до обработки регулярными выражениями: {markdown_text}")
# Удаление переносов строк из-за -
markdown_text = re.sub(r'-\s*\n\s*', '-', markdown_text, flags=re.DOTALL)
markdown_text = re.sub(r'-\s*\n*', '-', markdown_text, flags=re.DOTALL)
# Убираем переносы строк внутри круглых скобок ()
markdown_text = re.sub(r'\((.*?)\)', lambda x: '(' + x.group(1).replace('\n', ' ') + ')', markdown_text, flags=re.DOTALL)
# Убираем переносы строк внутри квадратных скобок []
markdown_text = re.sub(r'\[(.*?)\]', lambda x: '[' + x.group(1).replace('\n', ' ') + ']', markdown_text, flags=re.DOTALL)
# Удаление строк, содержащих '* * *'
markdown_text = re.sub(r'^.*\* \* \*.*$', '', markdown_text, flags=re.MULTILINE)
# Преобразование всех ссылок с параметрами URL
markdown_text = self.convert_links(markdown_text)
# Работа с #
patterns_to_remove = [
r'###',
r'##',
r'#',
r'\[scripts\]\(\/tag\/scripts\) version \d+ ',
r'##\[scripts\]\(\) version \d+ ',
r'\d{4}×\d{3} \d+ KB'
]
for pattern in patterns_to_remove:
markdown_text = re.sub(pattern, '', markdown_text)
# Удаление избыточных пустых строк после удаления строк
markdown_text = re.sub(r'\n\s*\n', '\n', markdown_text)
# Замена текстов типа "image1280×474 99.7 KB", "807×454 64.1 KB" на "."
markdown_text = re.sub(r'image\d+×\d+\s+\d+(\.\d+)?\s+KB', '.', markdown_text)
markdown_text = re.sub(r'\d+×\d+\s+\d+(\.\d+)?\s+KB', '.', markdown_text)
# Изменение ссылок без описания
markdown_text = re.sub(r'\[\]\((https:\/\/[^\)]+)\)', r'[.](\1)', markdown_text)
markdown_text = re.sub(r'\[\s]\((https:\/\/[^\)]+)\)', r'[.](\1)', markdown_text)
# Удаление дублирующихся ссылок
markdown_text = self.remove_duplicate_links(markdown_text)
# Удаление лишних отступов для строк, начинающихся с '*'
markdown_text = re.sub(r' \*', r'*', markdown_text)
# Перемещение ссылки на изображение в конец последней строки
image_link = "[.](https://linux-gaming.ru/uploads/default/original/1X/5cfa59077a5275971401fab0114e56f3ffdd0ec4.png)"
if image_link in markdown_text:
markdown_text = markdown_text.replace(image_link, '')
markdown_text = markdown_text + image_link
self.logger.debug(f"Текст после обработки: {markdown_text}")
return markdown_text
def convert_links(self, text):
self.logger.debug("Конвертируем ссылки")
url_pattern = re.compile(r'https?://[^\s\)]+')
url_pattern = url_pattern.sub(lambda match: self.decode_url_params(match.group(0)), text)
self.logger.debug(f"Результат конвертации ссылок: {url_pattern}")
return url_pattern
def decode_url_params(self, url):
self.logger.debug(f"Декодируем URL параметры: {url}")
parsed_url = urllib.parse.urlparse(url)
query_params = urllib.parse.parse_qs(parsed_url.query)
for key, values in query_params.items():
if key.lower() == 'to' and values:
return urllib.parse.unquote(values[0])
self.logger.debug(f"Возвращаем URL: {url}")
return url
def remove_empty_lines(self, text_data):
self.logger.debug("Удаляем пустые строки")
lines = text_data.splitlines()
non_empty_lines = [line for line in lines if line.strip()]
non_empty_lines = '\n'.join(non_empty_lines)
self.logger.debug(f"Результат удаления пустых строк: {non_empty_lines}")
return non_empty_lines
def remove_markdown_links(self, markdown_text):
self.logger.debug("Удаляем markdown ссылки")
markdown_text = re.sub(r'\[.*?\]\((https?://.*?)\)', r'\1', markdown_text)
self.logger.debug(f"Результат удаления markdown ссылок: {markdown_text}")
return markdown_text
def remove_duplicate_links(self, text):
self.logger.debug("Удаляем дубликаты ссылок")
seen_links = set()
def replace_link(match):
link = match.group(2)
if link in seen_links:
return ''
seen_links.add(link)
return match.group(0)
link_pattern = re.compile(r'(\[.*?\]\((https:\/\/.*?)\))')
text = re.sub(link_pattern, replace_link, text)
self.logger.debug(f"Результат удаления дубликатов ссылок: {text}")
return text
def extract_links(self, text):
self.logger.debug("Извлекаем ссылки из текста")
# Улучшенное регулярное выражение, исключающее конечные знаки препинания
url_pattern = re.compile(r'https?://[^\s\)\]\}\>,;]+')
links = url_pattern.findall(text)
# Дополнительная очистка: убираем точки и запятые в конце
cleaned_links = []
for link in links:
link = link.rstrip('.,!?')
cleaned_links.append(link)
self.logger.debug(f"Найденные ссылки: {cleaned_links}")
return cleaned_links
def format_for_vk(self, content):
"""Форматирование контента для VK"""
self.logger.debug("Форматируем контент для VK")
# Замена маркеров списка
content = re.sub(r'\* ', '', content)
content = re.sub(r'', '', content)
content = re.sub(r'', '', content)
# Удаление markdown ссылок
content = self.remove_markdown_links(content)
# Замена изображения
content = re.sub(
r'https://linux-gaming.ru/uploads/default/original/1X/5cfa59077a5275971401fab0114e56f3ffdd0ec4.png',
'\n',
content,
flags=re.DOTALL
)
return content
def format_for_telegram(self, content):
"""Форматирование контента для Telegram"""
self.logger.debug("Форматируем контент для Telegram")
return content # Telegram поддерживает markdown
def create_script_content(self, script_ver, next_version, response):
"""Создание контента для обновления скрипта"""
self.logger.debug(f"Создаем контент для версии скрипта от {script_ver} до {next_version}")
soup = self.make_soup(response)
page_text = str(soup)
page_text = page_text.replace("Вы можете помочь развитию проекта: https://linux-gaming.ru/donate/", '')
# В changelog версии идут от новых к старым (2444, 2443, 2442...)
# Нужно найти текущую версию (next_version) и предыдущую (script_ver)
# Предыдущая версия находится ПОСЛЕ текущей в файле
current_text = f"###Scripts version {next_version}### / stable"
self.logger.debug(f"Ищем текущую версию: {current_text}")
index_current = page_text.find(current_text)
self.logger.debug(f"Индекс текущей версии: {index_current}")
if index_current != -1:
# Ищем предыдущую версию ПОСЛЕ текущей
text_after_current = page_text[index_current:]
# Попробуем разные варианты формата предыдущей версии
possible_formats = [
f"###Scripts version {script_ver}### / stable",
f"###Scripts version {script_ver}###",
f"Scripts version {script_ver}"
]
index_prev_relative = -1
for prev_text in possible_formats:
self.logger.debug(f"Ищем предыдущую версию (формат): {prev_text}")
index_prev_relative = text_after_current.find(prev_text)
if index_prev_relative != -1:
self.logger.debug(f"Найдено! Относительный индекс: {index_prev_relative}")
break
if index_prev_relative == -1:
self.logger.error(f"Не найдена версия {script_ver} после версии {next_version}")
self.logger.debug(f"Первые 1000 символов после текущей версии: {text_after_current[:1000]}")
return None
# Извлекаем текст от начала текущей версии до начала предыдущей
index_prev = index_current + index_prev_relative
changelog_text = page_text[index_current:index_prev]
self.logger.debug(f"Длина извлеченного текста: {len(changelog_text)} символов")
changelog_text = re.sub(
r'###Scripts version (\d+)### / Дата: (\d{2}\.\d{2}\.\d{4}) / Размер скачиваемого обновления: \d+ \S+',
r'\1 - \2' + ":",
changelog_text
)
changelog_text = re.sub(
r'###Scripts version (\d+)### / stable / Дата: (\d{2}\.\d{2}\.\d{4}) / Размер скачиваемого обновления: \d+ \S+',
r'\1 - \2' + ":",
changelog_text
)
post_text = "-----------------------------\n" + changelog_text
self.logger.debug(f"Возвращаем post_text длиной {len(post_text)} символов")
return post_text
else:
self.logger.error(f"Не найдена версия {next_version} в changelog (конец диапазона)")
return None
return None