#!/usr/bin/env python3 """ EBoek.info Scraper GUI Application Main entry point for the PyQt5 GUI version of the EBoek.info scraper. """ import sys import os import traceback import warnings from pathlib import Path # Suppress urllib3 OpenSSL warnings on macOS warnings.filterwarnings("ignore", message="urllib3 v2 only supports OpenSSL 1.1.1+") warnings.filterwarnings("ignore", category=UserWarning, module="urllib3") # Ensure we can import PyQt5 try: from PyQt5.QtWidgets import QApplication, QMessageBox from PyQt5.QtCore import Qt from PyQt5.QtGui import QIcon except ImportError as e: print("Error: PyQt5 is not installed.") print("Please run: pip install PyQt5") print(f"Import error: {e}") sys.exit(1) # Add the project root to Python path project_root = Path(__file__).parent sys.path.insert(0, str(project_root)) # Import our GUI components try: from gui.main_window import MainWindow from core.credentials import CredentialManager except ImportError as e: print(f"Error importing application modules: {e}") print("Please ensure all required files are present.") traceback.print_exc() sys.exit(1) class EBoekScraperApp(QApplication): """ Main application class for the EBoek.info Scraper GUI. """ def __init__(self, argv): super().__init__(argv) self.setApplicationName("EBoek.info Scraper") self.setApplicationVersion("2.0") self.setOrganizationName("EBoek Scraper") # Set application icon if available self.set_application_icon() # Handle exceptions sys.excepthook = self.handle_exception self.main_window = None def set_application_icon(self): """Set the application icon if available.""" # You can add an icon file here if desired # icon_path = project_root / "resources" / "icon.png" # if icon_path.exists(): # self.setWindowIcon(QIcon(str(icon_path))) pass def handle_exception(self, exc_type, exc_value, exc_traceback): """Handle uncaught exceptions.""" if issubclass(exc_type, KeyboardInterrupt): # Allow Ctrl+C to exit gracefully sys.__excepthook__(exc_type, exc_value, exc_traceback) return # Log the exception error_msg = "".join(traceback.format_exception(exc_type, exc_value, exc_traceback)) print("Uncaught exception:") print(error_msg) # Show error dialog to user if self.main_window: try: QMessageBox.critical( self.main_window, "Unexpected Error", f"An unexpected error occurred:\n\n{str(exc_value)}\n\n" f"The application may need to be restarted.\n\n" f"Error type: {exc_type.__name__}" ) except: # If we can't show the dialog, just print print("Could not display error dialog") def initialize(self): """Initialize the application.""" try: # Check system requirements self.check_requirements() # Create and show main window self.main_window = MainWindow() self.main_window.show() return True except Exception as e: print(f"Error initializing application: {e}") traceback.print_exc() # Try to show error dialog try: msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setWindowTitle("Initialization Error") msg.setText(f"Could not initialize the application:\n\n{str(e)}") msg.setDetailedText(traceback.format_exc()) msg.exec_() except: print("Could not display initialization error dialog") return False def check_requirements(self): """Check system requirements and dependencies.""" errors = [] # Check Python version if sys.version_info < (3, 6): errors.append(f"Python 3.6+ required (found {sys.version_info.major}.{sys.version_info.minor})") # Check required modules required_modules = ['selenium', 'urllib3'] missing_modules = [] for module in required_modules: try: __import__(module) except ImportError: missing_modules.append(module) if missing_modules: errors.append(f"Missing required modules: {', '.join(missing_modules)}") # Check Chrome/Chromium availability (basic check) chrome_paths = [ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome", # macOS "/usr/bin/google-chrome", # Linux "/usr/bin/chromium-browser", # Linux (Chromium) "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe", # Windows "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe", # Windows 32-bit ] chrome_found = any(Path(path).exists() for path in chrome_paths) if not chrome_found: # This is a warning, not an error print("Warning: Chrome browser not detected in standard locations.") print("Make sure Google Chrome is installed for the scraper to work.") if errors: error_text = "System requirement errors:\n\n" + "\n".join(f"• {error}" for error in errors) error_text += "\n\nPlease install missing requirements and try again." raise RuntimeError(error_text) def show_startup_error(title, message): """Show a startup error dialog without a main window.""" app = QApplication.instance() if not app: app = QApplication(sys.argv) msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setWindowTitle(title) msg.setText(message) msg.exec_() def main(): """Main entry point for the GUI application.""" # Set up high DPI support if hasattr(Qt, 'AA_EnableHighDpiScaling'): QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True) if hasattr(Qt, 'AA_UseHighDpiPixmaps'): QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True) # Create the application try: app = EBoekScraperApp(sys.argv) # Initialize and run if app.initialize(): # Run the application sys.exit(app.exec_()) else: print("Application initialization failed") sys.exit(1) except Exception as e: print(f"Fatal error starting application: {e}") traceback.print_exc() # Try to show error dialog try: show_startup_error( "Startup Error", f"Could not start the EBoek.info Scraper:\n\n{str(e)}\n\n" f"Please check the installation and try again." ) except: print("Could not display startup error dialog") sys.exit(1) if __name__ == "__main__": main()