#Requires -Version 5.1 <# .SYNOPSIS FastCompress - Interactive video compression tool using FFmpeg .DESCRIPTION Video Compression Made Easy Compress videos with preset quality options or custom settings. Supports multiple formats: .mp4, .mkv, .avi, .mov, .webm Features: - High/Medium/Low quality presets - Custom compression settings - Animated progress indicator - Detailed compression statistics .EXAMPLE .\compress_video.ps1 .NOTES Version: 1.0 Author: Faiz Intifada Copyright: © 2025 Faiz Intifada #> # Helper Functions function Test-FFmpegAvailability { <# .SYNOPSIS Check if ffmpeg is available in PATH or current directory #> # Check in PATH $ffmpegInPath = Get-Command ffmpeg -ErrorAction SilentlyContinue if ($ffmpegInPath) { return $ffmpegInPath.Source } # Check in current directory $ffmpegLocal = Join-Path -Path $PSScriptRoot -ChildPath "ffmpeg.exe" if (Test-Path $ffmpegLocal) { return $ffmpegLocal } return $null } function Test-VideoFile { <# .SYNOPSIS Validate video file exists and format is supported #> param ( [string]$FilePath ) $supportedFormats = @('.mp4', '.mkv', '.avi', '.mov', '.webm') if (-not (Test-Path $FilePath)) { Write-Host "`n[ERROR] File not found: $FilePath" -ForegroundColor Red return $false } $extension = [System.IO.Path]::GetExtension($FilePath).ToLower() if ($extension -notin $supportedFormats) { Write-Host "`n[ERROR] Unsupported format: $extension" -ForegroundColor Red Write-Host "Supported formats: $($supportedFormats -join ', ')" -ForegroundColor Yellow return $false } return $true } function Show-CompressionMenu { <# .SYNOPSIS Display compression quality options menu #> Write-Host "`n╔════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ VIDEO COMPRESSION OPTIONS ║" -ForegroundColor Cyan Write-Host "╚════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" Write-Host " 1. " -NoNewline -ForegroundColor White Write-Host "High Quality " -NoNewline -ForegroundColor Green Write-Host "(CRF 23, ~80% original size)" -ForegroundColor Gray Write-Host " └─ Preset: medium, Audio: 192k" -ForegroundColor DarkGray Write-Host "" Write-Host " 2. " -NoNewline -ForegroundColor White Write-Host "Medium Quality " -NoNewline -ForegroundColor Yellow Write-Host "(CRF 28, ~60% original size)" -ForegroundColor Gray Write-Host " └─ Preset: medium, Audio: 128k" -ForegroundColor DarkGray Write-Host "" Write-Host " 3. " -NoNewline -ForegroundColor White Write-Host "Low Quality " -NoNewline -ForegroundColor Magenta Write-Host "(CRF 32, ~40% original size)" -ForegroundColor Gray Write-Host " └─ Preset: fast, Audio: 96k" -ForegroundColor DarkGray Write-Host "" Write-Host " 4. " -NoNewline -ForegroundColor White Write-Host "Custom Settings" -ForegroundColor Cyan Write-Host " └─ Manual CRF and preset configuration" -ForegroundColor DarkGray Write-Host "" } function Get-CompressionParameters { <# .SYNOPSIS Get ffmpeg parameters based on user selection #> param ( [int]$Choice ) switch ($Choice) { 1 { return @{ CRF = 23 Preset = "medium" AudioBitrate = "192k" QualityName = "High Quality" } } 2 { return @{ CRF = 28 Preset = "medium" AudioBitrate = "128k" QualityName = "Medium Quality" } } 3 { return @{ CRF = 32 Preset = "fast" AudioBitrate = "96k" QualityName = "Low Quality" } } 4 { Write-Host "`n[CUSTOM SETTINGS]" -ForegroundColor Cyan # Get CRF value do { Write-Host "`nEnter CRF value (0-51, lower = better quality): " -NoNewline -ForegroundColor Yellow $crfInput = Read-Host $crfValue = $null $validCRF = [int]::TryParse($crfInput, [ref]$crfValue) -and $crfValue -ge 0 -and $crfValue -le 51 if (-not $validCRF) { Write-Host "Invalid CRF value. Please enter a number between 0 and 51." -ForegroundColor Red } } while (-not $validCRF) # Get preset Write-Host "`nAvailable presets:" -ForegroundColor Yellow Write-Host " 1. ultrafast (fastest, larger file)" -ForegroundColor Gray Write-Host " 2. fast" -ForegroundColor Gray Write-Host " 3. medium (balanced)" -ForegroundColor Gray Write-Host " 4. slow (slower, better compression)" -ForegroundColor Gray do { Write-Host "`nSelect preset (1-4): " -NoNewline -ForegroundColor Yellow $presetChoice = Read-Host $presetValid = $presetChoice -match '^[1-4]$' if (-not $presetValid) { Write-Host "Invalid selection. Please enter 1-4." -ForegroundColor Red } } while (-not $presetValid) $presetMap = @{ "1" = "ultrafast" "2" = "fast" "3" = "medium" "4" = "slow" } $selectedPreset = $presetMap[$presetChoice] # Calculate audio bitrate based on CRF $audioBitrate = if ($crfValue -le 25) { "192k" } elseif ($crfValue -le 30) { "128k" } else { "96k" } return @{ CRF = $crfValue Preset = $selectedPreset AudioBitrate = $audioBitrate QualityName = "Custom (CRF $crfValue, $selectedPreset)" } } default { return $null } } } function Confirm-Overwrite { <# .SYNOPSIS Handle existing output file scenario #> param ( [string]$FilePath ) if (Test-Path $FilePath) { Write-Host "`n[WARNING] Output file already exists:" -ForegroundColor Yellow Write-Host " $FilePath" -ForegroundColor Gray Write-Host "`nOverwrite existing file? (Y/N): " -NoNewline -ForegroundColor Yellow $response = Read-Host return $response -match '^[Yy]' } return $true } function Format-FileSize { <# .SYNOPSIS Format file size in bytes to MB #> param ( [long]$Bytes ) $sizeMB = $Bytes / 1MB return [math]::Round($sizeMB, 2) } function Get-VideoFilesInFolder { <# .SYNOPSIS Scan folder for video files #> param ( [string]$FolderPath = (Get-Location).Path ) $supportedExtensions = @('.mp4', '.mkv', '.avi', '.mov', '.webm') $videoFiles = Get-ChildItem -Path $FolderPath -File | Where-Object { $_.Extension.ToLower() -in $supportedExtensions } | Sort-Object Name return $videoFiles } function Show-FileSelectionMenu { <# .SYNOPSIS Display interactive file selection menu with arrow key navigation and search #> param ( [Parameter(Mandatory=$true)] [System.IO.FileInfo[]]$Files ) $selectedIndex = 0 $confirmed = $false $searchTerm = "" $filteredFiles = $Files # Hide cursor for smoother experience Write-Host "`e[?25l" -NoNewline while (-not $confirmed) { # Filter files based on search term (case-insensitive) if ($searchTerm -ne "") { $filteredFiles = $Files | Where-Object { $_.Name -like "*$searchTerm*" } # Reset index if out of bounds if ($selectedIndex -ge $filteredFiles.Count) { $selectedIndex = [Math]::Max(0, $filteredFiles.Count - 1) } } else { $filteredFiles = $Files } # Clear screen using ANSI escape codes (fast, no flicker) Write-Host "`e[2J`e[H" -NoNewline # Redraw header Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "FastCompress v1.0" -NoNewline -ForegroundColor White Write-Host " ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "Video Compression Made Easy" -NoNewline -ForegroundColor Gray Write-Host " ║" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "by Faiz Intifada" -NoNewline -ForegroundColor DarkCyan Write-Host " ║" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" # Show current step Write-Host "[3/5] Select video to compress" -ForegroundColor Yellow Write-Host "╔════════════════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "↑↓" -NoNewline -ForegroundColor White Write-Host ": Navigate | " -NoNewline -ForegroundColor Gray Write-Host "Type" -NoNewline -ForegroundColor White Write-Host ": Search | " -NoNewline -ForegroundColor Gray Write-Host "Backspace" -NoNewline -ForegroundColor White Write-Host ": Clear | " -NoNewline -ForegroundColor Gray Write-Host "Enter" -NoNewline -ForegroundColor White Write-Host ": Select | " -NoNewline -ForegroundColor Gray Write-Host "ESC" -NoNewline -ForegroundColor White Write-Host ": Cancel ║" -ForegroundColor Cyan Write-Host "╚════════════════════════════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" # Show search bar if ($searchTerm -ne "") { Write-Host "Search: " -NoNewline -ForegroundColor Yellow Write-Host "$searchTerm" -NoNewline -ForegroundColor White Write-Host "█" -NoNewline -ForegroundColor Green Write-Host " " -NoNewline Write-Host "[$($filteredFiles.Count) of $($Files.Count) files]" -ForegroundColor Cyan } else { Write-Host "Type to search..." -ForegroundColor DarkGray } Write-Host "" # Display filtered file list if ($filteredFiles.Count -gt 0) { for ($i = 0; $i -lt $filteredFiles.Count; $i++) { $file = $filteredFiles[$i] $sizeMB = Format-FileSize -Bytes $file.Length $extension = $file.Extension.TrimStart('.').ToUpper() if ($i -eq $selectedIndex) { Write-Host " → " -NoNewline -ForegroundColor Green Write-Host $file.Name.PadRight(45) -NoNewline -ForegroundColor White Write-Host " $($sizeMB.ToString().PadLeft(10)) MB " -NoNewline -ForegroundColor Cyan Write-Host "[$extension]" -ForegroundColor Yellow } else { Write-Host " " -NoNewline Write-Host $file.Name.PadRight(45) -NoNewline -ForegroundColor Gray Write-Host " $($sizeMB.ToString().PadLeft(10)) MB " -NoNewline -ForegroundColor DarkGray Write-Host "[$extension]" -ForegroundColor DarkGray } } } else { Write-Host " No files match your search. Press " -NoNewline -ForegroundColor Yellow Write-Host "Backspace" -NoNewline -ForegroundColor White Write-Host " to clear." -ForegroundColor Yellow } Write-Host "" # Read key $key = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") switch ($key.VirtualKeyCode) { 8 { # Backspace if ($searchTerm.Length -gt 0) { $searchTerm = $searchTerm.Substring(0, $searchTerm.Length - 1) $selectedIndex = 0 } } 38 { # Up arrow if ($filteredFiles.Count -gt 0) { $selectedIndex = [Math]::Max(0, $selectedIndex - 1) } } 40 { # Down arrow if ($filteredFiles.Count -gt 0) { $selectedIndex = [Math]::Min($filteredFiles.Count - 1, $selectedIndex + 1) } } 13 { # Enter if ($filteredFiles.Count -gt 0) { $confirmed = $true } } 27 { # ESC if ($searchTerm -ne "") { # Clear search first $searchTerm = "" $selectedIndex = 0 } else { # Exit if no search active Write-Host "`e[2J`e[H" -NoNewline Write-Host "`e[?25h" -NoNewline Write-Host "" Write-Host "Operation cancelled by user." -ForegroundColor Yellow Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 0 } } default { # Accept alphanumeric, space, dash, underscore, dot if ($key.Character -match '[a-zA-Z0-9 \-_\.]') { $searchTerm += $key.Character $selectedIndex = 0 } } } } # Show cursor before returning Write-Host "`e[?25h" -NoNewline return $filteredFiles[$selectedIndex] } function Show-FFmpegInstallMenu { <# .SYNOPSIS Display FFmpeg installation options menu #> Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Red Write-Host "║ FFmpeg Required ║" -ForegroundColor Red Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Red Write-Host "" Write-Host "FastCompress needs FFmpeg to compress videos." -ForegroundColor Yellow Write-Host "" Write-Host "Options:" -ForegroundColor Cyan Write-Host " 1. " -NoNewline -ForegroundColor White Write-Host "Auto-download FFmpeg " -NoNewline -ForegroundColor Green Write-Host "(~130 MB, recommended)" -ForegroundColor Gray Write-Host "" Write-Host " 2. " -NoNewline -ForegroundColor White Write-Host "View manual installation instructions" -ForegroundColor Yellow Write-Host "" Write-Host " 3. " -NoNewline -ForegroundColor White Write-Host "Exit" -ForegroundColor Red Write-Host "" do { Write-Host "Select option (1-3): " -NoNewline -ForegroundColor Cyan $choice = Read-Host $valid = $choice -match '^[1-3]$' if (-not $valid) { Write-Host "Invalid selection. Please enter 1, 2, or 3." -ForegroundColor Red } } while (-not $valid) return [int]$choice } function Show-ManualInstallInstructions { <# .SYNOPSIS Display manual FFmpeg installation instructions #> Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ Manual FFmpeg Installation ║" -ForegroundColor Cyan Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" Write-Host "Option A: Portable (Recommended)" -ForegroundColor Yellow Write-Host " 1. Download FFmpeg from:" -ForegroundColor Gray Write-Host " https://github.com/BtbN/FFmpeg-Builds/releases" -ForegroundColor White Write-Host "" Write-Host " 2. Extract the zip file" -ForegroundColor Gray Write-Host "" Write-Host " 3. Copy " -NoNewline -ForegroundColor Gray Write-Host "ffmpeg.exe" -NoNewline -ForegroundColor White Write-Host " to this folder:" -ForegroundColor Gray Write-Host " $PSScriptRoot" -ForegroundColor Cyan Write-Host "" Write-Host "Option B: System-wide" -ForegroundColor Yellow Write-Host " 1. Download FFmpeg from:" -ForegroundColor Gray Write-Host " https://ffmpeg.org/download.html" -ForegroundColor White Write-Host "" Write-Host " 2. Extract and add to Windows PATH" -ForegroundColor Gray Write-Host "" Write-Host " 3. Restart PowerShell" -ForegroundColor Gray Write-Host "" } function Install-FFmpeg { <# .SYNOPSIS Auto-download and install FFmpeg #> Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Green Write-Host "║ Installing FFmpeg ║" -ForegroundColor Green Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Green Write-Host "" $ffmpegUrl = "https://github.com/BtbN/FFmpeg-Builds/releases/download/latest/ffmpeg-master-latest-win64-gpl.zip" $tempZip = Join-Path $env:TEMP "ffmpeg_temp.zip" $tempExtract = Join-Path $env:TEMP "ffmpeg_extract" $targetPath = Join-Path $PSScriptRoot "ffmpeg.exe" try { # Download FFmpeg Write-Host "[1/4] Downloading FFmpeg..." -ForegroundColor Yellow Write-Host " Source: GitHub BtbN/FFmpeg-Builds" -ForegroundColor Gray Write-Host " Size: ~130 MB (this may take a few minutes)" -ForegroundColor Gray Write-Host "" # Check internet connectivity try { $null = Test-Connection -ComputerName github.com -Count 1 -ErrorAction Stop } catch { Write-Host " ✗ No internet connection detected!" -ForegroundColor Red Write-Host "" Write-Host "Please check your internet connection and try again." -ForegroundColor Yellow return $null } # Download with progress $ProgressPreference = 'SilentlyContinue' # Faster download Write-Host " ⏳ Downloading... Please wait" -ForegroundColor Cyan try { Invoke-WebRequest -Uri $ffmpegUrl -OutFile $tempZip -UseBasicParsing -ErrorAction Stop Write-Host " ✓ Download completed!" -ForegroundColor Green } catch { Write-Host " ✗ Download failed: $($_.Exception.Message)" -ForegroundColor Red Write-Host "" Write-Host "Please try manual installation instead." -ForegroundColor Yellow return $null } Write-Host "" # Extract FFmpeg Write-Host "[2/4] Extracting FFmpeg..." -ForegroundColor Yellow # Clean temp extract folder if exists if (Test-Path $tempExtract) { Remove-Item $tempExtract -Recurse -Force -ErrorAction SilentlyContinue } try { # Extract zip Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::ExtractToDirectory($tempZip, $tempExtract) # Find ffmpeg.exe in extracted files (it's nested in folders) $ffmpegExe = Get-ChildItem -Path $tempExtract -Filter "ffmpeg.exe" -Recurse | Select-Object -First 1 if (-not $ffmpegExe) { throw "ffmpeg.exe not found in downloaded archive" } Write-Host " ✓ Extraction completed!" -ForegroundColor Green } catch { Write-Host " ✗ Extraction failed: $($_.Exception.Message)" -ForegroundColor Red Write-Host "" Write-Host "The downloaded file may be corrupted. Please try again." -ForegroundColor Yellow return $null } Write-Host "" # Copy to script directory Write-Host "[3/4] Installing FFmpeg..." -ForegroundColor Yellow try { Copy-Item -Path $ffmpegExe.FullName -Destination $targetPath -Force Write-Host " ✓ FFmpeg installed to: $targetPath" -ForegroundColor Green } catch { Write-Host " ✗ Installation failed: $($_.Exception.Message)" -ForegroundColor Red return $null } Write-Host "" # Verify installation Write-Host "[4/4] Verifying installation..." -ForegroundColor Yellow $version = & $targetPath -version 2>&1 | Select-Object -First 1 if ($version -match "ffmpeg version") { Write-Host " ✓ FFmpeg is working correctly!" -ForegroundColor Green Write-Host " Version: $($version -replace 'ffmpeg version ', '')" -ForegroundColor Gray } else { Write-Host " ⚠ FFmpeg installed but verification failed" -ForegroundColor Yellow Write-Host " The file may still work, continuing..." -ForegroundColor Gray } Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Green Write-Host "║ Installation Successful! ║" -ForegroundColor Green Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Green Write-Host "" return $targetPath } catch { Write-Host "" Write-Host "✗ Unexpected error: $($_.Exception.Message)" -ForegroundColor Red return $null } finally { # Cleanup temp files if (Test-Path $tempZip) { Remove-Item $tempZip -Force -ErrorAction SilentlyContinue } if (Test-Path $tempExtract) { Remove-Item $tempExtract -Recurse -Force -ErrorAction SilentlyContinue } $ProgressPreference = 'Continue' } } function Show-LoadingIndicator { <# .SYNOPSIS Display animated loading indicator #> param ( [Parameter(Mandatory=$true)] [System.Diagnostics.Process]$Process ) $spinners = @('⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏') $i = 0 while (-not $Process.HasExited) { $spinner = $spinners[$i % $spinners.Length] Write-Host "`r$spinner Compressing video... Please wait" -NoNewline -ForegroundColor Yellow Start-Sleep -Milliseconds 100 $i++ } Write-Host "`r" -NoNewline } function Start-VideoCompression { <# .SYNOPSIS Execute ffmpeg compression with progress monitoring #> param ( [string]$FFmpegPath, [string]$InputFile, [string]$OutputFile, [hashtable]$Parameters ) $ffmpegArgs = @( "-i", "`"$InputFile`"" "-vcodec", "libx264" "-crf", $Parameters.CRF "-preset", $Parameters.Preset "-acodec", "aac" "-b:a", $Parameters.AudioBitrate "-y" # Overwrite output file "`"$OutputFile`"" ) $ffmpegCommand = "& `"$FFmpegPath`" $($ffmpegArgs -join ' ')" Write-Host "`n╔════════════════════════════════════════════════╗" -ForegroundColor Green Write-Host "║ STARTING COMPRESSION ║" -ForegroundColor Green Write-Host "╚════════════════════════════════════════════════╝" -ForegroundColor Green Write-Host "" Write-Host "Quality: " -NoNewline -ForegroundColor Gray Write-Host $Parameters.QualityName -ForegroundColor Cyan Write-Host "Input: " -NoNewline -ForegroundColor Gray Write-Host $InputFile -ForegroundColor White Write-Host "Output: " -NoNewline -ForegroundColor Gray Write-Host $OutputFile -ForegroundColor White Write-Host "" $startTime = Get-Date try { # Execute ffmpeg with progress indicator $process = Start-Process -FilePath $FFmpegPath ` -ArgumentList $ffmpegArgs ` -NoNewWindow ` -PassThru ` -RedirectStandardError (Join-Path $env:TEMP "ffmpeg_error.log") # Show loading indicator Show-LoadingIndicator -Process $process # Wait for process to complete $process.WaitForExit() $endTime = Get-Date $duration = $endTime - $startTime if ($process.ExitCode -eq 0) { Write-Host "✓ Compression completed successfully!" -ForegroundColor Green # Display file sizes $inputSize = (Get-Item $InputFile).Length / 1MB $outputSize = (Get-Item $OutputFile).Length / 1MB $reduction = (1 - ($outputSize / $inputSize)) * 100 Write-Host "" Write-Host "File Size Comparison:" -ForegroundColor Cyan Write-Host " Original: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($inputSize, 2)) MB" -ForegroundColor White Write-Host " Compressed: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($outputSize, 2)) MB" -ForegroundColor White Write-Host " Reduction: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($reduction, 1))%" -ForegroundColor Green Write-Host " Time Taken: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($duration.TotalSeconds, 1)) seconds" -ForegroundColor White Write-Host "" Write-Host "Output saved to: " -NoNewline -ForegroundColor Gray Write-Host $OutputFile -ForegroundColor Cyan return @{ Success = $true InputSize = $inputSize OutputSize = $outputSize Reduction = $reduction Duration = $duration OutputFile = $OutputFile } } else { Write-Host "" Write-Host "[ERROR] Compression failed with exit code: $($process.ExitCode)" -ForegroundColor Red $errorLog = Join-Path $env:TEMP "ffmpeg_error.log" if (Test-Path $errorLog) { Write-Host "`nFFmpeg Error Details:" -ForegroundColor Yellow Get-Content $errorLog | Select-Object -Last 20 | ForEach-Object { Write-Host " $_" -ForegroundColor Gray } } return @{ Success = $false } } } catch { Write-Host "" Write-Host "[ERROR] Failed to execute ffmpeg: $($_.Exception.Message)" -ForegroundColor Red return @{ Success = $false } } } # Main Script Clear-Host Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "FastCompress v1.0" -NoNewline -ForegroundColor White Write-Host " ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "Video Compression Made Easy" -NoNewline -ForegroundColor Gray Write-Host " ║" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "by Faiz Intifada" -NoNewline -ForegroundColor DarkCyan Write-Host " ║" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" # Check FFmpeg availability Write-Host "[1/5] Checking FFmpeg availability..." -ForegroundColor Yellow $ffmpegPath = Test-FFmpegAvailability if (-not $ffmpegPath) { Write-Host " ✗ FFmpeg not found!" -ForegroundColor Red # Show installation menu $choice = Show-FFmpegInstallMenu if ($choice -eq 1) { # Auto-download FFmpeg $ffmpegPath = Install-FFmpeg if (-not $ffmpegPath) { Write-Host "" Write-Host "Installation failed. Please try manual installation." -ForegroundColor Red Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 1 } Write-Host "Press any key to continue..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") Clear-Host # Redraw header after install Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "FastCompress v1.0" -NoNewline -ForegroundColor White Write-Host " ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "Video Compression Made Easy" -NoNewline -ForegroundColor Gray Write-Host " ║" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "║ " -NoNewline -ForegroundColor Cyan Write-Host "by Faiz Intifada" -NoNewline -ForegroundColor DarkCyan Write-Host " ║" -ForegroundColor Cyan Write-Host "║ ║" -ForegroundColor Cyan Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Cyan Write-Host "" Write-Host "[1/5] Checking FFmpeg availability..." -ForegroundColor Yellow Write-Host " ✓ FFmpeg installed successfully!" -ForegroundColor Green } elseif ($choice -eq 2) { # Show manual instructions Show-ManualInstallInstructions Write-Host "After installing FFmpeg, please run this script again." -ForegroundColor Yellow Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 0 } else { # User chose to exit Write-Host "" Write-Host "Exiting..." -ForegroundColor Yellow exit 0 } } else { Write-Host " ✓ FFmpeg found: $ffmpegPath" -ForegroundColor Green } # Scan for video files Write-Host "" Write-Host "[2/5] Scanning for video files..." -ForegroundColor Yellow $currentFolder = (Get-Location).Path Write-Host " • Scanning: " -NoNewline -ForegroundColor Gray Write-Host $currentFolder -ForegroundColor White $videoFiles = Get-VideoFilesInFolder -FolderPath $currentFolder if ($videoFiles.Count -eq 0) { Write-Host "" Write-Host "[ERROR] No video files found in current folder!" -ForegroundColor Red Write-Host "" Write-Host "Supported formats: .mp4, .mkv, .avi, .mov, .webm" -ForegroundColor Yellow Write-Host "" Write-Host "Please navigate to a folder containing video files and run the script again." -ForegroundColor Gray Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 1 } Write-Host " ✓ Found " -NoNewline -ForegroundColor Green Write-Host $videoFiles.Count -NoNewline -ForegroundColor Cyan Write-Host " video file(s)" -ForegroundColor Green # Select video file if ($videoFiles.Count -eq 1) { # Auto-select single file with confirmation $fileInfo = $videoFiles[0] $fileSizeMB = Format-FileSize -Bytes $fileInfo.Length Write-Host "" Write-Host "[3/5] Video file detected" -ForegroundColor Yellow Write-Host "" Write-Host " File: " -NoNewline -ForegroundColor Gray Write-Host $fileInfo.Name -ForegroundColor White Write-Host " Size: " -NoNewline -ForegroundColor Gray Write-Host "$fileSizeMB MB" -ForegroundColor Cyan Write-Host "" Write-Host "Proceed with this file? (Y/N): " -NoNewline -ForegroundColor Yellow $response = Read-Host if ($response -notmatch '^[Yy]') { Write-Host "" Write-Host "Operation cancelled by user." -ForegroundColor Yellow Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 0 } } else { # Multiple files - show interactive menu $fileInfo = Show-FileSelectionMenu -Files $videoFiles $fileSizeMB = Format-FileSize -Bytes $fileInfo.Length } $inputFile = $fileInfo.FullName # File selected confirmation Write-Host "" Write-Host " ✓ Selected: " -NoNewline -ForegroundColor Green Write-Host $fileInfo.Name -NoNewline -ForegroundColor White Write-Host " ($fileSizeMB MB)" -ForegroundColor Gray # Generate output filename $outputFile = Join-Path -Path $fileInfo.DirectoryName -ChildPath "$($fileInfo.BaseName)_compressed$($fileInfo.Extension)" # Show compression menu Write-Host "" Write-Host "[4/5] Select compression quality" -ForegroundColor Yellow Show-CompressionMenu do { Write-Host "Select option (1-4): " -NoNewline -ForegroundColor Cyan $choice = Read-Host $validChoice = $choice -match '^[1-4]$' if (-not $validChoice) { Write-Host "Invalid selection. Please enter 1-4." -ForegroundColor Red } } while (-not $validChoice) # Get compression parameters $params = Get-CompressionParameters -Choice ([int]$choice) if (-not $params) { Write-Host "" Write-Host "[ERROR] Failed to get compression parameters." -ForegroundColor Red exit 1 } # Confirmation Write-Host "" Write-Host "[5/5] Confirmation" -ForegroundColor Yellow Write-Host "" Write-Host "═══════════════════════════════════════════════════════" -ForegroundColor DarkGray Write-Host " Input File: " -NoNewline -ForegroundColor Gray Write-Host $fileInfo.Name -ForegroundColor White Write-Host " Output File: " -NoNewline -ForegroundColor Gray Write-Host "$($fileInfo.BaseName)_compressed$($fileInfo.Extension)" -ForegroundColor White Write-Host " Quality: " -NoNewline -ForegroundColor Gray Write-Host $params.QualityName -ForegroundColor Cyan Write-Host " Settings: " -NoNewline -ForegroundColor Gray Write-Host "CRF $($params.CRF), Preset $($params.Preset), Audio $($params.AudioBitrate)" -ForegroundColor Gray Write-Host "═══════════════════════════════════════════════════════" -ForegroundColor DarkGray Write-Host "" # Check if output exists if (-not (Confirm-Overwrite -FilePath $outputFile)) { Write-Host "" Write-Host "Operation cancelled by user." -ForegroundColor Yellow Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 0 } Write-Host "Proceed with compression? (Y/N): " -NoNewline -ForegroundColor Yellow $confirm = Read-Host if ($confirm -notmatch '^[Yy]') { Write-Host "" Write-Host "Operation cancelled by user." -ForegroundColor Yellow Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor Gray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 0 } # Execute compression $result = Start-VideoCompression -FFmpegPath $ffmpegPath ` -InputFile $inputFile ` -OutputFile $outputFile ` -Parameters $params Write-Host "" Write-Host "═══════════════════════════════════════════════════════" -ForegroundColor Cyan if ($result.Success) { Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Green Write-Host "║ ║" -ForegroundColor Green Write-Host "║ COMPRESSION COMPLETED! ║" -ForegroundColor Green Write-Host "║ ║" -ForegroundColor Green Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Green Write-Host "" Write-Host "📊 Summary:" -ForegroundColor Cyan Write-Host " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor DarkCyan Write-Host " Source File: " -NoNewline -ForegroundColor Gray Write-Host $fileInfo.Name -ForegroundColor White Write-Host " Output File: " -NoNewline -ForegroundColor Gray Write-Host (Split-Path $result.OutputFile -Leaf) -ForegroundColor White Write-Host " Quality: " -NoNewline -ForegroundColor Gray Write-Host $params.QualityName -ForegroundColor Cyan Write-Host " Original: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($result.InputSize, 2)) MB" -ForegroundColor White Write-Host " Compressed: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($result.OutputSize, 2)) MB" -ForegroundColor White Write-Host " Space Saved: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($result.InputSize - $result.OutputSize, 2)) MB " -NoNewline -ForegroundColor White Write-Host "($([math]::Round($result.Reduction, 1))%)" -ForegroundColor Green Write-Host " Time Elapsed: " -NoNewline -ForegroundColor Gray Write-Host "$([math]::Round($result.Duration.TotalSeconds, 1)) seconds" -ForegroundColor White Write-Host " ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" -ForegroundColor DarkCyan Write-Host "" Write-Host "✓ Your compressed video is ready to use!" -ForegroundColor Green Write-Host "" } else { Write-Host "" Write-Host "╔═══════════════════════════════════════════════════════╗" -ForegroundColor Red Write-Host "║ ║" -ForegroundColor Red Write-Host "║ COMPRESSION FAILED ║" -ForegroundColor Red Write-Host "║ ║" -ForegroundColor Red Write-Host "╚═══════════════════════════════════════════════════════╝" -ForegroundColor Red Write-Host "" Write-Host "✗ Video compression failed. Please check the errors above." -ForegroundColor Red Write-Host " Common issues:" -ForegroundColor Yellow Write-Host " • Input file may be corrupted" -ForegroundColor Gray Write-Host " • Insufficient disk space" -ForegroundColor Gray Write-Host " • Unsupported codec in source file" -ForegroundColor Gray Write-Host "" } Write-Host "─────────────────────────────────────────────────────────" -ForegroundColor DarkGray Write-Host "FastCompress v1.0 | by Faiz Intifada" -ForegroundColor DarkGray Write-Host "" Write-Host "Press any key to exit..." -ForegroundColor DarkGray $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")