diff --git a/src/core/ytsage_deno.py b/src/core/ytsage_deno.py index e470a97..5d6d137 100644 --- a/src/core/ytsage_deno.py +++ b/src/core/ytsage_deno.py @@ -462,6 +462,50 @@ def get_deno_path() -> Path: return "deno" # type: ignore[return-value] +def get_deno_version_direct(deno_path=None) -> str: + """ + Get Deno version directly without caching. + + Args: + deno_path: Optional path to Deno binary. If None, uses get_deno_path() + + Returns: + str: Version string or error message + """ + try: + if deno_path is None: + deno_path = get_deno_path() + + if not deno_path or deno_path == "deno": + return "Not found" + + result = subprocess.run( + [str(deno_path), "--version"], + capture_output=True, + text=True, + timeout=10, + creationflags=SUBPROCESS_CREATIONFLAGS + ) + + if result.returncode == 0: + # Deno outputs: "deno 1.38.0 (release, x86_64-pc-windows-msvc)" + # Extract version from first line + lines = result.stdout.strip().split("\n") + if lines: + first_line = lines[0] + # Extract version number (e.g., "1.38.0" from "deno 1.38.0 ...") + parts = first_line.split() + if len(parts) >= 2 and parts[0] == "deno": + return parts[1] + return first_line.strip() + return "Unknown version" + else: + return "Error getting version" + except Exception as e: + logger.exception(f"Error getting Deno version: {e}") + return "Error getting version" + + def setup_deno(parent_widget=None): """ Show the Deno setup dialog and handle the result. diff --git a/src/core/ytsage_utils.py b/src/core/ytsage_utils.py index 6f273bb..3cfe5e5 100644 --- a/src/core/ytsage_utils.py +++ b/src/core/ytsage_utils.py @@ -45,6 +45,7 @@ except ImportError: _version_cache = { "ytdlp": {"version": None, "path": None, "last_check": 0, "path_mtime": 0}, "ffmpeg": {"version": None, "path": None, "last_check": 0, "path_mtime": 0}, + "deno": {"version": None, "path": None, "last_check": 0, "path_mtime": 0}, } # Cache expiry time in seconds (5 minutes) @@ -173,8 +174,34 @@ def get_ffmpeg_version_cached() -> str: return "Error getting version" +def get_deno_version_cached() -> str: + """Get Deno version with caching support.""" + try: + from src.core.ytsage_deno import get_deno_path + + current_path = get_deno_path() + + # Check if we need to refresh cache + if not should_refresh_cache("deno", current_path): + cached_version = _version_cache["deno"].get("version") + if cached_version: + return cached_version + + # Get fresh version info + from src.core.ytsage_deno import get_deno_version_direct + version_info = get_deno_version_direct(current_path) + + # Update cache + update_version_cache("deno", version_info, current_path) + + return version_info + except Exception as e: + logger.exception(f"Error getting cached Deno version: {e}") + return "Error getting version" + + def refresh_version_cache(force=False) -> bool: - """Manually refresh version cache for both tools.""" + """Manually refresh version cache for all tools.""" try: # Refresh yt-dlp current_path = get_yt_dlp_path() @@ -185,6 +212,12 @@ def refresh_version_cache(force=False) -> bool: version_info = get_ffmpeg_version_direct() update_version_cache("ffmpeg", version_info, "ffmpeg", force_save=True) + # Refresh Deno + from src.core.ytsage_deno import get_deno_path, get_deno_version_direct + deno_path = get_deno_path() + version_info = get_deno_version_direct(deno_path) + update_version_cache("deno", version_info, deno_path, force_save=True) + return True except Exception as e: logger.exception(f"Error refreshing version cache: {e}") @@ -201,6 +234,11 @@ def get_ffmpeg_version() -> str: return get_ffmpeg_version_cached() +def get_deno_version() -> str: + """Get the version of Deno (uses cached version for performance).""" + return get_deno_version_cached() + + def get_ytdlp_version_direct(yt_dlp_path=None) -> str: """Get yt-dlp version directly without caching.""" try: diff --git a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_base.py b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_base.py index b5788d4..3ac4a39 100644 --- a/src/gui/ytsage_gui_dialogs/ytsage_dialogs_base.py +++ b/src/gui/ytsage_gui_dialogs/ytsage_dialogs_base.py @@ -23,8 +23,9 @@ from src import __version__ as APP_VERSION from src.utils.ytsage_localization import _ from src.core.ytsage_ffmpeg import get_ffmpeg_path -from src.core.ytsage_utils import _version_cache, check_ffmpeg, get_ffmpeg_version, get_ytdlp_version, refresh_version_cache +from src.core.ytsage_utils import _version_cache, check_ffmpeg, get_ffmpeg_version, get_ytdlp_version, get_deno_version, refresh_version_cache from src.core.ytsage_yt_dlp import check_ytdlp_installed, get_yt_dlp_path +from src.core.ytsage_deno import check_deno_installed, get_deno_path class LogWindow(QDialog): @@ -442,6 +443,42 @@ class AboutDialog(QDialog): ) self.status_container.addWidget(ffmpeg_item) + # Deno Status - compact version with path (only show path if in app bin directory) + deno_found = check_deno_installed() + deno_status_text = ( + f"{_('about.detected')}" if deno_found else f"{_('about.missing')}" + ) + deno_version = get_deno_version() if deno_found else _('about.not_available') + + # Get Deno path - only show if in app bin directory + deno_path_text = None + if deno_found: + deno_path = get_deno_path() + # Only show path if it's not the fallback "deno" and the file exists + if deno_path and deno_path != "deno": + from pathlib import Path + from src.utils.ytsage_constants import DENO_APP_BIN_PATH + # Check if the path is our managed binary + if Path(deno_path).resolve() == DENO_APP_BIN_PATH.resolve(): + deno_path_text = deno_path + + # Simplified cache status for Deno + deno_cache = _version_cache.get("deno", {}) + last_check = deno_cache.get("last_check", 0) + cache_status = "" + if last_check > 0 and deno_found: + cache_time = datetime.fromtimestamp(last_check).strftime("%H:%M") + cache_status = f" ({cache_time})" + + deno_item = self._create_status_item( + "🦕", + "Deno", + deno_status_text, + deno_version + cache_status, + deno_path_text, + ) + self.status_container.addWidget(deno_item) + def refresh_version_info(self) -> None: """Refresh version information manually.""" self.refresh_btn.setText(_('about.refreshing'))