Automatically detect and install python on Windows machines
This commit is contained in:
@@ -10,6 +10,7 @@ import subprocess
|
||||
import threading
|
||||
import sys
|
||||
import os
|
||||
import platform
|
||||
from pathlib import Path
|
||||
import queue
|
||||
|
||||
@@ -35,12 +36,184 @@ class YouTubeArchiverGUI:
|
||||
self.download_process = None
|
||||
self.is_downloading = False
|
||||
|
||||
# Check Python installation on Windows first
|
||||
if not self.check_python_installation():
|
||||
return # Exit if Python installation failed
|
||||
|
||||
self.create_widgets()
|
||||
self.check_dependencies()
|
||||
|
||||
# Start checking queue for output updates
|
||||
self.root.after(100, self.check_queue)
|
||||
|
||||
def check_python_installation(self):
|
||||
"""Check if Python is properly installed on Windows."""
|
||||
if platform.system() != "Windows":
|
||||
return True # Not Windows, proceed normally
|
||||
|
||||
try:
|
||||
# Try to run python and get version
|
||||
result = subprocess.run([sys.executable, "--version"],
|
||||
capture_output=True, text=True, check=True)
|
||||
python_version = result.stdout.strip()
|
||||
print(f"Python is available: {python_version}")
|
||||
return True
|
||||
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
# Python not found, try to install it
|
||||
return self.install_python_windows()
|
||||
|
||||
def install_python_windows(self):
|
||||
"""Install Python on Windows using the provided MSIX installer."""
|
||||
installer_path = Path("windows/python.msix")
|
||||
|
||||
if not installer_path.exists():
|
||||
messagebox.showerror(
|
||||
"Python Installation Error",
|
||||
f"Python is not installed and the installer was not found at:\n{installer_path.absolute()}\n\n"
|
||||
"Please install Python manually from python.org or place the installer at the expected location."
|
||||
)
|
||||
return False
|
||||
|
||||
# Show installation dialog
|
||||
result = messagebox.askyesno(
|
||||
"Python Installation Required",
|
||||
"Python is not installed on this system. Would you like to install it now?\n\n"
|
||||
f"The installer will be launched from:\n{installer_path.absolute()}"
|
||||
)
|
||||
|
||||
if not result:
|
||||
messagebox.showinfo(
|
||||
"Installation Cancelled",
|
||||
"Python installation cancelled. The application cannot run without Python."
|
||||
)
|
||||
return False
|
||||
|
||||
try:
|
||||
# Create a temporary window to show installation progress
|
||||
install_window = tk.Toplevel(self.root)
|
||||
install_window.title("Installing Python")
|
||||
install_window.geometry("400x200")
|
||||
install_window.resizable(False, False)
|
||||
install_window.transient(self.root)
|
||||
install_window.grab_set()
|
||||
|
||||
# Center the window
|
||||
install_window.update_idletasks()
|
||||
x = (install_window.winfo_screenwidth() // 2) - (install_window.winfo_width() // 2)
|
||||
y = (install_window.winfo_screenheight() // 2) - (install_window.winfo_height() // 2)
|
||||
install_window.geometry(f"+{x}+{y}")
|
||||
|
||||
# Add progress indicator and message
|
||||
frame = ttk.Frame(install_window, padding="20")
|
||||
frame.pack(fill="both", expand=True)
|
||||
|
||||
ttk.Label(frame, text="Installing Python...",
|
||||
font=('Arial', 12, 'bold')).pack(pady=(0, 10))
|
||||
|
||||
progress = ttk.Progressbar(frame, mode='indeterminate')
|
||||
progress.pack(fill="x", pady=(0, 10))
|
||||
progress.start()
|
||||
|
||||
status_label = ttk.Label(frame, text="Launching installer...", wraplength=350)
|
||||
status_label.pack(pady=(0, 10))
|
||||
|
||||
# Update the window
|
||||
install_window.update()
|
||||
|
||||
# Launch the MSIX installer
|
||||
status_label.config(text="Running Python installer. Please follow the installation prompts.")
|
||||
install_window.update()
|
||||
|
||||
# Use PowerShell to install the MSIX package
|
||||
powershell_cmd = f'Add-AppxPackage -Path "{installer_path.absolute()}"'
|
||||
|
||||
result = subprocess.run([
|
||||
"powershell", "-Command", powershell_cmd
|
||||
], capture_output=True, text=True)
|
||||
|
||||
progress.stop()
|
||||
|
||||
if result.returncode == 0:
|
||||
status_label.config(text="Installation completed successfully!")
|
||||
install_window.update()
|
||||
|
||||
# Wait a moment and then verify installation
|
||||
self.root.after(2000, lambda: self.verify_python_installation(install_window))
|
||||
return True
|
||||
else:
|
||||
# Installation failed
|
||||
error_msg = result.stderr or result.stdout or "Unknown error occurred"
|
||||
status_label.config(text=f"Installation failed: {error_msg[:100]}...")
|
||||
install_window.update()
|
||||
|
||||
messagebox.showerror(
|
||||
"Installation Failed",
|
||||
f"Python installation failed:\n{error_msg}\n\n"
|
||||
"Please try installing Python manually from python.org"
|
||||
)
|
||||
install_window.destroy()
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
messagebox.showerror(
|
||||
"Installation Error",
|
||||
f"An error occurred while installing Python:\n{str(e)}\n\n"
|
||||
"Please try installing Python manually from python.org"
|
||||
)
|
||||
if 'install_window' in locals():
|
||||
install_window.destroy()
|
||||
return False
|
||||
|
||||
def verify_python_installation(self, install_window):
|
||||
"""Verify that Python was installed successfully."""
|
||||
try:
|
||||
# Try to find Python in common locations
|
||||
possible_python_paths = [
|
||||
"python",
|
||||
"python3",
|
||||
"py",
|
||||
os.path.expandvars(r"%LOCALAPPDATA%\Microsoft\WindowsApps\python.exe"),
|
||||
os.path.expandvars(r"%LOCALAPPDATA%\Programs\Python\Python*\python.exe"),
|
||||
]
|
||||
|
||||
python_found = False
|
||||
for python_path in possible_python_paths:
|
||||
try:
|
||||
result = subprocess.run([python_path, "--version"],
|
||||
capture_output=True, text=True, check=True)
|
||||
python_version = result.stdout.strip()
|
||||
print(f"Python found at {python_path}: {python_version}")
|
||||
python_found = True
|
||||
break
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
continue
|
||||
|
||||
install_window.destroy()
|
||||
|
||||
if python_found:
|
||||
messagebox.showinfo(
|
||||
"Installation Successful",
|
||||
f"Python has been installed successfully!\n{python_version}\n\n"
|
||||
"The application will now continue."
|
||||
)
|
||||
return True
|
||||
else:
|
||||
messagebox.showwarning(
|
||||
"Installation Verification Failed",
|
||||
"Python installation completed, but Python could not be found in the expected locations.\n\n"
|
||||
"You may need to restart the application or your system for the installation to take effect."
|
||||
)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
install_window.destroy()
|
||||
messagebox.showerror(
|
||||
"Verification Error",
|
||||
f"Could not verify Python installation:\n{str(e)}"
|
||||
)
|
||||
return False
|
||||
|
||||
def create_widgets(self):
|
||||
# Main frame
|
||||
main_frame = ttk.Frame(self.root, padding="10")
|
||||
@@ -308,6 +481,11 @@ def main():
|
||||
|
||||
app = YouTubeArchiverGUI(root)
|
||||
|
||||
# Only proceed if Python installation check passed
|
||||
if not hasattr(app, 'output_queue'):
|
||||
root.destroy()
|
||||
return
|
||||
|
||||
# Handle window closing
|
||||
def on_closing():
|
||||
if app.is_downloading:
|
||||
|
Reference in New Issue
Block a user