From 9f548309f82f7775d924c0de2a1a4e6f251b6a84 Mon Sep 17 00:00:00 2001 From: louis Date: Sun, 19 Jul 2026 21:24:05 +0200 Subject: [PATCH] feat: Add simplified build script for creating executables Added build.py to simplify the process of building standalone executables with PyInstaller. Also added .gitignore to exclude build artifacts. Co-Authored-By: Claude Sonnet 4.5 --- .gitignore | 37 +++++++++++++++ build.py | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 166 insertions(+) create mode 100644 .gitignore create mode 100644 build.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1e1efb5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info/ +dist/ +build/ +*.egg +.pytest_cache/ + +# PyInstaller +*.spec + +# Virtual Environment +venv/ +env/ +ENV/ + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Credentials +credentials.json +*.log + +# Claude +.claude/settings.local.json diff --git a/build.py b/build.py new file mode 100644 index 0000000..0870f33 --- /dev/null +++ b/build.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python3 +""" +Simple build wrapper for EBoek.info Scraper +Creates a standalone executable using PyInstaller +""" + +import os +import sys +import subprocess +import shutil +from pathlib import Path + + +def main(): + """Main build process.""" + print("=" * 50) + print("EBoek.info Scraper - Executable Builder") + print("=" * 50) + print() + + project_root = Path(__file__).parent + os.chdir(project_root) + print(f"Working from: {project_root}") + print() + + # Check if PyInstaller is installed + try: + import PyInstaller + print(f"PyInstaller {PyInstaller.__version__} found") + except ImportError: + print("Installing PyInstaller...") + subprocess.run([sys.executable, "-m", "pip", "install", "pyinstaller"], check=True) + + # Clean previous builds + print() + for directory in ["dist", "build"]: + if Path(directory).exists(): + shutil.rmtree(directory) + print(f"Cleaned {directory}/") + + # Determine platform-specific settings + is_windows = sys.platform.startswith('win') + app_name = "EBoek_Scraper" + + # Build command + build_cmd = [ + sys.executable, "-m", "PyInstaller", + "--onefile", + "--windowed", + "--name", app_name, + # Hidden imports for PyQt5 + "--hidden-import", "PyQt5.QtCore", + "--hidden-import", "PyQt5.QtGui", + "--hidden-import", "PyQt5.QtWidgets", + # Hidden imports for Selenium + "--hidden-import", "selenium", + "--hidden-import", "selenium.webdriver", + "--hidden-import", "selenium.webdriver.chrome", + "--hidden-import", "selenium.webdriver.chrome.options", + "--hidden-import", "selenium.webdriver.common.by", + # Hidden imports for our modules + "--hidden-import", "core.scraper", + "--hidden-import", "core.scraper_thread", + "--hidden-import", "core.credentials", + "--hidden-import", "gui.main_window", + "--hidden-import", "gui.login_dialog", + "--hidden-import", "gui.progress_dialog", + "--hidden-import", "utils.validators", + # Bookys scraper modules + "--hidden-import", "core.bookys_scraper", + "--hidden-import", "core.bookys_thread", + "--hidden-import", "gui.bookys_window", + "--hidden-import", "gui.startup_dialog", + # Exclude unnecessary modules + "--exclude-module", "tkinter", + "--exclude-module", "matplotlib", + "--exclude-module", "numpy", + "--exclude-module", "pandas", + # Main script + "gui_main.py" + ] + + print() + print("Building executable...") + print("This may take a few minutes...") + print() + + # Run PyInstaller + result = subprocess.run(build_cmd) + + if result.returncode != 0: + print("Build failed!") + sys.exit(1) + + print("Build completed successfully!") + + # Check if executable was created + exe_name = "EBoek_Scraper.exe" if is_windows else "EBoek_Scraper" + exe_path = Path("dist") / exe_name + + if not exe_path.exists(): + print(f"Error: Executable not found at {exe_path}") + sys.exit(1) + + # Display results + file_size = exe_path.stat().st_size / (1024 * 1024) # MB + print() + print("=" * 50) + print("BUILD SUCCESSFUL!") + print("=" * 50) + print(f"Executable location: {exe_path}") + print(f"File size: {file_size:.1f} MB") + print() + + if is_windows: + print("Windows Instructions:") + print(f" Run: {exe_path}") + print(" Windows may show security warning on first run") + print(" Click 'More Info' -> 'Run Anyway' if prompted") + else: + print("macOS/Linux Instructions:") + print(f" Run: ./{exe_path}") + + print() + print("Ready for distribution!") + + +if __name__ == "__main__": + main()