diff --git a/news-bot.py b/news-bot.py index 3eb3275..224df41 100755 --- a/news-bot.py +++ b/news-bot.py @@ -3,6 +3,7 @@ import re import sys import time +import schedule import asyncio import discord import logging @@ -19,10 +20,10 @@ from telethon.errors import FloodWaitError import keys url_post = "https://linux-gaming.ru/posts.json" -url_news = f"https://linux-gaming.ru/c/news/6.json" +url_news = f"https://linux-gaming.ru/c/news/{keys.cat_num}.json" url_vk_post = "https://api.vk.com/method/wall.post" url_vk_get = "https://api.vk.com/method/wall.get" -url_changelog = "https://gitlab.eterfund.ru/Castro-Fidel/PortWINE/raw/devel/data_from_portwine/changelog_ru" +url_changelog = "https://gitlab.eterfund.ru/Castro-Fidel/PortWINE/raw/master/data_from_portwine/changelog_ru" heads_site = { "Content-Type": "application/json", @@ -44,7 +45,8 @@ logger.setLevel(logging.DEBUG) handler = colorlog.StreamHandler() handler.setFormatter(colorlog.ColoredFormatter( - '%(log_color)s%(levelname)s: %(message)s', + '%(log_color)s%(asctime)s - %(levelname)s: %(message)s', + datefmt='%Y-%m-%d %H:%M:%S', log_colors={ 'DEBUG': 'cyan', 'INFO': 'green', @@ -57,12 +59,12 @@ handler.setFormatter(colorlog.ColoredFormatter( logger.addHandler(handler) -def main(): - last_changelog, resp_changelog = resp_change() - check_version(last_changelog, resp_changelog) - check_discord_public() +async def job(): + matches_changelog, last_changelog, resp_changelog = resp_change() + check_version(matches_changelog, last_changelog, resp_changelog) + await check_discord_public() check_vk_posts() - check_tg_news() + await check_tg_news() def make_soup(resp_changelog): @@ -83,6 +85,8 @@ def html_to_text(html_content): logging.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) @@ -167,7 +171,7 @@ def remove_empty_lines(text_data): def remove_markdown_links(markdown_text): logging.debug(f"Входим в remove_markdown_links") # Регулярное выражение для поиска Markdown-ссылок и замена их на только URL - markdown_text = re.sub(r'\[.*?\]\((https?://.*?)\)', r'\1' or r'(`https?://.*?)`\)', markdown_text) + markdown_text = re.sub(r'\[.*?\]\((https?://.*?)\)', r'\1' or r'(https?://.*?)\)', markdown_text) logging.debug(f"Возврат markdown_text {markdown_text}") return markdown_text @@ -199,38 +203,35 @@ def extract_links(text): return url_pattern -def script_content(last_topics_script, last_changelog, resp_changelog): - logging.debug(f"Вход в script_content") +def script_content(script_ver, next_version, resp_changelog): + logging.debug(f"Вход в script_content c версией стабильного скрипта {script_ver}") soup = make_soup(resp_changelog) page_text = str(soup) page_text = page_text.replace("Вы можете помочь развитию проекта: https://linux-gaming.ru/donate/", '') - changelog_text = "" - for script_ver in range(last_topics_script + 1, last_changelog + 1): - current_ver_text = f"###Scripts version {script_ver}### / stable" - next_ver_text = f"###Scripts version {script_ver + 1}### / stable" + # Находим текст до определенного текста, тега или класса (например, до тега
) + last_text = f"###Scripts version {next_version}### / stable" + last_text = str(last_text) + index_last_text = page_text.find(last_text) - start_index = page_text.find(current_ver_text) - end_index = page_text.find(next_ver_text) + if index_last_text != -1: + changelog_text_last = page_text[:index_last_text] + prev_text = f"###Scripts version {script_ver}### / stable" + index_script_ver = changelog_text_last.find(prev_text) + changelog_text = changelog_text_last[index_script_ver:] + changelog_text = re.sub(r'###Scripts version (\d+)### / Дата: (\d{2}\.\d{2}\.\d{4}) / Размер скачиваемого обновления: \d+ \S+', r'\1 - \2'":", changelog_text) + post_text = (f"-----------------------------\n") + changelog_text + site_text = (f"[center][img]/uploads/default/original/1X/5cfa59077a5275971401fab0114e56f3ffdd0ec4.png[/img][/center]\n{post_text}") - if start_index != -1: - if end_index != -1: - changelog_text += page_text[start_index:end_index] - else: - changelog_text += page_text[start_index:] + logging.debug(f"Сообщение на сайт {site_text}") - post_text = f"-----------------------------\n{changelog_text}" - site_text = f"[center][img]/uploads/default/original/1X/5cfa59077a5275971401fab0114e56f3ffdd0ec4.png[/img][/center]\n{post_text}" - - logging.debug(f"Сообщение на сайт {site_text}") - - post_data = { - "title": f"Обновление скриптов {last_changelog}", - "raw": site_text, - "category": keys.cat_num - } - logging.debug(f"Возвращаем post_text - {post_text}\n post_data - {post_data}") - return post_text, post_data + post_data = { + "title": f"Обновление скриптов {script_ver}", + "raw": site_text, + "category": keys.cat_num + } + logging.debug(f"Возвращаем post_text - {post_text}\n post_data - {post_data}") + return post_text, post_data, post_text def news_content(post_id): @@ -269,8 +270,8 @@ def resp_change(): matches_changelog = re.findall(r'###Scripts version (\d+)### / stable', resp_changelog.text) logging.debug(f"Найдены версии в истории изменений: {matches_changelog}") last_changelog = int(max(matches_changelog)) - logging.info(f"Последняя версия в истории изменений: {last_changelog}") - return last_changelog, resp_changelog + logging.info(f"Последняя стабильная версия в истории изменений: {last_changelog}") + return matches_changelog, last_changelog, resp_changelog else: logging.error( f'Ошибка при запросе changelog: {resp_changelog.status_code if resp_changelog else "No Response"}') @@ -311,7 +312,7 @@ def site_post(url, headers, json): time.sleep(900) -def check_version(last_changelog, resp_changelog): +def check_version(matches_changelog, last_changelog, resp_changelog): list_titles_and_ids = news() pattern = re.compile(r'Обновление скриптов (\d+)') @@ -321,31 +322,31 @@ def check_version(last_changelog, resp_changelog): return int(match.group(1)) return None - numbers = [extract_number(title) for _, title in list_titles_and_ids if extract_number(title) is not None] + def posting_news(): + list_new_ver = [] + for script_ver, next_version in zip(reversed(matches_changelog[:-1]), reversed(matches_changelog[1:])): + logging.info(f"Найдена новая версия скрипта {script_ver}") + changelog_text, post_data, params = script_content(script_ver, next_version, resp_changelog) + if post_data: + logging.debug(f"Публикуем {post_data}") + site_post(url_post, heads_site, post_data) + if not list_new_ver: + logging.warning(f"Не найдена новая стабильная версия скрипта") + + numbers = [extract_number(title) for _, title in list_titles_and_ids if extract_number(title) is not None] if numbers: last_topics_script = max(numbers) logging.info(f"Последняя новость на сайте о версии: {last_topics_script}") + + if last_topics_script < last_changelog: + posting_news() + + else: + logging.warning("Нет новых версий скриптов PortProton") else: logging.warning("На сайте нет новостей о скриптах") - last_topics_script = 0 - - if last_topics_script < last_changelog: - changelog_text, post_data = script_content(last_topics_script, last_changelog, resp_changelog) - if post_data: - logging.debug(f"Публикуем {post_data}") - site_post(url_post, heads_site, post_data) - else: - logging.warning("Нет новых версий скриптов PortProton") - - # Публикация топиков - if not numbers or last_topics_script < last_changelog: - changelog_text, post_data = script_content(last_topics_script, last_changelog, resp_changelog) - if post_data: - logging.debug(f"Публикуем {post_data}") - site_post(url_post, heads_site, post_data) - else: - logging.warning("Нет новых версий скриптов PortProton") + posting_news() async def discord_post(post_text, client): @@ -372,7 +373,7 @@ async def get_discord_messages(client_discord, channel_id): return messages -def check_discord_public(): +async def check_discord_public(): intents = discord.Intents.default() intents.messages = True client_discord = discord.Client(intents=intents) @@ -411,7 +412,7 @@ def check_discord_public(): await channel.send(content[i:i+2000]) await client_discord.close() - client_discord.run(keys.discord_token) + await client_discord.start(keys.discord_token) def vk_post(url, post_text, links=None): @@ -421,7 +422,7 @@ def vk_post(url, post_text, links=None): 'owner_id': str(keys.own_id), 'message': f'{post_text}' # Дополнительные параметры можно добавить здесь - } + } if links: params_post['attachments'] = links @@ -527,18 +528,11 @@ async def get_tg_messages(client_tg, channel_username_tg): return messages -def check_tg_news(): +async def check_tg_news(): session_file = 'LG_news' - loop = asyncio.new_event_loop() - asyncio.set_event_loop(loop) - client_tg = TelegramClient(session_file, keys.api_id_tg, keys.api_hash_tg) - @client_tg.on(events.NewMessage(chats=keys.channel_username_tg)) - async def handler(event): - logging.debug(f"Новое сообщение в Telegram: {event.message.message}") - - async def main_tg(): + async with client_tg: await client_tg.start() tg_messages = await get_tg_messages(client_tg, keys.channel_username_tg) list_titles_and_ids = news() @@ -551,7 +545,6 @@ def check_tg_news(): if not list_for_public: logging.warning(f"Новостей для публикации в Telegram нет") - await client_tg.disconnect() else: logging.info(f"Новости для публикации в Telegram: {list_for_public}") for topic_id, topic_title in reversed(list_for_public): @@ -565,11 +558,21 @@ def check_tg_news(): except FloodWaitError as e: logging.warning(f"Flood wait error: нужно подождать {e.seconds} секунд.") await asyncio.sleep(e.seconds) # Ждем указанное время перед повторной попыткой - await client_tg.disconnect() + +def run_job(): loop = asyncio.get_event_loop() - loop.run_until_complete(main_tg()) + loop.run_until_complete(job()) if __name__ == '__main__': - main() + # Выполняем задачу немедленно при старте + run_job() + + # Планируем выполнение задачи каждые 10 минут + schedule.every(30).minutes.do(run_job) + + logger.info("Запуск планировщика задач") + while True: + schedule.run_pending() + time.sleep(1)