diff --git a/portprotonqt/context_menu_manager.py b/portprotonqt/context_menu_manager.py index 4773d62..1d0de62 100644 --- a/portprotonqt/context_menu_manager.py +++ b/portprotonqt/context_menu_manager.py @@ -1035,7 +1035,15 @@ Icon={icon_path} ) return - if os.path.isfile(new_cover_path): + # Check if new_cover_path is a URL by checking for common image extensions + image_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp') + has_image_extension = any(new_cover_path.lower().endswith(ext) for ext in image_extensions) + + # Consider it a URL if it has image extension and is not a local file + is_url = has_image_extension and not os.path.isfile(new_cover_path) + + # Use the downloaded file path if we have a URL and the file was downloaded, otherwise use the local file + if os.path.isfile(new_cover_path) or (is_url and dialog.last_cover_path and os.path.isfile(dialog.last_cover_path)): exe_name = os.path.splitext(os.path.basename(new_exe_path))[0] xdg_data_home = os.getenv( "XDG_DATA_HOME", @@ -1043,16 +1051,25 @@ Icon={icon_path} ) custom_folder = os.path.join(xdg_data_home, "PortProtonQt", "custom_data", exe_name) os.makedirs(custom_folder, exist_ok=True) - ext = os.path.splitext(new_cover_path)[1].lower() + + # Use the actual cover file path (either from URL download or local file) + cover_to_copy = dialog.last_cover_path if is_url and dialog.last_cover_path and os.path.isfile(dialog.last_cover_path) else new_cover_path + ext = os.path.splitext(cover_to_copy)[1].lower() if ext in [".png", ".jpg", ".jpeg", ".bmp"]: try: - shutil.copyfile(new_cover_path, os.path.join(custom_folder, f"cover{ext}")) + shutil.copyfile(cover_to_copy, os.path.join(custom_folder, f"cover{ext}")) except OSError as e: self.signals.show_warning_dialog.emit( _("Error"), _("Failed to copy cover image: {error}").format(error=str(e)) ) return + else: + self.signals.show_warning_dialog.emit( + _("Error"), + _("Unsupported image format: {extension}").format(extension=ext) + ) + return def add_to_steam(self, game_name, exec_line, cover_path): """ diff --git a/portprotonqt/dialogs.py b/portprotonqt/dialogs.py index 61857c1..9a9a779 100644 --- a/portprotonqt/dialogs.py +++ b/portprotonqt/dialogs.py @@ -906,6 +906,7 @@ class AddGameDialog(QDialog): self.coverEdit = CustomLineEdit(self, theme=self.theme) self.coverEdit.setStyleSheet(self.theme.ADDGAME_INPUT_STYLE) + self.coverEdit.setPlaceholderText(_("Enter local path or URL for cover image")) if cover_path: self.coverEdit.setText(cover_path) @@ -949,7 +950,12 @@ class AddGameDialog(QDialog): # Подключение сигналов self.select_button.clicked.connect(self.accept) self.cancel_button.clicked.connect(self.reject) - self.coverEdit.textChanged.connect(self.updatePreview) + # Set up a timer for debounced cover preview updates + self.cover_preview_timer = QTimer(self) + self.cover_preview_timer.setSingleShot(True) + self.cover_preview_timer.timeout.connect(self.updatePreview) + + self.coverEdit.textChanged.connect(self.onCoverTextChanged) self.exeEdit.textChanged.connect(self.updatePreview) # Установка одинаковой ширины для кнопок и полей ввода @@ -1094,22 +1100,32 @@ class AddGameDialog(QDialog): self.coverPreview.setText(_("Failed to download cover")) logger.warning(f"Failed to download cover to {file_path}") + def onCoverTextChanged(self): + """Handle cover text changes with debounce.""" + # Restart the timer to delay the preview update + self.cover_preview_timer.start(500) # 500ms delay + def updatePreview(self): """Update the cover preview image.""" cover_path = self.coverEdit.text().strip() exe_path = self.exeEdit.text().strip() - # Check if cover_path is a URL - url_pattern = r'^https?://[^\s/$.?#].[^\s]*$' - if re.match(url_pattern, cover_path): + # Check if cover_path is a URL by checking for common image extensions + image_extensions = ('.jpg', '.jpeg', '.png', '.bmp', '.gif', '.webp') + has_image_extension = any(cover_path.lower().endswith(ext) for ext in image_extensions) + + # Consider it a URL if it has image extension and is not a local file + if has_image_extension and not os.path.isfile(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 + # Add protocol if not present + download_url = cover_path if cover_path.startswith(('http://', 'https://')) else f'https://{cover_path}' self.downloader.download_async( - url=cover_path, + url=download_url, local_path=local_path, timeout=10, callback=self.handleDownloadedCover