From c00ef147034af2b71366142055643b49874c8d4f Mon Sep 17 00:00:00 2001 From: oop7 <110548351+oop7@users.noreply.github.com> Date: Sat, 25 Oct 2025 18:10:04 +0300 Subject: [PATCH] Add 'Open Folder' button after download completion Introduces an 'Open Folder' button to the UI, shown after a download completes, allowing users to quickly open the folder containing the downloaded file. Updates all language files to include translations for the new button tooltip. --- languages/ar.json | 3 +- languages/de.json | 3 +- languages/en.json | 3 +- languages/es.json | 3 +- languages/fr.json | 3 +- languages/hi.json | 3 +- languages/id.json | 3 +- languages/it.json | 3 +- languages/ja.json | 3 +- languages/pl.json | 3 +- languages/pt.json | 3 +- languages/ru.json | 3 +- languages/tr.json | 3 +- languages/zh.json | 3 +- src/gui/ytsage_gui_main.py | 86 +++++++++++++++++++++++++++++++++++++- 15 files changed, 113 insertions(+), 15 deletions(-) diff --git a/languages/ar.json b/languages/ar.json index a44b1a3..de6c4c7 100644 --- a/languages/ar.json +++ b/languages/ar.json @@ -80,7 +80,8 @@ "update": "تحديث yt-dlp", "select_defaults": "اختر الافتراضي", "select_all": "تحديد الكل", - "deselect_all": "إلغاء تحديد الكل" + "deselect_all": "إلغاء تحديد الكل", + "open_folder": "فتح موقع المجلد" }, "dialogs": { "custom_options": "خيارات مخصصة", diff --git a/languages/de.json b/languages/de.json index f6388f7..70183d1 100644 --- a/languages/de.json +++ b/languages/de.json @@ -80,7 +80,8 @@ "update": "yt-dlp aktualisieren", "select_defaults": "Standard auswählen", "select_all": "Alle auswählen", - "deselect_all": "Alle abwählen" + "deselect_all": "Alle abwählen", + "open_folder": "Ordnerspeicherort öffnen" }, "dialogs": { "custom_options": "Benutzerdefinierte Optionen", diff --git a/languages/en.json b/languages/en.json index 41b3fae..5d742da 100644 --- a/languages/en.json +++ b/languages/en.json @@ -80,7 +80,8 @@ "update": "Update yt-dlp", "select_defaults": "Select Defaults", "select_all": "Select All", - "deselect_all": "Deselect All" + "deselect_all": "Deselect All", + "open_folder": "Open folder location" }, "dialogs": { "custom_options": "Custom Options", diff --git a/languages/es.json b/languages/es.json index 10f644c..a98b2f9 100644 --- a/languages/es.json +++ b/languages/es.json @@ -47,7 +47,8 @@ "download_settings": "Configuración de Descarga", "select_defaults": "Seleccionar Predeterminados", "select_all": "Seleccionar Todos", - "deselect_all": "Deseleccionar Todos" + "deselect_all": "Deseleccionar Todos", + "open_folder": "Abrir ubicación de carpeta" }, "dialogs": { "custom_options": "Opciones Personalizadas", diff --git a/languages/fr.json b/languages/fr.json index 89c6ade..bffc2d2 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -80,7 +80,8 @@ "update": "Mettre à jour yt-dlp", "select_defaults": "Sélectionner par défaut", "select_all": "Tout sélectionner", - "deselect_all": "Tout désélectionner" + "deselect_all": "Tout désélectionner", + "open_folder": "Ouvrir l'emplacement du dossier" }, "dialogs": { "custom_options": "Options personnalisées", diff --git a/languages/hi.json b/languages/hi.json index b69ad8e..c947f46 100644 --- a/languages/hi.json +++ b/languages/hi.json @@ -80,7 +80,8 @@ "update": "yt-dlp अपडेट करें", "select_defaults": "डिफ़ॉल्ट चुनें", "select_all": "सभी चुनें", - "deselect_all": "सभी को अचयनित करें" + "deselect_all": "सभी को अचयनित करें", + "open_folder": "फ़ोल्डर स्थान खोलें" }, "dialogs": { "custom_options": "कस्टम विकल्प", diff --git a/languages/id.json b/languages/id.json index d97d6ea..edac6a3 100644 --- a/languages/id.json +++ b/languages/id.json @@ -80,7 +80,8 @@ "update": "Perbarui yt-dlp", "select_defaults": "Pilih default", "select_all": "Pilih semua", - "deselect_all": "Batalkan pilihan semua" + "deselect_all": "Batalkan pilihan semua", + "open_folder": "Buka lokasi folder" }, "dialogs": { "custom_options": "Opsi khusus", diff --git a/languages/it.json b/languages/it.json index a7e7179..c0d0535 100644 --- a/languages/it.json +++ b/languages/it.json @@ -80,7 +80,8 @@ "update": "Aggiorna yt-dlp", "select_defaults": "Seleziona predefiniti", "select_all": "Seleziona tutto", - "deselect_all": "Deseleziona tutto" + "deselect_all": "Deseleziona tutto", + "open_folder": "Apri posizione cartella" }, "dialogs": { "custom_options": "Opzioni personalizzate", diff --git a/languages/ja.json b/languages/ja.json index 3c5c8a8..691b6dd 100644 --- a/languages/ja.json +++ b/languages/ja.json @@ -80,7 +80,8 @@ "update": "yt-dlpを更新", "select_defaults": "デフォルトを選択", "select_all": "すべて選択", - "deselect_all": "すべて解除" + "deselect_all": "すべて解除", + "open_folder": "フォルダの場所を開く" }, "dialogs": { "custom_options": "カスタムオプション", diff --git a/languages/pl.json b/languages/pl.json index 57b6dbf..c444f06 100644 --- a/languages/pl.json +++ b/languages/pl.json @@ -80,7 +80,8 @@ "update": "Zaktualizuj yt-dlp", "select_defaults": "Wybierz domyślne", "select_all": "Zaznacz wszystko", - "deselect_all": "Odznacz wszystko" + "deselect_all": "Odznacz wszystko", + "open_folder": "Otwórz lokalizację folderu" }, "dialogs": { "custom_options": "Opcje niestandardowe", diff --git a/languages/pt.json b/languages/pt.json index 14e2d9a..cd388e3 100644 --- a/languages/pt.json +++ b/languages/pt.json @@ -80,7 +80,8 @@ "update": "Atualizar yt-dlp", "select_defaults": "Selecionar Padrões", "select_all": "Selecionar Tudo", - "deselect_all": "Desmarcar Tudo" + "deselect_all": "Desmarcar Tudo", + "open_folder": "Abrir local da pasta" }, "dialogs": { "custom_options": "Opções Personalizadas", diff --git a/languages/ru.json b/languages/ru.json index 2d519d5..d29f441 100644 --- a/languages/ru.json +++ b/languages/ru.json @@ -80,7 +80,8 @@ "update": "Обновить yt-dlp", "select_defaults": "Выбрать по умолчанию", "select_all": "Выбрать всё", - "deselect_all": "Снять выделение" + "deselect_all": "Снять выделение", + "open_folder": "Открыть расположение папки" }, "dialogs": { "custom_options": "Пользовательские опции", diff --git a/languages/tr.json b/languages/tr.json index 4bec2f2..c23f164 100644 --- a/languages/tr.json +++ b/languages/tr.json @@ -80,7 +80,8 @@ "update": "yt-dlp'yi güncelle", "select_defaults": "Varsayılanları seç", "select_all": "Tümünü seç", - "deselect_all": "Tüm seçimi kaldır" + "deselect_all": "Tüm seçimi kaldır", + "open_folder": "Klasör konumunu aç" }, "dialogs": { "custom_options": "Özel seçenekler", diff --git a/languages/zh.json b/languages/zh.json index 7d8887a..79c2e1f 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -80,7 +80,8 @@ "update": "更新 yt-dlp", "select_defaults": "选择默认值", "select_all": "全选", - "deselect_all": "取消全选" + "deselect_all": "取消全选", + "open_folder": "打开文件夹位置" }, "dialogs": { "custom_options": "自定义选项", diff --git a/src/gui/ytsage_gui_main.py b/src/gui/ytsage_gui_main.py index d7cbdd2..3d0eaae 100644 --- a/src/gui/ytsage_gui_main.py +++ b/src/gui/ytsage_gui_main.py @@ -645,6 +645,9 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from ) progress_layout.addWidget(self.download_details_label) + # Create a horizontal layout for status label and open folder button + status_layout = QHBoxLayout() + self.status_label = QLabel(_("app.ready")) self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter) self.status_label.setStyleSheet( @@ -656,7 +659,36 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from } """ ) - progress_layout.addWidget(self.status_label) + status_layout.addWidget(self.status_label) + + # Add "Open Folder" button (initially hidden) + self.open_folder_btn = QPushButton("📁") + self.open_folder_btn.setToolTip(_("buttons.open_folder")) + self.open_folder_btn.setFixedSize(30, 30) + self.open_folder_btn.setStyleSheet( + """ + QPushButton { + background-color: #2a2d2e; + color: #cccccc; + border: 1px solid #404040; + border-radius: 5px; + font-size: 16px; + padding: 2px; + } + QPushButton:hover { + background-color: #3a3d3e; + border: 1px solid #505050; + } + QPushButton:pressed { + background-color: #1a1d1e; + } + """ + ) + self.open_folder_btn.clicked.connect(self.open_download_folder) + self.open_folder_btn.setVisible(False) # Hidden by default + status_layout.addWidget(self.open_folder_btn) + + progress_layout.addLayout(status_layout) layout.addLayout(progress_layout) @@ -970,6 +1002,7 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from # Show preparation message self.status_label.setText(_('download.preparing')) self.progress_bar.setValue(0) + self.open_folder_btn.setVisible(False) # Hide the open folder button on new download # Get resolution for filename resolution = "default" @@ -1081,10 +1114,61 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from # Default case else: self.status_label.setText(_('download.completed')) + + # Show the open folder button + self.open_folder_btn.setVisible(True) # Play notification sound when download completes self.play_notification_sound() + def open_download_folder(self) -> None: + """Open the folder containing the downloaded file and select it if possible""" + try: + if self.download_thread and self.download_thread.last_file_path: + file_path = Path(self.download_thread.last_file_path) + + if file_path.exists(): + # On Windows, use explorer with /select to highlight the file + if subprocess.sys.platform == "win32": + subprocess.run(['explorer', '/select,', str(file_path)], creationflags=SUBPROCESS_CREATIONFLAGS) + # On macOS, use open with -R to reveal in Finder + elif subprocess.sys.platform == "darwin": + subprocess.run(['open', '-R', str(file_path)]) + # On Linux, try to open the folder (file selection not widely supported) + else: + folder_path = file_path.parent + subprocess.run(['xdg-open', str(folder_path)]) + + logger.info(f"Opened folder for: {file_path}") + else: + # If file doesn't exist, just open the download folder + folder_path = Path(self.last_path) + if folder_path.exists(): + if subprocess.sys.platform == "win32": + subprocess.run(['explorer', str(folder_path)], creationflags=SUBPROCESS_CREATIONFLAGS) + elif subprocess.sys.platform == "darwin": + subprocess.run(['open', str(folder_path)]) + else: + subprocess.run(['xdg-open', str(folder_path)]) + else: + logger.warning(f"Download folder does not exist: {folder_path}") + else: + # Fallback to opening the general download folder + folder_path = Path(self.last_path) + if folder_path.exists(): + if subprocess.sys.platform == "win32": + subprocess.run(['explorer', str(folder_path)], creationflags=SUBPROCESS_CREATIONFLAGS) + elif subprocess.sys.platform == "darwin": + subprocess.run(['open', str(folder_path)]) + else: + subprocess.run(['xdg-open', str(folder_path)]) + else: + logger.warning(f"Download folder does not exist: {folder_path}") + + except Exception as e: + logger.exception(f"Error opening download folder: {e}") + QMessageBox.warning(self, "Error", f"Could not open folder: {str(e)}") + def download_error(self, error_message) -> None: self.toggle_download_controls(True) self.pause_btn.setVisible(False)