From 894f99901797acb8a1aa22cb4392151affa212b4 Mon Sep 17 00:00:00 2001
From: oop7 <110548351+oop7@users.noreply.github.com>
Date: Fri, 14 Nov 2025 18:19:02 +0200
Subject: [PATCH] Add Deno version detection and caching support
Introduces functions to detect Deno version directly and with caching in ytsage_deno.py and ytsage_utils.py. Updates the About dialog to display Deno status, version, and path if available. Also extends version cache refresh logic to include Deno.
---
src/core/ytsage_deno.py | 44 +++++++++++++++++++
src/core/ytsage_utils.py | 40 ++++++++++++++++-
.../ytsage_gui_dialogs/ytsage_dialogs_base.py | 39 +++++++++++++++-
3 files changed, 121 insertions(+), 2 deletions(-)
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'))