From b337667ce889f19a0351394d5e02a632055a3b03 Mon Sep 17 00:00:00 2001 From: Your Name Date: Wed, 27 Aug 2025 01:57:58 +0300 Subject: [PATCH] Switch Windows build to Python script, remove PowerShell Replaces PowerShell build script with Python in CI workflow and deletes the old build/README.md and windows-build-universal.ps1. This streamlines the build process and consolidates build logic into Python for better maintainability. --- .github/workflows/build-windows.yml | 4 +- build/README.md | 211 ---------- build/windows/windows-build-universal.ps1 | 474 ---------------------- 3 files changed, 2 insertions(+), 687 deletions(-) delete mode 100644 build/README.md delete mode 100644 build/windows/windows-build-universal.ps1 diff --git a/.github/workflows/build-windows.yml b/.github/workflows/build-windows.yml index cfa563d..0f941a2 100644 --- a/.github/workflows/build-windows.yml +++ b/.github/workflows/build-windows.yml @@ -75,14 +75,14 @@ jobs: run: | .\venv\Scripts\Activate.ps1 Write-Host "Building Standard Version..." - .\build\windows\windows-build-universal.ps1 -Verbose + python build\windows\windows_build_universal.py --verbose - name: Build FFmpeg Version (MSI + ZIP) shell: powershell run: | .\venv\Scripts\Activate.ps1 Write-Host "Building FFmpeg Version..." - .\build\windows\windows-build-universal.ps1 -FFmpeg -Verbose + python build\windows\windows_build_universal.py --ffmpeg --verbose - name: Prepare release artifacts shell: powershell diff --git a/build/README.md b/build/README.md deleted file mode 100644 index 5bf0a5d..0000000 --- a/build/README.md +++ /dev/null @@ -1,211 +0,0 @@ -# YTSage Build System - -This directory contains all build-related files and configurations for creating YTSage distributions. - -## 🏗️ Build Architecture - -### Automated Builds (CI/CD) -- **GitHub Actions**: Fully automated releases triggered by git tags -- **Location**: `.github/workflows/build-windows.yml` -- **Triggers**: Version tags (e.g., `v4.8.0`, `v4.9.1`) -- **Output**: MSI installers + ZIP portable versions (Standard & FFmpeg) - -### Local Development Builds -- **Script**: `build/windows/windows-build-universal.ps1` -- **Purpose**: Local testing and development -- **Flexibility**: Manual control over build options - -## 📁 Directory Structure - -``` -build/ -├── windows/ -│ ├── setup.py # Standard cx_Freeze configuration -│ ├── setup-ffmpeg.py # FFmpeg bundle cx_Freeze configuration -│ ├── windows-build-universal.ps1 # Local development build script -│ └── README.md # This file -└── (future platforms) -``` - -## 🚀 Quick Start - -### For Releases (Recommended) -```bash -# Create and push a version tag -git tag v4.8.1 -git push origin v4.8.1 - -# GitHub Actions will automatically: -# 1. Build both versions -# 2. Create MSI installers -# 3. Create ZIP portable versions -# 4. Generate draft release with artifacts -``` - -### For Local Development -```powershell -# Navigate to project root -cd c:\path\to\YTSage\build-env - -# Run the universal build script -.\build\windows\windows-build-universal.ps1 -Verbose - -# Build only FFmpeg version -.\build\windows\windows-build-universal.ps1 -FFmpeg -Verbose - -# Build only MSI (no ZIP) -.\build\windows\windows-build-universal.ps1 -MSIOnly - -# Build only ZIP (no MSI) -.\build\windows\windows-build-universal.ps1 -ZIPOnly -``` - -## 📋 Build Configurations - -### Standard Version (`setup.py`) -- **Target**: General users -- **Size**: Smaller download -- **FFmpeg**: Downloaded automatically when needed - -### FFmpeg Bundle (`setup-ffmpeg.py`) -- **Target**: Users without internet or restricted environments -- **Size**: Larger download (~100MB+) -- **FFmpeg**: Included in installer - -## 🔧 Build Script Options - -### windows-build-universal.ps1 Parameters -```powershell --SkipVenv # Skip virtual environment creation --Verbose # Enable detailed output --FFmpeg # Build FFmpeg bundle version --MSIOnly # Create only MSI installer --ZIPOnly # Create only ZIP distribution --OutputDir # Custom output directory (default: "releases") --FFmpegPath # Custom FFmpeg binaries path -``` - -### Examples -```powershell -# Full build with verbose output -.\build\windows\windows-build-universal.ps1 -Verbose - -# Quick standard version build -.\build\windows\windows-build-universal.ps1 -MSIOnly - -# FFmpeg version to custom directory -.\build\windows\windows-build-universal.ps1 -FFmpeg -OutputDir "custom-builds" -``` - -## 📦 Output Artifacts - -### CI/CD Builds (GitHub Actions) -``` -releases/ -├── YTSage-v4.8.1.msi # Standard installer -├── YTSage-v4.8.1.zip # Standard portable -├── YTSage-v4.8.1-ffmpeg.msi # FFmpeg installer -└── YTSage-v4.8.1-ffmpeg.zip # FFmpeg portable -``` - -### Local Builds -``` -releases/ -├── YTSage-4.8.1.msi # Standard installer -├── YTSage-4.8.1.zip # Standard portable -├── YTSage-4.8.1-ffmpeg.msi # FFmpeg installer (if built) -└── YTSage-4.8.1-ffmpeg.zip # FFmpeg portable (if built) -``` - -## 🛠️ Build Requirements - -### System Requirements -- **OS**: Windows 10/11 -- **PowerShell**: 5.1 or later -- **Python**: 3.12+ (3.12.10 recommended for MSI compatibility) -- **Memory**: 4GB+ RAM recommended -- **Storage**: 2GB+ free space - -### Python Dependencies -- **cx_Freeze**: 6.x for MSI creation -- **playsound3**: Audio notification system -- **All project dependencies**: Listed in `requirements.txt` - -### Optional Components -- **FFmpeg**: For bundled builds (auto-downloaded if not present) -- **Code Signing**: Certificate for signed installers (optional) - -## 🔍 Troubleshooting - -### Common Issues - -#### Build Fails with Import Errors -```powershell -# Recreate virtual environment -Remove-Item venv -Recurse -Force -.\build\windows\windows-build-universal.ps1 -Verbose -``` - -#### MSI Creation Fails -- Ensure Python 3.12.x (required for MSI compatibility) -- Check cx_Freeze version (should be 6.x) -- Verify all dependencies are installed - -#### FFmpeg Not Found -```powershell -# Specify custom FFmpeg path -.\build\windows\windows-build-universal.ps1 -FFmpeg -FFmpegPath "C:\ffmpeg\bin" -``` - -#### CI/CD Build Fails -- Check GitHub Actions logs -- Verify tag format (`v*`) -- Ensure all required files are present -- Check file paths in workflow - -### Debug Mode -```powershell -# Enable maximum verbosity -.\build\windows\windows-build-universal.ps1 -Verbose -Debug -``` - -## 📈 Version Management - -### Automatic Version Detection -- **CI/CD**: Extracts version from git tag -- **Local**: Uses version from setup.py files -- **Format**: Semantic versioning (e.g., 4.8.1) - -### Manual Version Update -```powershell -# Update version in setup files -(Get-Content build\windows\setup.py) -replace 'version="[^"]*"', 'version="4.8.2"' | Set-Content build\windows\setup.py -(Get-Content build\windows\setup-ffmpeg.py) -replace 'version="[^"]*"', 'version="4.8.2"' | Set-Content build\windows\setup-ffmpeg.py -``` - -## 🔮 Future Enhancements - -### Planned Features -- **Linux builds**: Future cross-platform support -- **macOS builds**: Apple platform support -- **Auto-updater**: Built-in update mechanism -- **Digital signing**: Code signing for Windows - -### Contributing -- Build improvements welcome -- Cross-platform configurations -- Performance optimizations -- Documentation enhancements - -## 📚 Related Documentation - -- **CI/CD Guide**: `.github/CI_CD_README.md` -- **Project README**: `../README.md` -- **Release Notes**: GitHub Releases -- **Issue Tracking**: GitHub Issues - ---- - -**Last Updated**: August 2025 -**Build System Version**: 4.8.x -**Supported Platforms**: Windows (primary) diff --git a/build/windows/windows-build-universal.ps1 b/build/windows/windows-build-universal.ps1 deleted file mode 100644 index ccbcd27..0000000 --- a/build/windows/windows-build-universal.ps1 +++ /dev/null @@ -1,474 +0,0 @@ -#Requires -Version 5.1 - -<# -.SYNOPSIS - YTSage Universal Build Script - Creates MSI Installers and ZIP Distributions -.DESCRIPTION - This PowerShell script builds YTSage using cx_Freeze and creates: - - MSI installer packages - - ZIP file distributions (portable) - - Both standard and FFmpeg versions -.NOTES - Version: Auto-detected from setup.py - Location: build/windows/windows-build-universal.ps1 - Usage: Run from project root directory (build-env/) - - IMPORTANT: This script must be executed from the project root directory! - Example: .\build\windows\windows-build-universal.ps1 -Verbose -#> - -param( - [switch]$SkipVenv, - [switch]$Verbose, - [switch]$FFmpeg, - [switch]$MSIOnly, - [switch]$ZIPOnly, - [string]$OutputDir = "releases", - [string]$FFmpegPath = "$env:LOCALAPPDATA\ffmpeg\ffmpeg-7.1.1-full_build\bin" -) - -# Set error handling -$ErrorActionPreference = "Stop" - -# Script configuration - Auto-detect version from setup.py -$APP_NAME = "YTSage" -$RELEASE_DATE = Get-Date -Format "yyyy-MM-dd" - -# Auto-detect version from setup.py -function Get-VersionFromSetup { - try { - $setupContent = Get-Content "build\windows\setup.py" -Raw - if ($setupContent -match 'version="([^"]*)"') { - $version = $matches[1] - Write-Host "Detected version: $version" -ForegroundColor Gray - return $version - } else { - Write-Warning-Custom "Could not extract version from setup.py, using 1.0.0" - return "1.0.0" - } - } catch { - Write-Warning-Custom "Could not read setup.py, using 1.0.0" - return "1.0.0" - } -} - -$SCRIPT_VERSION = Get-VersionFromSetup - -# Determine build type -$BUILD_TYPE = if ($FFmpeg) { "FFmpeg" } else { "Standard" } -$SETUP_FILE = if ($FFmpeg) { "build\windows\setup-ffmpeg.py" } else { "build\windows\setup.py" } -$OUTPUT_NAME_BASE = if ($FFmpeg) { "$APP_NAME-v$SCRIPT_VERSION-ffmpeg" } else { "$APP_NAME-v$SCRIPT_VERSION" } - -# Banner -Write-Host "================================================" -ForegroundColor Cyan -Write-Host "YTSage Universal Build Script v$SCRIPT_VERSION" -ForegroundColor Cyan -Write-Host "Build Type: $BUILD_TYPE" -ForegroundColor Yellow -Write-Host "================================================" -ForegroundColor Cyan -Write-Host "" -Write-Host "This script will create:" -ForegroundColor Yellow -if (-not $ZIPOnly) { - Write-Host "- MSI installer package" -ForegroundColor White -} -if (-not $MSIOnly) { - Write-Host "- ZIP portable distribution" -ForegroundColor White -} -Write-Host "- Professional packaging with metadata" -ForegroundColor White -Write-Host "" - -function Write-Step { - param($Message) - Write-Host "[STEP] $Message" -ForegroundColor Green -} - -function Write-Error-Custom { - param($Message) - Write-Host "[ERROR] $Message" -ForegroundColor Red -} - -function Write-Warning-Custom { - param($Message) - Write-Host "[WARNING] $Message" -ForegroundColor Yellow -} - -function Test-Command { - param($Command) - try { - & $Command --version | Out-Null - return $true - } - catch { - return $false - } -} - -function Test-FFmpegBinaries { - if (-not $FFmpeg) { return $null } - - Write-Step "Checking FFmpeg binaries..." - - $ffmpegExe = Join-Path $FFmpegPath "ffmpeg.exe" - $ffprobeExe = Join-Path $FFmpegPath "ffprobe.exe" - $ffplayExe = Join-Path $FFmpegPath "ffplay.exe" - - $missingFiles = @() - - if (-not (Test-Path $ffmpegExe)) { $missingFiles += "ffmpeg.exe" } - if (-not (Test-Path $ffprobeExe)) { $missingFiles += "ffprobe.exe" } - if (-not (Test-Path $ffplayExe)) { $missingFiles += "ffplay.exe" } - - if ($missingFiles.Count -gt 0) { - Write-Error-Custom "Missing FFmpeg binaries: $($missingFiles -join ', ')" - Write-Host "Expected FFmpeg path: $FFmpegPath" -ForegroundColor Yellow - throw "FFmpeg binaries not found" - } - - Write-Host "✓ Found all FFmpeg binaries" -ForegroundColor Green - return @{ - ffmpeg = $ffmpegExe - ffprobe = $ffprobeExe - ffplay = $ffplayExe - } -} - -function New-VirtualEnvironment { - Write-Step "Creating virtual environment..." - try { - python -m venv venv - Write-Host "Virtual environment created successfully." -ForegroundColor Green - } - catch { - Write-Error-Custom "Failed to create virtual environment: $($_.Exception.Message)" - throw - } -} - -function Start-VirtualEnvironment { - Write-Step "Activating virtual environment..." - - $venvScript = ".\venv\Scripts\Activate.ps1" - if (-not (Test-Path $venvScript)) { - Write-Error-Custom "Virtual environment activation script not found at: $venvScript" - throw "Virtual environment not properly created" - } - - try { - & $venvScript - Write-Host "Virtual environment activated successfully." -ForegroundColor Green - } - catch { - Write-Error-Custom "Failed to activate virtual environment: $($_.Exception.Message)" - throw - } -} - -function Install-Dependencies { - Write-Step "Installing/Upgrading required packages..." - - try { - Write-Host "Upgrading pip..." -ForegroundColor White - python -m pip install --upgrade pip | Out-Null - - Write-Host "Installing requirements..." -ForegroundColor White - pip install --no-cache-dir -r requirements.txt | Out-Null - - Write-Host "Installing cx_Freeze..." -ForegroundColor White - pip install --no-cache-dir cx_Freeze | Out-Null - - Write-Host "Installing yt-dlp (temporary for build)..." -ForegroundColor White - pip install --no-cache-dir yt-dlp | Out-Null - - Write-Host "All packages installed successfully." -ForegroundColor Green - } - catch { - Write-Error-Custom "Failed to install required packages: $($_.Exception.Message)" - throw - } -} - -function Remove-BuildArtifacts { - Write-Step "Cleaning previous build artifacts..." - - $itemsToRemove = @("build", "dist", $OutputDir) - - foreach ($item in $itemsToRemove) { - if (Test-Path $item) { - Remove-Item $item -Recurse -Force - Write-Host "Removed: $item" -ForegroundColor Gray - } - } - - Write-Host "Build artifacts cleaned." -ForegroundColor Green -} - -function Build-Executable { - param($FFmpegBinaries) - - Write-Step "Building executable with cx_Freeze..." - - try { - if ($FFmpegBinaries) { - $env:FFMPEG_PATH = $FFmpegBinaries.ffmpeg | Split-Path - } - - # Build the executable - python $SETUP_FILE build - - if ($LASTEXITCODE -ne 0) { - throw "cx_Freeze build failed with exit code $LASTEXITCODE" - } - - Write-Host "Executable built successfully." -ForegroundColor Green - } - catch { - Write-Error-Custom "Failed to build executable: $($_.Exception.Message)" - throw - } -} - -function Build-MSI { - Write-Step "Creating MSI installer..." - - try { - # Build MSI package - python $SETUP_FILE bdist_msi - - if ($LASTEXITCODE -ne 0) { - throw "MSI build failed with exit code $LASTEXITCODE" - } - - Write-Host "MSI installer created successfully." -ForegroundColor Green - } - catch { - Write-Error-Custom "Failed to build MSI: $($_.Exception.Message)" - throw - } -} - -function New-ZIPDistribution { - Write-Step "Creating ZIP distribution..." - - try { - # Ensure output directory exists - if (-not (Test-Path $OutputDir)) { - New-Item -ItemType Directory -Path $OutputDir | Out-Null - } - - # Find the built executable directory - $executableDir = if ($FFmpeg) { "dist\YTSage-FFmpeg" } else { "dist\YTSage" } - - if (-not (Test-Path $executableDir)) { - throw "Executable directory not found: $executableDir" - } - - # Create ZIP file - $zipPath = Join-Path $OutputDir "$OUTPUT_NAME_BASE.zip" - Compress-Archive -Path "$executableDir\*" -DestinationPath $zipPath -Force - - Write-Host "ZIP distribution created: $zipPath" -ForegroundColor Green - - # Get ZIP file size - $zipSize = (Get-Item $zipPath).Length - $zipSizeMB = [math]::Round($zipSize / 1MB, 2) - Write-Host "ZIP size: $zipSizeMB MB" -ForegroundColor Gray - - } - catch { - Write-Error-Custom "Failed to create ZIP distribution: $($_.Exception.Message)" - throw - } -} - -function Move-MSIFiles { - Write-Step "Organizing MSI files..." - - try { - # Ensure output directory exists - if (-not (Test-Path $OutputDir)) { - New-Item -ItemType Directory -Path $OutputDir | Out-Null - } - - # Find and move MSI files - $msiFiles = Get-ChildItem -Path "dist" -Filter "*.msi" -Recurse - - foreach ($msiFile in $msiFiles) { - $newName = "$OUTPUT_NAME_BASE.msi" - $destination = Join-Path $OutputDir $newName - - Move-Item $msiFile.FullName $destination -Force - Write-Host "MSI installer moved to: $destination" -ForegroundColor Green - - # Get MSI file size - $msiSize = (Get-Item $destination).Length - $msiSizeMB = [math]::Round($msiSize / 1MB, 2) - Write-Host "MSI size: $msiSizeMB MB" -ForegroundColor Gray - } - } - catch { - Write-Error-Custom "Failed to organize MSI files: $($_.Exception.Message)" - throw - } -} - -function New-ReleaseNotes { - Write-Step "Creating release notes..." - - $releaseNotes = "# YTSage v$SCRIPT_VERSION Release`n`n" - $releaseNotes += "**Release Date:** $RELEASE_DATE`n" - $releaseNotes += "**Build Type:** $BUILD_TYPE`n`n" - $releaseNotes += "## Installation Options`n`n" - $releaseNotes += "### MSI Installer (Recommended)`n" - $releaseNotes += "- **File:** $OUTPUT_NAME_BASE.msi`n" - $releaseNotes += "- **Installation:** Double-click to install system-wide`n" - $releaseNotes += "- **Updates:** Automatic update notifications`n" - $releaseNotes += "- **Uninstall:** Via Windows Programs `& Features`n`n" - $releaseNotes += "### Portable ZIP`n" - $releaseNotes += "- **File:** $OUTPUT_NAME_BASE.zip`n" - $releaseNotes += "- **Installation:** Extract and run - no installation required`n" - $releaseNotes += "- **Updates:** Manual download and replacement`n" - $releaseNotes += "- **Uninstall:** Simply delete the folder`n`n" - $releaseNotes += "## System Requirements`n" - $releaseNotes += "- Windows 10/11 64-bit`n" - $releaseNotes += "- .NET Framework 4.7.2 or later`n" - $releaseNotes += "- Internet connection for yt-dlp updates`n`n" - $releaseNotes += "## Support`n" - $releaseNotes += "For issues or questions, please visit the project repository.`n`n" - $releaseNotes += "---`n" - $releaseNotes += "*Built with cx_Freeze*`n" - - try { - $releaseNotesPath = Join-Path $OutputDir "RELEASE_NOTES.md" - $releaseNotes | Out-File -FilePath $releaseNotesPath -Encoding UTF8 - Write-Host "Release notes created: $releaseNotesPath" -ForegroundColor Green - } - catch { - Write-Warning-Custom "Failed to create release notes: $($_.Exception.Message)" - } -} - -function Remove-PostBuildArtifacts { - Write-Step "Cleaning up post-build artifacts..." - - try { - if (Test-Path "build") { - Remove-Item "build" -Recurse -Force - Write-Host "Removed build folder." -ForegroundColor Gray - } - - Write-Host "Post-build cleanup completed." -ForegroundColor Green - } - catch { - Write-Warning-Custom "Some cleanup operations failed: $($_.Exception.Message)" - } -} - -function Stop-VirtualEnvironment { - try { - deactivate - Write-Host "Virtual environment deactivated." -ForegroundColor Green - } - catch { - Write-Warning-Custom "Failed to deactivate virtual environment (this might be normal)" - } -} - -function Show-BuildSummary { - Write-Host "" - Write-Host "================================================" -ForegroundColor Cyan - Write-Host "Build completed successfully!" -ForegroundColor Green - Write-Host "================================================" -ForegroundColor Cyan - Write-Host "" - Write-Host "Build Type: $BUILD_TYPE" -ForegroundColor Yellow - Write-Host "Version: $SCRIPT_VERSION" -ForegroundColor Yellow - Write-Host "Output Directory: $OutputDir" -ForegroundColor Yellow - Write-Host "" - - if (Test-Path $OutputDir) { - Write-Host "Created files:" -ForegroundColor Green - Get-ChildItem $OutputDir | ForEach-Object { - $size = if ($_.PSIsContainer) { "Folder" } else { "$([math]::Round($_.Length / 1MB, 2)) MB" } - Write-Host " ✓ $($_.Name) ($size)" -ForegroundColor White - } - } - - Write-Host "" - Write-Host "Distribution ready for release!" -ForegroundColor Green - Write-Host "" -} - -# Main execution -try { - # Validation - Write-Step "Checking prerequisites..." - - if (-not (Test-Command "python")) { - Write-Error-Custom "Python is not installed or not in PATH" - exit 1 - } - - if (-not (Test-Path $SETUP_FILE)) { - Write-Error-Custom "Setup file not found: $SETUP_FILE" - exit 1 - } - - $pythonVersion = python --version - Write-Host "Found: $pythonVersion" -ForegroundColor Green - - # Check for Python 3.13 MSI limitation - $pythonVersionInfo = python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" - $isPython313 = $pythonVersionInfo -eq "3.13" - - if ($isPython313 -and -not $ZIPOnly) { - Write-Warning-Custom "Python 3.13 detected. MSI building is not supported yet by cx_Freeze." - Write-Host "See: https://github.com/marcelotduarte/cx_Freeze/issues/2837" -ForegroundColor Yellow - Write-Host "Switching to ZIP-only mode. Use Python 3.12 for MSI support." -ForegroundColor Yellow - $ZIPOnly = $true - $MSIOnly = $false - } - - # Check FFmpeg if needed - $ffmpegBinaries = Test-FFmpegBinaries - - # Virtual environment - if (-not $SkipVenv) { - if (-not (Test-Path "venv")) { - New-VirtualEnvironment - } else { - Write-Step "Using existing virtual environment..." - } - Start-VirtualEnvironment - } - - # Build process - Install-Dependencies - Remove-BuildArtifacts - Build-Executable -FFmpegBinaries $ffmpegBinaries - - # Create distributions - if (-not $ZIPOnly) { - Build-MSI - Move-MSIFiles - } - - if (-not $MSIOnly) { - New-ZIPDistribution - } - - New-ReleaseNotes - Remove-PostBuildArtifacts - Show-BuildSummary -} -catch { - Write-Error-Custom "Build failed: $($_.Exception.Message)" - if ($Verbose) { - Write-Host $_.Exception.StackTrace -ForegroundColor Red - } - exit 1 -} -finally { - if (-not $SkipVenv) { - Stop-VirtualEnvironment - } -} - -Write-Host "Press any key to continue..." -ForegroundColor Gray -$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")