Add generic-mode URL validation and UI

Introduce a "generic_mode" option to allow validating/downloading from non-YouTube sites and wire it through the UI, config, and validation logic. Key changes:

- Add generic_mode default to ConfigManager and persist setting from DownloadSettingsDialog (checkbox + help text).
- Extend validate_video_url to accept a generic_mode flag and allow any http/https URL with a domain when enabled; pass this flag from Analysis and Download flows.
- Update YTSageApp to load/save generic_mode, update URL placeholder and settings tooltip behavior, and refresh tooltip when settings change.
- Improve robustness in FormatTableMixin: handle None/incorrect types for format_note, abr, resolution, ext, and codec values to avoid type errors and ensure consistent display.
- Add localization entries for generic mode, placeholder, and related help text across multiple language files and update the in-app default localization strings.

These changes enable broader site support via yt-dlp while hardening UI format handling and keeping user settings persistent.
This commit is contained in:
oop7
2026-03-12 11:10:10 +02:00
parent a98dad0a33
commit 9afca46c5d
21 changed files with 152 additions and 30 deletions
+36 -20
View File
@@ -257,6 +257,7 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin, AnalysisMixin):
self.preferred_output_format = ConfigManager.get("preferred_output_format") or "mp4"
self.force_audio_format = ConfigManager.get("force_audio_format") or False
self.preferred_audio_format = ConfigManager.get("preferred_audio_format") or "best"
self.generic_mode_enabled = ConfigManager.get("generic_mode") or False
# Track if video analysis is completed
self.analysis_completed = False
@@ -351,7 +352,7 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin, AnalysisMixin):
url_layout.setSpacing(10)
self.url_input = QLineEdit()
self.url_input.setPlaceholderText(_("main_ui.url_placeholder"))
self._update_url_placeholder()
self.url_input.returnPressed.connect(self.analyze_url) # Analyze on Enter key
self.url_input.textChanged.connect(self._on_url_text_changed) # Enable/disable analyze button
self.url_input.setMinimumHeight(42)
@@ -489,13 +490,7 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin, AnalysisMixin):
# --- Rename Path Button to Settings Button ---
self.settings_button = QPushButton(_("buttons.download_settings")) # Renamed button
self.settings_button.clicked.connect(self.show_download_settings_dialog) # Renamed method
self.settings_button.setToolTip(
_(
"main_ui.settings_tooltip",
path=self.last_path,
speed_limit=_("main_ui.speed_limit_none"),
)
) # Update initial tooltip
self._update_settings_tooltip()
# --- End Settings Button ---
self.download_btn = QPushButton(_("buttons.download"))
@@ -581,6 +576,27 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin, AnalysisMixin):
"""Enable or disable the Analyze button based on URL input content."""
self.analyze_button.setEnabled(bool(text.strip()))
def _get_speed_limit_tooltip_text(self) -> str:
"""Return the current speed limit string for the settings tooltip."""
if self.speed_limit_value:
return f"{self.speed_limit_value} {['KB/s', 'MB/s'][self.speed_limit_unit_index]}"
return _("main_ui.speed_limit_none")
def _update_settings_tooltip(self) -> None:
"""Refresh the download settings tooltip text."""
self.settings_button.setToolTip(
_(
"main_ui.settings_tooltip",
path=self.last_path,
speed_limit=self._get_speed_limit_tooltip_text(),
)
)
def _update_url_placeholder(self) -> None:
"""Update the URL placeholder based on the selected validation mode."""
placeholder_key = "main_ui.url_placeholder_generic" if self.generic_mode_enabled else "main_ui.url_placeholder"
self.url_input.setPlaceholderText(_(placeholder_key))
def paste_url(self) -> None:
@@ -631,18 +647,18 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin, AnalysisMixin):
audio_format_changed = True
logger.info(f"Audio format settings updated - Force: {self.force_audio_format}, Preferred: {self.preferred_audio_format}")
# Update Generic Mode Setting
new_generic_mode = dialog.get_generic_mode_enabled()
generic_mode_changed = False
if new_generic_mode != self.generic_mode_enabled:
self.generic_mode_enabled = new_generic_mode
generic_mode_changed = True
self._update_url_placeholder()
logger.info(f"Generic mode updated - Enabled: {self.generic_mode_enabled}")
# Update Tooltip if anything changed
if path_changed or limit_changed or format_changed or audio_format_changed:
limit_text = _("main_ui.speed_limit_none")
if self.speed_limit_value:
limit_text = f"{self.speed_limit_value} {['KB/s', 'MB/s'][self.speed_limit_unit_index]}"
self.settings_button.setToolTip(
_(
"main_ui.settings_tooltip",
path=self.last_path,
speed_limit=limit_text,
)
)
if path_changed or limit_changed or format_changed or audio_format_changed or generic_mode_changed:
self._update_settings_tooltip()
def start_download(self) -> None:
if self.is_updating_ytdlp:
@@ -669,7 +685,7 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin, AnalysisMixin):
# --- End Path Change ---
# Validate URL before starting download
is_valid, error_message = validate_video_url(url)
is_valid, error_message = validate_video_url(url, generic_mode=self.generic_mode_enabled)
if not is_valid:
QMessageBox.warning(self, _("main_ui.error_title"), error_message)
self.animate_widget_shake(self.url_input)