From 9d924bea6ecfbe49433fa25dbd968f5aaf2a8746 Mon Sep 17 00:00:00 2001 From: Scheianu Ionut Date: Fri, 26 Sep 2025 18:53:04 +0300 Subject: [PATCH] updated download --- py_app/app/__pycache__/routes.cpython-312.pyc | Bin 79602 -> 93353 bytes py_app/app/routes.py | 372 ++++++++++++++++ ...quality_print_service_complete_package.zip | Bin 0 -> 44175 bytes .../static/quality_recticel_print_helper.zip | Bin 9270 -> 9270 bytes py_app/app/templates/download_extension.html | 199 +++++++-- .../create_portable_package.py | 406 ++++++++++++++++++ 6 files changed, 950 insertions(+), 27 deletions(-) create mode 100644 py_app/app/static/quality_print_service_complete_package.zip create mode 100644 windows_print_service/create_portable_package.py diff --git a/py_app/app/__pycache__/routes.cpython-312.pyc b/py_app/app/__pycache__/routes.cpython-312.pyc index 45c2c954ad24c8d006ac5cd158bee4b5e3fbf7c1..fc53a575fed532d37d23cbf1a4f4fe32c521d0ce 100644 GIT binary patch delta 12711 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 delta 1309 zcmZvbe@xVM7{|Zw@7?!v$6bIH9v4a-j-X2jmV_HJC$1!OvarIE0)b<+M$$e9Zn0J_ zn`7G6wD1O3r`Sy2q0C@u@QN0Dj@^aT@<4va*Px~bW~Hu~-e zmIM>I3%i5lnwX5CckHvt!5r)z>z%Fl*@6P>@~M6}4m>+th+R+vVl4B_ z$|4*J8PPG%ar85Gx(Ld1Z}aSzD-Z>S%!Lxvt5HcP^z7zRysDNQ5JP_>Pp+S(x{)|& ziz=`i*+XJX2im$idmh@J)GwNoH)9CH=Kf0LV%+pp;;?#CQW`wFbQL!F)G09zduDqT z_TVjZz6vq*j<}xp%(bhryZi;wap)}hGx?#Fl&=%hHwmXh9qrxC-7T%1?MeNf_=i1n zW;IUArT0~%VEs4``!$=Sza=_|bS+o&qM8{=SG=)>ieXl~boXare+!dy_;m@T-$u*9NtwO}Ub}Mdx zRQO>%o{Rp<3cnEnd78NUul@sOs20n@e@ftcp53%?cBU2+E)Lj3w__{R1quJ|*^3)- z+*_P(?s-;9cX%Flq8@X=F=OwEqflTkmFM>Nw^Q~@GLd_rFa zRalPo`s&JRbckkzRl-zP5Si{q;T*HGXgdsNQ_WB-x(n^l;PUmZX)l|56G8}*3AJ-M)iZ|Ls8xEpzFYnKV*IabX z4cFXa&Gpknul 2>&1 +if %errorLevel% neq 0 ( + echo āŒ ERROR: Administrator privileges required + echo Please right-click this file and select "Run as administrator" + echo. + pause + exit /b 1 +) + +echo [1/7] Administrator privileges confirmed āœ… +echo. + +REM Set variables +set CURRENT_DIR=%~dp0 +set SERVICE_NAME=QualityPrintService +set SERVICE_DISPLAY_NAME=Quality Label Print Service +set INSTALL_DIR=C:\\QualityPrintService +set PYTHON_EXE=%INSTALL_DIR%\\{PYTHON_DIR_NAME}\\python.exe +set PYTHON_SCRIPT=%INSTALL_DIR%\\print_service_complete.py +set LOG_DIR=%USERPROFILE%\\PrintService\\logs + +echo [2/7] Using embedded Python distribution āœ… +echo Python location: %PYTHON_EXE% +echo. + +REM Stop existing service if running +echo [3/7] Stopping existing service (if any)... +sc query "%SERVICE_NAME%" >nul 2>&1 +if %errorLevel% equ 0 ( + echo Stopping existing service... + net stop "%SERVICE_NAME%" >nul 2>&1 + sc delete "%SERVICE_NAME%" >nul 2>&1 + timeout /t 2 >nul +) +echo Service cleanup completed āœ… +echo. + +REM Create installation directory +echo [4/7] Creating installation directory... +if exist "%INSTALL_DIR%" ( + echo Removing old installation... + rmdir /s /q "%INSTALL_DIR%" >nul 2>&1 +) +mkdir "%INSTALL_DIR%" >nul 2>&1 +echo Installation directory: %INSTALL_DIR% āœ… +echo. + +REM Copy all files to installation directory +echo [5/7] Installing service files... +echo Copying embedded Python... +xcopy "%CURRENT_DIR%{PYTHON_DIR_NAME}" "%INSTALL_DIR%\\{PYTHON_DIR_NAME}\\" /E /I /Y >nul +echo Copying service script... +copy "%CURRENT_DIR%print_service_complete.py" "%INSTALL_DIR%\\" >nul +echo Service files installed āœ… +echo. + +REM Create log directory +echo [6/7] Setting up logging... +mkdir "%LOG_DIR%" >nul 2>&1 +echo Log directory: %LOG_DIR% āœ… +echo. + +REM Install and start Windows service +echo [7/7] Installing Windows service... +sc create "%SERVICE_NAME%" binPath= "\\"%PYTHON_EXE%\\" \\"%PYTHON_SCRIPT%\\"" DisplayName= "%SERVICE_DISPLAY_NAME%" start= auto +if %errorLevel% neq 0 ( + echo āŒ Failed to create Windows service + pause + exit /b 1 +) + +REM Configure service recovery +sc failure "%SERVICE_NAME%" reset= 60 actions= restart/10000/restart/30000/restart/60000 +sc config "%SERVICE_NAME%" depend= "" + +REM Start the service +echo Starting service... +net start "%SERVICE_NAME%" +if %errorLevel% neq 0 ( + echo āš ļø Service created but failed to start immediately + echo This is normal - the service will start automatically on reboot +) else ( + echo Service started successfully āœ… +) + +echo. +echo ======================================== +echo INSTALLATION COMPLETED! šŸŽ‰ +echo ======================================== +echo. +echo āœ… Python embedded distribution installed +echo āœ… Windows Print Service installed and configured +echo āœ… Auto-recovery enabled (restarts on failure) +echo āœ… Service will start automatically on boot +echo. +echo 🌐 Service URL: http://localhost:8765 +echo šŸ“Š Health check: http://localhost:8765/health +echo šŸ“ Logs location: %LOG_DIR% +echo. +echo šŸ“‹ NEXT STEPS: +echo 1. Install Chrome extension from 'chrome_extension' folder +echo 2. Test service: http://localhost:8765/health +echo 3. Configure web application to use service +echo. +echo Press any key to test service connection... +pause >nul + +REM Test service +echo Testing service connection... +timeout /t 3 >nul +curl -s http://localhost:8765/health >nul 2>&1 +if %errorLevel% equ 0 ( + echo āœ… Service is responding correctly! +) else ( + echo āš ļø Service test failed - may need a moment to start + echo Check logs in: %LOG_DIR% +) + +echo. +echo Installation complete! Service is ready to use. +pause +''' + + zipf.writestr("INSTALL_ZERO_DEPENDENCIES.bat", installer_content) + files_added += 1 + + # Add comprehensive README + readme_content = f'''# Quality Print Service - ZERO DEPENDENCIES Package + +## šŸŽÆ COMPLETE SELF-CONTAINED INSTALLATION + +This package contains EVERYTHING needed to run the Quality Print Service: + +### āœ… What's Included: +- **Embedded Python {PYTHON_VERSION}** - No system Python required! +- **Complete Print Service** - Zero external dependencies +- **Windows Service Installer** - Automatic installation and recovery +- **Chrome Extension** - Web browser integration +- **Comprehensive Documentation** - Installation and usage guides + +### šŸš€ INSTALLATION (5 Minutes): + +#### Requirements: +- Windows 10/11 or Windows Server 2016+ +- Administrator privileges (for service installation) +- Google Chrome browser + +#### Step 1: Extract Package +- Extract this ZIP file to any location (Desktop, Downloads, etc.) +- No permanent location needed - installer copies files automatically + +#### Step 2: Install Service +- Right-click `INSTALL_ZERO_DEPENDENCIES.bat` +- Select "Run as administrator" +- Follow the installation prompts + +#### Step 3: Install Chrome Extension +- Open Chrome browser +- Navigate to `chrome://extensions/` +- Enable "Developer mode" (toggle in top-right) +- Click "Load unpacked" +- Select the `chrome_extension` folder from extracted package + +#### Step 4: Test Installation +- Visit: http://localhost:8765/health +- Should return: {{"status": "healthy", "service": "Windows Print Service"}} + +### šŸ”§ Technical Details: + +**Service Architecture:** +``` +Quality Web App → Chrome Extension → Windows Service → Printer +``` + +**Printing Methods (automatic fallback):** +1. Adobe Reader (silent printing) +2. SumatraPDF (if Adobe unavailable) +3. PowerShell Print-Document +4. Microsoft Edge (fallback) +5. Windows default printer + +**Service Management:** +- Automatic startup on Windows boot +- Auto-recovery on failure (3 restart attempts) +- Comprehensive logging in: `%USERPROFILE%\\PrintService\\logs\\` + +**Network Configuration:** +- Service runs on: http://localhost:8765 +- Chrome extension communicates via this local endpoint +- No external network access required + +### šŸ“¦ Package Size: ~15MB (includes full Python runtime) +### ā±ļø Installation Time: ~5 minutes +### šŸ”§ Maintenance Required: Zero (auto-starts with Windows) + +Ready to use immediately after installation! +''' + + zipf.writestr("README_ZERO_DEPENDENCIES.md", readme_content) + files_added += 1 + + # Verify ZIP was created successfully + if os.path.exists(zip_path): + zip_size = os.path.getsize(zip_path) + print(f"āœ… Zero-dependency package created: {zip_path}") + print(f"šŸ“„ Total files: {files_added}") + print(f"šŸ“ Size: {zip_size / 1024 / 1024:.1f} MB") + + if zip_size > 0: + return jsonify({ + 'success': True, + 'download_url': f'/static/{zip_filename}', + 'files_included': files_added, + 'zip_size': zip_size, + 'package_type': 'Zero Dependencies - Complete Package', + 'python_version': PYTHON_VERSION, + 'dependencies': 'None - Everything included!', + 'estimated_size_mb': round(zip_size / 1024 / 1024, 1) + }) + else: + return jsonify({ + 'success': False, + 'error': 'ZIP file was created but is empty' + }), 500 + else: + return jsonify({ + 'success': False, + 'error': 'Failed to create zero-dependency ZIP file' + }), 500 + + except Exception as e: + print(f"āŒ Error creating zero-dependency service package: {e}") + import traceback + traceback.print_exc() + return jsonify({ + 'success': False, + 'error': str(e) + }), 500 + @bp.route('/test_extension_files') def test_extension_files(): """Test route to check extension files""" diff --git a/py_app/app/static/quality_print_service_complete_package.zip b/py_app/app/static/quality_print_service_complete_package.zip new file mode 100644 index 0000000000000000000000000000000000000000..c818ecca43f6a3261a35bd4dd6814dd9d68d76a3 GIT binary patch literal 44175 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%0D4hA9o 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

-

šŸ–Øļø Quality Recticel Print Extension

-

Simple & Robust Chrome Extension for PDF Printing

-
- ✨ NEW SIMPLIFIED APPROACH: No Windows service needed! Just install the Chrome extension and print directly from your browser. +

šŸ–Øļø Quality Recticel Print Solutions

+

Choose Your Printing Method: Chrome Extension or Windows Service

+
+ šŸ†• TWO POWERFUL OPTIONS: Simple browser-based Chrome extension or enterprise-grade Windows service for advanced printing needs.
@@ -22,28 +22,28 @@
-

šŸš€ Simple Chrome Extension Solution

+

šŸš€ Two Printing Solutions Available

-
šŸ† What You Get:
+
ļæ½ Chrome Extension (Recommended)
    -
  • āœ… Direct PDF Printing - Uses browser's print dialog
  • -
  • āœ… Zero Configuration - Works immediately after install
  • -
  • āœ… Cross-Platform - Works on Windows, Mac, Linux
  • -
  • āœ… No External Services - No Windows service needed
  • -
  • āœ… Robust Fallback - Downloads PDF if extension unavailable
  • +
  • āœ… Easy Setup - 2 minutes to install
  • +
  • āœ… Cross-Platform - Windows, Mac, Linux
  • +
  • āœ… User Control - Print dialog for printer selection
  • +
  • āœ… Zero Configuration - Works immediately
  • +
  • āœ… Secure - No external services needed
-
šŸ”§ How It Works:
+
šŸ”§ Windows Service (Enterprise)
    -
  • 🌐 Chrome Extension - Simple browser integration
  • -
  • šŸ“„ Hidden Tab Method - Opens PDF in background tab
  • -
  • ļæ½ļø Native Print Dialog - User controls printer selection
  • -
  • šŸ”„ Auto Cleanup - Closes tab after printing
  • -
  • šŸ›”ļø Secure - No external connections required
  • +
  • ⚔ Silent Printing - No user interaction needed
  • +
  • ļæ½ļø Direct Printer Access - System-level printing
  • +
  • šŸ¢ Enterprise Ready - Service auto-recovery
  • +
  • ļæ½ Advanced Features - Multiple print methods
  • +
  • šŸ›”ļø Self-Contained - Zero external dependencies
@@ -54,21 +54,21 @@
- -
+ +
-

🌐 Chrome Extension - All You Need!

- Simple browser-based printing solution +

🌐 Chrome Extension

+ Browser-based printing solution
- šŸŽ‰ SIMPLIFIED: Just install this Chrome extension - no Windows service needed! + šŸ“‹ RECOMMENDED: Easy setup, works everywhere!
šŸŽÆ Key Features:
    -
  • ļæ½ļø Opens PDF in hidden browser tab and triggers print dialog
  • +
  • šŸ–Øļø Opens PDF in hidden browser tab and triggers print dialog
  • šŸ” Automatic extension detection on web page
  • šŸ“Š Print status feedback and error handling
  • šŸ”„ Graceful fallback to PDF download
  • @@ -103,6 +103,60 @@
+ + +
+
+
+

šŸ”§ Windows Print Service

+ Enterprise-grade silent printing +
+
+
+ šŸ¢ ENTERPRISE: Silent printing with no user interaction! +
+ +
šŸŽÆ Key Features:
+
    +
  • ⚔ Silent printing - no print dialogs
  • +
  • šŸ–Øļø Direct system printer access
  • +
  • šŸ”„ Multiple print methods (Adobe, SumatraPDF, PowerShell)
  • +
  • šŸ›”ļø Windows service with auto-recovery
  • +
  • šŸ“¦ Self-contained - zero dependencies
  • +
  • šŸ¢ Perfect for production environments
  • +
+ +
šŸš€ Quick Install (3 steps):
+
    +
  1. Download and extract the service package
  2. +
  3. Run install_service_complete.bat as Administrator
  4. +
  5. Install Chrome extension (included in package)
  6. +
+ +
+
+ + +
+ +
+ + šŸ“¦ Standard Package (~50KB): Requires Python 3.7+ installed
+ šŸš€ Zero Dependencies (~15MB): Includes everything - no Python needed! +
+
+ +
+ āš ļø Windows Only: Requires Administrator privileges for service installation +
+
+
+
+
@@ -269,6 +323,97 @@ document.getElementById('download-extension-btn').addEventListener('click', func }); }); +// Windows Service Download Handler +document.getElementById('download-service-btn').addEventListener('click', function(e) { + e.preventDefault(); + + // Show loading state + const originalText = this.innerHTML; + this.innerHTML = 'ā³ Preparing Windows Service Package...'; + this.disabled = true; + + // Create the service package + fetch('/create_service_package', {method: 'POST'}) + .then(response => response.json()) + .then(data => { + if (data.success) { + // Start download + window.location.href = data.download_url; + + // Show success message + setTimeout(() => { + this.innerHTML = 'āœ… Download Started!'; + }, 500); + + // Reset button + setTimeout(() => { + this.innerHTML = originalText; + this.disabled = false; + }, 3000); + } else { + alert('Error creating service package: ' + data.error); + this.innerHTML = originalText; + this.disabled = false; + } + }) + .catch(error => { + alert('Error: ' + error.message); + this.innerHTML = originalText; + this.disabled = false; + }); +}); + +// Zero Dependencies Service Download Handler +document.getElementById('download-zero-deps-btn').addEventListener('click', function(e) { + e.preventDefault(); + + // Show loading state + const originalText = this.innerHTML; + this.innerHTML = 'ā³ Creating Zero-Dependency Package (may take 1-2 minutes)...'; + this.disabled = true; + + // Show progress info + const progressInfo = document.createElement('div'); + progressInfo.className = 'alert alert-info mt-2'; + progressInfo.innerHTML = 'šŸ“„ Downloading Python embedded distribution and creating complete package...'; + this.parentElement.appendChild(progressInfo); + + // Create the zero-dependency service package + fetch('/create_zero_dependency_service_package', {method: 'POST'}) + .then(response => response.json()) + .then(data => { + if (data.success) { + // Start download + window.location.href = data.download_url; + + // Show success message + setTimeout(() => { + this.innerHTML = `āœ… Download Started! (${data.estimated_size_mb}MB)`; + progressInfo.innerHTML = `šŸŽ‰ Complete package created with ${data.files_included} files including Python ${data.python_version}!`; + progressInfo.className = 'alert alert-success mt-2'; + }, 500); + + // Reset button + setTimeout(() => { + this.innerHTML = originalText; + this.disabled = false; + progressInfo.remove(); + }, 5000); + } else { + alert('Error creating zero-dependency package: ' + data.error); + this.innerHTML = originalText; + this.disabled = false; + progressInfo.remove(); + } + }) + .catch(error => { + alert('Error: ' + error.message); + this.innerHTML = originalText; + this.disabled = false; + progressInfo.remove(); + }); +}); + // Extension Test Functionality document.getElementById('test-extension-btn').addEventListener('click', function(e) { e.preventDefault(); @@ -375,10 +520,10 @@ async function testExtensionConnection() { // Show installation tips function showInstallationTips() { const tips = [ - 'šŸ’” Tip: This new approach is much simpler - no Windows service needed!', - 'šŸ’” Tip: The extension works on Windows, Mac, and Linux', - 'šŸ’” Tip: Users will see Chrome\'s print dialog for printer selection', - 'šŸ’” Tip: The system gracefully falls back to PDF downloads if needed' + 'šŸ’” Tip: Chrome Extension is recommended for most users - cross-platform and easy!', + 'šŸ’” Tip: Windows Service is perfect for enterprise environments requiring silent printing', + 'šŸ’” Tip: Both solutions work with the same web interface and automatically detected', + 'šŸ’” Tip: The system gracefully falls back to PDF downloads if neither is available' ]; let tipIndex = 0; diff --git a/windows_print_service/create_portable_package.py b/windows_print_service/create_portable_package.py new file mode 100644 index 0000000..7501e84 --- /dev/null +++ b/windows_print_service/create_portable_package.py @@ -0,0 +1,406 @@ +#!/usr/bin/env python3 +""" +Script to create a completely self-contained Windows Print Service package +with embedded Python distribution - Zero external dependencies required! +""" + +import os +import sys +import zipfile +import urllib.request +import tempfile +import shutil +from pathlib import Path + +# Python embeddable version details +PYTHON_VERSION = "3.11.9" +PYTHON_DOWNLOAD_URL = f"https://www.python.org/ftp/python/{PYTHON_VERSION}/python-{PYTHON_VERSION}-embed-amd64.zip" +PYTHON_DIR_NAME = "python_embedded" + +def download_portable_python(temp_dir): + """Download and extract Python embedded distribution""" + print(f"šŸ“„ Downloading Python {PYTHON_VERSION} embedded distribution...") + + python_zip_path = os.path.join(temp_dir, "python-embed.zip") + + try: + # Download Python embedded + urllib.request.urlretrieve(PYTHON_DOWNLOAD_URL, python_zip_path) + print(f"āœ… Downloaded Python to: {python_zip_path}") + + # Create extraction directory + python_extract_dir = os.path.join(temp_dir, PYTHON_DIR_NAME) + os.makedirs(python_extract_dir, exist_ok=True) + + # Extract Python + with zipfile.ZipFile(python_zip_path, 'r') as zip_ref: + zip_ref.extractall(python_extract_dir) + + print(f"āœ… Extracted Python to: {python_extract_dir}") + + # Enable site-packages by modifying pth file + pth_files = [f for f in os.listdir(python_extract_dir) if f.endswith('._pth')] + if pth_files: + pth_file = os.path.join(python_extract_dir, pth_files[0]) + with open(pth_file, 'a') as f: + f.write('\nimport site\n') + print("āœ… Enabled site-packages in embedded Python") + + return python_extract_dir + + except Exception as e: + print(f"āŒ Failed to download Python: {e}") + return None + +def create_complete_package(): + """Create complete self-contained package with embedded Python""" + + # Get current directory (should be windows_print_service) + current_dir = Path(__file__).parent + print(f"šŸ“‚ Working from: {current_dir}") + + # Create temporary directory + with tempfile.TemporaryDirectory() as temp_dir: + print(f"šŸ”§ Using temporary directory: {temp_dir}") + + # Download and extract portable Python + python_dir = download_portable_python(temp_dir) + if not python_dir: + print("āŒ Failed to prepare Python distribution") + return False + + # Create the complete package + package_path = current_dir / "QualityPrintService_COMPLETE_ZERO_DEPENDENCIES.zip" + + print(f"šŸ“¦ Creating complete package: {package_path}") + + with zipfile.ZipFile(package_path, 'w', zipfile.ZIP_DEFLATED) as zipf: + files_added = 0 + + # Add Python embedded distribution + print("šŸ“ Adding Python embedded distribution...") + for root, dirs, files in os.walk(python_dir): + for file in files: + file_path = os.path.join(root, file) + arcname = os.path.join(PYTHON_DIR_NAME, os.path.relpath(file_path, python_dir)) + zipf.write(file_path, arcname) + files_added += 1 + + # Add all service files + print("šŸ“ Adding service files...") + service_files = [ + "print_service_complete.py", + "install_service_complete.bat", + "uninstall_service_complete.bat", + "INSTALLATION_COMPLETE.md", + "PACKAGE_SUMMARY.md", + "README_COMPLETE.md" + ] + + for file_name in service_files: + file_path = current_dir / file_name + if file_path.exists(): + zipf.write(file_path, file_name) + files_added += 1 + print(f" āœ… Added: {file_name}") + + # Add Chrome extension + chrome_ext_dir = current_dir / "chrome_extension" + if chrome_ext_dir.exists(): + print("šŸ“ Adding Chrome extension...") + for root, dirs, files in os.walk(chrome_ext_dir): + for file in files: + if not file.startswith('.'): + file_path = os.path.join(root, file) + arcname = os.path.relpath(file_path, current_dir) + zipf.write(file_path, arcname) + files_added += 1 + + # Create updated installer that uses embedded Python + updated_installer = f'''@echo off +setlocal enabledelayedexpansion + +echo ======================================== +echo Quality Label Print Service Installer +echo ZERO DEPENDENCIES - COMPLETE PACKAGE +echo ======================================== +echo. +echo This package includes EVERYTHING needed: +echo āœ… Embedded Python {PYTHON_VERSION} +echo āœ… Complete Print Service +echo āœ… Windows Service Installer +echo āœ… Chrome Extension +echo āœ… Auto-recovery System +echo. + +REM Check for administrator privileges +net session >nul 2>&1 +if %errorLevel% neq 0 ( + echo āŒ ERROR: Administrator privileges required + echo Please right-click this file and select "Run as administrator" + echo. + pause + exit /b 1 +) + +echo [1/7] Administrator privileges confirmed āœ… +echo. + +REM Set variables +set CURRENT_DIR=%~dp0 +set SERVICE_NAME=QualityPrintService +set SERVICE_DISPLAY_NAME=Quality Label Print Service +set INSTALL_DIR=C:\\QualityPrintService +set PYTHON_EXE=%INSTALL_DIR%\\{PYTHON_DIR_NAME}\\python.exe +set PYTHON_SCRIPT=%INSTALL_DIR%\\print_service_complete.py +set LOG_DIR=%USERPROFILE%\\PrintService\\logs + +echo [2/7] Using embedded Python distribution āœ… +echo Python location: %PYTHON_EXE% +echo. + +REM Stop existing service if running +echo [3/7] Stopping existing service (if any)... +sc query "%SERVICE_NAME%" >nul 2>&1 +if %errorLevel% equ 0 ( + echo Stopping existing service... + net stop "%SERVICE_NAME%" >nul 2>&1 + sc delete "%SERVICE_NAME%" >nul 2>&1 + timeout /t 2 >nul +) +echo Service cleanup completed āœ… +echo. + +REM Create installation directory +echo [4/7] Creating installation directory... +if exist "%INSTALL_DIR%" ( + echo Removing old installation... + rmdir /s /q "%INSTALL_DIR%" >nul 2>&1 +) +mkdir "%INSTALL_DIR%" >nul 2>&1 +echo Installation directory: %INSTALL_DIR% āœ… +echo. + +REM Copy all files to installation directory +echo [5/7] Installing service files... +echo Copying embedded Python... +xcopy "%CURRENT_DIR%{PYTHON_DIR_NAME}" "%INSTALL_DIR%\\{PYTHON_DIR_NAME}\\" /E /I /Y >nul +echo Copying service script... +copy "%CURRENT_DIR%print_service_complete.py" "%INSTALL_DIR%\\" >nul +echo Service files installed āœ… +echo. + +REM Create log directory +echo [6/7] Setting up logging... +mkdir "%LOG_DIR%" >nul 2>&1 +echo Log directory: %LOG_DIR% āœ… +echo. + +REM Install and start Windows service +echo [7/7] Installing Windows service... +sc create "%SERVICE_NAME%" binPath= "\\"%PYTHON_EXE%\\" \\"%PYTHON_SCRIPT%\\"" DisplayName= "%SERVICE_DISPLAY_NAME%" start= auto +if %errorLevel% neq 0 ( + echo āŒ Failed to create Windows service + pause + exit /b 1 +) + +REM Configure service recovery +sc failure "%SERVICE_NAME%" reset= 60 actions= restart/10000/restart/30000/restart/60000 +sc config "%SERVICE_NAME%" depend= "" + +REM Start the service +echo Starting service... +net start "%SERVICE_NAME%" +if %errorLevel% neq 0 ( + echo āš ļø Service created but failed to start immediately + echo This is normal - the service will start automatically on reboot +) else ( + echo Service started successfully āœ… +) + +echo. +echo ======================================== +echo INSTALLATION COMPLETED! šŸŽ‰ +echo ======================================== +echo. +echo āœ… Python embedded distribution installed +echo āœ… Windows Print Service installed and configured +echo āœ… Auto-recovery enabled (restarts on failure) +echo āœ… Service will start automatically on boot +echo. +echo 🌐 Service URL: http://localhost:8765 +echo šŸ“Š Health check: http://localhost:8765/health +echo šŸ“ Logs location: %LOG_DIR% +echo. +echo šŸ“‹ NEXT STEPS: +echo 1. Install Chrome extension from 'chrome_extension' folder +echo 2. Test service: http://localhost:8765/health +echo 3. Configure web application to use service +echo. +echo Press any key to test service connection... +pause >nul + +REM Test service +echo Testing service connection... +timeout /t 3 >nul +curl -s http://localhost:8765/health >nul 2>&1 +if %errorLevel% equ 0 ( + echo āœ… Service is responding correctly! +) else ( + echo āš ļø Service test failed - may need a moment to start + echo Check logs in: %LOG_DIR% +) + +echo. +echo Installation complete! Service is ready to use. +pause +''' + + # Add the updated installer + zipf.writestr("install_service_ZERO_DEPENDENCIES.bat", updated_installer) + files_added += 1 + + # Add comprehensive README + readme_content = f'''# Quality Print Service - ZERO DEPENDENCIES Package + +## šŸŽÆ COMPLETE SELF-CONTAINED INSTALLATION + +This package contains EVERYTHING needed to run the Quality Print Service: + +### āœ… What's Included: +- **Embedded Python {PYTHON_VERSION}** - No system Python required! +- **Complete Print Service** - Zero external dependencies +- **Windows Service Installer** - Automatic installation and recovery +- **Chrome Extension** - Web browser integration +- **Comprehensive Documentation** - Installation and usage guides + +### šŸš€ INSTALLATION (5 Minutes): + +#### Requirements: +- Windows 10/11 or Windows Server 2016+ +- Administrator privileges (for service installation) +- Google Chrome browser + +#### Step 1: Extract Package +- Extract this ZIP file to any location (Desktop, Downloads, etc.) +- No permanent location needed - installer copies files automatically + +#### Step 2: Install Service +- Right-click `install_service_ZERO_DEPENDENCIES.bat` +- Select "Run as administrator" +- Follow the installation prompts + +#### Step 3: Install Chrome Extension +- Open Chrome browser +- Navigate to `chrome://extensions/` +- Enable "Developer mode" (toggle in top-right) +- Click "Load unpacked" +- Select the `chrome_extension` folder from extracted package + +#### Step 4: Test Installation +- Visit: http://localhost:8765/health +- Should return: {{"status": "healthy", "service": "Windows Print Service"}} + +### šŸ”§ Technical Details: + +**Service Architecture:** +``` +Quality Web App → Chrome Extension → Windows Service → Printer +``` + +**Printing Methods (automatic fallback):** +1. Adobe Reader (silent printing) +2. SumatraPDF (if Adobe unavailable) +3. PowerShell Print-Document +4. Microsoft Edge (fallback) +5. Windows default printer + +**Service Management:** +- Automatic startup on Windows boot +- Auto-recovery on failure (3 restart attempts) +- Comprehensive logging in: `%USERPROFILE%\\PrintService\\logs\\` + +**Network Configuration:** +- Service runs on: http://localhost:8765 +- Chrome extension communicates via this local endpoint +- No external network access required + +### šŸ“‚ Package Contents: +``` +QualityPrintService_COMPLETE_ZERO_DEPENDENCIES.zip +ā”œā”€ā”€ python_embedded/ # Python {PYTHON_VERSION} embedded +ā”œā”€ā”€ print_service_complete.py # Main service script +ā”œā”€ā”€ install_service_ZERO_DEPENDENCIES.bat # Installer +ā”œā”€ā”€ chrome_extension/ # Browser extension +│ ā”œā”€ā”€ manifest.json +│ ā”œā”€ā”€ background.js +│ ā”œā”€ā”€ content.js +│ ā”œā”€ā”€ popup.html +│ └── popup.js +└── README.md # This file +``` + +### šŸ› ļø Troubleshooting: + +**Service Won't Start:** +1. Check Windows Event Viewer → Windows Logs → Application +2. Check service logs in: `%USERPROFILE%\\PrintService\\logs\\` +3. Verify Python embedded installation in: `C:\\QualityPrintService\\` + +**Chrome Extension Not Working:** +1. Verify extension is enabled in `chrome://extensions/` +2. Check browser console for error messages +3. Ensure service is running: http://localhost:8765/health + +**Printing Issues:** +1. Verify printer is installed and accessible +2. Check service logs for printing attempts +3. Test manual PDF printing to verify printer functionality + +### šŸ”„ Uninstallation: +```cmd +# Stop and remove service +sc stop QualityPrintService +sc delete QualityPrintService + +# Remove installation directory +rmdir /s /q C:\\QualityPrintService + +# Remove Chrome extension manually from chrome://extensions/ +``` + +### šŸ“ž Support: +- Service logs: `%USERPROFILE%\\PrintService\\logs\\service.log` +- Health check: http://localhost:8765/health +- Printer list: http://localhost:8765/printers + +--- +**Package Version:** Complete Zero Dependencies +**Python Version:** {PYTHON_VERSION} (Embedded) +**Created:** {os.path.basename(__file__)} +''' + + zipf.writestr("README_ZERO_DEPENDENCIES.md", readme_content) + files_added += 1 + + print(f"\nšŸ“¦ Package created successfully!") + print(f"šŸ“„ Total files: {files_added}") + print(f"šŸ“‚ Location: {package_path}") + print(f"šŸ“ Size: {package_path.stat().st_size / 1024 / 1024:.1f} MB") + + return True + +if __name__ == "__main__": + print("šŸš€ Creating Complete Zero-Dependencies Package...") + print("=" * 60) + + if create_complete_package(): + print("\nāœ… SUCCESS: Complete package created!") + print("\nšŸ“‹ Next steps:") + print("1. Test the package on a clean Windows system") + print("2. Verify zero external dependencies") + print("3. Update Flask app to serve this package") + else: + print("\nāŒ FAILED: Package creation failed") + sys.exit(1) \ No newline at end of file