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