Add Deno integration check and system info thread
Introduce check_ytdlp_deno_integration() in ytsage_yt_dlp.py to detect Deno integration by running `yt-dlp --verbose` and scanning debug output for JS runtimes containing "deno" (with timeout and logging/fallback). Add SystemInfoThread (QThread) in ytsage_dialogs_base.py to collect yt-dlp, ffmpeg and deno presence, versions, paths, cache timestamps and integration status in the background, emitting the gathered info via info_ready. AboutDialog now starts the thread in update_system_info() and populates the UI asynchronously via _populate_system_info(), showing a small "+ yt-dlp" integration indicator next to the Deno status when detected. Refactors usage of version/cache lookups to use the thread-provided info dictionary.
This commit is contained in:
@@ -712,3 +712,43 @@ def setup_ytdlp(parent_widget=None):
|
|||||||
# User cancelled or setup failed, return the fallback command
|
# User cancelled or setup failed, return the fallback command
|
||||||
logger.debug("Returning fallback command 'yt-dlp'")
|
logger.debug("Returning fallback command 'yt-dlp'")
|
||||||
return "yt-dlp"
|
return "yt-dlp"
|
||||||
|
|
||||||
|
|
||||||
|
def check_ytdlp_deno_integration() -> bool:
|
||||||
|
"""
|
||||||
|
Check if yt-dlp is integrated with Deno by running 'yt-dlp --verbose'.
|
||||||
|
Returns:
|
||||||
|
bool: True if Deno is detected in JS runtimes, False otherwise
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
ytdlp_path = get_yt_dlp_path()
|
||||||
|
if not ytdlp_path or ytdlp_path == "yt-dlp":
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Run yt-dlp --verbose to check JS runtimes
|
||||||
|
# We use a dummy URL or just --verbose with no URL (which might error but should print debug info)
|
||||||
|
# However, yt-dlp might not print debug info if no URL is provided and it errors out immediately with "usage".
|
||||||
|
# But per user example: "yt-dlp.exe: error: You must provide at least one URL." comes AFTER debug info.
|
||||||
|
|
||||||
|
result = subprocess.run(
|
||||||
|
[str(ytdlp_path), "--verbose"],
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
timeout=10,
|
||||||
|
creationflags=SUBPROCESS_CREATIONFLAGS
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check stderr for "[debug] JS runtimes: deno"
|
||||||
|
output = result.stderr
|
||||||
|
if "[debug] JS runtimes:" in output and "deno" in output:
|
||||||
|
# Find the line
|
||||||
|
for line in output.splitlines():
|
||||||
|
if "[debug] JS runtimes:" in line and "deno" in line:
|
||||||
|
logger.info(f"Deno integration detected: {line.strip()}")
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Failed to check yt-dlp Deno integration: {e}")
|
||||||
|
return False
|
||||||
|
|||||||
@@ -24,10 +24,55 @@ from ...utils.ytsage_localization import _
|
|||||||
|
|
||||||
from ...core.ytsage_ffmpeg import get_ffmpeg_path
|
from ...core.ytsage_ffmpeg import get_ffmpeg_path
|
||||||
from ...core.ytsage_utils import _version_cache, check_ffmpeg, get_ffmpeg_version, get_ytdlp_version, get_deno_version, refresh_version_cache
|
from ...core.ytsage_utils import _version_cache, check_ffmpeg, get_ffmpeg_version, get_ytdlp_version, get_deno_version, refresh_version_cache
|
||||||
from ...core.ytsage_yt_dlp import check_ytdlp_installed, get_yt_dlp_path
|
from ...core.ytsage_yt_dlp import check_ytdlp_installed, get_yt_dlp_path, check_ytdlp_deno_integration
|
||||||
from ...core.ytsage_deno import check_deno_installed, get_deno_path
|
from ...core.ytsage_deno import check_deno_installed, get_deno_path
|
||||||
|
|
||||||
|
|
||||||
|
class SystemInfoThread(QThread):
|
||||||
|
"""Background thread to gather system information."""
|
||||||
|
info_ready = Signal(dict)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
info = {}
|
||||||
|
|
||||||
|
# yt-dlp Status
|
||||||
|
ytdlp_found = check_ytdlp_installed()
|
||||||
|
info['ytdlp_found'] = ytdlp_found
|
||||||
|
info['ytdlp_version'] = get_ytdlp_version()
|
||||||
|
info['ytdlp_path'] = get_yt_dlp_path() if ytdlp_found else None
|
||||||
|
|
||||||
|
# yt-dlp cache status
|
||||||
|
ytdlp_cache = _version_cache.get("ytdlp", {})
|
||||||
|
info['ytdlp_last_check'] = ytdlp_cache.get("last_check", 0)
|
||||||
|
|
||||||
|
# FFmpeg Status
|
||||||
|
ffmpeg_found = check_ffmpeg()
|
||||||
|
info['ffmpeg_found'] = ffmpeg_found
|
||||||
|
info['ffmpeg_version'] = get_ffmpeg_version() if ffmpeg_found else _('about.not_available')
|
||||||
|
info['ffmpeg_path'] = get_ffmpeg_path() if ffmpeg_found else None
|
||||||
|
|
||||||
|
# FFmpeg cache status
|
||||||
|
ffmpeg_cache = _version_cache.get("ffmpeg", {})
|
||||||
|
info['ffmpeg_last_check'] = ffmpeg_cache.get("last_check", 0)
|
||||||
|
|
||||||
|
# Deno Status
|
||||||
|
deno_found = check_deno_installed()
|
||||||
|
info['deno_found'] = deno_found
|
||||||
|
info['deno_version'] = get_deno_version() if deno_found else _('about.not_available')
|
||||||
|
info['deno_path'] = get_deno_path() if deno_found else None
|
||||||
|
|
||||||
|
# Deno cache status
|
||||||
|
deno_cache = _version_cache.get("deno", {})
|
||||||
|
info['deno_last_check'] = deno_cache.get("last_check", 0)
|
||||||
|
|
||||||
|
# Check integration with yt-dlp if both are present
|
||||||
|
info['integration_status'] = False
|
||||||
|
if deno_found and ytdlp_found:
|
||||||
|
info['integration_status'] = check_ytdlp_deno_integration()
|
||||||
|
|
||||||
|
self.info_ready.emit(info)
|
||||||
|
|
||||||
|
|
||||||
class LogWindow(QDialog):
|
class LogWindow(QDialog):
|
||||||
def __init__(self, parent=None) -> None:
|
def __init__(self, parent=None) -> None:
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@@ -378,7 +423,13 @@ class AboutDialog(QDialog):
|
|||||||
return item_widget
|
return item_widget
|
||||||
|
|
||||||
def update_system_info(self) -> None:
|
def update_system_info(self) -> None:
|
||||||
"""Update the system information display with compact layout."""
|
"""Start background thread to gather system info."""
|
||||||
|
self.info_thread = SystemInfoThread()
|
||||||
|
self.info_thread.info_ready.connect(self._populate_system_info)
|
||||||
|
self.info_thread.start()
|
||||||
|
|
||||||
|
def _populate_system_info(self, info: dict) -> None:
|
||||||
|
"""Populate UI with gathered info."""
|
||||||
# Clear existing items
|
# Clear existing items
|
||||||
for i in reversed(range(self.status_container.count())):
|
for i in reversed(range(self.status_container.count())):
|
||||||
child = self.status_container.itemAt(i).widget()
|
child = self.status_container.itemAt(i).widget()
|
||||||
@@ -386,19 +437,18 @@ class AboutDialog(QDialog):
|
|||||||
child.deleteLater()
|
child.deleteLater()
|
||||||
|
|
||||||
# yt-dlp Status - compact version with path
|
# yt-dlp Status - compact version with path
|
||||||
ytdlp_found = check_ytdlp_installed()
|
ytdlp_found = info['ytdlp_found']
|
||||||
ytdlp_status_text = (
|
ytdlp_status_text = (
|
||||||
f"<span style='color: #4CAF50;'>{_('about.detected')}</span>" if ytdlp_found else f"<span style='color: #F44336;'>{_('about.missing')}</span>"
|
f"<span style='color: #4CAF50;'>{_('about.detected')}</span>" if ytdlp_found else f"<span style='color: #F44336;'>{_('about.missing')}</span>"
|
||||||
)
|
)
|
||||||
ytdlp_version = get_ytdlp_version()
|
ytdlp_version = info['ytdlp_version']
|
||||||
|
|
||||||
# Get yt-dlp path
|
# Get yt-dlp path
|
||||||
ytdlp_path = get_yt_dlp_path() if ytdlp_found else None
|
ytdlp_path = info['ytdlp_path']
|
||||||
ytdlp_path_text = ytdlp_path if ytdlp_path and ytdlp_path != "yt-dlp" else None
|
ytdlp_path_text = ytdlp_path if ytdlp_path and ytdlp_path != "yt-dlp" else None
|
||||||
|
|
||||||
# Simplified cache status
|
# Simplified cache status
|
||||||
ytdlp_cache = _version_cache.get("ytdlp", {})
|
last_check = info['ytdlp_last_check']
|
||||||
last_check = ytdlp_cache.get("last_check", 0)
|
|
||||||
cache_status = ""
|
cache_status = ""
|
||||||
if last_check > 0:
|
if last_check > 0:
|
||||||
cache_time = datetime.fromtimestamp(last_check).strftime("%H:%M")
|
cache_time = datetime.fromtimestamp(last_check).strftime("%H:%M")
|
||||||
@@ -414,23 +464,19 @@ class AboutDialog(QDialog):
|
|||||||
self.status_container.addWidget(ytdlp_item)
|
self.status_container.addWidget(ytdlp_item)
|
||||||
|
|
||||||
# FFmpeg Status - compact version with path
|
# FFmpeg Status - compact version with path
|
||||||
ffmpeg_found = check_ffmpeg()
|
ffmpeg_found = info['ffmpeg_found']
|
||||||
ffmpeg_status_text = (
|
ffmpeg_status_text = (
|
||||||
f"<span style='color: #4CAF50;'>{_('about.detected')}</span>"
|
f"<span style='color: #4CAF50;'>{_('about.detected')}</span>"
|
||||||
if ffmpeg_found
|
if ffmpeg_found
|
||||||
else f"<span style='color: #F44336;'>{_('about.missing')}</span>"
|
else f"<span style='color: #F44336;'>{_('about.missing')}</span>"
|
||||||
)
|
)
|
||||||
ffmpeg_version = get_ffmpeg_version() if ffmpeg_found else _('about.not_available')
|
ffmpeg_version = info['ffmpeg_version']
|
||||||
|
|
||||||
# Get FFmpeg path
|
# Get FFmpeg path
|
||||||
ffmpeg_path_text = None
|
ffmpeg_path_text = info['ffmpeg_path']
|
||||||
if ffmpeg_found:
|
|
||||||
ffmpeg_path = get_ffmpeg_path()
|
|
||||||
ffmpeg_path_text = ffmpeg_path if ffmpeg_path else None
|
|
||||||
|
|
||||||
# Simplified cache status for FFmpeg
|
# Simplified cache status for FFmpeg
|
||||||
ffmpeg_cache = _version_cache.get("ffmpeg", {})
|
last_check = info['ffmpeg_last_check']
|
||||||
last_check = ffmpeg_cache.get("last_check", 0)
|
|
||||||
cache_status = ""
|
cache_status = ""
|
||||||
if last_check > 0 and ffmpeg_found:
|
if last_check > 0 and ffmpeg_found:
|
||||||
cache_time = datetime.fromtimestamp(last_check).strftime("%H:%M")
|
cache_time = datetime.fromtimestamp(last_check).strftime("%H:%M")
|
||||||
@@ -446,16 +492,16 @@ class AboutDialog(QDialog):
|
|||||||
self.status_container.addWidget(ffmpeg_item)
|
self.status_container.addWidget(ffmpeg_item)
|
||||||
|
|
||||||
# Deno Status - compact version with path (only show path if in app bin directory)
|
# Deno Status - compact version with path (only show path if in app bin directory)
|
||||||
deno_found = check_deno_installed()
|
deno_found = info['deno_found']
|
||||||
deno_status_text = (
|
deno_status_text = (
|
||||||
f"<span style='color: #4CAF50;'>{_('about.detected')}</span>" if deno_found else f"<span style='color: #F44336;'>{_('about.missing')}</span>"
|
f"<span style='color: #4CAF50;'>{_('about.detected')}</span>" if deno_found else f"<span style='color: #F44336;'>{_('about.missing')}</span>"
|
||||||
)
|
)
|
||||||
deno_version = get_deno_version() if deno_found else _('about.not_available')
|
deno_version = info['deno_version']
|
||||||
|
|
||||||
# Get Deno path - only show if in app bin directory
|
# Get Deno path - only show if in app bin directory
|
||||||
deno_path_text = None
|
deno_path_text = None
|
||||||
if deno_found:
|
if deno_found:
|
||||||
deno_path = get_deno_path()
|
deno_path = info['deno_path']
|
||||||
# Only show path if it's not the fallback "deno" and the file exists
|
# Only show path if it's not the fallback "deno" and the file exists
|
||||||
if deno_path and deno_path != "deno":
|
if deno_path and deno_path != "deno":
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -465,22 +511,27 @@ class AboutDialog(QDialog):
|
|||||||
deno_path_text = deno_path
|
deno_path_text = deno_path
|
||||||
|
|
||||||
# Simplified cache status for Deno
|
# Simplified cache status for Deno
|
||||||
deno_cache = _version_cache.get("deno", {})
|
last_check = info['deno_last_check']
|
||||||
last_check = deno_cache.get("last_check", 0)
|
|
||||||
cache_status = ""
|
cache_status = ""
|
||||||
if last_check > 0 and deno_found:
|
if last_check > 0 and deno_found:
|
||||||
cache_time = datetime.fromtimestamp(last_check).strftime("%H:%M")
|
cache_time = datetime.fromtimestamp(last_check).strftime("%H:%M")
|
||||||
cache_status = f" <span style='color: #888; font-size: 10px;'>({cache_time})</span>"
|
cache_status = f" <span style='color: #888; font-size: 10px;'>({cache_time})</span>"
|
||||||
|
|
||||||
|
# Check integration with yt-dlp if both are present
|
||||||
|
integration_status = ""
|
||||||
|
if info.get('integration_status', False):
|
||||||
|
integration_status = f" <span style='color: #4CAF50; font-size: 10px; font-weight: bold;'> + yt-dlp</span>"
|
||||||
|
|
||||||
deno_item = self._create_status_item(
|
deno_item = self._create_status_item(
|
||||||
"🦕",
|
"🦕",
|
||||||
"Deno",
|
"Deno",
|
||||||
deno_status_text,
|
deno_status_text,
|
||||||
deno_version + cache_status,
|
deno_version + cache_status + integration_status,
|
||||||
deno_path_text,
|
deno_path_text,
|
||||||
)
|
)
|
||||||
self.status_container.addWidget(deno_item)
|
self.status_container.addWidget(deno_item)
|
||||||
|
|
||||||
|
|
||||||
def refresh_version_info(self) -> None:
|
def refresh_version_info(self) -> None:
|
||||||
"""Refresh version information manually."""
|
"""Refresh version information manually."""
|
||||||
self.refresh_btn.setText(_('about.refreshing'))
|
self.refresh_btn.setText(_('about.refreshing'))
|
||||||
|
|||||||
Reference in New Issue
Block a user