diff --git a/languages/ar.json b/languages/ar.json index 8c38248..a560206 100644 --- a/languages/ar.json +++ b/languages/ar.json @@ -477,22 +477,17 @@ "redownload_started": "بدأ التنزيل" }, "ffmpeg_updater": { - "title": "محدث FFmpeg", + "title": "مدقق إصدار FFmpeg", "current_version": "الإصدار الحالي:", "latest_version": "أحدث إصدار:", "status_up_to_date": "✓ محدث", - "status_update_available": "⚠ تحديث متاح", + "status_update_available": "⚠ يتوفر تحديث", "status_not_installed": "✗ غير مثبت", - "status_checking": "🔄 جارٍ التحقق من التحديثات...", - "status_downloading": "⬇ جارٍ تنزيل FFmpeg...", - "status_installing": "⚙ جارٍ تثبيت FFmpeg...", - "status_verifying": "✓ جارٍ التحقق من السلامة...", - "check_updates": "التحقق من التحديثات", - "update_button": "تحديث FFmpeg", - "update_success": "تم تحديث FFmpeg بنجاح إلى الإصدار {version}!", - "update_failed": "فشل تحديث FFmpeg. يرجى المحاولة مرة أخرى.", - "check_failed": "فشل التحقق من التحديثات. يرجى التحقق من اتصال الإنترنت.", - "install_first": "FFmpeg غير مثبت. انقر فوق تحديث للتثبيت.", - "description": "حافظ على تحديث FFmpeg للحصول على أفضل أداء وتوافق." + "status_idle": "انقر على 'التحقق من الإصدار' للبدء", + "status_checking": "🔄 جاري التحقق من الإصدار...", + "check_updates": "التحقق من الإصدار", + "check_failed": "فشل التحقق من الإصدار. يرجى التحقق من اتصال الإنترنت.", + "description": "تحقق من إصدار FFmpeg الخاص بك وقارنه بأحدث إصدار متاح.", + "guide_info": " لتثبيت أو تحديث FFmpeg، انقر هنا لعرض دليل التثبيت الشامل." } } \ No newline at end of file diff --git a/languages/de.json b/languages/de.json index dbc66bc..15b9f3f 100644 --- a/languages/de.json +++ b/languages/de.json @@ -477,22 +477,17 @@ "redownload_started": "Download gestartet" }, "ffmpeg_updater": { - "title": "FFmpeg-Updater", + "title": "FFmpeg-Versionsprüfer", "current_version": "Aktuelle Version:", "latest_version": "Neueste Version:", "status_up_to_date": "✓ Auf dem neuesten Stand", "status_update_available": "⚠ Update verfügbar", "status_not_installed": "✗ Nicht installiert", - "status_checking": "🔄 Suche nach Updates...", - "status_downloading": "⬇ FFmpeg wird heruntergeladen...", - "status_installing": "⚙ FFmpeg wird installiert...", - "status_verifying": "✓ Integrität wird überprüft...", - "check_updates": "Nach Updates suchen", - "update_button": "FFmpeg aktualisieren", - "update_success": "FFmpeg erfolgreich auf Version {version} aktualisiert!", - "update_failed": "FFmpeg-Update fehlgeschlagen. Bitte versuchen Sie es erneut.", - "check_failed": "Update-Prüfung fehlgeschlagen. Bitte überprüfen Sie Ihre Internetverbindung.", - "install_first": "FFmpeg ist nicht installiert. Klicken Sie auf Aktualisieren, um zu installieren.", - "description": "Halten Sie FFmpeg auf dem neuesten Stand für beste Leistung und Kompatibilität." + "status_idle": "Klicken Sie auf 'Version prüfen' um zu beginnen", + "status_checking": "🔄 Version wird geprüft...", + "check_updates": "Version prüfen", + "check_failed": "Versionprüfung fehlgeschlagen. Bitte überprüfen Sie Ihre Internetverbindung.", + "description": "Überprüfen Sie Ihre FFmpeg-Version und vergleichen Sie sie mit der neuesten verfügbaren Version.", + "guide_info": " Um FFmpeg zu installieren oder zu aktualisieren, klicken Sie hier, um unseren umfassenden Installationsleitfaden anzuzeigen." } } \ No newline at end of file diff --git a/languages/en.json b/languages/en.json index f945663..56c434f 100644 --- a/languages/en.json +++ b/languages/en.json @@ -477,23 +477,17 @@ "redownload_started": "Redownload started" }, "ffmpeg_updater": { - "title": "FFmpeg Updater", + "title": "FFmpeg Version Checker", "current_version": "Current Version:", "latest_version": "Latest Version:", "status_up_to_date": "✓ Up to date", "status_update_available": "⚠ Update available", "status_not_installed": "✗ Not installed", - "status_idle": "Click 'Check for Updates' to get started", - "status_checking": "🔄 Checking for updates...", - "status_downloading": "⬇ Downloading FFmpeg...", - "status_installing": "⚙ Installing FFmpeg...", - "status_verifying": "✓ Verifying integrity...", - "check_updates": "Check for Updates", - "update_button": "Update FFmpeg", - "update_success": "FFmpeg successfully updated to version {version}!", - "update_failed": "Failed to update FFmpeg. Please try again.", - "check_failed": "Failed to check for updates. Please check your internet connection.", - "install_first": "FFmpeg is not installed. Click Update to install.", - "description": "Keep FFmpeg up to date for the best performance and compatibility." + "status_idle": "Click 'Check Version' to get started", + "status_checking": "🔄 Checking version...", + "check_updates": "Check Version", + "check_failed": "Failed to check version. Please check your internet connection.", + "description": "Check your FFmpeg version and compare it with the latest available version.", + "guide_info": " To install or update FFmpeg, click here to view our comprehensive installation guide." } } \ No newline at end of file diff --git a/languages/es.json b/languages/es.json index a4e572c..b917369 100644 --- a/languages/es.json +++ b/languages/es.json @@ -460,22 +460,17 @@ "redownload_started": "Descarga iniciada" }, "ffmpeg_updater": { - "title": "Actualizador de FFmpeg", + "title": "Comprobador de Versión FFmpeg", "current_version": "Versión Actual:", "latest_version": "Última Versión:", "status_up_to_date": "✓ Actualizado", "status_update_available": "⚠ Actualización disponible", "status_not_installed": "✗ No instalado", - "status_checking": "🔄 Verificando actualizaciones...", - "status_downloading": "⬇ Descargando FFmpeg...", - "status_installing": "⚙ Instalando FFmpeg...", - "status_verifying": "✓ Verificando integridad...", - "check_updates": "Buscar Actualizaciones", - "update_button": "Actualizar FFmpeg", - "update_success": "¡FFmpeg actualizado exitosamente a la versión {version}!", - "update_failed": "Error al actualizar FFmpeg. Por favor, inténtelo de nuevo.", - "check_failed": "Error al verificar actualizaciones. Por favor, verifique su conexión a internet.", - "install_first": "FFmpeg no está instalado. Haga clic en Actualizar para instalar.", - "description": "Mantenga FFmpeg actualizado para el mejor rendimiento y compatibilidad." + "status_idle": "Haga clic en 'Comprobar Versión' para comenzar", + "status_checking": "🔄 Verificando versión...", + "check_updates": "Comprobar Versión", + "check_failed": "Error al verificar la versión. Por favor, verifique su conexión a internet.", + "description": "Compruebe su versión de FFmpeg y compárela con la última versión disponible.", + "guide_info": " Para instalar o actualizar FFmpeg, haga clic aquí para ver nuestra guía completa de instalación." } } \ No newline at end of file diff --git a/languages/fr.json b/languages/fr.json index b8a619b..708f5af 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -477,22 +477,17 @@ "redownload_started": "Téléchargement démarré" }, "ffmpeg_updater": { - "title": "Mise à jour FFmpeg", + "title": "Vérificateur de Version FFmpeg", "current_version": "Version Actuelle:", "latest_version": "Dernière Version:", "status_up_to_date": "✓ À jour", "status_update_available": "⚠ Mise à jour disponible", "status_not_installed": "✗ Non installé", - "status_checking": "🔄 Vérification des mises à jour...", - "status_downloading": "⬇ Téléchargement de FFmpeg...", - "status_installing": "⚙ Installation de FFmpeg...", - "status_verifying": "✓ Vérification de l'intégrité...", - "check_updates": "Vérifier les mises à jour", - "update_button": "Mettre à jour FFmpeg", - "update_success": "FFmpeg mis à jour avec succès vers la version {version}!", - "update_failed": "Échec de la mise à jour de FFmpeg. Veuillez réessayer.", - "check_failed": "Échec de la vérification des mises à jour. Vérifiez votre connexion Internet.", - "install_first": "FFmpeg n'est pas installé. Cliquez sur Mettre à jour pour installer.", - "description": "Maintenez FFmpeg à jour pour les meilleures performances et compatibilité." + "status_idle": "Cliquez sur 'Vérifier la Version' pour commencer", + "status_checking": "🔄 Vérification de la version...", + "check_updates": "Vérifier la Version", + "check_failed": "Échec de la vérification de la version. Vérifiez votre connexion Internet.", + "description": "Vérifiez votre version de FFmpeg et comparez-la avec la dernière version disponible.", + "guide_info": " Pour installer ou mettre à jour FFmpeg, cliquez ici pour consulter notre guide d'installation complet." } } \ No newline at end of file diff --git a/languages/hi.json b/languages/hi.json index 9335223..58f951f 100644 --- a/languages/hi.json +++ b/languages/hi.json @@ -477,22 +477,17 @@ "redownload_started": "डाउनलोड शुरू हुआ" }, "ffmpeg_updater": { - "title": "FFmpeg अपडेटर", + "title": "FFmpeg संस्करण जांचकर्ता", "current_version": "वर्तमान संस्करण:", "latest_version": "नवीनतम संस्करण:", "status_up_to_date": "✓ अप टू डेट", "status_update_available": "⚠ अपडेट उपलब्ध", "status_not_installed": "✗ इंस्टॉल नहीं है", - "status_checking": "🔄 अपडेट जांच रहे हैं...", - "status_downloading": "⬇ FFmpeg डाउनलोड हो रहा है...", - "status_installing": "⚙ FFmpeg इंस्टॉल हो रहा है...", - "status_verifying": "✓ अखंडता सत्यापित कर रहे हैं...", - "check_updates": "अपडेट जांचें", - "update_button": "FFmpeg अपडेट करें", - "update_success": "FFmpeg सफलतापूर्वक संस्करण {version} में अपडेट किया गया!", - "update_failed": "FFmpeg अपडेट विफल रहा। कृपया पुनः प्रयास करें।", - "check_failed": "अपडेट जांच विफल रही। कृपया अपना इंटरनेट कनेक्शन जांचें।", - "install_first": "FFmpeg इंस्टॉल नहीं है। इंस्टॉल करने के लिए अपडेट पर क्लिक करें।", - "description": "सर्वोत्तम प्रदर्शन और संगतता के लिए FFmpeg को अप टू डेट रखें।" + "status_idle": "शुरू करने के लिए 'संस्करण जांचें' पर क्लिक करें", + "status_checking": "🔄 संस्करण जांच रहे हैं...", + "check_updates": "संस्करण जांचें", + "check_failed": "संस्करण जांच विफल रही। कृपया अपना इंटरनेट कनेक्शन जांचें।", + "description": "अपने FFmpeg संस्करण की जांच करें और इसे नवीनतम उपलब्ध संस्करण से तुलना करें।", + "guide_info": " FFmpeg को इंस्टॉल या अपडेट करने के लिए, हमारी व्यापक इंस्टॉलेशन गाइड देखने के लिए यहां क्लिक करें." } } \ No newline at end of file diff --git a/languages/id.json b/languages/id.json index dd2e99a..116612c 100644 --- a/languages/id.json +++ b/languages/id.json @@ -477,22 +477,17 @@ "redownload_started": "Unduhan dimulai" }, "ffmpeg_updater": { - "title": "Pembaruan FFmpeg", + "title": "Pemeriksa Versi FFmpeg", "current_version": "Versi Saat Ini:", "latest_version": "Versi Terbaru:", "status_up_to_date": "✓ Terbaru", "status_update_available": "⚠ Pembaruan tersedia", "status_not_installed": "✗ Tidak terinstal", - "status_checking": "🔄 Memeriksa pembaruan...", - "status_downloading": "⬇ Mengunduh FFmpeg...", - "status_installing": "⚙ Menginstal FFmpeg...", - "status_verifying": "✓ Memverifikasi integritas...", - "check_updates": "Periksa Pembaruan", - "update_button": "Perbarui FFmpeg", - "update_success": "FFmpeg berhasil diperbarui ke versi {version}!", - "update_failed": "Gagal memperbarui FFmpeg. Silakan coba lagi.", - "check_failed": "Gagal memeriksa pembaruan. Periksa koneksi internet Anda.", - "install_first": "FFmpeg tidak terinstal. Klik Perbarui untuk menginstal.", - "description": "Jaga FFmpeg tetap terbaru untuk performa dan kompatibilitas terbaik." + "status_idle": "Klik 'Periksa Versi' untuk memulai", + "status_checking": "🔄 Memeriksa versi...", + "check_updates": "Periksa Versi", + "check_failed": "Gagal memeriksa versi. Periksa koneksi internet Anda.", + "description": "Periksa versi FFmpeg Anda dan bandingkan dengan versi terbaru yang tersedia.", + "guide_info": " Untuk menginstal atau memperbarui FFmpeg, klik di sini untuk melihat panduan instalasi lengkap kami." } } \ No newline at end of file diff --git a/languages/it.json b/languages/it.json index 6708a9b..eeda165 100644 --- a/languages/it.json +++ b/languages/it.json @@ -477,22 +477,17 @@ "redownload_started": "Download avviato" }, "ffmpeg_updater": { - "title": "Aggiornamento FFmpeg", + "title": "Controllo Versione FFmpeg", "current_version": "Versione corrente:", "latest_version": "Ultima versione:", "status_up_to_date": "✓ Aggiornato", "status_update_available": "⚠ Aggiornamento disponibile", "status_not_installed": "✗ Non installato", - "status_checking": "🔄 Verifica aggiornamenti...", - "status_downloading": "⬇ Download di FFmpeg...", - "status_installing": "⚙ Installazione di FFmpeg...", - "status_verifying": "✓ Verifica integrità...", - "check_updates": "Verifica aggiornamenti", - "update_button": "Aggiorna FFmpeg", - "update_success": "FFmpeg aggiornato con successo alla versione {version}!", - "update_failed": "Aggiornamento di FFmpeg non riuscito. Riprova.", - "check_failed": "Verifica aggiornamenti non riuscita. Controlla la connessione Internet.", - "install_first": "FFmpeg non è installato. Clicca Aggiorna per installare.", - "description": "Mantieni FFmpeg aggiornato per le migliori prestazioni e compatibilità." + "status_idle": "Clicca 'Controlla Versione' per iniziare", + "status_checking": "🔄 Verifica versione...", + "check_updates": "Controlla Versione", + "check_failed": "Verifica versione non riuscita. Controlla la connessione Internet.", + "description": "Controlla la tua versione di FFmpeg e confrontala con l'ultima versione disponibile.", + "guide_info": " Per installare o aggiornare FFmpeg, clicca qui per visualizzare la nostra guida completa all'installazione." } } \ No newline at end of file diff --git a/languages/ja.json b/languages/ja.json index 62d3227..8ed2959 100644 --- a/languages/ja.json +++ b/languages/ja.json @@ -477,22 +477,17 @@ "redownload_started": "ダウンロード開始" }, "ffmpeg_updater": { - "title": "FFmpegアップデーター", + "title": "FFmpegバージョンチェッカー", "current_version": "現在のバージョン:", "latest_version": "最新バージョン:", "status_up_to_date": "✓ 最新", "status_update_available": "⚠ 更新可能", "status_not_installed": "✗ 未インストール", - "status_checking": "🔄 更新を確認中...", - "status_downloading": "⬇ FFmpegをダウンロード中...", - "status_installing": "⚙ FFmpegをインストール中...", - "status_verifying": "✓ 整合性を検証中...", - "check_updates": "更新を確認", - "update_button": "FFmpegを更新", - "update_success": "FFmpegがバージョン{version}に更新されました!", - "update_failed": "FFmpegの更新に失敗しました。再試行してください。", - "check_failed": "更新の確認に失敗しました。インターネット接続を確認してください。", - "install_first": "FFmpegがインストールされていません。インストールするには「更新」をクリックしてください。", - "description": "最高のパフォーマンスと互換性のためにFFmpegを最新の状態に保ってください。" + "status_idle": "開始するには「バージョンを確認」をクリック", + "status_checking": "🔄 バージョンを確認中...", + "check_updates": "バージョンを確認", + "check_failed": "バージョンの確認に失敗しました。インターネット接続を確認してください。", + "description": "FFmpegのバージョンを確認し、利用可能な最新バージョンと比較します。", + "guide_info": " FFmpegをインストールまたは更新するには、こちらをクリックして包括的なインストールガイドをご覧ください。" } } \ No newline at end of file diff --git a/languages/pl.json b/languages/pl.json index 18818ff..35b2800 100644 --- a/languages/pl.json +++ b/languages/pl.json @@ -477,22 +477,17 @@ "redownload_started": "Rozpoczęto pobieranie" }, "ffmpeg_updater": { - "title": "Aktualizator FFmpeg", + "title": "Sprawdzanie Wersji FFmpeg", "current_version": "Obecna wersja:", "latest_version": "Najnowsza wersja:", "status_up_to_date": "✓ Aktualne", "status_update_available": "⚠ Dostępna aktualizacja", "status_not_installed": "✗ Nie zainstalowano", - "status_checking": "🔄 Sprawdzanie aktualizacji...", - "status_downloading": "⬇ Pobieranie FFmpeg...", - "status_installing": "⚙ Instalowanie FFmpeg...", - "status_verifying": "✓ Weryfikacja integralności...", - "check_updates": "Sprawdź aktualizacje", - "update_button": "Aktualizuj FFmpeg", - "update_success": "FFmpeg zaktualizowano pomyślnie do wersji {version}!", - "update_failed": "Nie udało się zaktualizować FFmpeg. Spróbuj ponownie.", - "check_failed": "Nie udało się sprawdzić aktualizacji. Sprawdź połączenie internetowe.", - "install_first": "FFmpeg nie jest zainstalowany. Kliknij Aktualizuj, aby zainstalować.", - "description": "Utrzymuj FFmpeg w aktualnej wersji dla najlepszej wydajności i kompatybilności." + "status_idle": "Kliknij 'Sprawdź Wersję', aby rozpocząć", + "status_checking": "🔄 Sprawdzanie wersji...", + "check_updates": "Sprawdź Wersję", + "check_failed": "Nie udało się sprawdzić wersji. Sprawdź połączenie internetowe.", + "description": "Sprawdź swoją wersję FFmpeg i porównaj ją z najnowszą dostępną wersją.", + "guide_info": " Aby zainstalować lub zaktualizować FFmpeg, kliknij tutaj, aby wyświetlić nasz kompleksowy przewodnik instalacji." } } \ No newline at end of file diff --git a/languages/pt.json b/languages/pt.json index 165be32..db01578 100644 --- a/languages/pt.json +++ b/languages/pt.json @@ -477,22 +477,17 @@ "redownload_started": "Download iniciado" }, "ffmpeg_updater": { - "title": "Atualizador FFmpeg", + "title": "Verificador de Versão FFmpeg", "current_version": "Versão Atual:", "latest_version": "Última Versão:", "status_up_to_date": "✓ Atualizado", "status_update_available": "⚠ Atualização disponível", "status_not_installed": "✗ Não instalado", - "status_checking": "🔄 Verificando atualizações...", - "status_downloading": "⬇ Baixando FFmpeg...", - "status_installing": "⚙ Instalando FFmpeg...", - "status_verifying": "✓ Verificando integridade...", - "check_updates": "Verificar Atualizações", - "update_button": "Atualizar FFmpeg", - "update_success": "FFmpeg atualizado com sucesso para a versão {version}!", - "update_failed": "Falha ao atualizar FFmpeg. Tente novamente.", - "check_failed": "Falha ao verificar atualizações. Verifique sua conexão com a Internet.", - "install_first": "FFmpeg não está instalado. Clique em Atualizar para instalar.", - "description": "Mantenha o FFmpeg atualizado para melhor desempenho e compatibilidade." + "status_idle": "Clique em 'Verificar Versão' para começar", + "status_checking": "🔄 Verificando versão...", + "check_updates": "Verificar Versão", + "check_failed": "Falha ao verificar versão. Verifique sua conexão com a Internet.", + "description": "Verifique sua versão do FFmpeg e compare com a última versão disponível.", + "guide_info": " Para instalar ou atualizar o FFmpeg, clique aqui para ver nosso guia completo de instalação." } } \ No newline at end of file diff --git a/languages/ru.json b/languages/ru.json index c3a8d23..52f4986 100644 --- a/languages/ru.json +++ b/languages/ru.json @@ -477,22 +477,17 @@ "redownload_started": "Загрузка начата" }, "ffmpeg_updater": { - "title": "Обновление FFmpeg", + "title": "Проверка версии FFmpeg", "current_version": "Текущая версия:", "latest_version": "Последняя версия:", "status_up_to_date": "✓ Обновлено", "status_update_available": "⚠ Доступно обновление", "status_not_installed": "✗ Не установлено", - "status_checking": "🔄 Проверка обновлений...", - "status_downloading": "⬇ Загрузка FFmpeg...", - "status_installing": "⚙ Установка FFmpeg...", - "status_verifying": "✓ Проверка целостности...", - "check_updates": "Проверить обновления", - "update_button": "Обновить FFmpeg", - "update_success": "FFmpeg успешно обновлен до версии {version}!", - "update_failed": "Не удалось обновить FFmpeg. Попробуйте еще раз.", - "check_failed": "Не удалось проверить обновления. Проверьте подключение к Интернету.", - "install_first": "FFmpeg не установлен. Нажмите Обновить для установки.", - "description": "Поддерживайте FFmpeg в актуальном состоянии для лучшей производительности и совместимости." + "status_idle": "Нажмите 'Проверить версию' для начала", + "status_checking": "🔄 Проверка версии...", + "check_updates": "Проверить версию", + "check_failed": "Не удалось проверить версию. Проверьте подключение к Интернету.", + "description": "Проверьте версию FFmpeg и сравните ее с последней доступной версией.", + "guide_info": " Для установки или обновления FFmpeg, нажмите здесь, чтобы просмотреть наше подробное руководство по установке." } } \ No newline at end of file diff --git a/languages/tr.json b/languages/tr.json index 0d33adc..ca85c4e 100644 --- a/languages/tr.json +++ b/languages/tr.json @@ -477,22 +477,17 @@ "redownload_started": "İndirme başladı" }, "ffmpeg_updater": { - "title": "FFmpeg Güncelleyici", + "title": "FFmpeg Sürüm Denetçisi", "current_version": "Mevcut Sürüm:", "latest_version": "En Son Sürüm:", "status_up_to_date": "✓ Güncel", "status_update_available": "⚠ Güncelleme mevcut", "status_not_installed": "✗ Yüklü değil", - "status_checking": "🔄 Güncellemeler kontrol ediliyor...", - "status_downloading": "⬇ FFmpeg indiriliyor...", - "status_installing": "⚙ FFmpeg yükleniyor...", - "status_verifying": "✓ Bütünlük doğrulanıyor...", - "check_updates": "Güncellemeleri Kontrol Et", - "update_button": "FFmpeg'i Güncelle", - "update_success": "FFmpeg başarıyla {version} sürümüne güncellendi!", - "update_failed": "FFmpeg güncellemesi başarısız oldu. Lütfen tekrar deneyin.", - "check_failed": "Güncelleme kontrolü başarısız oldu. İnternet bağlantınızı kontrol edin.", - "install_first": "FFmpeg yüklü değil. Yüklemek için Güncelle'ye tıklayın.", - "description": "En iyi performans ve uyumluluk için FFmpeg'i güncel tutun." + "status_idle": "Başlamak için 'Sürümü Kontrol Et'e tıklayın", + "status_checking": "🔄 Sürüm kontrol ediliyor...", + "check_updates": "Sürümü Kontrol Et", + "check_failed": "Sürüm kontrolu başarısız oldu. İnternet bağlantınızı kontrol edin.", + "description": "FFmpeg sürümünüzü kontrol edin ve mevcut en son sürümle karşılaştırın.", + "guide_info": " FFmpeg'i yüklemek veya güncellemek için, kapsamlı kurulum kılavuzumuzu görüntülemek için buraya tıklayın." } } \ No newline at end of file diff --git a/languages/zh.json b/languages/zh.json index 3c2cf32..32ceda2 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -477,22 +477,17 @@ "redownload_started": "已开始下载" }, "ffmpeg_updater": { - "title": "FFmpeg 更新器", + "title": "FFmpeg 版本检查器", "current_version": "当前版本:", "latest_version": "最新版本:", "status_up_to_date": "✓ 已是最新", "status_update_available": "⚠ 有可用更新", "status_not_installed": "✗ 未安装", - "status_checking": "🔄 正在检查更新...", - "status_downloading": "⬇ 正在下载 FFmpeg...", - "status_installing": "⚙ 正在安装 FFmpeg...", - "status_verifying": "✓ 正在验证完整性...", - "check_updates": "检查更新", - "update_button": "更新 FFmpeg", - "update_success": "FFmpeg 已成功更新到版本 {version}!", - "update_failed": "更新 FFmpeg 失败。请重试。", - "check_failed": "检查更新失败。请检查您的网络连接。", - "install_first": "FFmpeg 未安装。点击更新以安装。", - "description": "保持 FFmpeg 更新以获得最佳性能和兼容性。" + "status_idle": "点击「检查版本」开始", + "status_checking": "🔄 正在检查版本...", + "check_updates": "检查版本", + "check_failed": "检查版本失败。请检查您的网络连接。", + "description": "检查您的 FFmpeg 版本并与最新可用版本进行比较。", + "guide_info": " 要安装或更新 FFmpeg,请点击此处查看我们的综合安装指南。" } } \ No newline at end of file diff --git a/src/core/ytsage_ffmpeg.py b/src/core/ytsage_ffmpeg.py index 57e29c4..deb1073 100644 --- a/src/core/ytsage_ffmpeg.py +++ b/src/core/ytsage_ffmpeg.py @@ -12,6 +12,7 @@ from src.utils.ytsage_constants import ( FFMPEG_7Z_DOWNLOAD_URL, FFMPEG_7Z_SHA256_URL, FFMPEG_ZIP_DOWNLOAD_URL, + FFMPEG_ZIP_SHA256_URL, OS_NAME, SUBPROCESS_CREATIONFLAGS, ) @@ -194,7 +195,7 @@ def check_ffmpeg_installed() -> bool: def install_ffmpeg_windows(progress_callback=None) -> bool: - """Install FFmpeg on Windows using 7z method primarily, with zip as fallback.""" + """Install FFmpeg on Windows using essentials build with 7z method primarily, with zip as fallback.""" # Check if already installed if check_ffmpeg_installed(): logger.info("FFmpeg is already installed!") @@ -203,14 +204,176 @@ def install_ffmpeg_windows(progress_callback=None) -> bool: return True try: - # Import the updater for installation - from src.core.ytsage_ffmpeg_updater import update_ffmpeg_windows + # Define variables for essentials build + extract_dir = Path(os.getenv("LOCALAPPDATA")) / "ffmpeg" # type: ignore - # Use the updater to install the latest version - logger.info("Installing FFmpeg using the updater module...") + # Create extraction directory if it doesn't exist + extract_dir.mkdir(exist_ok=True) + + # Try 7z method first (smaller size) + use_7zip = check_7zip_installed() + success = False + + if use_7zip: + logger.info("Using 7-Zip method (smaller download size)...") + if progress_callback: + progress_callback("⚡ Using 7-Zip method...") + temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".7z").name + + # Download 7z file + if progress_callback: + progress_callback("⬇ Downloading FFmpeg (7z)...") + if download_file( + FFMPEG_7Z_DOWNLOAD_URL, + temp_file, + progress_callback=progress_callback, + ): + # Verify SHA-256 hash for 7z file + if progress_callback: + progress_callback("🔐 Verifying download integrity...") + if verify_sha256(temp_file, FFMPEG_7Z_SHA256_URL): + logger.info("Extracting FFmpeg components from 7z archive...") + if progress_callback: + progress_callback("⚙ Extracting FFmpeg...") + try: + subprocess.run( + ["7z", "x", temp_file, f"-o{extract_dir}", "-y"], + creationflags=SUBPROCESS_CREATIONFLAGS, + timeout=300, + check=True, + ) + success = True + except Exception as e: + logger.exception(f"7z extraction failed: {e}, trying zip fallback...") + if progress_callback: + progress_callback("❌ 7z extraction failed, trying zip fallback...") + else: + logger.error("SHA-256 verification failed for 7z file, trying zip fallback...") + if progress_callback: + progress_callback("❌ SHA-256 verification failed, trying zip fallback...") + + # Clean up temp file + try: + Path(temp_file).unlink(missing_ok=True) + except Exception: + pass + + # Fallback to zip method if 7z failed or not available + if not success: + logger.info("Using ZIP method as fallback...") + if progress_callback: + progress_callback("📦 Using ZIP method...") + temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".zip").name + + # Download zip file + if progress_callback: + progress_callback("⬇ Downloading FFmpeg (zip)...") + if not download_file( + FFMPEG_ZIP_DOWNLOAD_URL, + temp_file, + progress_callback=progress_callback, + ): + logger.error("Failed to download FFmpeg (both 7z and zip methods failed)") + if progress_callback: + progress_callback("❌ Failed to download FFmpeg") + return False + + # Verify SHA-256 hash for zip + if progress_callback: + progress_callback("🔐 Verifying download integrity...") + if not verify_sha256(temp_file, FFMPEG_ZIP_SHA256_URL): + logger.warning("SHA-256 verification failed for zip file, proceeding anyway...") + if progress_callback: + progress_callback("⚠️ SHA-256 verification failed, proceeding anyway...") + + logger.info("Extracting FFmpeg components from zip archive...") + if progress_callback: + progress_callback("⚙ Extracting FFmpeg...") + try: + import zipfile + with zipfile.ZipFile(temp_file, "r") as zip_ref: + zip_ref.extractall(extract_dir) + success = True + except Exception as e: + logger.exception(f"Extraction failed: {e}") + if progress_callback: + progress_callback(f"❌ Extraction failed: {e}") + return False + finally: + # Clean up temp file + try: + Path(temp_file).unlink(missing_ok=True) + except Exception: + pass + + if not success: + logger.error("Both 7z and zip methods failed") + if progress_callback: + progress_callback("❌ Installation failed") + return False + + # Find the bin directory in the extracted essentials build + logger.info("Locating FFmpeg binaries...") if progress_callback: - progress_callback("📦 Installing FFmpeg...") - return update_ffmpeg_windows(progress_callback=progress_callback) + progress_callback("🔍 Locating FFmpeg binaries...") + + bin_dir = None + # Look for any directory matching ffmpeg-*-essentials_build pattern + for item in extract_dir.iterdir(): + if item.is_dir() and "essentials_build" in item.name.lower(): + potential_bin = item / "bin" + if potential_bin.exists(): + bin_dir = potential_bin + logger.info(f"Found FFmpeg bin directory: {bin_dir}") + break + + if not bin_dir: + logger.error("Could not locate FFmpeg bin directory") + if progress_callback: + progress_callback("❌ Could not locate FFmpeg bin directory") + return False + + logger.info("Configuring system paths...") + if progress_callback: + progress_callback("🔧 Configuring system paths...") + + # Add to System Path + user_path = os.environ.get("PATH", "") + path_parts = user_path.split(os.pathsep) + + # Remove old FFmpeg paths and add new one + cleaned_paths = [p for p in path_parts if "ffmpeg" not in p.lower() or str(bin_dir) in p] + if str(bin_dir) not in cleaned_paths: + cleaned_paths.insert(0, str(bin_dir)) + + new_path = os.pathsep.join(cleaned_paths) + + try: + subprocess.run( + ["setx", "PATH", new_path], + creationflags=SUBPROCESS_CREATIONFLAGS, + timeout=30, + check=True, + ) + os.environ["PATH"] = new_path + except Exception as e: + logger.warning(f"Failed to update PATH permanently: {e}") + # Still update for current session + os.environ["PATH"] = new_path + + # Verify installation + if progress_callback: + progress_callback("✅ Verifying installation...") + if not check_ffmpeg_installed(): + logger.error("FFmpeg installation verification failed") + if progress_callback: + progress_callback("⚠️ Installation completed but verification failed") + return True # Still return True as files were extracted + + logger.info("FFmpeg installation completed successfully!") + if progress_callback: + progress_callback("✅ FFmpeg installation completed successfully!") + return True except Exception as e: logger.exception(f"Error installing FFmpeg: {e}") diff --git a/src/core/ytsage_ffmpeg_updater.py b/src/core/ytsage_ffmpeg_updater.py deleted file mode 100644 index 814e5bc..0000000 --- a/src/core/ytsage_ffmpeg_updater.py +++ /dev/null @@ -1,413 +0,0 @@ -""" -FFmpeg updater module for YTSage application. -Handles checking for updates and updating FFmpeg to the latest Essentials build. -""" - -import hashlib -import os -import re -import shutil -import subprocess -import tempfile -from pathlib import Path -from typing import Optional, Tuple, Callable - -import requests - -from src.utils.ytsage_logger import logger -from src.utils.ytsage_constants import ( - FFMPEG_7Z_DOWNLOAD_URL, - FFMPEG_7Z_SHA256_URL, - FFMPEG_7Z_VERSION_URL, - FFMPEG_ZIP_DOWNLOAD_URL, - FFMPEG_ZIP_SHA256_URL, - FFMPEG_ZIP_VERSION_URL, - OS_NAME, - SUBPROCESS_CREATIONFLAGS, -) -from src.core.ytsage_ffmpeg import ( - check_7zip_installed, - download_file, - get_file_sha256, - verify_sha256, - get_ffmpeg_install_path, -) -from src.core.ytsage_utils import get_ffmpeg_version_direct - - -def get_latest_ffmpeg_version() -> Optional[str]: - """ - Fetch the latest FFmpeg version from the version URL. - - Returns: - str: Version string (e.g., "8.0") or None if fetch failed - """ - try: - # Try 7z version URL first - response = requests.get(FFMPEG_7Z_VERSION_URL, timeout=10) - response.raise_for_status() - version = response.text.strip() - - # Validate version format (should be something like "8.0" or "7.1.1") - if re.match(r'^\d+\.\d+(\.\d+)?$', version): - logger.info(f"Latest FFmpeg version: {version}") - return version - else: - logger.warning(f"Unexpected version format: {version}") - return None - - except requests.RequestException as e: - logger.error(f"Failed to fetch latest FFmpeg version: {e}") - return None - except Exception as e: - logger.exception(f"Unexpected error fetching FFmpeg version: {e}") - return None - - -def parse_version(version_str: str) -> Tuple[int, ...]: - """ - Parse version string into tuple of integers for comparison. - - Args: - version_str: Version string like "8.0" or "7.1.1" - - Returns: - Tuple of integers (e.g., (8, 0) or (7, 1, 1)) - """ - try: - # Extract version numbers from string - # Handles formats like "8.0", "7.1.1", "ffmpeg version 8.0", etc. - match = re.search(r'(\d+\.\d+(?:\.\d+)?)', version_str) - if match: - version_str = match.group(1) - - parts = version_str.split('.') - return tuple(int(p) for p in parts) - except (ValueError, AttributeError): - logger.warning(f"Could not parse version: {version_str}") - return (0,) - - -def compare_versions(current: str, latest: str) -> bool: - """ - Compare two version strings. - - Args: - current: Current version string - latest: Latest version string - - Returns: - True if update is needed (latest > current), False otherwise - """ - try: - current_tuple = parse_version(current) - latest_tuple = parse_version(latest) - - logger.info(f"Comparing versions - Current: {current_tuple}, Latest: {latest_tuple}") - - # Pad shorter version with zeros for comparison - max_len = max(len(current_tuple), len(latest_tuple)) - current_padded = current_tuple + (0,) * (max_len - len(current_tuple)) - latest_padded = latest_tuple + (0,) * (max_len - len(latest_tuple)) - - return latest_padded > current_padded - except Exception as e: - logger.exception(f"Error comparing versions: {e}") - return False - - -def check_ffmpeg_update_available() -> Tuple[bool, str, str]: - """ - Check if FFmpeg update is available. - - Returns: - Tuple of (update_available, current_version, latest_version) - - update_available: True if update is needed - - current_version: Currently installed version or "Not installed" - - latest_version: Latest available version or "Unknown" - """ - try: - # Get current version - current_version = get_ffmpeg_version_direct() - if current_version in ["Not found", "Error getting version", "Unknown version"]: - current_version = "Not installed" - - # Get latest version - latest_version = get_latest_ffmpeg_version() - if latest_version is None: - latest_version = "Unknown" - return False, current_version, latest_version - - # If not installed, update is needed - if current_version == "Not installed": - return True, current_version, latest_version - - # Compare versions - update_needed = compare_versions(current_version, latest_version) - - return update_needed, current_version, latest_version - - except Exception as e: - logger.exception(f"Error checking for FFmpeg updates: {e}") - return False, "Error", "Error" - - -def get_ffmpeg_extract_dir() -> Path: - """Get the directory where FFmpeg should be extracted.""" - if OS_NAME == "Windows": - return Path(os.getenv("LOCALAPPDATA")) / "ffmpeg" # type: ignore - elif OS_NAME == "Darwin": - return Path.home() / "Library" / "Application Support" / "ffmpeg" - else: - return Path.home() / ".local" / "share" / "ffmpeg" - - -def find_ffmpeg_bin_dir(extract_dir: Path, version: str) -> Optional[Path]: - """ - Find the FFmpeg bin directory after extraction. - - Args: - extract_dir: Directory where FFmpeg was extracted - version: Version string (e.g., "8.0") - - Returns: - Path to bin directory or None if not found - """ - # Expected pattern: ffmpeg-{version}-essentials_build - pattern = f"ffmpeg-{version}-essentials_build" - - # Look for the directory - for item in extract_dir.iterdir(): - if item.is_dir() and item.name.startswith(f"ffmpeg-{version}"): - bin_dir = item / "bin" - if bin_dir.exists(): - logger.info(f"Found FFmpeg bin directory: {bin_dir}") - return bin_dir - - logger.warning(f"Could not find FFmpeg bin directory with pattern: {pattern}") - return None - - -def update_ffmpeg_windows(progress_callback: Optional[Callable[[str], None]] = None) -> bool: - """ - Update FFmpeg on Windows to the latest Essentials build. - - Args: - progress_callback: Optional callback function for progress updates - - Returns: - True if update was successful, False otherwise - """ - if OS_NAME != "Windows": - logger.error("This update method is only for Windows") - return False - - try: - # Track last progress percentage to avoid spam - last_percent = -1 - - def report_progress(msg: str, force: bool = False): - """Helper to report progress (always logged, callback only if force=True or status message).""" - logger.info(msg) - - # Only send callback for non-percentage messages or when forced - if progress_callback and (force or not msg.strip().endswith('%')): - progress_callback(msg) - - def download_progress_wrapper(msg: str): - """Wrapper for download progress that throttles percentage updates.""" - nonlocal last_percent - - # Extract percentage if present - percent_match = re.search(r'(\d+)%', msg) - if percent_match: - current_percent = int(percent_match.group(1)) - # Only report every 10% and to logger only - if current_percent != last_percent and current_percent % 10 == 0: - logger.info(msg) - if progress_callback: - progress_callback(msg) - last_percent = current_percent - else: - # Non-percentage messages get reported normally - report_progress(msg, force=True) - - # Get latest version - report_progress("🔍 Checking latest FFmpeg version...", force=True) - latest_version = get_latest_ffmpeg_version() - if not latest_version: - report_progress("❌ Failed to determine latest version", force=True) - return False - - report_progress(f"📦 Latest version: {latest_version}", force=True) - - extract_dir = get_ffmpeg_extract_dir() - extract_dir.mkdir(exist_ok=True) - - # Try 7z method first (smaller size) - use_7zip = check_7zip_installed() - success = False - - if use_7zip: - report_progress("⚡ Using 7-Zip method (smaller download)...", force=True) - temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".7z").name - - # Download 7z file - report_progress("⬇ Downloading FFmpeg (7z)...", force=True) - last_percent = -1 # Reset for this download - if download_file( - FFMPEG_7Z_DOWNLOAD_URL, - temp_file, - progress_callback=download_progress_wrapper, - ): - # Verify SHA-256 hash - report_progress("🔐 Verifying download integrity...", force=True) - if verify_sha256(temp_file, FFMPEG_7Z_SHA256_URL): - report_progress("⚙ Extracting FFmpeg...", force=True) - try: - subprocess.run( - ["7z", "x", temp_file, f"-o{extract_dir}", "-y"], - creationflags=SUBPROCESS_CREATIONFLAGS, - timeout=300, - check=True, - ) - success = True - except Exception as e: - logger.exception(f"7z extraction failed: {e}") - report_progress(f"❌ 7z extraction failed, trying zip fallback...", force=True) - else: - report_progress("❌ SHA-256 verification failed, trying zip fallback...", force=True) - - # Clean up temp file - try: - Path(temp_file).unlink(missing_ok=True) - except Exception: - pass - - # Fallback to zip method - if not success: - report_progress("📦 Using ZIP method...", force=True) - temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".zip").name - - # Download zip file - report_progress("⬇ Downloading FFmpeg (zip)...", force=True) - last_percent = -1 # Reset for this download - if not download_file( - FFMPEG_ZIP_DOWNLOAD_URL, - temp_file, - progress_callback=download_progress_wrapper, - ): - report_progress("❌ Failed to download FFmpeg", force=True) - return False - - # Verify SHA-256 hash for zip - report_progress("🔐 Verifying download integrity...", force=True) - if not verify_sha256(temp_file, FFMPEG_ZIP_SHA256_URL): - report_progress("⚠️ SHA-256 verification failed, proceeding anyway...", force=True) - - report_progress("⚙ Extracting FFmpeg...", force=True) - try: - import zipfile - with zipfile.ZipFile(temp_file, "r") as zip_ref: - zip_ref.extractall(extract_dir) - success = True - except Exception as e: - logger.exception(f"Extraction failed: {e}") - report_progress(f"❌ Extraction failed: {e}", force=True) - return False - finally: - # Clean up temp file - try: - Path(temp_file).unlink(missing_ok=True) - except Exception: - pass - - if not success: - report_progress("❌ Both 7z and zip methods failed", force=True) - return False - - # Find the bin directory - report_progress("🔍 Locating FFmpeg binaries...", force=True) - bin_dir = find_ffmpeg_bin_dir(extract_dir, latest_version) - if not bin_dir: - report_progress("❌ Could not locate FFmpeg bin directory", force=True) - return False - - # Add to System Path - report_progress("🔧 Configuring system paths...", force=True) - user_path = os.environ.get("PATH", "") - - # Remove old FFmpeg paths from PATH - path_parts = user_path.split(os.pathsep) - cleaned_paths = [p for p in path_parts if "ffmpeg" not in p.lower() or str(bin_dir) in p] - - # Add new path if not already present - if str(bin_dir) not in cleaned_paths: - cleaned_paths.insert(0, str(bin_dir)) - - new_path = os.pathsep.join(cleaned_paths) - - try: - subprocess.run( - ["setx", "PATH", new_path], - creationflags=SUBPROCESS_CREATIONFLAGS, - timeout=30, - check=True, - ) - os.environ["PATH"] = new_path - except Exception as e: - logger.warning(f"Failed to update PATH permanently: {e}") - # Still update for current session - os.environ["PATH"] = new_path - - # Verify installation - report_progress("✅ Verifying installation...", force=True) - new_version = get_ffmpeg_version_direct() - if new_version not in ["Not found", "Error getting version", "Unknown version"]: - report_progress(f"✅ FFmpeg successfully updated to version {new_version}!", force=True) - return True - else: - report_progress("⚠️ Update completed but verification failed", force=True) - return True # Still return True as files were extracted - - except Exception as e: - logger.exception(f"Error updating FFmpeg: {e}") - if progress_callback: - progress_callback(f"❌ Error: {e}") - return False - - -def update_ffmpeg(progress_callback: Optional[Callable[[str], None]] = None) -> bool: - """ - Update FFmpeg based on the operating system. - - Args: - progress_callback: Optional callback function for progress updates - - Returns: - True if update was successful, False otherwise - """ - if OS_NAME == "Windows": - return update_ffmpeg_windows(progress_callback) - elif OS_NAME == "Darwin": - # macOS update via Homebrew - if progress_callback: - progress_callback("🍺 Updating FFmpeg via Homebrew...") - try: - subprocess.run(["brew", "upgrade", "ffmpeg"], check=True, timeout=300) - if progress_callback: - progress_callback("✅ FFmpeg updated successfully!") - return True - except Exception as e: - logger.exception(f"Error updating FFmpeg on macOS: {e}") - if progress_callback: - progress_callback(f"❌ Error: {e}") - return False - elif OS_NAME == "Linux": - # Linux update via package manager - if progress_callback: - progress_callback("📦 Please use your package manager to update FFmpeg") - return False - else: - logger.error(f"Unsupported operating system: {OS_NAME}") - return False diff --git a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py index cc20268..c0a67b2 100644 --- a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py +++ b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_updater.py @@ -1,19 +1,20 @@ """ Updater tab for Custom Options dialog. -Handles checking for and installing FFmpeg updates and yt-dlp auto-update settings. +Handles FFmpeg version checking and yt-dlp auto-update settings. """ +import re import subprocess import threading -from typing import TYPE_CHECKING, cast +from typing import Optional, Tuple, TYPE_CHECKING, cast -from PySide6.QtCore import QObject, Signal +import requests +from PySide6.QtCore import Qt, Signal from PySide6.QtWidgets import ( QCheckBox, QGroupBox, QHBoxLayout, QLabel, - QProgressBar, QPushButton, QRadioButton, QScrollArea, @@ -24,6 +25,7 @@ from PySide6.QtWidgets import ( from src.core.ytsage_utils import ( get_auto_update_settings, + get_ffmpeg_version_direct, update_auto_update_settings, ) from src.core.ytsage_yt_dlp import get_yt_dlp_path @@ -31,35 +33,127 @@ 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 +from src.utils.ytsage_constants import ( + FFMPEG_7Z_VERSION_URL, + OS_NAME, + SUBPROCESS_CREATIONFLAGS, +) if TYPE_CHECKING: from src.gui.ytsage_gui_dialogs.ytsage_dialogs_custom import CustomOptionsDialog -class UpdateWorker(QObject): - """Worker class for running FFmpeg updates in a separate thread.""" +# Helper functions for FFmpeg version checking (copied from removed ytsage_ffmpeg_updater.py) +def get_latest_ffmpeg_version() -> Optional[str]: + """ + Fetch the latest FFmpeg version from the version URL. - progress = Signal(str) # Progress messages - finished = Signal(bool) # Completion status (success/failure) + Returns: + str: Version string (e.g., "8.0") or None if fetch failed + """ + try: + response = requests.get(FFMPEG_7Z_VERSION_URL, timeout=10) + response.raise_for_status() + version = response.text.strip() + + # Validate version format (should be something like "8.0" or "7.1.1") + if re.match(r'^\d+\.\d+(\.\d+)?$', version): + logger.info(f"Latest FFmpeg version: {version}") + return version + else: + logger.warning(f"Unexpected version format: {version}") + return None + + except requests.RequestException as e: + logger.error(f"Failed to fetch latest FFmpeg version: {e}") + return None + except Exception as e: + logger.exception(f"Unexpected error fetching FFmpeg version: {e}") + return None + + +def parse_version(version_str: str) -> Tuple[int, ...]: + """ + Parse version string into tuple of integers for comparison. - def run_update(self): - """Run the FFmpeg update process.""" - try: - def progress_callback(msg: str): - """Callback for progress updates.""" - self.progress.emit(msg) - - # Run the update - success = update_ffmpeg(progress_callback=progress_callback) - self.finished.emit(success) - - except Exception as e: - logger.exception(f"Error during FFmpeg update: {e}") - self.progress.emit(f"❌ Error: {e}") - self.finished.emit(False) + Args: + version_str: Version string like "8.0" or "7.1.1" + + Returns: + Tuple of integers (e.g., (8, 0) or (7, 1, 1)) + """ + try: + # Extract version numbers from string + match = re.search(r'(\d+\.\d+(?:\.\d+)?)', version_str) + if match: + version_str = match.group(1) + + parts = version_str.split('.') + return tuple(int(p) for p in parts) + except (ValueError, AttributeError): + logger.warning(f"Could not parse version: {version_str}") + return (0,) + + +def compare_versions(current: str, latest: str) -> bool: + """ + Compare two version strings. + + Args: + current: Current version string + latest: Latest version string + + Returns: + True if update is needed (latest > current), False otherwise + """ + try: + current_tuple = parse_version(current) + latest_tuple = parse_version(latest) + + logger.info(f"Comparing versions - Current: {current_tuple}, Latest: {latest_tuple}") + + # Pad shorter version with zeros for comparison + max_len = max(len(current_tuple), len(latest_tuple)) + current_padded = current_tuple + (0,) * (max_len - len(current_tuple)) + latest_padded = latest_tuple + (0,) * (max_len - len(latest_tuple)) + + return latest_padded > current_padded + except Exception as e: + logger.exception(f"Error comparing versions: {e}") + return False + + +def check_ffmpeg_version() -> Tuple[bool, str, str]: + """ + Check FFmpeg version and compare with latest. + + Returns: + Tuple of (update_available, current_version, latest_version) + """ + try: + # Get current version + current_version = get_ffmpeg_version_direct() + if current_version in ["Not found", "Error getting version", "Unknown version"]: + current_version = "Not installed" + + # Get latest version + latest_version = get_latest_ffmpeg_version() + if latest_version is None: + latest_version = "Unknown" + return False, current_version, latest_version + + # If not installed, update is available + if current_version == "Not installed": + return True, current_version, latest_version + + # Compare versions + update_needed = compare_versions(current_version, latest_version) + + return update_needed, current_version, latest_version + + except Exception as e: + logger.exception(f"Error checking FFmpeg version: {e}") + return False, "Error", "Error" class UpdaterTabWidget(QWidget): @@ -69,9 +163,6 @@ class UpdaterTabWidget(QWidget): super().__init__(parent) self._parent: "CustomOptionsDialog" = cast("CustomOptionsDialog", self.parent()) - self.update_thread = None - self.update_worker = None - # State variables self.current_version = "Unknown" self.latest_version = "Unknown" @@ -102,7 +193,7 @@ class UpdaterTabWidget(QWidget): help_text.setStyleSheet("color: #999999; padding: 10px;") layout.addWidget(help_text) - # FFmpeg Update Section + # FFmpeg Version Check Section ffmpeg_group = QGroupBox(_('ffmpeg_updater.title')) ffmpeg_layout = QVBoxLayout(ffmpeg_group) @@ -144,10 +235,8 @@ class UpdaterTabWidget(QWidget): ) ffmpeg_layout.addWidget(self.status_label) - # Button layout - button_layout = QHBoxLayout() - - # Check for updates button + # Check version button + check_button_layout = QHBoxLayout() self.check_button = QPushButton(_('ffmpeg_updater.check_updates')) self.check_button.clicked.connect(self.check_for_updates) self.check_button.setStyleSheet( @@ -170,84 +259,34 @@ class UpdaterTabWidget(QWidget): } """ ) - button_layout.addWidget(self.check_button) + check_button_layout.addWidget(self.check_button) + check_button_layout.addStretch() + ffmpeg_layout.addLayout(check_button_layout) - button_layout.addStretch() - - # Update button - self.update_button = QPushButton(_('ffmpeg_updater.update_button')) - self.update_button.clicked.connect(self.start_update) - self.update_button.setEnabled(False) - self.update_button.setStyleSheet( + # Installation guide info + guide_label = QLabel(_('ffmpeg_updater.guide_info')) + guide_label.setWordWrap(True) + guide_label.setOpenExternalLinks(True) # Enable clickable links + guide_label.setTextFormat(Qt.TextFormat.RichText) # Enable HTML formatting + guide_label.setStyleSheet( """ - QPushButton { - padding: 8px 15px; - background-color: #c90000; - border: none; + QLabel { + color: #cccccc; + font-size: 11px; + padding: 8px; + background-color: #1a1d20; border-radius: 4px; - color: white; - font-weight: bold; - min-width: 120px; } - QPushButton:hover { - background-color: #a50000; + QLabel a { + color: #4da6ff; + text-decoration: underline; } - QPushButton:disabled { - background-color: #4a4a4a; - color: #888888; + QLabel a:hover { + color: #66b3ff; } """ ) - button_layout.addWidget(self.update_button) - - ffmpeg_layout.addLayout(button_layout) - - # Progress bar - self.progress_bar = QProgressBar() - self.progress_bar.setRange(0, 0) # Indeterminate progress - self.progress_bar.setVisible(False) - self.progress_bar.setStyleSheet( - """ - QProgressBar { - border: 2px solid #2a2d36; - border-radius: 4px; - background-color: #1d1e22; - text-align: center; - color: #ffffff; - height: 20px; - } - QProgressBar::chunk { - background-color: #c90000; - border-radius: 2px; - } - """ - ) - ffmpeg_layout.addWidget(self.progress_bar) - - # Log output - log_label = QLabel("Update Log:") - 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(60) - self.log_output.setMaximumHeight(100) - self.log_output.setStyleSheet( - """ - QTextEdit { - background-color: #1d1e22; - color: #ffffff; - border: 2px solid #2a2d36; - border-radius: 6px; - padding: 8px; - font-family: 'Consolas', 'Monaco', 'Courier New', monospace; - font-size: 11px; - } - """ - ) - ffmpeg_layout.addWidget(self.log_output) + ffmpeg_layout.addWidget(guide_label) layout.addWidget(ffmpeg_group) @@ -596,27 +635,25 @@ class UpdaterTabWidget(QWidget): dialog.show() # Use show() instead of exec() to avoid blocking def check_for_updates(self) -> None: - """Check if FFmpeg updates are available.""" + """Check FFmpeg version and compare with latest.""" self.check_button.setEnabled(False) - self.update_button.setEnabled(False) self.status_label.setText(_('ffmpeg_updater.status_checking')) self.status_label.setStyleSheet( "color: #ffaa00; font-size: 12px; padding: 8px; " "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" ) - self.log_output.append("🔍 Checking for FFmpeg updates...") # Run check in background thread def check_thread(): try: - update_available, current_version, latest_version = check_ffmpeg_update_available() + update_available, current_version, latest_version = check_ffmpeg_version() - # Update UI in main thread using signals + # Update UI in main thread self.check_button.setEnabled(True) self._update_check_results(update_available, current_version, latest_version) except Exception as e: - logger.exception(f"Error checking for updates: {e}") + logger.exception(f"Error checking FFmpeg version: {e}") self.check_button.setEnabled(True) self._show_check_error(str(e)) @@ -624,7 +661,7 @@ class UpdaterTabWidget(QWidget): thread.start() def _update_check_results(self, update_available: bool, current_version: str, latest_version: str) -> None: - """Handle completion of update check.""" + """Handle completion of version check.""" self.update_available = update_available self.current_version = current_version self.latest_version = latest_version @@ -635,97 +672,28 @@ class UpdaterTabWidget(QWidget): # Update status if current_version == "Not installed": - self.status_label.setText(_('ffmpeg_updater.install_first')) + self.status_label.setText(_('ffmpeg_updater.status_not_installed')) self.status_label.setStyleSheet( "color: #ff6666; font-size: 12px; padding: 8px; " "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" ) - self.update_button.setEnabled(True if OS_NAME == "Windows" else False) - self.log_output.append(f"❌ FFmpeg is not installed. Latest version available: {latest_version}") elif update_available: self.status_label.setText(_('ffmpeg_updater.status_update_available')) self.status_label.setStyleSheet( "color: #ffaa00; font-size: 12px; padding: 8px; " "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" ) - self.update_button.setEnabled(True if OS_NAME == "Windows" else False) - self.log_output.append(f"⚠ Update available: {current_version} → {latest_version}") else: self.status_label.setText(_('ffmpeg_updater.status_up_to_date')) self.status_label.setStyleSheet( "color: #00cc00; font-size: 12px; padding: 8px; " "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" ) - self.update_button.setEnabled(False) - self.log_output.append(f"✅ FFmpeg is up to date (version {current_version})") - - # Show message for non-Windows systems - if OS_NAME != "Windows" and update_available: - self.log_output.append("ℹ️ Automatic updates are only available on Windows.") - self.log_output.append(" Please use your system's package manager to update FFmpeg.") def _show_check_error(self, error: str) -> None: - """Handle error during update check.""" + """Handle error during version check.""" self.status_label.setText(_('ffmpeg_updater.check_failed')) self.status_label.setStyleSheet( "color: #ff6666; font-size: 12px; padding: 8px; " "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" ) - self.log_output.append(f"❌ Error checking for updates: {error}") - - def start_update(self) -> None: - """Start the FFmpeg update process.""" - if OS_NAME != "Windows": - self.log_output.append("❌ Automatic updates are only supported on Windows.") - return - - # Disable buttons during update - self.check_button.setEnabled(False) - self.update_button.setEnabled(False) - self.progress_bar.setVisible(True) - - self.log_output.append("=" * 60) - self.log_output.append("🚀 Starting FFmpeg update process...") - self.log_output.append("=" * 60) - - # Create worker and thread - self.update_worker = UpdateWorker() - self.update_thread = threading.Thread(target=self.update_worker.run_update, daemon=True) - - # Connect signals - self.update_worker.progress.connect(self._on_update_progress) - self.update_worker.finished.connect(self._on_update_finished) - - # Start update - self.update_thread.start() - - def _on_update_progress(self, message: str) -> None: - """Handle progress updates from the update worker.""" - self.log_output.append(message) - # Auto-scroll to bottom - cursor = self.log_output.textCursor() - cursor.movePosition(cursor.MoveOperation.End) - self.log_output.setTextCursor(cursor) - - def _on_update_finished(self, success: bool) -> None: - """Handle completion of the update process.""" - self.progress_bar.setVisible(False) - self.check_button.setEnabled(True) - - self.log_output.append("=" * 60) - - if success: - self.log_output.append(_('ffmpeg_updater.update_success', version=self.latest_version)) - self.status_label.setText(_('ffmpeg_updater.status_up_to_date')) - self.status_label.setStyleSheet( - "color: #00cc00; font-size: 12px; padding: 8px; " - "background-color: #2a2d36; border-radius: 4px; margin: 5px 0;" - ) - # Re-check to update version info - self.check_for_updates() - else: - self.log_output.append(_('ffmpeg_updater.update_failed')) - self.status_label.setText(_('ffmpeg_updater.status_update_available')) - self.update_button.setEnabled(True) - - self.log_output.append("=" * 60)