3 Commits

Author SHA1 Message Date
4818cf5b67 fix(dev-scripts): parse all topics from linux-gaming
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-07-11 13:31:28 +05:00
59bfcdbbba feat(dev-scripts): add DEBUG_MODE to disable SSL verification
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-07-11 10:39:06 +05:00
989af36e5b feat(dev-scripts): add environment-based source toggling
Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
2025-07-11 10:29:17 +05:00

View File

@@ -5,12 +5,19 @@ import json
import asyncio import asyncio
import aiohttp import aiohttp
import tarfile import tarfile
import ssl
# Получаем ключи и данные из переменных окружения # Получаем ключи и данные из переменных окружения
STEAM_KEY = os.environ.get('STEAM_KEY') STEAM_KEY = os.environ.get('STEAM_KEY')
LINUX_GAMING_API_KEY = os.environ.get('LINUX_GAMING_API_KEY') LINUX_GAMING_API_KEY = os.environ.get('LINUX_GAMING_API_KEY')
LINUX_GAMING_API_USERNAME = os.environ.get('LINUX_GAMING_API_USERNAME') LINUX_GAMING_API_USERNAME = os.environ.get('LINUX_GAMING_API_USERNAME')
# Флаги для включения/отключения источников
ENABLE_STEAM = os.environ.get('ENABLE_STEAM', 'true').lower() == 'true'
ENABLE_ANTICHEAT = os.environ.get('ENABLE_ANTICHEAT', 'true').lower() == 'true'
ENABLE_LINUX_GAMING = os.environ.get('ENABLE_LINUX_GAMING', 'true').lower() == 'true'
DEBUG_MODE = os.environ.get('DEBUG_MODE', 'false').lower() == 'true'
# Конфигурация API # Конфигурация API
STEAM_BASE_URL = "https://api.steampowered.com/IStoreService/GetAppList/v1/?" STEAM_BASE_URL = "https://api.steampowered.com/IStoreService/GetAppList/v1/?"
LINUX_GAMING_BASE_URL = "https://linux-gaming.ru" LINUX_GAMING_BASE_URL = "https://linux-gaming.ru"
@@ -21,6 +28,10 @@ LINUX_GAMING_HEADERS = {
"Api-Username": LINUX_GAMING_API_USERNAME "Api-Username": LINUX_GAMING_API_USERNAME
} }
# Отключаем предупреждения об SSL в дебаг-режиме
if DEBUG_MODE:
print("DEBUG_MODE enabled: SSL verification is disabled (insecure, use for debugging only).")
def normalize_name(s): def normalize_name(s):
""" """
Приведение строки к нормальному виду: Приведение строки к нормальному виду:
@@ -69,7 +80,7 @@ async def get_app_list(session, last_appid, endpoint):
url = endpoint url = endpoint
if last_appid: if last_appid:
url = f"{url}&last_appid={last_appid}" url = f"{url}&last_appid={last_appid}"
async with session.get(url) as response: async with session.get(url, verify_ssl=not DEBUG_MODE) as response:
response.raise_for_status() response.raise_for_status()
return await response.json() return await response.json()
@@ -79,7 +90,7 @@ async def fetch_games_json(session):
""" """
url = "https://raw.githubusercontent.com/AreWeAntiCheatYet/AreWeAntiCheatYet/HEAD/games.json" url = "https://raw.githubusercontent.com/AreWeAntiCheatYet/AreWeAntiCheatYet/HEAD/games.json"
try: try:
async with session.get(url) as response: async with session.get(url, verify_ssl=not DEBUG_MODE) as response:
response.raise_for_status() response.raise_for_status()
text = await response.text() text = await response.text()
data = json.loads(text) data = json.loads(text)
@@ -89,52 +100,130 @@ async def fetch_games_json(session):
return [] return []
async def get_linux_gaming_topics(session, category_slug): async def get_linux_gaming_topics(session, category_slug):
"""
Получает все темы из указанной категории linux-gaming.ru.
Сохраняет только нормализованное название (normalized_title) и slug.
"""
page = 0 page = 0
all_topics = [] all_topics = []
max_pages = 100
while True: while page < max_pages:
page += 1 # Пробуем несколько вариантов URL
url = f"{LINUX_GAMING_BASE_URL}/c/{category_slug}/l/latest.json?page={page}" urls_to_try = [
try: f"{LINUX_GAMING_BASE_URL}/c/{category_slug}/5/l/latest.json", # с id категории
async with session.get(url, headers=LINUX_GAMING_HEADERS) as response: f"{LINUX_GAMING_BASE_URL}/c/{category_slug}/l/latest.json", # только slug
response.raise_for_status() f"{LINUX_GAMING_BASE_URL}/c/5/l/latest.json", # только id
data = await response.json() f"{LINUX_GAMING_BASE_URL}/latest.json" # все темы
topics = data.get("topic_list", {}).get("topics", []) ]
if not topics:
success = False
data = None
for url in urls_to_try:
try:
# Добавляем параметры пагинации
params = {
'page': page,
'order': 'default'
}
async with session.get(url, headers=LINUX_GAMING_HEADERS,
params=params, verify_ssl=not DEBUG_MODE) as response:
if response.status == 429:
print(f"Слишком много запросов на странице {page}, ожидание...")
await asyncio.sleep(5)
continue
if response.status == 404:
if DEBUG_MODE:
print(f"URL не найден: {url}")
continue
response.raise_for_status()
data = await response.json()
# Проверяем структуру ответа
topic_list = data.get("topic_list", {})
topics = topic_list.get("topics", [])
if not topics:
if page == 0:
if DEBUG_MODE:
print(f"Нет тем в URL: {url}")
continue
else:
print(f"Страница {page} пуста, завершаем пагинацию.")
return all_topics
if DEBUG_MODE and page == 0:
print(f"Успешно подключились к URL: {url}")
success = True
break break
for topic in topics:
all_topics.append({ except Exception as e:
"normalized_title": normalize_name(topic["title"]), if DEBUG_MODE:
"slug": topic["slug"] print(f"Ошибка с URL {url}: {e}")
}) continue
print(f"Обработано {len(topics)} тем на странице {page}, всего: {len(all_topics)}.")
except Exception as error: if not success:
print(f"Ошибка получения тем для страницы {page}: {error}") print(f"Не удалось загрузить страницу {page}")
break break
# Обрабатываем темы (этот блок должен быть внутри основного цикла)
try:
topic_list = data.get("topic_list", {})
topics = topic_list.get("topics", [])
page_topics_added = 0
for topic in topics:
slug = topic["slug"]
# Пропускаем тему описания категории
if slug is None or slug == "opisanie-kategorii-portprotondb":
if DEBUG_MODE:
print(f"Пропущена тема описания категории")
continue
normalized_title = normalize_name(topic["title"])
# Добавляем только валидные темы
all_topics.append({
"normalized_title": normalized_title,
"slug": slug,
})
page_topics_added += 1
if DEBUG_MODE and page_topics_added <= 3: # Показываем первые 3 темы
print(f"Добавлена тема: {normalized_title} (slug: {slug}")
print(f"Обработано {len(topics)} тем на странице {page}, добавлено: {page_topics_added}, всего: {len(all_topics)}.")
# Проверяем, есть ли еще страницы
more_topics_url = topic_list.get("more_topics_url")
if not more_topics_url:
print("Больше тем нет, завершаем пагинацию.")
break
page += 1
# Добавляем небольшую задержку между запросами
await asyncio.sleep(0.5)
except Exception as e:
print(f"Ошибка при обработке тем на странице {page}: {e}")
break
if not all_topics:
print("Предупреждение: не удалось получить ни одной темы из linux-gaming.ru.")
else:
print(f"Всего получено {len(all_topics)} тем из категории {category_slug}")
return all_topics return all_topics
async def request_data(): async def request_data():
""" """
Получает данные из Steam, AreWeAntiCheatYet и linux-gaming.ru, Получает данные из Steam, AreWeAntiCheatYet и linux-gaming.ru,
обрабатывает их и сохраняет в JSON-файлы и tar.xz архивы. обрабатывает их и сохраняет в JSON-файлы и tar.xz архивы.
""" """
# Параметры запроса для Steam
game_param = "&include_games=true"
dlc_param = "&include_dlc=false"
software_param = "&include_software=false"
videos_param = "&include_videos=false"
hardware_param = "&include_hardware=false"
endpoint = (
f"{STEAM_BASE_URL}key={STEAM_KEY}"
f"{game_param}{dlc_param}{software_param}{videos_param}{hardware_param}"
f"&max_results=50000"
)
output_json = [] output_json = []
total_parsed = 0 total_parsed = 0
linux_gaming_topics = [] linux_gaming_topics = []
@@ -143,26 +232,48 @@ async def request_data():
try: try:
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
# Загружаем данные Steam # Загружаем данные Steam
have_more_results = True if ENABLE_STEAM:
last_appid_val = None # Параметры запроса для Steam
while have_more_results: game_param = "&include_games=true"
app_list = await get_app_list(session, last_appid_val, endpoint) dlc_param = "&include_dlc=false"
apps = app_list['response']['apps'] software_param = "&include_software=false"
apps = process_steam_apps(apps) videos_param = "&include_videos=false"
output_json.extend(apps) hardware_param = "&include_hardware=false"
total_parsed += len(apps)
have_more_results = app_list['response'].get('have_more_results', False) endpoint = (
last_appid_val = app_list['response'].get('last_appid') f"{STEAM_BASE_URL}key={STEAM_KEY}"
print(f"Обработано {len(apps)} игр Steam, всего: {total_parsed}.") f"{game_param}{dlc_param}{software_param}{videos_param}{hardware_param}"
f"&max_results=50000"
)
have_more_results = True
last_appid_val = None
while have_more_results:
app_list = await get_app_list(session, last_appid_val, endpoint)
apps = app_list['response']['apps']
apps = process_steam_apps(apps)
output_json.extend(apps)
total_parsed += len(apps)
have_more_results = app_list['response'].get('have_more_results', False)
last_appid_val = app_list['response'].get('last_appid')
print(f"Обработано {len(apps)} игр Steam, всего: {total_parsed}.")
else:
print("Пропущена загрузка данных Steam (ENABLE_STEAM=false).")
# Загружаем данные AreWeAntiCheatYet # Загружаем данные AreWeAntiCheatYet
anticheat_games = await fetch_games_json(session) if ENABLE_ANTICHEAT:
anticheat_games = await fetch_games_json(session)
else:
print("Пропущена загрузка данных AreWeAntiCheatYet (ENABLE_ANTICHEAT=false).")
# Загружаем данные linux-gaming.ru # Загружаем данные linux-gaming.ru
if LINUX_GAMING_API_KEY and LINUX_GAMING_API_USERNAME: if ENABLE_LINUX_GAMING:
linux_gaming_topics = await get_linux_gaming_topics(session, CATEGORY_LINUX_GAMING) if LINUX_GAMING_API_KEY and LINUX_GAMING_API_USERNAME:
linux_gaming_topics = await get_linux_gaming_topics(session, CATEGORY_LINUX_GAMING)
else:
print("Предупреждение: LINUX_GAMING_API_KEY или LINUX_GAMING_API_USERNAME не установлены.")
else: else:
print("Предупреждение: LINUX_GAMING_API_KEY или LINUX_GAMING_API_USERNAME не установлены.") print("Пропущена загрузка данных linux-gaming.ru (ENABLE_LINUX_GAMING=false).")
except Exception as error: except Exception as error:
print(f"Ошибка получения данных: {error}") print(f"Ошибка получения данных: {error}")
@@ -173,55 +284,55 @@ async def request_data():
os.makedirs(data_dir, exist_ok=True) os.makedirs(data_dir, exist_ok=True)
# Сохранение данных Steam # Сохранение данных Steam
output_json_full = os.path.join(data_dir, f"{CATEGORY_STEAM}_appid.json") if ENABLE_STEAM and output_json:
output_json_min = os.path.join(data_dir, f"{CATEGORY_STEAM}_appid_min.json") output_json_full = os.path.join(data_dir, f"{CATEGORY_STEAM}_appid.json")
with open(output_json_full, "w", encoding="utf-8") as f: output_json_min = os.path.join(data_dir, f"{CATEGORY_STEAM}_appid_min.json")
json.dump(output_json, f, ensure_ascii=False, indent=2) with open(output_json_full, "w", encoding="utf-8") as f:
with open(output_json_min, "w", encoding="utf-8") as f: json.dump(output_json, f, ensure_ascii=False, indent=2)
json.dump(output_json, f, ensure_ascii=False, separators=(',',':')) with open(output_json_min, "w", encoding="utf-8") as f:
json.dump(output_json, f, ensure_ascii=False, separators=(',',':'))
# Упаковка минифицированного JSON Steam в tar.xz архив
steam_archive_path = os.path.join(data_dir, f"{CATEGORY_STEAM}_appid.tar.xz")
try:
with tarfile.open(steam_archive_path, "w:xz", preset=9) as tar:
tar.add(output_json_min, arcname=os.path.basename(output_json_min))
print(f"Упаковано минифицированное JSON Steam в архив: {steam_archive_path}")
os.remove(output_json_min)
except Exception as e:
print(f"Ошибка при упаковке архива Steam: {e}")
return False
# Сохранение данных AreWeAntiCheatYet # Сохранение данных AreWeAntiCheatYet
anticheat_json_full = os.path.join(data_dir, "anticheat_games.json") if ENABLE_ANTICHEAT and anticheat_games:
anticheat_json_min = os.path.join(data_dir, "anticheat_games_min.json") anticheat_json_full = os.path.join(data_dir, "anticheat_games.json")
with open(anticheat_json_full, "w", encoding="utf-8") as f: anticheat_json_min = os.path.join(data_dir, "anticheat_games_min.json")
json.dump(anticheat_games, f, ensure_ascii=False, indent=2) with open(anticheat_json_full, "w", encoding="utf-8") as f:
with open(anticheat_json_min, "w", encoding="utf-8") as f: json.dump(anticheat_games, f, ensure_ascii=False, indent=2)
json.dump(anticheat_games, f, ensure_ascii=False, separators=(',',':')) with open(anticheat_json_min, "w", encoding="utf-8") as f:
json.dump(anticheat_games, f, ensure_ascii=False, separators=(',',':'))
# Упаковка минифицированного JSON AreWeAntiCheatYet в tar.xz архив
anticheat_archive_path = os.path.join(data_dir, "anticheat_games.tar.xz")
try:
with tarfile.open(anticheat_archive_path, "w:xz", preset=9) as tar:
tar.add(anticheat_json_min, arcname=os.path.basename(anticheat_json_min))
print(f"Упаковано минифицированное JSON AreWeAntiCheatYet в архив: {anticheat_archive_path}")
os.remove(anticheat_json_min)
except Exception as e:
print(f"Ошибка при упаковке архива AreWeAntiCheatYet: {e}")
return False
# Сохранение данных linux-gaming.ru # Сохранение данных linux-gaming.ru
linux_gaming_json_full = os.path.join(data_dir, "linux_gaming_topics.json") if ENABLE_LINUX_GAMING and linux_gaming_topics:
linux_gaming_json_min = os.path.join(data_dir, "linux_gaming_topics_min.json") linux_gaming_json_full = os.path.join(data_dir, "linux_gaming_topics.json")
if linux_gaming_topics: linux_gaming_json_min = os.path.join(data_dir, "linux_gaming_topics_min.json")
with open(linux_gaming_json_full, "w", encoding="utf-8") as f: with open(linux_gaming_json_full, "w", encoding="utf-8") as f:
json.dump(linux_gaming_topics, f, ensure_ascii=False, indent=2) json.dump(linux_gaming_topics, f, ensure_ascii=False, indent=2)
with open(linux_gaming_json_min, "w", encoding="utf-8") as f: with open(linux_gaming_json_min, "w", encoding="utf-8") as f:
json.dump(linux_gaming_topics, f, ensure_ascii=False, separators=(',',':')) json.dump(linux_gaming_topics, f, ensure_ascii=False, separators=(',',':'))
# Упаковка минифицированных JSON в tar.xz архивы # Упаковка минифицированного JSON linux-gaming.ru в tar.xz архив
# Архив для Steam
steam_archive_path = os.path.join(data_dir, f"{CATEGORY_STEAM}_appid.tar.xz")
try:
with tarfile.open(steam_archive_path, "w:xz", preset=9) as tar:
tar.add(output_json_min, arcname=os.path.basename(output_json_min))
print(f"Упаковано минифицированное JSON Steam в архив: {steam_archive_path}")
os.remove(output_json_min)
except Exception as e:
print(f"Ошибка при упаковке архива Steam: {e}")
return False
# Архив для AreWeAntiCheatYet
anticheat_archive_path = os.path.join(data_dir, "anticheat_games.tar.xz")
try:
with tarfile.open(anticheat_archive_path, "w:xz", preset=9) as tar:
tar.add(anticheat_json_min, arcname=os.path.basename(anticheat_json_min))
print(f"Упаковано минифицированное JSON AreWeAntiCheatYet в архив: {anticheat_archive_path}")
os.remove(anticheat_json_min)
except Exception as e:
print(f"Ошибка при упаковке архива AreWeAntiCheatYet: {e}")
return False
# Архив для linux-gaming.ru
if linux_gaming_topics:
linux_gaming_archive_path = os.path.join(data_dir, "linux_gaming_topics.tar.xz") linux_gaming_archive_path = os.path.join(data_dir, "linux_gaming_topics.tar.xz")
try: try:
with tarfile.open(linux_gaming_archive_path, "w:xz", preset=9) as tar: with tarfile.open(linux_gaming_archive_path, "w:xz", preset=9) as tar: