From d81adc4781b8f7468cdfdda971052a2c91bb4fef Mon Sep 17 00:00:00 2001 From: Your Name Date: Thu, 2 Oct 2025 21:16:27 +0300 Subject: [PATCH] Replace notes column with FPS in format table The format table now displays FPS (frame rate) instead of notes in both playlist and normal modes. All translations were updated to remove the 'notes' and related size/quality fields, replacing them with 'fps'. The table column widths were adjusted for better visibility, and FPS values are color-coded based on their value. The obsolete _get_format_notes method was removed. --- languages/ar.json | 9 +- languages/de.json | 9 +- languages/en.json | 9 +- languages/es.json | 9 +- languages/fr.json | 9 +- languages/hi.json | 9 +- languages/id.json | 9 +- languages/it.json | 9 +- languages/ja.json | 9 +- languages/pl.json | 9 +- languages/pt.json | 9 +- languages/ru.json | 9 +- languages/tr.json | 9 +- languages/zh.json | 9 +- src/gui/ytsage_gui_format_table.py | 148 +++++++++++++---------------- 15 files changed, 95 insertions(+), 179 deletions(-) diff --git a/languages/ar.json b/languages/ar.json index 95cf234..e7253ea 100644 --- a/languages/ar.json +++ b/languages/ar.json @@ -39,16 +39,11 @@ "file_size": "حجم الملف", "codec": "الترميز", "audio": "الصوت", - "notes": "ملاحظات", + "fps": "إطار/ث", "will_merge_audio": "سيتم دمج الصوت", "has_audio": "✓ يحتوي على صوت", "audio_only": "صوت فقط", - "large_size": "حجم كبير", - "medium_size": "حجم متوسط", - "standard_size": "حجم قياسي", - "compatible": "متوافق", - "efficient": "فعال", - "high_quality": "جودة عالية", + "best_4k": "الأفضل (4K)", "best_2k": "الأفضل (2K)", "high_1080p": "عالية (1080p)", diff --git a/languages/de.json b/languages/de.json index e2afb9e..9f98326 100644 --- a/languages/de.json +++ b/languages/de.json @@ -39,16 +39,11 @@ "file_size": "Dateigröße", "codec": "Codec", "audio": "Audio", - "notes": "Notizen", + "fps": "FPS", "will_merge_audio": "Audio wird zusammengeführt", "has_audio": "✓ Hat Audio", "audio_only": "Nur Audio", - "large_size": "Große Größe", - "medium_size": "Mittlere Größe", - "standard_size": "Standardgröße", - "compatible": "Kompatibel", - "efficient": "Effizient", - "high_quality": "Hohe Qualität", + "best_4k": "Beste (4K)", "best_2k": "Beste (2K)", "high_1080p": "Hoch (1080p)", diff --git a/languages/en.json b/languages/en.json index f515192..bb5f6c6 100644 --- a/languages/en.json +++ b/languages/en.json @@ -39,16 +39,11 @@ "file_size": "File Size", "codec": "Codec", "audio": "Audio", - "notes": "Notes", + "fps": "FPS", "will_merge_audio": "Will merge audio", "has_audio": "✓ Has Audio", "audio_only": "Audio Only", - "large_size": "Large size", - "medium_size": "Medium size", - "standard_size": "Standard size", - "compatible": "Compatible", - "efficient": "Efficient", - "high_quality": "High quality", + "best_4k": "Best (4K)", "best_2k": "Best (2K)", "high_1080p": "High (1080p)", diff --git a/languages/es.json b/languages/es.json index 68ce558..05dbf62 100644 --- a/languages/es.json +++ b/languages/es.json @@ -132,16 +132,11 @@ "file_size": "Tamaño", "codec": "Códec", "audio": "Audio", - "notes": "Notas", + "fps": "FPS", "will_merge_audio": "Se combinará audio", "has_audio": "✓ Tiene Audio", "audio_only": "Solo Audio", - "large_size": "Tamaño grande", - "medium_size": "Tamaño mediano", - "standard_size": "Tamaño estándar", - "compatible": "Compatible", - "efficient": "Eficiente", - "high_quality": "Alta calidad", + "best_4k": "Óptima (4K)", "best_2k": "Óptima (2K)", "high_1080p": "Alta (1080p)", diff --git a/languages/fr.json b/languages/fr.json index be3cc05..365d266 100644 --- a/languages/fr.json +++ b/languages/fr.json @@ -39,16 +39,11 @@ "file_size": "Taille du fichier", "codec": "Codec", "audio": "Audio", - "notes": "Notes", + "fps": "IPS", "will_merge_audio": "L'audio sera fusionné", "has_audio": "✓ Contient de l'audio", "audio_only": "Audio uniquement", - "large_size": "Taille importante", - "medium_size": "Taille moyenne", - "standard_size": "Taille standard", - "compatible": "Compatible", - "efficient": "Efficace", - "high_quality": "Haute qualité", + "best_4k": "Meilleure (4K)", "best_2k": "Meilleure (2K)", "high_1080p": "Haute (1080p)", diff --git a/languages/hi.json b/languages/hi.json index 0daaa7a..253449e 100644 --- a/languages/hi.json +++ b/languages/hi.json @@ -39,16 +39,11 @@ "file_size": "फ़ाइल आकार", "codec": "कोडेक", "audio": "ऑडियो", - "notes": "नोट्स", + "fps": "फ्रेम दर", "will_merge_audio": "ऑडियो मर्ज किया जाएगा", "has_audio": "✓ ऑडियो है", "audio_only": "केवल ऑडियो", - "large_size": "बड़ा आकार", - "medium_size": "मध्यम आकार", - "standard_size": "मानक आकार", - "compatible": "संगत", - "efficient": "कुशल", - "high_quality": "उच्च गुणवत्ता", + "best_4k": "सर्वोत्तम (4K)", "best_2k": "सर्वोत्तम (2K)", "high_1080p": "उच्च (1080p)", diff --git a/languages/id.json b/languages/id.json index 1e0cebf..54375c6 100644 --- a/languages/id.json +++ b/languages/id.json @@ -39,16 +39,11 @@ "file_size": "Ukuran file", "codec": "Codec", "audio": "Audio", - "notes": "Catatan", + "fps": "FPS", "will_merge_audio": "Audio akan digabungkan", "has_audio": "✓ Memiliki audio", "audio_only": "Audio saja", - "large_size": "Ukuran besar", - "medium_size": "Ukuran sedang", - "standard_size": "Ukuran standar", - "compatible": "Kompatibel", - "efficient": "Efisien", - "high_quality": "Kualitas tinggi", + "best_4k": "Terbaik (4K)", "best_2k": "Terbaik (2K)", "high_1080p": "Tinggi (1080p)", diff --git a/languages/it.json b/languages/it.json index 379661b..501a5dc 100644 --- a/languages/it.json +++ b/languages/it.json @@ -39,16 +39,11 @@ "file_size": "Dimensione file", "codec": "Codec", "audio": "Audio", - "notes": "Note", + "fps": "FPS", "will_merge_audio": "L'audio verrà unito", "has_audio": "✓ Contiene audio", "audio_only": "Solo audio", - "large_size": "Dimensione grande", - "medium_size": "Dimensione media", - "standard_size": "Dimensione standard", - "compatible": "Compatibile", - "efficient": "Efficiente", - "high_quality": "Alta qualità", + "best_4k": "Migliore (4K)", "best_2k": "Migliore (2K)", "high_1080p": "Alta (1080p)", diff --git a/languages/ja.json b/languages/ja.json index 4736feb..d03c55f 100644 --- a/languages/ja.json +++ b/languages/ja.json @@ -39,16 +39,11 @@ "file_size": "ファイルサイズ", "codec": "コーデック", "audio": "音声", - "notes": "備考", + "fps": "FPS", "will_merge_audio": "音声が結合されます", "has_audio": "✓ 音声あり", "audio_only": "音声のみ", - "large_size": "大サイズ", - "medium_size": "中サイズ", - "standard_size": "標準サイズ", - "compatible": "互換性あり", - "efficient": "効率的", - "high_quality": "高品質", + "best_4k": "最高 (4K)", "best_2k": "最高 (2K)", "high_1080p": "高 (1080p)", diff --git a/languages/pl.json b/languages/pl.json index 9ac5bf3..f560a4d 100644 --- a/languages/pl.json +++ b/languages/pl.json @@ -39,16 +39,11 @@ "file_size": "Rozmiar pliku", "codec": "Kodek", "audio": "Dźwięk", - "notes": "Notatki", + "fps": "KL/S", "will_merge_audio": "Dźwięk zostanie połączony", "has_audio": "✓ Zawiera dźwięk", "audio_only": "Tylko dźwięk", - "large_size": "Duży rozmiar", - "medium_size": "Średni rozmiar", - "standard_size": "Standardowy rozmiar", - "compatible": "Zgodny", - "efficient": "Wydajny", - "high_quality": "Wysoka jakość", + "best_4k": "Najlepsza (4K)", "best_2k": "Najlepsza (2K)", "high_1080p": "Wysoka (1080p)", diff --git a/languages/pt.json b/languages/pt.json index 3e2bfd3..7f9cefe 100644 --- a/languages/pt.json +++ b/languages/pt.json @@ -39,16 +39,11 @@ "file_size": "Tamanho do Arquivo", "codec": "Codec", "audio": "Áudio", - "notes": "Notas", + "fps": "FPS", "will_merge_audio": "Irá mesclar áudio", "has_audio": "✓ Tem Áudio", "audio_only": "Apenas Áudio", - "large_size": "Tamanho grande", - "medium_size": "Tamanho médio", - "standard_size": "Tamanho padrão", - "compatible": "Compatível", - "efficient": "Eficiente", - "high_quality": "Alta qualidade", + "best_4k": "Melhor (4K)", "best_2k": "Melhor (2K)", "high_1080p": "Alta (1080p)", diff --git a/languages/ru.json b/languages/ru.json index 21bc797..9759dd2 100644 --- a/languages/ru.json +++ b/languages/ru.json @@ -39,16 +39,11 @@ "file_size": "Размер файла", "codec": "Кодек", "audio": "Аудио", - "notes": "Заметки", + "fps": "Кадр/с", "will_merge_audio": "Объединит аудио", "has_audio": "✓ Есть аудио", "audio_only": "Только аудио", - "large_size": "Большой размер", - "medium_size": "Средний размер", - "standard_size": "Стандартный размер", - "compatible": "Совместимый", - "efficient": "Эффективный", - "high_quality": "Высокое качество", + "best_4k": "Лучшее (4K)", "best_2k": "Лучшее (2K)", "high_1080p": "Высокое (1080p)", diff --git a/languages/tr.json b/languages/tr.json index 78a075e..105717a 100644 --- a/languages/tr.json +++ b/languages/tr.json @@ -39,16 +39,11 @@ "file_size": "Dosya boyutu", "codec": "Codec", "audio": "Ses", - "notes": "Notlar", + "fps": "FPS", "will_merge_audio": "Ses birleştirilecek", "has_audio": "✓ Ses var", "audio_only": "Sadece ses", - "large_size": "Büyük boyut", - "medium_size": "Orta boyut", - "standard_size": "Standart boyut", - "compatible": "Uyumlu", - "efficient": "Verimli", - "high_quality": "Yüksek kalite", + "best_4k": "En iyi (4K)", "best_2k": "En iyi (2K)", "high_1080p": "Yüksek (1080p)", diff --git a/languages/zh.json b/languages/zh.json index e49884f..3a34211 100644 --- a/languages/zh.json +++ b/languages/zh.json @@ -39,16 +39,11 @@ "file_size": "文件大小", "codec": "编解码器", "audio": "音频", - "notes": "备注", + "fps": "帧率", "will_merge_audio": "将合并音频", "has_audio": "✓ 有音频", "audio_only": "仅音频", - "large_size": "大尺寸", - "medium_size": "中等尺寸", - "standard_size": "标准尺寸", - "compatible": "兼容", - "efficient": "高效", - "high_quality": "高质量", + "best_4k": "最佳 (4K)", "best_2k": "最佳 (2K)", "high_1080p": "高清 (1080p)", diff --git a/src/gui/ytsage_gui_format_table.py b/src/gui/ytsage_gui_format_table.py index 9be5186..ecfc410 100644 --- a/src/gui/ytsage_gui_format_table.py +++ b/src/gui/ytsage_gui_format_table.py @@ -31,7 +31,7 @@ class FormatTableMixin: _("formats.file_size"), _("formats.codec"), _("formats.audio"), - _("formats.notes"), + _("formats.fps"), ] ) @@ -40,27 +40,28 @@ class FormatTableMixin: # Set specific column widths and resize modes self.format_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.Fixed) # Select - self.format_table.setColumnWidth(0, 80) # Select column width (increased for longer translations) + self.format_table.setColumnWidth(0, 70) # Select column width (slightly reduced) self.format_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed) # Quality - self.format_table.setColumnWidth(1, 100) # Quality width + self.format_table.setColumnWidth(1, 110) # Quality width (increased for better visibility) self.format_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Fixed) # Extension - self.format_table.setColumnWidth(2, 80) # Extension width + self.format_table.setColumnWidth(2, 85) # Extension width (slightly increased) self.format_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Fixed) # Resolution - self.format_table.setColumnWidth(3, 100) # Resolution width + self.format_table.setColumnWidth(3, 110) # Resolution width (increased for better visibility) self.format_table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.Fixed) # File Size - self.format_table.setColumnWidth(4, 100) # File Size width + self.format_table.setColumnWidth(4, 110) # File Size width (increased for better readability) self.format_table.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Fixed) # Codec - self.format_table.setColumnWidth(5, 150) # Codec width + self.format_table.setColumnWidth(5, 160) # Codec width (increased for codec names) self.format_table.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.Fixed) # Audio - self.format_table.setColumnWidth(6, 120) # Audio width + self.format_table.setColumnWidth(6, 140) # Audio width (increased for better text visibility) - self.format_table.horizontalHeader().setSectionResizeMode(7, QHeaderView.ResizeMode.Stretch) # Notes (will stretch) + self.format_table.horizontalHeader().setSectionResizeMode(7, QHeaderView.ResizeMode.Stretch) # FPS column stretches to fill + # FPS column will stretch to fill remaining space # Set vertical header (row numbers) visible to false self.format_table.verticalHeader().setVisible(False) @@ -185,7 +186,7 @@ class FormatTableMixin: # Configure columns based on mode if is_playlist_mode: self.format_table.setColumnCount(5) - self.format_table.setHorizontalHeaderLabels([_("formats.select"), _("formats.quality"), _("formats.resolution"), _("formats.notes"), _("formats.audio")]) + self.format_table.setHorizontalHeaderLabels([_("formats.select"), _("formats.quality"), _("formats.resolution"), _("formats.fps"), _("formats.audio")]) # Configure column visibility and resizing for playlist mode self.format_table.setColumnHidden(5, True) @@ -211,37 +212,32 @@ class FormatTableMixin: _("formats.file_size"), _("formats.codec"), _("formats.audio"), - _("formats.notes"), + _("formats.fps"), ] ) # Ensure all columns are visible for i in range(2, 8): self.format_table.setColumnHidden(i, False) - # Reapply resize modes for non-playlist mode if needed (optional, might be okay without) + # Reapply optimized resize modes for non-playlist mode self.format_table.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeMode.Fixed) - self.format_table.setColumnWidth(0, 80) # Match the width set in setup_format_table + self.format_table.setColumnWidth(0, 70) # Match the optimized width self.format_table.horizontalHeader().setSectionResizeMode(1, QHeaderView.ResizeMode.Fixed) - self.format_table.setColumnWidth(1, 100) + self.format_table.setColumnWidth(1, 110) self.format_table.horizontalHeader().setSectionResizeMode(2, QHeaderView.ResizeMode.Fixed) - self.format_table.setColumnWidth(2, 80) + self.format_table.setColumnWidth(2, 85) self.format_table.horizontalHeader().setSectionResizeMode(3, QHeaderView.ResizeMode.Fixed) - self.format_table.setColumnWidth(3, 100) + self.format_table.setColumnWidth(3, 110) self.format_table.horizontalHeader().setSectionResizeMode(4, QHeaderView.ResizeMode.Fixed) - self.format_table.setColumnWidth(4, 100) + self.format_table.setColumnWidth(4, 110) self.format_table.horizontalHeader().setSectionResizeMode(5, QHeaderView.ResizeMode.Fixed) - self.format_table.setColumnWidth(5, 150) + self.format_table.setColumnWidth(5, 160) self.format_table.horizontalHeader().setSectionResizeMode(6, QHeaderView.ResizeMode.Fixed) - self.format_table.setColumnWidth(6, 120) + self.format_table.setColumnWidth(6, 140) self.format_table.horizontalHeader().setSectionResizeMode(7, QHeaderView.ResizeMode.Stretch) + # FPS column stretches to fill remaining space + - # Find best quality format for recommendations (only needed for non-playlist mode notes) - best_video_size = 0 - if not is_playlist_mode: - best_video_size = max( - (f.get("filesize", 0) for f in formats if f.get("vcodec") != "none"), - default=0, - ) for f in formats: row = self.format_table.rowCount() @@ -284,18 +280,30 @@ class FormatTableMixin: resolution = _("formats.audio_only_resolution") self.format_table.setItem(row, 2, QTableWidgetItem(resolution)) - # Column 3: Notes for playlist mode, Extension for normal mode + # Column 3: FPS for playlist mode, Extension for normal mode if is_playlist_mode: - # Get notes for playlist mode - notes = self._get_format_notes(f) - notes_item = QTableWidgetItem(notes) - if "✨ Recommended" in notes: - notes_item.setForeground(QColor("#00ff00")) # Green for recommended - elif "💾 Storage friendly" in notes: - notes_item.setForeground(QColor("#00ccff")) # Blue for storage friendly - elif "📱 Mobile friendly" in notes: - notes_item.setForeground(QColor("#ff9900")) # Orange for mobile - self.format_table.setItem(row, 3, notes_item) + # Get FPS for playlist mode + fps_value = f.get("fps") + if fps_value is not None: + # Format FPS value appropriately + if fps_value >= 1: + fps_text = f"{fps_value:.0f}fps" + else: + fps_text = "N/A" # Very low fps like storyboards + else: + fps_text = "N/A" + + fps_item = QTableWidgetItem(fps_text) + # Color code based on FPS value + if fps_value and fps_value >= 60: + fps_item.setForeground(QColor("#00ff00")) # Green for 60+ fps + elif fps_value and fps_value >= 30: + fps_item.setForeground(QColor("#ffaa00")) # Orange for 30+ fps + elif fps_value and fps_value >= 1: + fps_item.setForeground(QColor("#ff5555")) # Red for low fps + else: + fps_item.setForeground(QColor("#888888")) # Gray for N/A + self.format_table.setItem(row, 3, fps_item) else: # Extension for normal mode (column 2) self.format_table.setItem(row, 2, QTableWidgetItem(f.get("ext", "").upper())) @@ -332,16 +340,28 @@ class FormatTableMixin: codec += f" / {f.get('acodec', 'N/A')}" self.format_table.setItem(row, 5, QTableWidgetItem(codec)) - # Column 7: Notes - notes = self._get_format_notes(f) - notes_item = QTableWidgetItem(notes) - if "✨ Recommended" in notes: - notes_item.setForeground(QColor("#00ff00")) # Green for recommended - elif "💾 Storage friendly" in notes: - notes_item.setForeground(QColor("#00ccff")) # Blue for storage friendly - elif "📱 Mobile friendly" in notes: - notes_item.setForeground(QColor("#ff9900")) # Orange for mobile - self.format_table.setItem(row, 7, notes_item) + # Column 7: FPS (Frame Rate) + fps_value = f.get("fps") + if fps_value is not None: + # Format FPS value appropriately + if fps_value >= 1: + fps_text = f"{fps_value:.0f}fps" + else: + fps_text = "N/A" # Very low fps like storyboards + else: + fps_text = "N/A" + + fps_item = QTableWidgetItem(fps_text) + # Color code based on FPS value + if fps_value and fps_value >= 60: + fps_item.setForeground(QColor("#00ff00")) # Green for 60+ fps + elif fps_value and fps_value >= 30: + fps_item.setForeground(QColor("#ffaa00")) # Orange for 30+ fps + elif fps_value and fps_value >= 1: + fps_item.setForeground(QColor("#ff5555")) # Red for low fps + else: + fps_item.setForeground(QColor("#888888")) # Gray for N/A + self.format_table.setItem(row, 7, fps_item) def handle_checkbox_click(self, clicked_checkbox) -> None: self = cast("YTSageApp", self) # for autocompletion and type inference. @@ -402,38 +422,4 @@ class FormatTableMixin: else: return _("formats.low_quality") - def _get_format_notes(self, format_info) -> str: - """Generate helpful format notes based on format info.""" - self = cast("YTSageApp", self) # for autocompletion and type inference. - - notes = [] - # Add storage indicator with more granular categories - file_size = format_info.get("filesize") or format_info.get("filesize_approx", 0) - - # Better file size categories - if file_size > 50 * 1024 * 1024: # Over 50MB - notes.append(_("formats.large_size")) - elif file_size > 15 * 1024 * 1024: # 15-50MB - notes.append(_("formats.medium_size")) - elif file_size > 5 * 1024 * 1024: # 5-15MB - notes.append(_("formats.standard_size")) - else: # Under 5MB - notes.append("Small size") - - # Add codec quality indicator - vcodec = format_info.get("vcodec", "") - if vcodec != "none": - if "avc1" in vcodec: # H.264 - notes.append(_("formats.compatible")) - elif "av01" in vcodec: # AV1 - notes.append(_("formats.efficient")) - elif "vp9" in vcodec: # VP9 - notes.append(_("formats.high_quality")) - - # Add quick mobile compatibility check - if "avc1" in vcodec and file_size < 8 * 1024 * 1024: - notes.append("Mobile") - - # Return simple string - return " • ".join(notes)