Compare commits
	
		
			1 Commits
		
	
	
		
			v0.1.8
			...
			3736bb279e
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 3736bb279e | 
| @@ -83,6 +83,43 @@ def load_pixmap_async(cover: str, width: int, height: int, callback: Callable[[Q | ||||
|             except Exception as e: | ||||
|                 logger.error(f"Ошибка обработки URL {cover}: {e}") | ||||
|  | ||||
|         # SteamGridDB (SGDB) | ||||
|         if cover and cover.startswith("https://cdn2.steamgriddb.com"): | ||||
|             try: | ||||
|                 parts = cover.split("/") | ||||
|                 filename = parts[-1] if parts else "sgdb_cover.png" | ||||
|                 # SGDB ссылки содержат уникальный хеш в названии — используем как имя | ||||
|                 local_path = os.path.join(image_folder, filename) | ||||
|  | ||||
|                 if os.path.exists(local_path): | ||||
|                     pixmap = QPixmap(local_path) | ||||
|                     finish_with(pixmap) | ||||
|                     return | ||||
|  | ||||
|                 def on_downloaded(result: str | None): | ||||
|                     pixmap = QPixmap() | ||||
|                     if result and os.path.exists(result): | ||||
|                         pixmap.load(result) | ||||
|                     if pixmap.isNull(): | ||||
|                         placeholder_path = theme_manager.get_theme_image("placeholder", current_theme_name) | ||||
|                         if placeholder_path and QFile.exists(placeholder_path): | ||||
|                             pixmap.load(placeholder_path) | ||||
|                         else: | ||||
|                             pixmap = QPixmap(width, height) | ||||
|                             pixmap.fill(QColor("#333333")) | ||||
|                             painter = QPainter(pixmap) | ||||
|                             painter.setPen(QPen(QColor("white"))) | ||||
|                             painter.drawText(pixmap.rect(), Qt.AlignmentFlag.AlignCenter, "No Image") | ||||
|                             painter.end() | ||||
|                     finish_with(pixmap) | ||||
|  | ||||
|                 logger.info("Downloading SGDB cover for %s -> %s", app_name or "unknown", filename) | ||||
|                 downloader.download_async(cover, local_path, timeout=5, callback=on_downloaded) | ||||
|                 return | ||||
|  | ||||
|             except Exception as e: | ||||
|                 logger.error(f"Ошибка обработки SGDB URL {cover}: {e}") | ||||
|  | ||||
|         if cover and cover.startswith(("http://", "https://")): | ||||
|             try: | ||||
|                 local_path = os.path.join(image_folder, f"{app_name}.jpg") | ||||
|   | ||||
| @@ -23,6 +23,7 @@ import requests | ||||
| import random | ||||
| import base64 | ||||
| import glob | ||||
| import urllib.parse | ||||
|  | ||||
| downloader = Downloader() | ||||
| logger = get_logger(__name__) | ||||
| @@ -411,6 +412,39 @@ def save_app_details(app_id, data): | ||||
|     with open(cache_file, "wb") as f: | ||||
|         f.write(orjson.dumps(data)) | ||||
|  | ||||
| def fetch_sgdb_cover(game_name: str) -> str: | ||||
|     """ | ||||
|     Fetch a cover image URL from steamgrid.usebottles.com for the given game. | ||||
|     The API returns a single string (quoted URL). | ||||
|     """ | ||||
|     try: | ||||
|         encoded = urllib.parse.quote(game_name) | ||||
|         url = f"https://steamgrid.usebottles.com/api/search/{encoded}" | ||||
|         resp = requests.get(url, timeout=5) | ||||
|         if resp.status_code != 200: | ||||
|             logger.warning("SGDB request failed for %s: %s", game_name, resp.status_code) | ||||
|             return "" | ||||
|         text = resp.text.strip() | ||||
|         # Убираем возможные кавычки вокруг строки | ||||
|         if text.startswith('"') and text.endswith('"'): | ||||
|             text = text[1:-1] | ||||
|         if text: | ||||
|             logger.info("Fetched SGDB cover for %s: %s", game_name, text) | ||||
|         return text | ||||
|     except Exception as e: | ||||
|         logger.warning("Failed to fetch SGDB cover for %s: %s", game_name, e) | ||||
|     return "" | ||||
|  | ||||
|  | ||||
| def check_url_exists(url: str) -> bool: | ||||
|     """Check whether a URL returns HTTP 200.""" | ||||
|     try: | ||||
|         r = requests.head(url, timeout=3) | ||||
|         return r.status_code == 200 | ||||
|     except Exception: | ||||
|         return False | ||||
|  | ||||
|  | ||||
| def fetch_app_info_async(app_id: int, callback: Callable[[dict | None], None]): | ||||
|     """ | ||||
|     Asynchronously fetches detailed app info from Steam API. | ||||
| @@ -629,6 +663,11 @@ def get_full_steam_game_info_async(appid: int, callback: Callable[[dict], None]) | ||||
|         title = decode_text(app_info.get("name", "")) | ||||
|         description = decode_text(app_info.get("short_description", "")) | ||||
|         cover = f"https://steamcdn-a.akamaihd.net/steam/apps/{appid}/library_600x900_2x.jpg" | ||||
|         if not check_url_exists(cover): | ||||
|             logger.info("Steam cover not found for %s, trying SGDB", title) | ||||
|             alt_cover = fetch_sgdb_cover(title) | ||||
|             if alt_cover: | ||||
|                 cover = alt_cover | ||||
|  | ||||
|         def on_protondb_tier(tier: str): | ||||
|             def on_anticheat_status(anticheat_status: str): | ||||
| @@ -722,12 +761,15 @@ def get_steam_game_info_async(desktop_name: str, exec_line: str, callback: Calla | ||||
|         game_name = desktop_name or exe_name.capitalize() | ||||
|  | ||||
|         if not matching_app: | ||||
|             cover = fetch_sgdb_cover(game_name) or "" | ||||
|             logger.info("Using SGDB cover for non-Steam game '%s': %s", game_name, cover) | ||||
|  | ||||
|             def on_anticheat_status(anticheat_status: str): | ||||
|                 callback({ | ||||
|                     "appid": "", | ||||
|                     "name": decode_text(game_name), | ||||
|                     "description": "", | ||||
|                     "cover": "", | ||||
|                     "cover": cover, | ||||
|                     "controller_support": "", | ||||
|                     "protondb_tier": "", | ||||
|                     "steam_game": "false", | ||||
| @@ -758,6 +800,11 @@ def get_steam_game_info_async(desktop_name: str, exec_line: str, callback: Calla | ||||
|             title = decode_text(app_info.get("name", game_name)) | ||||
|             description = decode_text(app_info.get("short_description", "")) | ||||
|             cover = f"https://steamcdn-a.akamaihd.net/steam/apps/{appid}/library_600x900_2x.jpg" | ||||
|             if not check_url_exists(cover): | ||||
|                 logger.info("Steam cover not found for %s, trying SGDB", title) | ||||
|                 alt_cover = fetch_sgdb_cover(title) | ||||
|                 if alt_cover: | ||||
|                     cover = alt_cover | ||||
|             controller_support = app_info.get("controller_support", "") | ||||
|  | ||||
|             def on_protondb_tier(tier: str): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user