132 lines
6.0 KiB
Python
Executable File
132 lines
6.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
||
|
||
import asyncio
|
||
import schedule
|
||
import time
|
||
|
||
from logger import setup_logger
|
||
from config import DISCORD_CONFIG
|
||
from content_processor import ContentProcessor
|
||
from site_api import SiteAPI
|
||
from telegram_client import TelegramNewsClient
|
||
from vk_client import VKClient
|
||
from discord_client import DiscordClient
|
||
from config_updater import ConfigUpdater
|
||
|
||
|
||
class NewsBot:
|
||
def __init__(self):
|
||
self.logger = setup_logger()
|
||
self.content_processor = ContentProcessor()
|
||
self.site_api = SiteAPI()
|
||
self.telegram_client = TelegramNewsClient(self.content_processor)
|
||
self.vk_client = VKClient(self.content_processor)
|
||
self.discord_client = DiscordClient(self.content_processor)
|
||
self.config_updater = ConfigUpdater()
|
||
|
||
self.logger.info("Бот инициализирован с модульной архитектурой")
|
||
if DISCORD_CONFIG['enabled']:
|
||
self.logger.info("Discord функциональность включена")
|
||
else:
|
||
self.logger.info("Discord функциональность отключена")
|
||
|
||
async def run_job(self):
|
||
"""Основная задача бота"""
|
||
self.logger.info("Запуск основной задачи бота")
|
||
|
||
try:
|
||
# Проверка и публикация новых версий скриптов
|
||
self.site_api.check_script_versions(self.content_processor)
|
||
|
||
# Получение списка новостей
|
||
news_list = self.site_api.get_news()
|
||
|
||
if news_list:
|
||
self.logger.info(f"Получено {len(news_list)} новостей для обработки")
|
||
|
||
# Отслеживаем успешно опубликованные новости во всех источниках
|
||
published_in_telegram = []
|
||
published_in_vk = []
|
||
published_in_discord = []
|
||
|
||
# Публикация в Telegram
|
||
if self.telegram_client.is_enabled():
|
||
published_in_telegram = await self.telegram_client.check_and_publish_news(news_list)
|
||
|
||
# Публикация в VK
|
||
if self.vk_client.is_enabled():
|
||
published_in_vk = await asyncio.get_event_loop().run_in_executor(
|
||
None, self.vk_client.check_and_publish_news, news_list
|
||
)
|
||
|
||
# Публикация в Discord (если включен)
|
||
if self.discord_client.is_enabled():
|
||
published_in_discord = await self.discord_client.check_and_publish_news(news_list)
|
||
|
||
# Определяем новости, опубликованные во ВСЕХ активных источниках
|
||
all_sources = []
|
||
if self.telegram_client.is_enabled():
|
||
all_sources.append(set(published_in_telegram))
|
||
if self.vk_client.is_enabled():
|
||
all_sources.append(set(published_in_vk or []))
|
||
if self.discord_client.is_enabled():
|
||
all_sources.append(set(published_in_discord or []))
|
||
|
||
if all_sources:
|
||
# Находим пересечение - новости, опубликованные везде
|
||
successfully_published_everywhere = set.intersection(*all_sources)
|
||
|
||
if successfully_published_everywhere:
|
||
# Находим максимальный topic_id среди успешно опубликованных
|
||
max_topic_id = max(successfully_published_everywhere)
|
||
|
||
# Обновляем start_topic_id в keys.py
|
||
if self.config_updater.update_start_topic_id(max_topic_id):
|
||
self.logger.info(f"start_topic_id обновлен на {max_topic_id} после успешной публикации во всех источниках")
|
||
else:
|
||
self.logger.warning("Не удалось обновить start_topic_id в keys.py")
|
||
else:
|
||
self.logger.info("Нет новостей, опубликованных во всех активных источниках")
|
||
else:
|
||
self.logger.warning("Новостей для обработки не найдено")
|
||
|
||
except Exception as e:
|
||
self.logger.error(f"Ошибка в основной задаче бота: {e}")
|
||
|
||
def run_sync_job(self):
|
||
"""Синхронная обертка для планировщика"""
|
||
asyncio.run(self.run_job())
|
||
|
||
def start(self):
|
||
"""Запуск бота"""
|
||
self.logger.info("Запуск новостного бота")
|
||
|
||
# Выполнение задачи при старте
|
||
self.logger.info("Выполнение первоначальной задачи...")
|
||
self.run_sync_job()
|
||
|
||
# Планирование периодического выполнения
|
||
schedule.every(30).minutes.do(self.run_sync_job)
|
||
|
||
self.logger.info("Запуск планировщика задач (каждые 30 минут)")
|
||
|
||
# Основной цикл
|
||
while True:
|
||
schedule.run_pending()
|
||
time.sleep(5)
|
||
|
||
|
||
def main():
|
||
"""Точка входа в приложение"""
|
||
bot = NewsBot()
|
||
|
||
try:
|
||
bot.start()
|
||
except KeyboardInterrupt:
|
||
bot.logger.info("Бот остановлен пользователем")
|
||
except Exception as e:
|
||
bot.logger.error(f"Критическая ошибка бота: {e}")
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main() |