From 4c07423b49429b81e1405ce0f5a1a8c465706294 Mon Sep 17 00:00:00 2001 From: oop7 <110548351+oop7@users.noreply.github.com> Date: Wed, 12 Nov 2025 22:09:58 +0200 Subject: [PATCH] Add yt-dlp release channel selection to updater UI Introduces UI elements and logic for selecting between stable and nightly yt-dlp release channels in the updater tab, with support for switching channels and displaying status. Updates all language files with new strings for channel selection and status messages, and adds a default 'ytdlp_channel' config key. --- languages/ar.json | 8 + languages/de.json | 8 + languages/en.json | 8 + languages/es.json | 8 + languages/fr.json | 8 + languages/hi.json | 8 + languages/id.json | 8 + languages/it.json | 8 + languages/ja.json | 8 + languages/pl.json | 8 + languages/pt.json | 8 + languages/ru.json | 8 + languages/tr.json | 8 + languages/zh.json | 8 + .../ytsage_dialogs_updater.py | 253 +++++++++++++++++- src/utils/ytsage_config_manager.py | 1 + 16 files changed, 362 insertions(+), 4 deletions(-) diff --git a/languages/ar.json b/languages/ar.json index 7304964..8c38248 100644 --- a/languages/ar.json +++ b/languages/ar.json @@ -267,6 +267,14 @@ "error_title": "خطأ", "failed_save_settings": "فشل حفظ إعدادات التحديث التلقائي.", "error_saving_settings": "خطأ في حفظ إعدادات التحديث التلقائي: {error}", + "ytdlp_channel": "قناة إصدار yt-dlp", + "ytdlp_channel_stable": "مستقر (إصدارات مختبرة)", + "ytdlp_channel_nightly": "ليلي (تحديثات يومية، موصى به من yt-dlp)", + "ytdlp_channel_description": "اختر بين الإصدارات المستقرة والليلية. يتم تحديث الإصدارات الليلية يومياً بأحدث الإصلاحات والميزات. يمكنك تبديل القنوات في أي وقت.", + "ytdlp_switching_channel": "التبديل إلى قناة {channel}...", + "ytdlp_channel_switched": "✅ تم التبديل بنجاح إلى قناة {channel}!", + "ytdlp_channel_switch_failed": "❌ فشل تبديل القناة: {error}", + "ytdlp_current_channel": "القناة الحالية: {channel}", "auto_update_title": "إعدادات التحديثات التلقائية", "auto_update_header": "🔄 إعدادات التحديثات التلقائية", "auto_update_description": "قم بتكوين التحديثات التلقائية لـ yt-dlp لضمان الحصول على أحدث الميزات وإصلاحات الأخطاء.", diff --git a/languages/de.json b/languages/de.json index b22ed1e..dbc66bc 100644 --- a/languages/de.json +++ b/languages/de.json @@ -267,6 +267,14 @@ "error_title": "Fehler", "failed_save_settings": "Speichern der Auto-Update-Einstellungen fehlgeschlagen.", "error_saving_settings": "Fehler beim Speichern der Auto-Update-Einstellungen: {error}", + "ytdlp_channel": "yt-dlp Release-Kanal", + "ytdlp_channel_stable": "Stabil (Getestete Versionen)", + "ytdlp_channel_nightly": "Nightly (Tägliche Updates, empfohlen von yt-dlp)", + "ytdlp_channel_description": "Wählen Sie zwischen stabilen und nächtlichen Versionen. Nightly-Builds werden täglich mit den neuesten Korrekturen und Funktionen aktualisiert. Sie können jederzeit zwischen den Kanälen wechseln.", + "ytdlp_switching_channel": "Wechsle zu {channel}-Kanal...", + "ytdlp_channel_switched": "✅ Erfolgreich zu {channel}-Kanal gewechselt!", + "ytdlp_channel_switch_failed": "❌ Kanalwechsel fehlgeschlagen: {error}", + "ytdlp_current_channel": "Aktueller Kanal: {channel}", "auto_update_title": "Auto-Update-Einstellungen", "auto_update_header": "🔄 Auto-Update-Einstellungen", "auto_update_description": "Konfigurieren Sie automatische Updates für yt-dlp, um sicherzustellen, dass Sie immer die neuesten Funktionen und Fehlerbehebungen haben.", diff --git a/languages/en.json b/languages/en.json index 7abedb5..f945663 100644 --- a/languages/en.json +++ b/languages/en.json @@ -267,6 +267,14 @@ "error_title": "Error", "failed_save_settings": "Failed to save auto-update settings.", "error_saving_settings": "Error saving auto-update settings: {error}", + "ytdlp_channel": "yt-dlp Release Channel", + "ytdlp_channel_stable": "Stable (Tested releases)", + "ytdlp_channel_nightly": "Nightly (Daily updates, recommended by yt-dlp)", + "ytdlp_channel_description": "Choose between stable and nightly releases. Nightly builds are updated daily with the latest fixes and features. You can switch channels at any time.", + "ytdlp_switching_channel": "Switching to {channel} channel...", + "ytdlp_channel_switched": "✅ Successfully switched to {channel} channel!", + "ytdlp_channel_switch_failed": "❌ Failed to switch channel: {error}", + "ytdlp_current_channel": "Current channel: {channel}", "auto_update_title": "Auto-Update Settings", "auto_update_header": "🔄 Auto-Update Settings", "auto_update_description": "Configure automatic updates for yt-dlp to ensure you always have the latest features and bug fixes.", diff --git a/languages/es.json b/languages/es.json index 8aa02ac..a4e572c 100644 --- a/languages/es.json +++ b/languages/es.json @@ -250,6 +250,14 @@ "error_title": "Error", "failed_save_settings": "Falló al guardar la configuración de auto-actualización.", "error_saving_settings": "Error al guardar la configuración de auto-actualización: {error}", + "ytdlp_channel": "Canal de Lanzamiento de yt-dlp", + "ytdlp_channel_stable": "Estable (Versiones probadas)", + "ytdlp_channel_nightly": "Nightly (Actualizaciones diarias, recomendado por yt-dlp)", + "ytdlp_channel_description": "Elige entre versiones estables y nightly. Las versiones nightly se actualizan diariamente con las últimas correcciones y características. Puedes cambiar de canal en cualquier momento.", + "ytdlp_switching_channel": "Cambiando al canal {channel}...", + "ytdlp_channel_switched": "✅ ¡Cambiado exitosamente al canal {channel}!", + "ytdlp_channel_switch_failed": "❌ Error al cambiar de canal: {error}", + "ytdlp_current_channel": "Canal actual: {channel}", "auto_update_title": "Configuración de Auto-Actualización", "auto_update_header": "🔄 Configuración de Auto-Actualización", "auto_update_description": "Configura las actualizaciones automáticas de yt-dlp para asegurar que siempre tengas las últimas funciones y correcciones de errores.", diff --git a/languages/fr.json b/languages/fr.json index caada1b..b8a619b 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -267,6 +267,14 @@ "error_title": "Erreur", "failed_save_settings": "Échec de la sauvegarde des paramètres de mise à jour automatique.", "error_saving_settings": "Erreur lors de la sauvegarde des paramètres de mise à jour automatique : {error}", + "ytdlp_channel": "Canal de version yt-dlp", + "ytdlp_channel_stable": "Stable (Versions testées)", + "ytdlp_channel_nightly": "Nightly (Mises à jour quotidiennes, recommandé par yt-dlp)", + "ytdlp_channel_description": "Choisissez entre les versions stables et nightly. Les versions nightly sont mises à jour quotidiennement avec les dernières corrections et fonctionnalités. Vous pouvez changer de canal à tout moment.", + "ytdlp_switching_channel": "Passage au canal {channel}...", + "ytdlp_channel_switched": "✅ Passage réussi au canal {channel} !", + "ytdlp_channel_switch_failed": "❌ Échec du changement de canal : {error}", + "ytdlp_current_channel": "Canal actuel : {channel}", "auto_update_title": "Paramètres de mise à jour automatique", "auto_update_header": "🔄 Paramètres de mise à jour automatique", "auto_update_description": "Configurez les mises à jour automatiques pour yt-dlp afin de vous assurer d'avoir toujours les dernières fonctionnalités et corrections de bogues.", diff --git a/languages/hi.json b/languages/hi.json index d44230e..9335223 100644 --- a/languages/hi.json +++ b/languages/hi.json @@ -267,6 +267,14 @@ "error_title": "त्रुटि", "failed_save_settings": "स्वचालित अपडेट सेटिंग्स सेव करना असफल।", "error_saving_settings": "स्वचालित अपडेट सेटिंग्स सेव करने में त्रुटि: {error}", + "ytdlp_channel": "yt-dlp रिलीज़ चैनल", + "ytdlp_channel_stable": "स्थिर (परीक्षित रिलीज़)", + "ytdlp_channel_nightly": "नाइटली (दैनिक अपडेट, yt-dlp द्वारा अनुशंसित)", + "ytdlp_channel_description": "स्थिर और नाइटली रिलीज़ के बीच चुनें। नाइटली बिल्ड नवीनतम फिक्स और सुविधाओं के साथ दैनिक अपडेट होते हैं। आप किसी भी समय चैनल बदल सकते हैं।", + "ytdlp_switching_channel": "{channel} चैनल पर स्विच किया जा रहा है...", + "ytdlp_channel_switched": "✅ सफलतापूर्वक {channel} चैनल पर स्विच किया गया!", + "ytdlp_channel_switch_failed": "❌ चैनल स्विच करना विफल: {error}", + "ytdlp_current_channel": "वर्तमान चैनल: {channel}", "auto_update_title": "स्वचालित अपडेट सेटिंग्स", "auto_update_header": "🔄 स्वचालित अपडेट सेटिंग्स", "auto_update_description": "yt-dlp के लिए स्वचालित अपडेट कॉन्फ़िगर करें ताकि आपके पास हमेशा नवीनतम सुविधाएं और बग फिक्स हों।", diff --git a/languages/id.json b/languages/id.json index 41d05a5..dd2e99a 100644 --- a/languages/id.json +++ b/languages/id.json @@ -267,6 +267,14 @@ "error_title": "Kesalahan", "failed_save_settings": "Gagal menyimpan pengaturan pembaruan otomatis.", "error_saving_settings": "Kesalahan menyimpan pengaturan pembaruan otomatis: {error}", + "ytdlp_channel": "Saluran Rilis yt-dlp", + "ytdlp_channel_stable": "Stabil (Rilis yang diuji)", + "ytdlp_channel_nightly": "Nightly (Pembaruan harian, direkomendasikan oleh yt-dlp)", + "ytdlp_channel_description": "Pilih antara rilis stabil dan nightly. Build nightly diperbarui setiap hari dengan perbaikan dan fitur terbaru. Anda dapat berganti saluran kapan saja.", + "ytdlp_switching_channel": "Beralih ke saluran {channel}...", + "ytdlp_channel_switched": "✅ Berhasil beralih ke saluran {channel}!", + "ytdlp_channel_switch_failed": "❌ Gagal beralih saluran: {error}", + "ytdlp_current_channel": "Saluran saat ini: {channel}", "auto_update_title": "Pengaturan pembaruan otomatis", "auto_update_header": "🔄 Pengaturan pembaruan otomatis", "auto_update_description": "Konfigurasi pembaruan otomatis untuk yt-dlp untuk memastikan Anda selalu memiliki fitur dan perbaikan bug terbaru.", diff --git a/languages/it.json b/languages/it.json index d5e2b93..6708a9b 100644 --- a/languages/it.json +++ b/languages/it.json @@ -267,6 +267,14 @@ "error_title": "Errore", "failed_save_settings": "Impossibile salvare le impostazioni di aggiornamento automatico.", "error_saving_settings": "Errore nel salvataggio delle impostazioni di aggiornamento automatico: {error}", + "ytdlp_channel": "Canale di rilascio yt-dlp", + "ytdlp_channel_stable": "Stabile (Rilasci testati)", + "ytdlp_channel_nightly": "Nightly (Aggiornamenti giornalieri, consigliato da yt-dlp)", + "ytdlp_channel_description": "Scegli tra rilasci stabili e nightly. Le build nightly vengono aggiornate quotidianamente con le ultime correzioni e funzionalità. Puoi cambiare canale in qualsiasi momento.", + "ytdlp_switching_channel": "Passaggio al canale {channel}...", + "ytdlp_channel_switched": "✅ Passaggio al canale {channel} riuscito!", + "ytdlp_channel_switch_failed": "❌ Impossibile cambiare canale: {error}", + "ytdlp_current_channel": "Canale attuale: {channel}", "auto_update_title": "Impostazioni aggiornamenti automatici", "auto_update_header": "🔄 Impostazioni aggiornamenti automatici", "auto_update_description": "Configura gli aggiornamenti automatici per yt-dlp per garantire le ultime funzionalità e correzioni bug.", diff --git a/languages/ja.json b/languages/ja.json index c783851..62d3227 100644 --- a/languages/ja.json +++ b/languages/ja.json @@ -267,6 +267,14 @@ "error_title": "エラー", "failed_save_settings": "自動更新設定の保存に失敗しました。", "error_saving_settings": "自動更新設定の保存エラー: {error}", + "ytdlp_channel": "yt-dlp リリースチャンネル", + "ytdlp_channel_stable": "安定版(テスト済みリリース)", + "ytdlp_channel_nightly": "Nightly(毎日更新、yt-dlp推奨)", + "ytdlp_channel_description": "安定版とNightlyリリースのどちらかを選択してください。Nightlyビルドは最新の修正と機能で毎日更新されます。いつでもチャンネルを切り替えることができます。", + "ytdlp_switching_channel": "{channel}チャンネルに切り替え中...", + "ytdlp_channel_switched": "✅ {channel}チャンネルへの切り替えに成功しました!", + "ytdlp_channel_switch_failed": "❌ チャンネルの切り替えに失敗しました: {error}", + "ytdlp_current_channel": "現在のチャンネル: {channel}", "auto_update_title": "自動更新設定", "auto_update_header": "🔄 自動更新設定", "auto_update_description": "yt-dlpの自動更新を設定して、最新の機能とバグ修正を確実に入手してください。", diff --git a/languages/pl.json b/languages/pl.json index f35e94c..18818ff 100644 --- a/languages/pl.json +++ b/languages/pl.json @@ -267,6 +267,14 @@ "error_title": "Błąd", "failed_save_settings": "Nie udało się zapisać ustawień automatycznych aktualizacji.", "error_saving_settings": "Błąd zapisywania ustawień automatycznych aktualizacji: {error}", + "ytdlp_channel": "Kanał wydań yt-dlp", + "ytdlp_channel_stable": "Stabilny (Przetestowane wydania)", + "ytdlp_channel_nightly": "Nightly (Codzienne aktualizacje, zalecane przez yt-dlp)", + "ytdlp_channel_description": "Wybierz między wydaniami stabilnymi a nightly. Buildy nightly są aktualizowane codziennie z najnowszymi poprawkami i funkcjami. Możesz zmienić kanał w dowolnym momencie.", + "ytdlp_switching_channel": "Przełączanie na kanał {channel}...", + "ytdlp_channel_switched": "✅ Pomyślnie przełączono na kanał {channel}!", + "ytdlp_channel_switch_failed": "❌ Nie udało się przełączyć kanału: {error}", + "ytdlp_current_channel": "Aktualny kanał: {channel}", "auto_update_title": "Ustawienia automatycznych aktualizacji", "auto_update_header": "🔄 Ustawienia automatycznych aktualizacji", "auto_update_description": "Skonfiguruj automatyczne aktualizacje dla yt-dlp, aby zapewnić najnowsze funkcje i poprawki błędów.", diff --git a/languages/pt.json b/languages/pt.json index 095020b..165be32 100644 --- a/languages/pt.json +++ b/languages/pt.json @@ -267,6 +267,14 @@ "error_title": "Erro", "failed_save_settings": "Falha ao salvar configurações de auto-atualização.", "error_saving_settings": "Erro ao salvar configurações de auto-atualização: {error}", + "ytdlp_channel": "Canal de Lançamento do yt-dlp", + "ytdlp_channel_stable": "Estável (Lançamentos testados)", + "ytdlp_channel_nightly": "Nightly (Atualizações diárias, recomendado pelo yt-dlp)", + "ytdlp_channel_description": "Escolha entre lançamentos estáveis e nightly. Builds nightly são atualizadas diariamente com as últimas correções e recursos. Você pode trocar de canal a qualquer momento.", + "ytdlp_switching_channel": "Mudando para o canal {channel}...", + "ytdlp_channel_switched": "✅ Mudado com sucesso para o canal {channel}!", + "ytdlp_channel_switch_failed": "❌ Falha ao trocar de canal: {error}", + "ytdlp_current_channel": "Canal atual: {channel}", "auto_update_title": "Configurações de Auto-Atualização", "auto_update_header": "🔄 Configurações de Auto-Atualização", "auto_update_description": "Configure atualizações automáticas para o yt-dlp para garantir que você sempre tenha os recursos mais recentes e correções de bugs.", diff --git a/languages/ru.json b/languages/ru.json index 6750f94..c3a8d23 100644 --- a/languages/ru.json +++ b/languages/ru.json @@ -267,6 +267,14 @@ "error_title": "Ошибка", "failed_save_settings": "Не удалось сохранить настройки автообновления.", "error_saving_settings": "Ошибка сохранения настроек автообновления: {error}", + "ytdlp_channel": "Канал выпуска yt-dlp", + "ytdlp_channel_stable": "Стабильный (Протестированные релизы)", + "ytdlp_channel_nightly": "Nightly (Ежедневные обновления, рекомендовано yt-dlp)", + "ytdlp_channel_description": "Выберите между стабильными и nightly релизами. Nightly сборки обновляются ежедневно с последними исправлениями и функциями. Вы можете переключать каналы в любое время.", + "ytdlp_switching_channel": "Переключение на канал {channel}...", + "ytdlp_channel_switched": "✅ Успешно переключено на канал {channel}!", + "ytdlp_channel_switch_failed": "❌ Не удалось переключить канал: {error}", + "ytdlp_current_channel": "Текущий канал: {channel}", "auto_update_title": "Настройки автообновления", "auto_update_header": "🔄 Настройки автообновления", "auto_update_description": "Настройте автоматические обновления для yt-dlp, чтобы всегда иметь последние функции и исправления ошибок.", diff --git a/languages/tr.json b/languages/tr.json index 37d999a..0d33adc 100644 --- a/languages/tr.json +++ b/languages/tr.json @@ -267,6 +267,14 @@ "error_title": "Hata", "failed_save_settings": "Otomatik güncelleme ayarları kaydedilemedi.", "error_saving_settings": "Otomatik güncelleme ayarları kaydetme hatası: {error}", + "ytdlp_channel": "yt-dlp Sürüm Kanalı", + "ytdlp_channel_stable": "Kararlı (Test edilmiş sürümler)", + "ytdlp_channel_nightly": "Nightly (Günlük güncellemeler, yt-dlp tarafından önerilir)", + "ytdlp_channel_description": "Kararlı ve nightly sürümler arasında seçim yapın. Nightly derlemeleri en son düzeltmeler ve özelliklerle günlük olarak güncellenir. İstediğiniz zaman kanal değiştirebilirsiniz.", + "ytdlp_switching_channel": "{channel} kanalına geçiliyor...", + "ytdlp_channel_switched": "✅ Başarıyla {channel} kanalına geçildi!", + "ytdlp_channel_switch_failed": "❌ Kanal değiştirilemedi: {error}", + "ytdlp_current_channel": "Mevcut kanal: {channel}", "auto_update_title": "Otomatik güncelleme ayarları", "auto_update_header": "🔄 Otomatik güncelleme ayarları", "auto_update_description": "En son özelliklere ve hata düzeltmelerine sahip olmak için yt-dlp otomatik güncellemelerini yapılandırın.", diff --git a/languages/zh.json b/languages/zh.json index 74c0937..3c2cf32 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -267,6 +267,14 @@ "error_title": "错误", "failed_save_settings": "保存自动更新设置失败。", "error_saving_settings": "保存自动更新设置时出错:{error}", + "ytdlp_channel": "yt-dlp 发布渠道", + "ytdlp_channel_stable": "稳定版(经过测试的版本)", + "ytdlp_channel_nightly": "夜间版(每日更新,yt-dlp 推荐)", + "ytdlp_channel_description": "在稳定版和夜间版之间选择。夜间构建版每天更新,包含最新修复和功能。您可以随时切换渠道。", + "ytdlp_switching_channel": "正在切换到 {channel} 渠道...", + "ytdlp_channel_switched": "✅ 成功切换到 {channel} 渠道!", + "ytdlp_channel_switch_failed": "❌ 切换渠道失败:{error}", + "ytdlp_current_channel": "当前渠道:{channel}", "auto_update_title": "自动更新设置", "auto_update_header": "🔄 自动更新设置", "auto_update_description": "为 yt-dlp 配置自动更新,以确保您始终拥有最新功能和错误修复。", diff --git a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py index 125142d..cc20268 100644 --- a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py +++ b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py @@ -3,6 +3,7 @@ Updater tab for Custom Options dialog. Handles checking for and installing FFmpeg updates and yt-dlp auto-update settings. """ +import subprocess import threading from typing import TYPE_CHECKING, cast @@ -15,6 +16,7 @@ from PySide6.QtWidgets import ( QProgressBar, QPushButton, QRadioButton, + QScrollArea, QTextEdit, QVBoxLayout, QWidget, @@ -24,10 +26,13 @@ from src.core.ytsage_utils import ( get_auto_update_settings, update_auto_update_settings, ) +from src.core.ytsage_yt_dlp import get_yt_dlp_path from src.gui.ytsage_gui_dialogs.ytsage_dialogs_update import YTDLPUpdateDialog +from src.utils.ytsage_config_manager import ConfigManager from src.utils.ytsage_localization import _ from src.utils.ytsage_logger import logger from src.core.ytsage_ffmpeg_updater import check_ffmpeg_update_available, update_ffmpeg +from src.utils.ytsage_constants import OS_NAME, SUBPROCESS_CREATIONFLAGS from src.utils.ytsage_constants import OS_NAME if TYPE_CHECKING: @@ -77,7 +82,19 @@ class UpdaterTabWidget(QWidget): def _init_ui(self) -> None: """Initialize the UI components.""" - layout = QVBoxLayout(self) + # Main layout for the tab + main_layout = QVBoxLayout(self) + main_layout.setContentsMargins(0, 0, 0, 0) + + # Create scroll area + scroll_area = QScrollArea() + scroll_area.setWidgetResizable(True) + scroll_area.setFrameShape(QScrollArea.Shape.NoFrame) + scroll_area.setStyleSheet("QScrollArea { background: transparent; }") + + # Create a widget to hold all content + content_widget = QWidget() + layout = QVBoxLayout(content_widget) # Help text help_text = QLabel(_('ffmpeg_updater.description')) @@ -209,14 +226,14 @@ class UpdaterTabWidget(QWidget): # Log output log_label = QLabel("Update Log:") - log_label.setStyleSheet("font-size: 12px; font-weight: bold; color: #ffffff; margin-top: 10px;") + log_label.setStyleSheet("font-size: 11px; font-weight: bold; color: #ffffff; margin-top: 5px;") ffmpeg_layout.addWidget(log_label) self.log_output = QTextEdit() self.log_output.setReadOnly(True) self.log_output.setPlaceholderText("Update logs will appear here...") - self.log_output.setMinimumHeight(80) - self.log_output.setMaximumHeight(120) + self.log_output.setMinimumHeight(60) + self.log_output.setMaximumHeight(100) self.log_output.setStyleSheet( """ QTextEdit { @@ -234,6 +251,65 @@ class UpdaterTabWidget(QWidget): layout.addWidget(ffmpeg_group) + # === yt-dlp Release Channel Section === + ytdlp_channel_group = QGroupBox(_("settings.ytdlp_channel")) + ytdlp_channel_layout = QVBoxLayout() + ytdlp_channel_layout.setSpacing(5) # Reduce spacing + ytdlp_channel_layout.setContentsMargins(10, 10, 10, 10) # Reduce margins + + # Description + channel_desc = QLabel(_("settings.ytdlp_channel_description")) + channel_desc.setWordWrap(True) + channel_desc.setStyleSheet("color: #cccccc; font-size: 11px; padding: 2px;") + ytdlp_channel_layout.addWidget(channel_desc) + + # Radio buttons for channel selection + self.channel_stable_radio = QRadioButton(_("settings.ytdlp_channel_stable")) + self.channel_nightly_radio = QRadioButton(_("settings.ytdlp_channel_nightly")) + + radio_button_style = """ + QRadioButton { + color: #ffffff; + spacing: 5px; + padding: 3px; + } + QRadioButton::indicator { + width: 16px; + height: 16px; + border-radius: 8px; + } + QRadioButton::indicator:unchecked { + border: 2px solid #666666; + background: #15181b; + } + QRadioButton::indicator:checked { + border: 2px solid #c90000; + background: #c90000; + } + """ + self.channel_stable_radio.setStyleSheet(radio_button_style) + self.channel_nightly_radio.setStyleSheet(radio_button_style) + + # Connect radio button signals + self.channel_stable_radio.toggled.connect(self._on_channel_changed) + self.channel_nightly_radio.toggled.connect(self._on_channel_changed) + + ytdlp_channel_layout.addWidget(self.channel_stable_radio) + ytdlp_channel_layout.addWidget(self.channel_nightly_radio) + + # Status label for channel operations + self.channel_status_label = QLabel("") + self.channel_status_label.setWordWrap(True) + self.channel_status_label.setStyleSheet( + "color: #888888; font-size: 11px; padding: 5px; " + "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" + ) + self.channel_status_label.setVisible(False) + ytdlp_channel_layout.addWidget(self.channel_status_label) + + ytdlp_channel_group.setLayout(ytdlp_channel_layout) + layout.addWidget(ytdlp_channel_group) + # === Auto-Update yt-dlp Section === auto_update_group_box = QGroupBox(_("settings.auto_update_ytdlp")) auto_update_layout = QVBoxLayout() @@ -310,6 +386,12 @@ class UpdaterTabWidget(QWidget): layout.addWidget(auto_update_group_box) layout.addStretch() + + # Set the content widget to the scroll area + scroll_area.setWidget(content_widget) + + # Add scroll area to main layout + main_layout.addWidget(scroll_area) def _load_auto_update_settings(self) -> None: """Load current auto-update settings for yt-dlp.""" @@ -327,6 +409,20 @@ class UpdaterTabWidget(QWidget): self.daily_radio.setChecked(True) else: # weekly self.weekly_radio.setChecked(True) + + # Load channel setting + channel = ConfigManager.get("ytdlp_channel") + if channel is None: + channel = "stable" # Default to stable if not set + + if channel == "nightly": + self.channel_nightly_radio.setChecked(True) + else: + self.channel_stable_radio.setChecked(True) + + # Update status label + self._update_channel_status(channel) + except Exception as e: logger.exception(f"Error loading auto-update settings: {e}") @@ -343,6 +439,155 @@ class UpdaterTabWidget(QWidget): return enabled, frequency + def _on_channel_changed(self, checked: bool) -> None: + """Handle channel selection change.""" + if not checked: + return + + # Determine which channel was selected + new_channel = "nightly" if self.channel_nightly_radio.isChecked() else "stable" + current_channel = ConfigManager.get("ytdlp_channel") + if current_channel is None: + current_channel = "stable" + + # If channel hasn't actually changed, just update status + if new_channel == current_channel: + self._update_channel_status(new_channel) + return + + # Show switching message + self.channel_status_label.setText(_("settings.ytdlp_switching_channel", channel=new_channel)) + self.channel_status_label.setStyleSheet( + "color: #ffaa00; font-size: 11px; padding: 5px; " + "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" + ) + self.channel_status_label.setVisible(True) + + # Disable radio buttons during switch + self.channel_stable_radio.setEnabled(False) + self.channel_nightly_radio.setEnabled(False) + + # Run channel switch in background thread + def switch_channel(): + try: + # Get yt-dlp path + yt_dlp_path = get_yt_dlp_path() + + # Build the update command + # When switching to stable from nightly, we need to get the latest stable version + # to force the switch even if versions have the same date + update_target = new_channel + + if new_channel == "stable" and current_channel == "nightly": + # Get the latest stable version tag + logger.info("Fetching latest stable version tag...") + try: + import requests + response = requests.get("https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest", timeout=10) + response.raise_for_status() + latest_tag = response.json().get("tag_name", "") + if latest_tag: + update_target = f"stable@{latest_tag}" + logger.info(f"Latest stable version tag: {latest_tag}") + else: + logger.warning("Could not determine latest stable tag, using 'stable'") + except Exception as e: + logger.warning(f"Failed to fetch latest stable tag, using 'stable': {e}") + + # Run the update-to command + logger.info(f"Switching yt-dlp to {new_channel} channel...") + logger.debug(f"Running command: {yt_dlp_path} --update-to {update_target}") + result = subprocess.run( + [yt_dlp_path, "--update-to", update_target], + capture_output=True, + text=True, + timeout=120, + creationflags=SUBPROCESS_CREATIONFLAGS, + ) + + # Log the output for debugging + if result.stdout: + logger.debug(f"yt-dlp stdout: {result.stdout.strip()}") + if result.stderr: + logger.debug(f"yt-dlp stderr: {result.stderr.strip()}") + logger.debug(f"yt-dlp return code: {result.returncode}") + + if result.returncode == 0: + # Success - save the preference + ConfigManager.set("ytdlp_channel", new_channel) + logger.info(f"Successfully switched to {new_channel} channel") + + # Update UI + self.channel_status_label.setText(_("settings.ytdlp_channel_switched", channel=new_channel)) + self.channel_status_label.setStyleSheet( + "color: #00cc00; font-size: 11px; padding: 5px; " + "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" + ) + + # Make executable on Unix systems + if OS_NAME != "Windows": + import os + os.chmod(yt_dlp_path, 0o755) + else: + # Failed - revert radio button + error_msg = result.stderr.strip() if result.stderr else result.stdout.strip() if result.stdout else "Unknown error" + logger.error(f"Failed to switch channel: {error_msg}") + + self.channel_status_label.setText(_("settings.ytdlp_channel_switch_failed", error=error_msg)) + self.channel_status_label.setStyleSheet( + "color: #ff6666; font-size: 11px; padding: 5px; " + "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" + ) + + # Revert radio selection + if current_channel == "nightly": + self.channel_nightly_radio.setChecked(True) + else: + self.channel_stable_radio.setChecked(True) + + except subprocess.TimeoutExpired: + logger.error("Channel switch timed out") + self.channel_status_label.setText(_("settings.ytdlp_channel_switch_failed", error="Timeout")) + self.channel_status_label.setStyleSheet( + "color: #ff6666; font-size: 11px; padding: 5px; " + "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" + ) + # Revert radio selection + if current_channel == "nightly": + self.channel_nightly_radio.setChecked(True) + else: + self.channel_stable_radio.setChecked(True) + + except Exception as e: + logger.exception(f"Error switching channel: {e}") + self.channel_status_label.setText(_("settings.ytdlp_channel_switch_failed", error=str(e))) + self.channel_status_label.setStyleSheet( + "color: #ff6666; font-size: 11px; padding: 5px; " + "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" + ) + # Revert radio selection + if current_channel == "nightly": + self.channel_nightly_radio.setChecked(True) + else: + self.channel_stable_radio.setChecked(True) + finally: + # Re-enable radio buttons + self.channel_stable_radio.setEnabled(True) + self.channel_nightly_radio.setEnabled(True) + + # Start the thread + thread = threading.Thread(target=switch_channel, daemon=True) + thread.start() + + def _update_channel_status(self, channel: str) -> None: + """Update the channel status label.""" + self.channel_status_label.setText(_("settings.ytdlp_current_channel", channel=channel)) + self.channel_status_label.setStyleSheet( + "color: #888888; font-size: 11px; padding: 5px; " + "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" + ) + self.channel_status_label.setVisible(True) + def test_update_check(self) -> None: """Open the yt-dlp update dialog with proper progress tracking.""" # Create and show the update dialog (non-modal to prevent blocking) diff --git a/src/utils/ytsage_config_manager.py b/src/utils/ytsage_config_manager.py index f7b9f9e..e024078 100644 --- a/src/utils/ytsage_config_manager.py +++ b/src/utils/ytsage_config_manager.py @@ -80,6 +80,7 @@ class ConfigManager: "auto_update_frequency": "daily", "last_update_check": 0, "language": "en", + "ytdlp_channel": "stable", "force_output_format": False, "preferred_output_format": "mp4", "cached_versions": {