diff --git a/main.py b/main.py index cf46651..cfbb542 100644 --- a/main.py +++ b/main.py @@ -1,50 +1,4 @@ import sys -import os - -# Early detection and handling of windowed mode to prevent console window flicker -def setup_windowed_mode(): - """ - Setup windowed mode handling to prevent console window flickering. - This must be called as early as possible in the application startup. - """ - if getattr(sys, 'frozen', False): - # Running as compiled executable (PyInstaller) - if sys.stdout is None or sys.stderr is None: - # Windowed mode - completely suppress console output - import io - null_stream = io.StringIO() - if sys.stdout is None: - sys.stdout = null_stream - if sys.stderr is None: - sys.stderr = null_stream - else: - # Console mode but compiled - redirect to null to prevent window flicker - if os.name == 'nt': # Windows - try: - import io - # Create a null output stream - null_stream = io.StringIO() - # Only redirect if we detect this might cause console window issues - # Check if we're not already in a console - try: - # Try to get console window handle - if this fails, we're likely windowed - import ctypes - kernel32 = ctypes.windll.kernel32 - console_window = kernel32.GetConsoleWindow() - if console_window == 0: - # No console window exists, redirect to prevent one from appearing - sys.stdout = null_stream - sys.stderr = null_stream - except: - # If console detection fails, err on the side of caution - sys.stdout = null_stream - sys.stderr = null_stream - except: - # If all else fails, continue normally - pass - -# Call windowed mode setup immediately -setup_windowed_mode() from PySide6.QtWidgets import QApplication, QMessageBox diff --git a/src/core/ytsage_logging.py b/src/core/ytsage_logging.py index 37d1478..7a17589 100644 --- a/src/core/ytsage_logging.py +++ b/src/core/ytsage_logging.py @@ -94,25 +94,9 @@ def setup_logging(): # Console handler - INFO and above, with colors # Check if stdout is available (it might be None in PyInstaller windowed apps) - # Also check if we're running in a windowed mode (likely PyInstaller --windowed) stdout_available = sys.stdout is not None - is_windowed_app = getattr(sys, 'frozen', False) and sys.stdout is None - - # Additional check for windowed mode - check if console window exists on Windows - is_console_hidden = False - if sys.platform == 'win32' and getattr(sys, 'frozen', False): - try: - import ctypes - kernel32 = ctypes.windll.kernel32 - console_window = kernel32.GetConsoleWindow() - if console_window == 0: - is_console_hidden = True - except: - # If console detection fails, assume we might be windowed - is_console_hidden = True - - # Skip console output if we're in a windowed application or console is hidden - if stdout_available and not is_windowed_app and not is_console_hidden: + + if stdout_available: try: logger.add( sys.stdout, @@ -133,13 +117,13 @@ def setup_logging(): except Exception: stdout_available = False - # If stdout is not available or we're in windowed mode, skip stderr too to prevent console windows - if (not stdout_available or is_windowed_app or is_console_hidden) and not (is_windowed_app or is_console_hidden): + # If stdout is not available, try stderr or skip console logging entirely + if not stdout_available: try: if sys.stderr is not None: logger.add( sys.stderr, - level="ERROR", # Only errors to stderr to minimize console window appearance + level="WARNING", # Only warnings and errors to stderr format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}", catch=True, ) @@ -175,27 +159,28 @@ def setup_logging(): # If file logging fails, just log to console logger.warning(f"Could not set up file logging: {e}") - # Log startup message - try: + # Log startup message if we have any handlers + if logger._core.handlers: logger.info("YTSage logging system initialized") if log_dir and log_dir.exists(): logger.debug(f"Log directory: {log_dir}") else: logger.warning("File logging disabled - could not create log directory") - except Exception: - # If logging fails, continue silently - pass # If no handlers were successfully added, add a null handler to prevent errors - try: - # Try to add a minimal fallback handler if needed + if not logger._core.handlers: + # Add a minimal handler that just discards messages + # This prevents loguru from complaining about no handlers import tempfile - temp_log = Path(tempfile.gettempdir()) / "ytsage_temp.log" - logger.add(temp_log, level="ERROR", catch=True) - except Exception: - # If even that fails, we're in a very restricted environment - # loguru should handle this gracefully with its internal fallbacks - pass + + try: + # Try to add a temporary file handler as last resort + temp_log = Path(tempfile.gettempdir()) / "ytsage_temp.log" + logger.add(temp_log, level="ERROR", catch=True) + except Exception: + # If even that fails, we're in a very restricted environment + # loguru should handle this gracefully with its internal fallbacks + pass return logger diff --git a/src/core/ytsage_utils.py b/src/core/ytsage_utils.py index 9eba40f..e3a9677 100644 --- a/src/core/ytsage_utils.py +++ b/src/core/ytsage_utils.py @@ -4,12 +4,8 @@ import subprocess import sys import tempfile import time -import warnings from pathlib import Path -# Suppress the pkg_resources deprecation warning to prevent console window flicker -warnings.filterwarnings("ignore", message=".*pkg_resources is deprecated.*", category=UserWarning) - import pkg_resources import requests from packaging import version @@ -36,37 +32,6 @@ _version_cache = { CACHE_EXPIRY = 300 -def run_subprocess_hidden(cmd_args, **kwargs): - """ - Run subprocess with proper console window hiding for windowed applications. - - Args: - cmd_args: Command arguments list - **kwargs: Additional subprocess.run arguments - - Returns: - subprocess.CompletedProcess result - """ - # Set up creation flags to hide console window - creation_flags = SUBPROCESS_CREATIONFLAGS - if getattr(sys, 'frozen', False): - # Running as compiled executable - use additional flags to prevent console flicker - creation_flags |= subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS - - # Set default parameters to suppress console - default_kwargs = { - 'capture_output': True, - 'text': True, - 'creationflags': creation_flags, - 'stdin': subprocess.DEVNULL - } - - # Merge with provided kwargs (user kwargs take precedence) - default_kwargs.update(kwargs) - - return subprocess.run(cmd_args, **default_kwargs) - - def get_file_mtime(filepath) -> float: """Get file modification time safely.""" try: @@ -227,8 +192,8 @@ def get_ytdlp_version_direct(yt_dlp_path=None) -> str: return "Not found" # Extra logic moved to src\utils\ytsage_constants.py - result = run_subprocess_hidden( - [yt_dlp_path, "--version"], timeout=10 + result = subprocess.run( + [yt_dlp_path, "--version"], capture_output=True, text=True, timeout=10, creationflags=SUBPROCESS_CREATIONFLAGS ) if result.returncode == 0: @@ -244,8 +209,8 @@ def get_ffmpeg_version_direct() -> str: """Get FFmpeg version directly without caching.""" try: # Extra logic moved to src\utils\ytsage_constants.py - result = run_subprocess_hidden( - ["ffmpeg", "-version"], timeout=10 + result = subprocess.run( + ["ffmpeg", "-version"], capture_output=True, text=True, timeout=10, creationflags=SUBPROCESS_CREATIONFLAGS ) if result.returncode == 0: @@ -273,8 +238,8 @@ def get_ffmpeg_version_direct() -> str: ffmpeg_exe = Path(ffmpeg_path).joinpath("ffmpeg") if ffmpeg_exe.exists(): - result = run_subprocess_hidden( - [ffmpeg_exe, "-version"], timeout=10 + result = subprocess.run( + [ffmpeg_exe, "-version"], capture_output=True, text=True, timeout=10, creationflags=SUBPROCESS_CREATIONFLAGS ) if result.returncode == 0: @@ -520,7 +485,7 @@ def update_yt_dlp() -> bool: # Compare versions and update if needed if version.parse(latest_version) > version.parse(current_version): logger.info(f"Updating yt-dlp from {current_version} to {latest_version}...") - update_result = run_subprocess_hidden( + update_result = subprocess.run( [ sys.executable, "-m", @@ -529,7 +494,10 @@ def update_yt_dlp() -> bool: "--upgrade", "yt-dlp", ], - check=False + capture_output=True, + text=True, + check=False, + creationflags=SUBPROCESS_CREATIONFLAGS, ) if update_result.returncode == 0: logger.info("yt-dlp successfully updated") diff --git a/src/core/ytsage_yt_dlp.py b/src/core/ytsage_yt_dlp.py index f74f244..b0b2a30 100644 --- a/src/core/ytsage_yt_dlp.py +++ b/src/core/ytsage_yt_dlp.py @@ -1,7 +1,6 @@ import os import shutil import subprocess -import sys from pathlib import Path from typing import Optional @@ -501,22 +500,10 @@ def check_ytdlp_binary() -> Optional[Path]: # Use subprocess to check if yt-dlp is available if OS_NAME == "Windows": # On Windows, use 'where' command and hide console window - # For windowed applications, use additional flags to prevent console window flicker - creation_flags = SUBPROCESS_CREATIONFLAGS - if getattr(sys, 'frozen', False): - # Running as compiled executable - use additional flags - creation_flags |= subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS + # Extra logic moved to src\utils\ytsage_constants.py result = subprocess.run( - ["where", "yt-dlp"], - capture_output=True, - text=True, - check=False, - creationflags=creation_flags, - # Additional parameters to suppress console - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE + ["where", "yt-dlp"], capture_output=True, text=True, check=False, creationflags=SUBPROCESS_CREATIONFLAGS ) if result.returncode == 0 and result.stdout.strip(): yt_dlp_path = result.stdout.strip().split("\n")[0] @@ -547,22 +534,9 @@ def check_ytdlp_installed() -> bool: if ytdlp_path: # Try to run yt-dlp --version to verify it's working try: - # For windowed applications, use additional flags to prevent console window flicker - creation_flags = SUBPROCESS_CREATIONFLAGS - if getattr(sys, 'frozen', False): - # Running as compiled executable - use additional flags - creation_flags |= subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS - + # Extra logic moved to src\utils\ytsage_constants.py result = subprocess.run( - [ytdlp_path, "--version"], - capture_output=True, - text=True, - timeout=5, - creationflags=creation_flags, - # Additional parameters to suppress console - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE + [ytdlp_path, "--version"], capture_output=True, text=True, timeout=5, creationflags=SUBPROCESS_CREATIONFLAGS ) return result.returncode == 0 except Exception: diff --git a/src/gui/ytsage_gui_main.py b/src/gui/ytsage_gui_main.py index 3fbc478..edc174d 100644 --- a/src/gui/ytsage_gui_main.py +++ b/src/gui/ytsage_gui_main.py @@ -1,6 +1,5 @@ import json import subprocess -import sys import threading import webbrowser from pathlib import Path @@ -1736,21 +1735,7 @@ class YTSageApp(QMainWindow, FormatTableMixin, VideoInfoMixin): # Inherit from # Execute command with hidden console window on Windows # Extra logic moved to src\utils\ytsage_constants.py - creation_flags = SUBPROCESS_CREATIONFLAGS - if getattr(sys, 'frozen', False): - # Running as compiled executable - use additional flags to prevent console flicker - creation_flags |= subprocess.CREATE_NEW_PROCESS_GROUP | subprocess.DETACHED_PROCESS - - result = subprocess.run( - cmd, - capture_output=True, - text=True, - timeout=60, - creationflags=creation_flags, - stdin=subprocess.DEVNULL, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE - ) + result = subprocess.run(cmd, capture_output=True, text=True, timeout=60, creationflags=SUBPROCESS_CREATIONFLAGS) if result.returncode != 0: raise Exception(f"yt-dlp failed: {result.stderr}")