Add URL validation and ytdlp error messages to translations

Added new translation keys for URL validation and ytdlp error messages in all supported languages. This improves error reporting and user feedback for invalid URLs and common download issues.
This commit is contained in:
oop7
2025-10-26 21:05:57 +03:00
parent 952ac88518
commit 8d2e7bd553
16 changed files with 340 additions and 56 deletions
+19 -55
View File
@@ -20,6 +20,7 @@ from src.utils.ytsage_constants import (
YTDLP_APP_BIN_PATH,
YTDLP_DOWNLOAD_URL,
)
from src.utils.ytsage_localization import _
from src.utils.ytsage_logger import logger
try:
@@ -677,17 +678,11 @@ def parse_yt_dlp_error(error_message: str) -> str:
# Private video errors
if any(keyword in error_str for keyword in ["private video", "login_required", "sign in if you"]):
return (
"This is a private video. You can download it by logging into your account using cookies.\n"
"Go to 'Custom Options''Login with Cookies''Extract cookies from browser' to authenticate."
)
return _("ytdlp_errors.private_video")
# Age-restricted content
if any(keyword in error_str for keyword in ["age restricted", "age-restricted", "confirm your age"]):
return (
"This video is age-restricted. You need to be logged in to access it.\n"
"Use 'Custom Options''Login with Cookies' to authenticate with your account."
)
return _("ytdlp_errors.age_restricted")
# Geo-blocked content
if any(
@@ -699,66 +694,42 @@ def parse_yt_dlp_error(error_message: str) -> str:
"not made this video available in your country",
]
):
return (
"This video is not available in your region (geo-blocked).\n"
"You may need to use a VPN or the video might be restricted in your country."
)
return _("ytdlp_errors.geo_blocked")
# Removed/deleted videos
if any(keyword in error_str for keyword in ["video unavailable", "this video has been removed", "video does not exist"]):
return (
"This video has been removed or is no longer available.\n"
"The video may have been deleted by the uploader or removed due to policy violations."
)
return _("ytdlp_errors.video_unavailable")
# Live stream errors
if any(keyword in error_str for keyword in ["live stream", "livestream", "is live"]):
return (
"This is a live stream that cannot be downloaded while active.\n"
"Wait for the stream to end, then try downloading the archived version."
)
return _("ytdlp_errors.live_stream")
# Playlist errors
if any(keyword in error_str for keyword in ["playlist", "no entries"]):
return (
"Unable to access this playlist. It may be private, deleted, or empty.\n"
"Check if the playlist exists and is publicly accessible."
)
return _("ytdlp_errors.playlist_error")
# Network/connection errors
if any(keyword in error_str for keyword in ["network error", "connection", "timeout", "unable to download"]):
return (
"Network connection error. Please check your internet connection and try again.\n"
"If the problem persists, the video server might be temporarily unavailable."
)
return _("ytdlp_errors.network_error")
# Invalid URL
if any(keyword in error_str for keyword in ["invalid url", "unsupported url", "no video found"]):
return (
"Invalid or unsupported URL. Please check the link and try again.\n"
"Make sure you're using a valid YouTube, Vimeo, or other supported platform URL."
)
return _("ytdlp_errors.invalid_url")
# YouTube premium content
if any(keyword in error_str for keyword in ["youtube premium", "premium", "members only"]):
return (
"This content requires YouTube Premium or channel membership.\n"
"You need to be logged in with an account that has access to this content."
)
return _("ytdlp_errors.premium_content")
# Copyright/DMCA
if any(keyword in error_str for keyword in ["copyright", "dmca", "blocked"]):
return "This video is blocked due to copyright claims.\n" "The content owner has restricted access to this video."
return _("ytdlp_errors.copyright_blocked")
# Extraction errors (could be temporary)
if any(keyword in error_str for keyword in ["unable to extract", "extraction failed"]):
return (
"Failed to extract video information. This might be a temporary issue.\n"
"Please try again in a few minutes, or check if the video link is correct."
)
return _("ytdlp_errors.extraction_failed")
# Generic fallback with the original error for debugging
return f"Could not extract video information. Please check your link.\n" f"Technical details: {error_message}"
return _("ytdlp_errors.generic_error", error=error_message)
def validate_video_url(url: str) -> tuple[bool, str]:
@@ -782,7 +753,7 @@ def validate_video_url(url: str) -> tuple[bool, str]:
# Check if URL is empty
if not url or not url.strip():
return False, "URL cannot be empty"
return False, _("url_validation.empty_url")
url = url.strip()
@@ -791,15 +762,15 @@ def validate_video_url(url: str) -> tuple[bool, str]:
parsed = urlparse(url)
except Exception as e:
logger.debug(f"URL parsing error: {e}")
return False, "Invalid URL format"
return False, _("url_validation.invalid_format")
# Check if scheme is http or https
if parsed.scheme not in ['http', 'https']:
return False, "URL must start with http:// or https://"
return False, _("url_validation.invalid_scheme")
# Check if netloc (domain) exists
if not parsed.netloc:
return False, "Invalid URL: missing domain name"
return False, _("url_validation.missing_domain")
# YTSage focuses on YouTube and YouTube Music only
# Supported YouTube domains
@@ -820,14 +791,7 @@ def validate_video_url(url: str) -> tuple[bool, str]:
)
if not is_youtube:
return False, (
"YTSage only supports YouTube and YouTube Music URLs.\n"
f"The domain '{parsed.netloc}' is not supported.\n\n"
"Supported domains:\n"
" • youtube.com\n"
" • youtu.be\n"
" • music.youtube.com"
)
return False, _("url_validation.unsupported_platform", domain=parsed.netloc)
# Optional: Validate YouTube URL patterns
# Common YouTube URL patterns:
@@ -849,7 +813,7 @@ def validate_video_url(url: str) -> tuple[bool, str]:
# For youtu.be, the path itself is the video ID
if 'youtu.be' in netloc_lower:
if not parsed.path or parsed.path == '/':
return False, "Invalid youtu.be URL: missing video ID"
return False, _("url_validation.invalid_youtu_be")
return True, ""
# For youtube.com domains, check for valid patterns
+13 -1
View File
@@ -29,7 +29,7 @@ from PySide6.QtWidgets import (
)
from src.core.ytsage_downloader import DownloadThread, SignalManager # Import downloader related classes
from src.core.ytsage_utils import check_ffmpeg, load_saved_path, parse_yt_dlp_error, save_path, should_check_for_auto_update
from src.core.ytsage_utils import check_ffmpeg, load_saved_path, parse_yt_dlp_error, save_path, should_check_for_auto_update, validate_video_url
from src.core.ytsage_yt_dlp import get_yt_dlp_path, setup_ytdlp # Import the new yt-dlp functions
from src.gui.ytsage_gui_dialogs import ( # use of src\gui\ytsage_gui_dialogs\__init__.py
AboutDialog,
@@ -707,6 +707,12 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from
if not url:
self.signals.update_status.emit(_("main_ui.invalid_url_or_enter"))
return
# Validate URL before processing
is_valid, error_message = validate_video_url(url)
if not is_valid:
self.signals.update_status.emit(error_message)
return
self.signals.update_status.emit(_("main_ui.analyzing_preparing"))
threading.Thread(target=self._analyze_url_thread, args=(url,), daemon=True).start()
@@ -788,6 +794,12 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from
self.status_label.setText(_('download.please_enter_url_and_path'))
return
# --- End Path Change ---
# Validate URL before starting download
is_valid, error_message = validate_video_url(url)
if not is_valid:
self.status_label.setText(error_message)
return
# Get selected format
format_id = self.get_selected_format()