feat(add_game): download cover if link is provided

Signed-off-by: Boris Yumankulov <boria138@altlinux.org>
This commit is contained in:
2025-07-06 17:54:53 +05:00
parent 9a27d67dc0
commit d26b9774a0

View File

@ -1,5 +1,6 @@
import os import os
import tempfile import tempfile
import re
from typing import cast, TYPE_CHECKING from typing import cast, TYPE_CHECKING
from PySide6.QtGui import QPixmap, QIcon from PySide6.QtGui import QPixmap, QIcon
from PySide6.QtWidgets import ( from PySide6.QtWidgets import (
@ -14,6 +15,7 @@ from portprotonqt.logger import get_logger
import portprotonqt.themes.standart.styles as default_styles import portprotonqt.themes.standart.styles as default_styles
from portprotonqt.theme_manager import ThemeManager from portprotonqt.theme_manager import ThemeManager
from portprotonqt.custom_widgets import AutoSizeButton from portprotonqt.custom_widgets import AutoSizeButton
from portprotonqt.downloader import Downloader
if TYPE_CHECKING: if TYPE_CHECKING:
from portprotonqt.main_window import MainWindow from portprotonqt.main_window import MainWindow
@ -449,6 +451,7 @@ class AddGameDialog(QDialog):
self.original_name = game_name self.original_name = game_name
self.last_exe_path = exe_path # Store last selected exe path self.last_exe_path = exe_path # Store last selected exe path
self.last_cover_path = cover_path # Store last selected cover path self.last_cover_path = cover_path # Store last selected cover path
self.downloader = Downloader(max_workers=4) # Initialize Downloader
self.setWindowTitle(_("Edit Game") if edit_mode else _("Add Game")) self.setWindowTitle(_("Edit Game") if edit_mode else _("Add Game"))
self.setModal(True) self.setModal(True)
@ -472,8 +475,7 @@ class AddGameDialog(QDialog):
# Exe path # Exe path
exe_label = QLabel(_("Path to Executable:")) exe_label = QLabel(_("Path to Executable:"))
exe_label.setStyleSheet( exe_label.setStyleSheet(self.theme.PARAMS_TITLE_STYLE)
self.theme.PARAMS_TITLE_STYLE)
self.exeEdit = CustomLineEdit(self, theme=self.theme) self.exeEdit = CustomLineEdit(self, theme=self.theme)
self.exeEdit.setStyleSheet(self.theme.ADDGAME_INPUT_STYLE) self.exeEdit.setStyleSheet(self.theme.ADDGAME_INPUT_STYLE)
@ -550,7 +552,7 @@ class AddGameDialog(QDialog):
exeBrowseButton.setFixedWidth(self.exeEdit.width()) exeBrowseButton.setFixedWidth(self.exeEdit.width())
coverBrowseButton.setFixedWidth(self.coverEdit.width()) coverBrowseButton.setFixedWidth(self.coverEdit.width())
# Вызываем после отображения окна, когда размеры установлены, чтобы реально дождаться, когда всё сформируется # Вызываем после отображения окна, когда размеры установлены
QTimer.singleShot(0, update_button_widths) QTimer.singleShot(0, update_button_widths)
# Обновляем превью, если в режиме редактирования # Обновляем превью, если в режиме редактирования
@ -615,15 +617,46 @@ class AddGameDialog(QDialog):
"""Обработчик выбора файла обложки в FileExplorer""" """Обработчик выбора файла обложки в FileExplorer"""
if file_path and os.path.splitext(file_path)[1].lower() in ('.png', '.jpg', '.jpeg', '.bmp'): if file_path and os.path.splitext(file_path)[1].lower() in ('.png', '.jpg', '.jpeg', '.bmp'):
self.coverEdit.setText(file_path) self.coverEdit.setText(file_path)
self.last_cover_path = file_path # Update last selected cover path self.last_cover_path = file_path
self.updatePreview()
else: else:
logger.warning(f"Selected file is not a valid image: {file_path}") logger.warning(f"Selected file is not a valid image: {file_path}")
def handleDownloadedCover(self, file_path):
"""Handle the downloaded cover image and update the preview."""
if file_path and os.path.isfile(file_path):
self.last_cover_path = file_path
pixmap = QPixmap(file_path)
if not pixmap.isNull():
self.coverPreview.setPixmap(pixmap.scaled(250, 250, Qt.AspectRatioMode.KeepAspectRatio))
else:
self.coverPreview.setText(_("Invalid image"))
else:
self.coverPreview.setText(_("Failed to download cover"))
logger.warning(f"Failed to download cover to {file_path}")
def updatePreview(self): def updatePreview(self):
"""Update the cover preview image.""" """Update the cover preview image."""
cover_path = self.coverEdit.text().strip() cover_path = self.coverEdit.text().strip()
exe_path = self.exeEdit.text().strip() exe_path = self.exeEdit.text().strip()
if cover_path and os.path.isfile(cover_path):
# Check if cover_path is a URL
url_pattern = r'^https?://[^\s/$.?#].[^\s]*$'
if re.match(url_pattern, cover_path):
# Create a temporary file for the downloaded image
fd, local_path = tempfile.mkstemp(suffix=".png")
os.close(fd)
os.unlink(local_path)
# Start asynchronous download
self.downloader.download_async(
url=cover_path,
local_path=local_path,
timeout=10,
callback=self.handleDownloadedCover
)
self.coverPreview.setText(_("Downloading cover..."))
elif cover_path and os.path.isfile(cover_path):
pixmap = QPixmap(cover_path) pixmap = QPixmap(cover_path)
if not pixmap.isNull(): if not pixmap.isNull():
self.coverPreview.setPixmap(pixmap.scaled(250, 250, Qt.AspectRatioMode.KeepAspectRatio)) self.coverPreview.setPixmap(pixmap.scaled(250, 250, Qt.AspectRatioMode.KeepAspectRatio))
@ -666,8 +699,8 @@ class AddGameDialog(QDialog):
os.makedirs(os.path.dirname(icon_path), exist_ok=True) os.makedirs(os.path.dirname(icon_path), exist_ok=True)
# Generate thumbnail (128x128) from exe # Generate thumbnail (128x128) from exe if no cover is provided
if not generate_thumbnail(exe_path, icon_path, size=128): if not self.last_cover_path and not generate_thumbnail(exe_path, icon_path, size=128):
logger.error(f"Failed to generate thumbnail from exe: {exe_path}") logger.error(f"Failed to generate thumbnail from exe: {exe_path}")
icon_path = "" # Set empty icon if generation fails icon_path = "" # Set empty icon if generation fails