diff --git a/ytsage_gui_video_info.py b/src/gui/ytsage_gui_video_info.py similarity index 74% rename from ytsage_gui_video_info.py rename to src/gui/ytsage_gui_video_info.py index c903fe4..50ab915 100644 --- a/ytsage_gui_video_info.py +++ b/src/gui/ytsage_gui_video_info.py @@ -16,13 +16,14 @@ from pathlib import Path from packaging import version import subprocess import re +from ..core.ytsage_logging import logger try: import yt_dlp YT_DLP_AVAILABLE = True except ImportError: YT_DLP_AVAILABLE = False - print("Warning: yt-dlp not available at startup, will be downloaded at runtime") -from ytsage_gui_dialogs import SubtitleSelectionDialog + logger.warning("yt-dlp not available at startup, will be downloaded at runtime") +from .ytsage_gui_dialogs import SubtitleSelectionDialog, SponsorBlockCategoryDialog class VideoInfoMixin: def setup_video_info_section(self): @@ -124,6 +125,53 @@ class VideoInfoMixin: video_info_layout.addLayout(subtitle_layout) # --- End Subtitle Section --- + # Add small spacing between subtitle and sponsorblock sections + video_info_layout.addSpacing(4) + + # --- SponsorBlock Section --- + sponsorblock_layout = QHBoxLayout() + + self.sponsorblock_select_btn = QPushButton("SponsorBlock Categories...") + self.sponsorblock_select_btn.setFixedHeight(30) + self.sponsorblock_select_btn.clicked.connect(self.open_sponsorblock_dialog) + self.sponsorblock_select_btn.setStyleSheet(""" + QPushButton { + background-color: #1d1e22; + border: 2px solid #1d1e22; + border-radius: 4px; + padding: 5px 10px; + } + QPushButton:hover { + background-color: #2a2d36; + } + QPushButton[sponsorBlockSelected="true"] { + border-color: #c90000; + } + QPushButton:disabled { + background-color: #3d3d3d; + color: #888888; + border-color: #3d3d3d; + } + """) + self.sponsorblock_select_btn.setProperty("sponsorBlockSelected", False) + self.sponsorblock_select_btn.setProperty("sponsorBlockSelected", False) + sponsorblock_layout.addWidget(self.sponsorblock_select_btn) + + # Label to show selection count + self.selected_sponsorblock_label = QLabel("0 selected") + self.selected_sponsorblock_label.setStyleSheet("color: #cccccc; padding-left: 5px;") + sponsorblock_layout.addWidget(self.selected_sponsorblock_label) + + sponsorblock_layout.addStretch() + + # Add the sponsorblock layout to the main video info layout + video_info_layout.addLayout(sponsorblock_layout) + # --- End SponsorBlock Section --- + + # Initialize SponsorBlock categories as empty initially (will be set to defaults when user opens dialog) + self.selected_sponsorblock_categories = [] + self._update_sponsorblock_display() + # Add stretch at the bottom video_info_layout.addStretch() @@ -208,7 +256,7 @@ class VideoInfoMixin: def open_subtitle_dialog(self): if not hasattr(self, 'available_subtitles') or not hasattr(self, 'available_automatic_subtitles'): - print("Subtitle info not loaded yet.") + logger.warning("Subtitle info not loaded yet.") return if not hasattr(self, 'selected_subtitles'): @@ -227,7 +275,7 @@ class VideoInfoMixin: if not isinstance(main_window, QMainWindow): # If the structure is different, this might need adjustment # Maybe self.parentWidget() or similar depending on how Mixin is used - print("Warning: Cannot find main window to access merge checkbox.") + logger.warning("Cannot find main window to access merge checkbox.") merge_checkbox = None else: merge_checkbox = getattr(main_window, 'merge_subs_checkbox', None) @@ -235,7 +283,7 @@ class VideoInfoMixin: if dialog.exec(): # If user clicks OK self.selected_subtitles = dialog.get_selected_subtitles() - print(f"Selected subtitles: {self.selected_subtitles}") + logger.info(f"Selected subtitles: {self.selected_subtitles}") # Update UI to reflect selection count = len(self.selected_subtitles) self.selected_subs_label.setText(f"{count} selected") @@ -249,13 +297,51 @@ class VideoInfoMixin: should_enable = count > 0 and not is_audio_only merge_checkbox.setEnabled(should_enable) else: - print("Warning: merge_subs_checkbox not found on parent window.") + logger.warning("merge_subs_checkbox not found on parent window.") # Re-apply stylesheet to update button border if property changed self.subtitle_select_btn.style().unpolish(self.subtitle_select_btn) self.subtitle_select_btn.style().polish(self.subtitle_select_btn) # No else needed for cancel, state remains unchanged + def open_sponsorblock_dialog(self): + """Open the SponsorBlock category selection dialog.""" + # Initialize selected categories if not exists or empty (first time opening) + if not hasattr(self, 'selected_sponsorblock_categories') or not self.selected_sponsorblock_categories: + # Use None to let the dialog set its own defaults + dialog_categories = None + else: + dialog_categories = self.selected_sponsorblock_categories + + dialog = SponsorBlockCategoryDialog(dialog_categories, self) + + if dialog.exec(): + self.selected_sponsorblock_categories = dialog.get_selected_categories() + logger.info(f"SponsorBlock categories selected: {self.selected_sponsorblock_categories}") + self._update_sponsorblock_display() + + def _update_sponsorblock_display(self): + """Update the SponsorBlock button and label to reflect current selection.""" + if not hasattr(self, 'selected_sponsorblock_categories'): + self.selected_sponsorblock_categories = [] + + count = len(self.selected_sponsorblock_categories) + + # Update label text + if count == 0: + self.selected_sponsorblock_label.setText("0 selected") + elif count == 1: + self.selected_sponsorblock_label.setText("1 category selected") + else: + self.selected_sponsorblock_label.setText(f"{count} categories selected") + + # Update button property for styling + self.sponsorblock_select_btn.setProperty("sponsorBlockSelected", count > 0) + + # Force style refresh + self.sponsorblock_select_btn.style().unpolish(self.sponsorblock_select_btn) + self.sponsorblock_select_btn.style().polish(self.sponsorblock_select_btn) + def download_thumbnail(self, url): try: # Store both thumbnail URL and video URL @@ -274,7 +360,7 @@ class VideoInfoMixin: pixmap.loadFromData(img_byte_arr.getvalue()) self.thumbnail_label.setPixmap(pixmap) except Exception as e: - print(f"Error loading thumbnail: {str(e)}") + logger.error(f"Error loading thumbnail: {str(e)}") def download_thumbnail_file(self, video_url, path): if not self.save_thumbnail: @@ -284,7 +370,7 @@ class VideoInfoMixin: from yt_dlp import YoutubeDL import requests # Use requests instead of urlopen - print(f"Attempting to save thumbnail for URL: {video_url}") + logger.debug(f"Attempting to save thumbnail for URL: {video_url}") ydl_opts = { 'quiet': True, @@ -323,13 +409,13 @@ class VideoInfoMixin: with open(thumbnail_path, 'wb') as f: f.write(response.content) - print(f"Thumbnail saved to: {thumbnail_path}") + logger.info(f"Thumbnail saved to: {thumbnail_path}") self.signals.update_status.emit(f"✅ Thumbnail saved: {filename}") return True except Exception as e: error_msg = f"❌ Thumbnail error: {str(e)}" - print(f"Thumbnail Save Error: {str(e)}") + logger.error(f"Thumbnail Save Error: {str(e)}") self.signals.update_status.emit(error_msg) return False