# CCLS Games CLI Tool # Complete Version with Setup, Search, Get functionality, and Logging # Configuration $baseUrl = "https://games.ccls.icu" $cliApiUrl = "$baseUrl/CLI" $settingsFolder = ".\settings" $credentialsFile = "$settingsFolder\credentials.dat" $settingsFile = "$settingsFolder\settings.json" # Using JSON instead of INI for simplicity $logsFolder = ".\logs" # Logs folder path # Script-level variables for progress display and logging $script:progressInitialized = $false $script:topProgressLine = $null $script:logFile = $null $script:sessionStartTime = Get-Date -Format "yyyy-MM-dd_HH-mm-ss" # Ensure settings and logs directories exist if (-not (Test-Path $settingsFolder)) { New-Item -Path $settingsFolder -ItemType Directory | Out-Null } if (-not (Test-Path $logsFolder)) { New-Item -Path $logsFolder -ItemType Directory | Out-Null } # Initialize log file for the current session $script:logFile = Join-Path -Path $logsFolder -ChildPath "ccls_session_$($script:sessionStartTime).log" "CCLS Games CLI Session started at $($script:sessionStartTime)" | Out-File -FilePath $script:logFile # Custom Write-Host function to handle logging and output filtering function Write-CCLSHost { param ( [Parameter(Position = 0)] [string]$Message = "", [Parameter()] [System.ConsoleColor]$ForegroundColor = [System.ConsoleColor]::White, [Parameter()] [System.ConsoleColor]$BackgroundColor = [System.ConsoleColor]::Black, [Parameter()] [switch]$NoNewline, [Parameter()] [switch]$Log, [Parameter()] [switch]$NoConsole ) # Check if the message is marked for removal if ($Message.StartsWith('#')) { # Don't show in console, but log it if needed if ($Log) { $cleanMessage = $Message.Substring(1).Trim() if (-not [string]::IsNullOrWhiteSpace($cleanMessage)) { $cleanMessage | Out-File -FilePath $script:logFile -Append } } return } if ($Message.StartsWith('/')) { # Skip completely - don't log or display return } # Handle empty lines if ([string]::IsNullOrWhiteSpace($Message)) { # Display in console if not suppressed if (-not $NoConsole) { Write-Host "" -NoNewline:$NoNewline } # But don't log empty lines return } # Display in console if not suppressed if (-not $NoConsole) { Write-Host $Message -ForegroundColor $ForegroundColor -BackgroundColor $BackgroundColor -NoNewline:$NoNewline } # Log if requested if ($Log) { $plainMessage = $Message $plainMessage | Out-File -FilePath $script:logFile -Append } } # Initialize or load settings function Initialize-Settings { if (-not (Test-Path $settingsFile)) { # Create default settings file $defaultSettings = @{ RememberLogin = $false DownloadPath = ".\downloads" TempDownloadPath = ".\tmp" HasCompletedSetup = $false } $defaultSettings | ConvertTo-Json | Set-Content -Path $settingsFile } # Load settings $settings = Get-Content -Path $settingsFile | ConvertFrom-Json return $settings } # Save settings function Save-Settings($settings) { $settings | ConvertTo-Json | Set-Content -Path $settingsFile } # Store credentials securely function Save-Credentials($username, $password) { $credentials = @{ Username = $username Password = $password } | ConvertTo-Json # Simple encryption (replace with more secure method if needed) $securePassword = ConvertTo-SecureString -String $credentials -AsPlainText -Force $encryptedText = ConvertFrom-SecureString -SecureString $securePassword # Save to file $encryptedText | Set-Content -Path $credentialsFile } # Load stored credentials function Get-StoredCredentials { if (Test-Path $credentialsFile) { try { $encryptedText = Get-Content -Path $credentialsFile $securePassword = ConvertTo-SecureString -String $encryptedText $credentials = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($securePassword) ) return $credentials | ConvertFrom-Json } catch { Write-CCLSHost "Error reading credentials: $($_.Exception.Message)" -ForegroundColor Red -Log return $null } } return $null } # Run setup process function Start-Setup { Write-CCLSHost "`n`nCCLS Games CLI Setup" -ForegroundColor Green -Log Write-CCLSHost "=====================" -ForegroundColor Green -Log Write-CCLSHost "Please configure the following settings:`n" -ForegroundColor Cyan -Log $settings = Initialize-Settings # Get game installation directory $validPath = $false while (-not $validPath) { Write-CCLSHost "Set your games default installation directory: " -ForegroundColor Yellow -NoNewline -Log $downloadPath = Read-Host Write-CCLSHost "$downloadPath" -NoConsole -Log if ([string]::IsNullOrWhiteSpace($downloadPath)) { Write-CCLSHost "Please enter a valid directory path." -ForegroundColor Red -Log } else { # Create directory if it doesn't exist if (-not (Test-Path $downloadPath)) { try { New-Item -ItemType Directory -Path $downloadPath -Force | Out-Null $validPath = $true } catch { Write-CCLSHost "Error creating directory: $($_.Exception.Message)" -ForegroundColor Red -Log } } else { $validPath = $true } } } # Get temporary download directory $validTempPath = $false while (-not $validTempPath) { Write-CCLSHost "Set the temporary directory of downloading files before they have finished downloading: " -ForegroundColor Yellow -NoNewline -Log $tempDownloadPath = Read-Host Write-CCLSHost "$tempDownloadPath" -NoConsole -Log if ([string]::IsNullOrWhiteSpace($tempDownloadPath)) { Write-CCLSHost "Please enter a valid directory path." -ForegroundColor Red -Log } else { # Create directory if it doesn't exist if (-not (Test-Path $tempDownloadPath)) { try { New-Item -ItemType Directory -Path $tempDownloadPath -Force | Out-Null $validTempPath = $true } catch { Write-CCLSHost "Error creating directory: $($_.Exception.Message)" -ForegroundColor Red -Log } } else { $validTempPath = $true } } } # Update settings $settings.DownloadPath = $downloadPath $settings.TempDownloadPath = $tempDownloadPath $settings.HasCompletedSetup = $true Save-Settings -settings $settings Write-CCLSHost "`nGreat, you have now completed the setup. Type 'help' for a list of commands to get you started." -ForegroundColor Green -Log } # Validate username against server function Test-Username($username) { $params = @{ Uri = "$cliApiUrl/username_check.php" Method = "POST" Headers = @{ "User-Agent" = "CCLS-CLI/1.0" } Body = @{ username = $username } } try { $response = Invoke-RestMethod @params return $response.exists } catch { Write-CCLSHost "Error connecting to the server: $($_.Exception.Message)" -ForegroundColor Red -Log return $false } } # Validate password against server function Test-Password($username, $password) { $params = @{ Uri = "$cliApiUrl/password_check.php" Method = "POST" Headers = @{ "User-Agent" = "CCLS-CLI/1.0" } Body = @{ username = $username password = $password } } try { $response = Invoke-RestMethod @params return $response.success } catch { Write-CCLSHost "Error connecting to the server: $($_.Exception.Message)" -ForegroundColor Red -Log return $false } } function Start-AutoLogin { $credentials = Get-StoredCredentials if ($credentials -ne $null) { Write-CCLSHost "#Attempting to login with stored credentials..." -Log if (Test-Password -username $credentials.Username -password $credentials.Password) { Write-CCLSHost "#Auto-login successful!" -Log return @{ Success = $true Username = $credentials.Username } } else { Write-CCLSHost "Stored credentials are no longer valid." -ForegroundColor Yellow -Log # Remove invalid credentials if (Test-Path $credentialsFile) { Remove-Item -Path $credentialsFile -Force } } } return @{ Success = $false } } function Start-ManualLogin { $maxAttempts = 3 $attempts = 0 while ($attempts -lt $maxAttempts) { Write-CCLSHost "Username: " -ForegroundColor Cyan -NoNewline -Log $username = Read-Host Write-CCLSHost "$username" -NoConsole -Log # Check if username exists Write-CCLSHost "#Checking username..." -Log if (Test-Username -username $username) { Write-CCLSHost "#Username found!" -Log Write-CCLSHost "Password: " -ForegroundColor Cyan -NoNewline -Log $password = Read-Host -AsSecureString $passwordPlain = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto( [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($password) ) Write-CCLSHost "********" -NoConsole -Log Write-CCLSHost "#Validating password..." -Log if (Test-Password -username $username -password $passwordPlain) { Write-CCLSHost "#Login successful!" -Log # Ask if user wants to save credentials - no newline before this Write-CCLSHost "Do you want to remember your login info for next time? (Y/N)" -ForegroundColor Yellow -Log $rememberLogin = Read-Host Write-CCLSHost "$rememberLogin" -NoConsole -Log if ($rememberLogin.ToLower() -eq "y") { Save-Credentials -username $username -password $passwordPlain $settings = Initialize-Settings $settings.RememberLogin = $true Save-Settings -settings $settings Write-CCLSHost "#Login information saved." -Log } return @{ Success = $true Username = $username } } else { Write-CCLSHost "Incorrect password, please try again." -ForegroundColor Red -Log $attempts++ } } else { Write-CCLSHost "Username not found, please try again." -ForegroundColor Red -Log $attempts++ } } Write-CCLSHost "Too many failed login attempts. Please try again later." -ForegroundColor Red -Log return @{ Success = $false } } # Search for game information by CG number function Search-Game($cgNumber) { # Validate CG number format if ($cgNumber -notmatch "^cg\d{4}$") { Write-CCLSHost "Invalid CG number format. Please use format 'cg0000'." -ForegroundColor Red -Log return } try { # Construct the URL for the game JSON file $gameJsonUrl = "$cliApiUrl/search.php?id=$cgNumber" # Attempt to fetch the game information $params = @{ Uri = $gameJsonUrl Method = "GET" Headers = @{ "User-Agent" = "CCLS-CLI/1.0" } } Write-CCLSHost "#Searching for game information..." -Log # Fetch game data from server try { $response = Invoke-RestMethod @params # Check if the request was successful if (-not $response.success) { Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log return } $gameInfo = $response } catch { Write-CCLSHost "Error fetching game information: $($_.Exception.Message)" -ForegroundColor Red -Log return } # Display game information in a formatted way Write-CCLSHost "`n==========================================================" -ForegroundColor DarkGray -Log Write-CCLSHost "Game Information for $($gameInfo.name) ($($gameInfo.id))" -ForegroundColor Green -Log Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log Write-CCLSHost "`nDescription:" -ForegroundColor Cyan -Log Write-CCLSHost $gameInfo.description -Log if ($gameInfo.safety_score -or $gameInfo.safety_level) { Write-CCLSHost "`nSafety:" -ForegroundColor Cyan -Log if ($gameInfo.safety_score) { Write-CCLSHost "Score: $($gameInfo.safety_score)" -Log } if ($gameInfo.safety_level) { Write-CCLSHost "Level: $($gameInfo.safety_level)" -Log } } Write-CCLSHost "`nDetails:" -ForegroundColor Cyan -Log if ($gameInfo.size) { Write-CCLSHost "Size: $($gameInfo.size)" -Log } if ($gameInfo.version -and $gameInfo.version -ne "") { Write-CCLSHost "Version: $($gameInfo.version)" -Log } if (($gameInfo.online -and $gameInfo.online -ne "") -or ($gameInfo.steam -and $gameInfo.steam -ne "") -or ($gameInfo.epic -and $gameInfo.epic -ne "")) { Write-CCLSHost "`nAvailability:" -ForegroundColor Cyan -Log if ($gameInfo.online -and $gameInfo.online -ne "") { Write-CCLSHost "Online: $($gameInfo.online)" -Log } if ($gameInfo.steam -and $gameInfo.steam -ne "") { Write-CCLSHost "Steam: $($gameInfo.steam)" -Log } if ($gameInfo.epic -and $gameInfo.epic -ne "") { Write-CCLSHost "Epic: $($gameInfo.epic)" -Log } } if ($gameInfo.false_av -and $gameInfo.false_av -ne "") { Write-CCLSHost "`nNote: " -ForegroundColor Yellow -NoNewline -Log Write-CCLSHost "This game may trigger false antivirus alerts: $($gameInfo.false_av)" -Log } if ($gameInfo.system_requirements) { Write-CCLSHost "`nSystem Requirements:" -ForegroundColor Cyan -Log if ($gameInfo.system_requirements.minimum) { Write-CCLSHost "Minimum:" -ForegroundColor Yellow -Log foreach ($prop in $gameInfo.system_requirements.minimum.PSObject.Properties) { Write-CCLSHost " $($prop.Name): $($prop.Value)" -Log } } if ($gameInfo.system_requirements.recommended) { Write-CCLSHost "`nRecommended:" -ForegroundColor Yellow -Log foreach ($prop in $gameInfo.system_requirements.recommended.PSObject.Properties) { Write-CCLSHost " $($prop.Name): $($prop.Value)" -Log } } } Write-CCLSHost "#Press any key to return to the main menu..." -Log $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") } catch { Write-CCLSHost "An error occurred while processing game information: $($_.Exception.Message)" -ForegroundColor Red -Log Write-CCLSHost "#Press any key to return to the main menu..." -Log $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") } } # Function to format file size function Format-FileSize { param ([string]$Size) if ([string]::IsNullOrEmpty($Size)) { return "Unknown Size" } # Extract numeric part and unit if ($Size -match "(\d+\.?\d*)\s*(GB|MB|KB|B)") { $value = [double]$matches[1] $unit = $matches[2] return "$value $unit" } return $Size } function Update-DownloadProgress { param ( [long]$bytesReceived, [long]$totalBytes, [int]$progressPercentage, [TimeSpan]$elapsedTime, [double]$downloadSpeed, [string]$gameName, [string]$gameId ) # Calculate values for display $downloadSpeedMbps = [math]::Round($downloadSpeed / 1024 / 1024 * 8, 2) $remainingBytes = $totalBytes - $bytesReceived $estimatedTimeRemaining = if ($downloadSpeed -gt 0) { [TimeSpan]::FromSeconds([math]::Floor($remainingBytes / $downloadSpeed)) } else { [TimeSpan]::Zero } # Format sizes for display $bytesSoFar = if ($bytesReceived -ge 1GB) { "{0:N2} GB" -f ($bytesReceived / 1GB) } elseif ($bytesReceived -ge 1MB) { "{0:N2} MB" -f ($bytesReceived / 1MB) } elseif ($bytesReceived -ge 1KB) { "{0:N2} KB" -f ($bytesReceived / 1KB) } else { "$bytesReceived B" } $totalSize = if ($totalBytes -ge 1GB) { "{0:N2} GB" -f ($totalBytes / 1GB) } elseif ($totalBytes -ge 1MB) { "{0:N2} MB" -f ($totalBytes / 1MB) } elseif ($totalBytes -ge 1KB) { "{0:N2} KB" -f ($totalBytes / 1KB) } else { "$totalBytes B" } $estimatedTime = if ($estimatedTimeRemaining.TotalHours -ge 1) { "{0:D2}:{1:D2}:{2:D2}" -f $estimatedTimeRemaining.Hours, $estimatedTimeRemaining.Minutes, $estimatedTimeRemaining.Seconds } else { "{0:D2}:{1:D2}" -f $estimatedTimeRemaining.Minutes, $estimatedTimeRemaining.Seconds } $elapsedTimeStr = if ($elapsedTime.TotalHours -ge 1) { "{0:D2}:{1:D2}:{2:D2}" -f $elapsedTime.Hours, $elapsedTime.Minutes, $elapsedTime.Seconds } else { "{0:D2}:{1:D2}" -f $elapsedTime.Minutes, $elapsedTime.Seconds } # Create the progress information lines $lines = @( "Progress: $progressPercentage%", "Downloaded: $bytesSoFar of $totalSize", "Speed: $downloadSpeedMbps Mbps", "Time Elapsed: $elapsedTimeStr", "Estimated Time Remaining: $estimatedTime", "Press Ctrl+C to cancel the download" ) # Log the progress foreach ($line in $lines) { $line | Out-File -FilePath $script:logFile -Append } # First time initialization if (-not $script:progressInitialized) { # Mark this as our first time $script:progressInitialized = $true # Print a header for the download progress - FIXED to properly display game name Write-CCLSHost "`n[Download Progress - $gameName ($gameId)]" -ForegroundColor Green # Create the initial progress block foreach ($line in $lines) { if ($line -eq $lines[-1]) { Write-CCLSHost $line -ForegroundColor Red } else { Write-CCLSHost $line -ForegroundColor Yellow } } # Store the beginning line number for future updates # Note: We're using the current cursor position - lines count to get the top line $script:topProgressLine = $host.UI.RawUI.CursorPosition.Y - $lines.Count } else { # Save current cursor position $currentPosition = $host.UI.RawUI.CursorPosition # Update each line of the progress display in place for ($i = 0; $i -lt $lines.Count; $i++) { # Set cursor to beginning of this progress line $host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates 0, ($script:topProgressLine + $i) # Clear the entire line first $lineWidth = $host.UI.RawUI.BufferSize.Width - 1 Write-Host (" " * $lineWidth) -NoNewline # Reset cursor and write the content $host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates 0, ($script:topProgressLine + $i) if ($i -eq ($lines.Count - 1)) { # Last line in red Write-Host $lines[$i] -ForegroundColor Red } else { # Other lines in yellow Write-Host $lines[$i] -ForegroundColor Yellow } } # Restore cursor position $host.UI.RawUI.CursorPosition = $currentPosition } } # Function to properly reset the progress display when download completes or fails function Reset-ProgressDisplay { # Only do something if we've initialized a progress display if ($script:progressInitialized) { # Save current cursor position $currentPosition = $host.UI.RawUI.CursorPosition # Move to one line after the progress display to add completion message $host.UI.RawUI.CursorPosition = New-Object System.Management.Automation.Host.Coordinates 0, ($script:topProgressLine + 6) # Reset the initialization flag $script:progressInitialized = $false $script:topProgressLine = $null # We don't reset cursor position here because we want to continue output from the end of progress display } } # Function to call before starting a new download function Initialize-DownloadTracking { # Ensure we always start fresh $script:progressInitialized = $false $script:topProgressLine = $null # Reset global variables used by event handlers $global:startTime = $null $global:lastUpdateTime = $null } # Function to download and extract a game function Get-Game($cgNumber) { # Initialize progress tracking for a fresh download Initialize-DownloadTracking # Validate CG number format if ($cgNumber -notmatch "^cg\d{4}$") { Write-CCLSHost "Invalid CG number format. Please use format 'cg0000'." -ForegroundColor Red -Log return } # Check if setup has been completed $settings = Initialize-Settings if (-not $settings.HasCompletedSetup) { Write-CCLSHost "ALERT, you must run the 'setup' command before downloading games." -ForegroundColor Red -Log return } # Ensure download directories exist if (-not (Test-Path $settings.DownloadPath)) { try { New-Item -ItemType Directory -Path $settings.DownloadPath -Force | Out-Null } catch { Write-CCLSHost "Error creating download directory: $($_.Exception.Message)" -ForegroundColor Red -Log return } } if (-not (Test-Path $settings.TempDownloadPath)) { try { New-Item -ItemType Directory -Path $settings.TempDownloadPath -Force | Out-Null } catch { Write-CCLSHost "Error creating temporary download directory: $($_.Exception.Message)" -ForegroundColor Red -Log return } } # Fetch game download information try { $gameInfoUrl = "$cliApiUrl/get.php?id=$cgNumber" $params = @{ Uri = $gameInfoUrl Method = "GET" Headers = @{ "User-Agent" = "CCLS-CLI/1.0" } } Write-CCLSHost "#Fetching game download information..." -Log $response = Invoke-RestMethod @params if (-not $response.success) { Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log return } $gameName = $response.name $gameId = $response.id $downloadUrl = $response.download_url $gameSize = $response.size # Create download file name from URL $fileName = Split-Path -Path $downloadUrl -Leaf if ([string]::IsNullOrEmpty($fileName)) { $fileName = "$gameId.7z" } $downloadPath = Join-Path -Path $settings.TempDownloadPath -ChildPath $fileName # Confirm download with user Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log Write-CCLSHost "Game Download: $gameName ($gameId)" -ForegroundColor Green -Log Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log Write-CCLSHost "Size: $gameSize" -ForegroundColor Yellow -Log Write-CCLSHost "Download URL: $downloadUrl" -ForegroundColor Cyan -Log Write-CCLSHost "Download Location: $downloadPath" -ForegroundColor Cyan -Log Write-CCLSHost "Extract Location: $($settings.DownloadPath)" -ForegroundColor Cyan -Log Write-CCLSHost "ALERT, the get command will start the downloading process of the game specified, to stop it do 'Ctrl C'" -ForegroundColor Red -Log Write-CCLSHost "Do you want to proceed with the download? (Y/N)" -ForegroundColor Yellow -Log $confirmation = Read-Host Write-CCLSHost "$confirmation" -NoConsole -Log if ($confirmation.ToLower() -ne "y") { Write-CCLSHost "Download cancelled by user." -ForegroundColor Yellow -Log return } # Set global variables that will be used for the download progress display # Make sure we're explicitly setting these so they're accessible in the event handlers $global:gameNameForProgress = $gameName $global:gameIdForProgress = $gameId # Start download $webClient = New-Object System.Net.WebClient $startTime = Get-Date $lastUpdateTime = $startTime # Set global variables for use in event handlers $global:startTime = $startTime $global:lastUpdateTime = $lastUpdateTime # Create event handlers for download progress $downloadProgressEvent = Register-ObjectEvent -InputObject $webClient -EventName DownloadProgressChanged -Action { $bytesReceived = $EventArgs.BytesReceived $totalBytes = $EventArgs.TotalBytesToReceive $progressPercentage = $EventArgs.ProgressPercentage $currentTime = Get-Date # Only update display every 500ms to avoid console flicker if (($currentTime - $global:lastUpdateTime).TotalMilliseconds -ge 500) { $global:lastUpdateTime = $currentTime $elapsedTime = $currentTime - $global:startTime $elapsedSeconds = [math]::Floor($elapsedTime.TotalSeconds) $downloadSpeed = if ($elapsedSeconds -gt 0) { $bytesReceived / $elapsedSeconds } else { 0 } # Use the new progress update function - PASSING PROPER GAME NAME AND ID Update-DownloadProgress -bytesReceived $bytesReceived -totalBytes $totalBytes ` -progressPercentage $progressPercentage -elapsedTime $elapsedTime ` -downloadSpeed $downloadSpeed -gameName $global:gameNameForProgress -gameId $global:gameIdForProgress } } $downloadCompletedEvent = Register-ObjectEvent -InputObject $webClient -EventName DownloadFileCompleted -Action { # Reset progress display properly Reset-ProgressDisplay Write-CCLSHost "#Download completed!" -Log Write-CCLSHost "#Starting extraction process..." -Log try { # Define the self-contained extraction function function Start-GameExtraction { # Load settings independently (similar to ass.ps1 but with adjusted path) $scriptPath = $settingsFolder $settingsPath = Join-Path -Path $scriptPath -ChildPath "settings.json" Write-CCLSHost "#Loading settings from: $settingsPath" -Log # Check if settings file exists if (-not (Test-Path -Path $settingsPath)) { Write-CCLSHost "Error: Settings file not found at '$settingsPath'." -ForegroundColor Red -Log return } # Load and parse the settings.json file $extractSettings = Get-Content -Path $settingsPath -ErrorAction Stop | ConvertFrom-Json # Get paths from settings $tempDownloadPath = $extractSettings.TempDownloadPath $downloadPath = $extractSettings.DownloadPath Write-CCLSHost "#Loaded TempDownloadPath: $tempDownloadPath" -Log Write-CCLSHost "#Loaded DownloadPath: $downloadPath" -Log # Verify paths exist if (-not (Test-Path -Path $tempDownloadPath)) { Write-CCLSHost "Error: TempDownloadPath '$tempDownloadPath' does not exist." -ForegroundColor Red -Log return } if (-not (Test-Path -Path $downloadPath)) { Write-CCLSHost "Error: DownloadPath '$downloadPath' does not exist." -ForegroundColor Red -Log return } # Check if 7-Zip is installed $7zipPath = "C:\Program Files\7-Zip\7z.exe" if (-not (Test-Path -Path $7zipPath)) { # Try alternative paths $alternativePaths = @( "${env:ProgramFiles(x86)}\7-Zip\7z.exe", ".\7zip\7z.exe" ) $found = $false foreach ($path in $alternativePaths) { if (Test-Path -Path $path) { $7zipPath = $path $found = $true break } } if (-not $found) { Write-CCLSHost "Error: 7-Zip is not installed at any expected location." -ForegroundColor Red -Log Write-CCLSHost "Please install 7-Zip or ensure it's in one of these locations:" -ForegroundColor Yellow -Log Write-CCLSHost " - C:\Program Files\7-Zip\7z.exe" -ForegroundColor Yellow -Log Write-CCLSHost " - C:\Program Files (x86)\7-Zip\7z.exe" -ForegroundColor Yellow -Log Write-CCLSHost " - .\7zip\7z.exe" -ForegroundColor Yellow -Log return } } # Get all .7z files in the temp download path Write-CCLSHost "#Searching for .7z files in: $tempDownloadPath" -Log $7zFiles = Get-ChildItem -Path $tempDownloadPath -Filter "*.7z" # If no .7z files found, exit if ($7zFiles.Count -eq 0) { Write-CCLSHost "No .7z files found in '$tempDownloadPath'." -ForegroundColor Yellow -Log return } Write-CCLSHost "#Found $($7zFiles.Count) .7z files to process." -Log # Process each .7z file foreach ($file in $7zFiles) { $filePath = $file.FullName # Extract the file Write-CCLSHost "Extracting: $filePath to $downloadPath" -ForegroundColor Cyan -Log & "$7zipPath" x "$filePath" -o"$downloadPath" -y # Check if extraction was successful if ($LASTEXITCODE -eq 0) { # Delete the original .7z file Write-CCLSHost "Extraction successful. Deleting original file: $filePath" -ForegroundColor Green -Log Remove-Item -Path $filePath -Force } else { Write-CCLSHost "Failed to extract: $filePath. Skipping deletion." -ForegroundColor Red -Log } } Write-CCLSHost "#All .7z files have been processed." -Log Write-CCLSHost "Go to $downloadPath to play the game." -ForegroundColor Cyan -Log } # Call the extraction function Start-GameExtraction } catch { Write-CCLSHost "An error occurred during extraction: $($_.Exception.Message)" -ForegroundColor Red -Log Write-CCLSHost "Error details: $($_.Exception.StackTrace)" -ForegroundColor Red -Log } } # Start the download try { $webClient.DownloadFileAsync([Uri]$downloadUrl, $downloadPath) # Wait for download to complete while ($webClient.IsBusy) { Start-Sleep -Milliseconds 100 } } catch { # Reset the progress display Reset-ProgressDisplay Write-CCLSHost "An error occurred during download: $($_.Exception.Message)" -ForegroundColor Red -Log } finally { # Clean up event handlers if ($downloadProgressEvent) { Unregister-Event -SourceIdentifier $downloadProgressEvent.Name } if ($downloadCompletedEvent) { Unregister-Event -SourceIdentifier $downloadCompletedEvent.Name } $webClient.Dispose() } } catch { Write-CCLSHost "An error occurred: $($_.Exception.Message)" -ForegroundColor Red -Log } } # Main CLI interface function Start-MainInterface($username) { Write-CCLSHost "`n`nWelcome to CCLS Games CLI Tool, $username!" -ForegroundColor Green -Log # Load settings to check setup status $settings = Initialize-Settings # Show appropriate message based on setup status if ($settings.HasCompletedSetup) { Write-CCLSHost "Type 'help' for a list of available commands.`n" -ForegroundColor Cyan -Log } else { Write-CCLSHost "ALERT, type command 'setup' to set critical values before downloading." -ForegroundColor Red -Log } } # Function to list all available games function Get-GamesList { try { # Construct the URL for the game list API $gamesListUrl = "$cliApiUrl/list.php" $params = @{ Uri = $gamesListUrl Method = "GET" Headers = @{ "User-Agent" = "CCLS-CLI/1.0" } } Write-CCLSHost "#Fetching game library..." -Log # Fetch game library from server try { $response = Invoke-RestMethod @params # Check if the request was successful if (-not $response.success) { Write-CCLSHost "Error: $($response.message)" -ForegroundColor Red -Log return } # Display game list Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log Write-CCLSHost "Game Library - $($response.count) games available" -ForegroundColor Green -Log Write-CCLSHost "==========================================================" -ForegroundColor DarkGray -Log if ($response.count -eq 0) { Write-CCLSHost "No games found in the library." -ForegroundColor Yellow -Log return } # Determine the maximum length for proper formatting $maxNameLength = ($response.games | ForEach-Object { $_.name.Length } | Measure-Object -Maximum).Maximum $maxIdLength = ($response.games | ForEach-Object { $_.id.Length } | Measure-Object -Maximum).Maximum # Ensure minimum column widths $nameColumnWidth = [Math]::Max($maxNameLength, 30) $idColumnWidth = [Math]::Max($maxIdLength, 8) # Create header Write-CCLSHost "$("Game Name".PadRight($nameColumnWidth)) => $("CG Number".PadRight($idColumnWidth))" -ForegroundColor Cyan -Log Write-CCLSHost "$("-" * $nameColumnWidth) => $("-" * $idColumnWidth)" -ForegroundColor Cyan -Log # Print each game with proper formatting foreach ($game in $response.games) { Write-CCLSHost "$($game.name.PadRight($nameColumnWidth)) => $($game.id)" -ForegroundColor White -Log } Write-CCLSHost "Use 'search [cgnumber]' to get detailed information about a specific game." -ForegroundColor Yellow -Log # REMOVED: The following lines that were causing the extra keypress requirement # Write-CCLSHost "#Press any key to return to the main menu..." -Log # $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") } catch { Write-CCLSHost "Error fetching game library: $($_.Exception.Message)" -ForegroundColor Red -Log # Also removed the keypress requirement here } } catch { Write-CCLSHost "An error occurred while processing game library: $($_.Exception.Message)" -ForegroundColor Red -Log # Also removed the keypress requirement here } } function Start-CclsCliTool { Write-CCLSHost "Hello and welcome to the CCLS Games CLI Tool" -ForegroundColor Green -Log Write-CCLSHost "Before proceeding to using this software you will need to sign in." -Log Write-CCLSHost "If you do not have an account already please go to $baseUrl/login.php?signup to register a new account." -ForegroundColor Cyan -Log $settings = Initialize-Settings # Try auto-login if remember login is enabled $loginResult = @{ Success = $false } if ($settings.RememberLogin) { $loginResult = Start-AutoLogin } # If auto-login failed or is disabled, do manual login if (-not $loginResult.Success) { $loginResult = Start-ManualLogin } # If login succeeded, show main interface if ($loginResult.Success) { # Notice we removed the "`n`n" at the beginning of the welcome message Write-CCLSHost "Welcome to CCLS Games CLI Tool, $($loginResult.Username)!" -ForegroundColor Green -Log # Show appropriate message based on setup status $settings = Initialize-Settings if ($settings.HasCompletedSetup) { Write-CCLSHost "Type 'help' for a list of available commands." -ForegroundColor Cyan -Log } else { Write-CCLSHost "ALERT, type command 'setup' to set critical values before downloading." -ForegroundColor Red -Log } Start-CommandInterface -username $loginResult.Username } else { Write-CCLSHost "Login failed. Press any key to exit..." -ForegroundColor Red -Log $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") } } function Clear-ConsoleScreen { # Log the clear command Write-CCLSHost "#User cleared the console screen" -Log -NoConsole # Use the PowerShell Clear-Host cmdlet to clear the console Clear-Host # Optionally, display a minimal header after clearing Write-CCLSHost "CCLS Games CLI Tool" -ForegroundColor Green -Log } # Function to format file size in a human-readable way function Format-Size { param ( [long]$Size ) if ($Size -ge 1GB) { return "{0:N2} GB" -f ($Size / 1GB) } elseif ($Size -ge 1MB) { return "{0:N2} MB" -f ($Size / 1MB) } elseif ($Size -ge 1KB) { return "{0:N2} KB" -f ($Size / 1KB) } else { return "$Size B" } } # Function to get folder size including subfolders function Get-FolderSize { param ( [string]$Path ) $totalSize = 0 try { # Get all files in the folder and subfolders $files = Get-ChildItem -Path $Path -Recurse -File -ErrorAction SilentlyContinue foreach ($file in $files) { $totalSize += $file.Length } } catch { Write-CCLSHost "Error calculating folder size: $($_.Exception.Message)" -ForegroundColor Red -Log } return $totalSize } # Function to list games in the download directory function Get-InstalledGames { param ( [switch]$Detailed ) # Get settings to find download directory $settings = Initialize-Settings $downloadPath = $settings.DownloadPath # Check if download path exists if (-not (Test-Path $downloadPath)) { Write-CCLSHost "Downloads folder does not exist yet. No games are installed." -ForegroundColor Yellow -Log return } # Get all folders in the download path try { $gameFolders = Get-ChildItem -Path $downloadPath -Directory # If no games found if ($gameFolders.Count -eq 0) { Write-CCLSHost "No games found in $downloadPath" -ForegroundColor Yellow -Log return } # Header Write-CCLSHost "`nInstalled Games" -ForegroundColor Green -Log Write-CCLSHost "==============" -ForegroundColor Green -Log # Calculate total size if detailed view $totalSize = 0 # List each game foreach ($folder in $gameFolders) { if ($Detailed) { # Get folder size for detailed view $size = Get-FolderSize -Path $folder.FullName $totalSize += $size $sizeFormatted = Format-Size -Size $size # Display with size Write-CCLSHost "$($folder.Name) - $sizeFormatted" -Log } else { # Simple list of names Write-CCLSHost "$($folder.Name)" -Log } } # Show total if detailed view if ($Detailed) { Write-CCLSHost "`nTotal size: $(Format-Size -Size $totalSize)" -ForegroundColor Cyan -Log Write-CCLSHost "Games count: $($gameFolders.Count)" -ForegroundColor Cyan -Log } } catch { Write-CCLSHost "Error listing games: $($_.Exception.Message)" -ForegroundColor Red -Log } } function Get-FullFileTree { param ( [string]$Path, [string]$Indent = "" ) $output = @() try { # Get items in the current directory $items = Get-ChildItem -Path $Path -ErrorAction SilentlyContinue foreach ($item in $items) { if ($item.PSIsContainer) { # It's a directory $output += "$Indent|- $($item.Name) (folder)" # Recursively get all subdirectories with no depth limit $childOutput = Get-FullFileTree -Path $item.FullName -Indent "$Indent| " if ($childOutput) { $output += $childOutput } } else { # It's a file $sizeFormatted = Format-Size -Size $item.Length $output += "$Indent|- $($item.Name) ($sizeFormatted)" } } } catch { $output += "$Indent Error accessing path: $($_.Exception.Message)" } return $output } # Updated function to list information about a specific game (with unlimited file tree depth) function Get-GameInfo { param ( [string]$GameName, [switch]$Detailed ) # Get settings to find download directory $settings = Initialize-Settings $downloadPath = $settings.DownloadPath $gamePath = Join-Path -Path $downloadPath -ChildPath $GameName # Check if game exists if (-not (Test-Path $gamePath)) { Write-CCLSHost "Game '$GameName' not found in $downloadPath" -ForegroundColor Yellow -Log return } # Get game size $size = Get-FolderSize -Path $gamePath $sizeFormatted = Format-Size -Size $size # Header Write-CCLSHost "`nGame Information: $GameName" -ForegroundColor Green -Log Write-CCLSHost "=======================" -ForegroundColor Green -Log Write-CCLSHost "Location: $gamePath" -Log Write-CCLSHost "Size: $sizeFormatted" -Log # If detailed view, show file tree if ($Detailed) { Write-CCLSHost "`nFile Structure (full directory tree):" -ForegroundColor Cyan -Log $fileTree = Get-FullFileTree -Path $gamePath foreach ($line in $fileTree) { Write-CCLSHost $line -Log } } } # Function to delete a game function Remove-Game { param ( [string]$GameName, [switch]$Force ) # Get settings to find download directory $settings = Initialize-Settings $downloadPath = $settings.DownloadPath $gamePath = Join-Path -Path $downloadPath -ChildPath $GameName # Check if game exists if (-not (Test-Path $gamePath)) { Write-CCLSHost "Game '$GameName' not found in $downloadPath" -ForegroundColor Yellow -Log return } # Get game size for informational purposes $size = Get-FolderSize -Path $gamePath $sizeFormatted = Format-Size -Size $size # Provide information about what will be deleted Write-CCLSHost "`nGame Deletion: $GameName" -ForegroundColor Red -Log Write-CCLSHost "===================" -ForegroundColor Red -Log Write-CCLSHost "Location: $gamePath" -Log Write-CCLSHost "Size: $sizeFormatted" -Log # If not forced, prompt for confirmation if (-not $Force) { Write-CCLSHost "`nWARNING: This will permanently delete the game and all its files!" -ForegroundColor Yellow -Log Write-CCLSHost "Are you sure you want to delete '$GameName'? (Y/N)" -ForegroundColor Yellow -Log $confirmation = Read-Host Write-CCLSHost "$confirmation" -NoConsole -Log if ($confirmation.ToLower() -ne "y") { Write-CCLSHost "Deletion cancelled." -ForegroundColor Green -Log return } } # Proceed with deletion try { # Use Remove-Item with -Recurse to delete the game folder and all contents Remove-Item -Path $gamePath -Recurse -Force Write-CCLSHost "`nGame '$GameName' has been successfully deleted." -ForegroundColor Green -Log Write-CCLSHost "Freed up $sizeFormatted of disk space." -ForegroundColor Green -Log } catch { Write-CCLSHost "Error deleting game: $($_.Exception.Message)" -ForegroundColor Red -Log } } # Alternative implementation using a direct embedding approach if web fetch doesn't work function Show-Dirty-Secret { try { $moosArt = Get-Content -Path "moos.txt" -Raw -Encoding UTF8 # If we can't get the file, embed a basic version of the art if ([string]::IsNullOrEmpty($moosArt)) { # Embed the ASCII art directly from moos.txt $moosArt = @' ╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╣╣╣ ╢╢╣╣╣╣╢╣▓╣▓▓▓▓╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╢╣╣╢╣╣╣╣╣╢╢╢╢╢╢╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢ ╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╢╢╣╣╣╣╣╣▒▒▒▒▒▒▒╢▒╢╢╢╣╢╢╢╢╢╢╢╢╢╢╢╢╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢ ▒╢╣╢╢╢╢╢╢╣╣╣╣╣╣╣╣╣╢╣╢╢╢▒╢▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╢╣╣╣╢╢╣╢╢╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣╢╢╢╣ ▒▒▒╢╢╢╣╣╣╣╣╣╣╣╢╣▒╢▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╣╣╣╣╣╢╣╢╢╢╢╢╢╢╢╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢╢╢╢╢ ▒▒▒▒╣╣╢╣╣╣╣╣╣╣╣▒╣╣╣╣▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╣╣╣╣╣╣╢╣╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢╢╢╣ ▒▒▒▒▒▒╣╣╣╣╢╣╣╣╣╣╣╣╣▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒╣╣▒╢╣╣╣╣╣╣╣╣╣╣╢╢╢╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢ ▒▒▒▒▒╣╣╢╣╣╣╢╣╣╣╣╣╣╣╣╣╣╣╣╣▒▒▒╣▒╣╣╣╣╢╣╣╣╣╣╣╢╣╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢ ▒▒▒▒▒▒╣╣╣╣╢╣╣╢╣╣╣╣╣╣╣╣╣╣╣╣╣▒╣╣╣╣╣╣╣╣╣╣╢╣╣╣╣╣╢╢╢╢╢╢╣╢╢╢╢╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢╢ ▒▒▒▒╣╣╣╣╣╣╢╢╢╣╢╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╣╢╣╣╢╣╢╢╣╣╣╢╣╢╢╢╢╢╢╢╢╢╢╢╣╣╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣ ▒▒▒▒╢╣╢╣╢╢╢╢╣╢╣╣╣╢╣╢╢╣╣╣╣╣╣╣╣╣╣╢╢╣╢╣╣╣╣╣╣╢╢╢╣╢╢╢╢╢╢╢╢╢╢╢╣╣╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▒▒▒▒▒╢╣╢╣╣╢╢╢╢╢╣╢╢╢╢╣╣╣╢╢╣╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▒▒▒▒▒╣╢╢╢╢╢╢╢╢╢╣╢╢╢╢╢╢╣╢╢╣╢╢╢╢╢╢╣╣╣╣╣╣▓▓╣╣╣╣╢╢╢╢╢╢╣╣╢╣╣▓╣╣╢╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▒▒▒╢╢╢╢╢╢╢╢╢╣╢╢╢╢╢╢╢╣╢╣╢╢╢╢╢╢╢╢╣╢╣▓▓╣╢╢╢╢╣╢╢╢╢╢╢╣╢╣╣╣╢╣▓▓▓╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣ ▒▒╢╢╢╣╣╣╣╣▓▓╣▓▓▓╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣▓╣╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢ ▒▒▒╢╢╢╢╢╢╣▓▓╣▓▓▓▓╣╣╣╢╢╢╢╢╢╢╢╢╢╣╣╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣▓╣╣▓▓▓▓▓▓▓▓▓▓▓▓╣╣▓▓▓▓▓╣╢ ▒▒▒▒╢╢╢╣▓▓▓▓▓▓▓▓▓╣╣╣╢╢╢╢╢╢╢╢╢╢╢╢╢╢╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓╣╢╢╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢▓▓▓╢╢╢ ▒▒▒▒▒▒╢╢╢╢▓▓▓▓▓╣▓▓▓╣╣╣╢╢╢╢╢╢╢╣╣╢╣╢╢▓▓▓▓▓▓▓▓╣╢╣╣╣╣╣╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢▓▓╣╢╢╢╢ ╢╣╣▒╢▒╢╢╢╢╢╢╢╣╣▓▓▓▓▓╣╢╢╢╢╢╣╢╢╢╢╢╣╣╢╢╢╢╢╣╣╣╣╢╢╢╣╣╢╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╣▓╣╢╢╢╢╢ ▒▒╢╢▒╣╢╢╢╢╢╣╣▓▓╣▓▓╣╢╢╢╢╢╢╣╣╣▓▓╣╣╣╣╢╢╣╣╢╢╢╣╣╣╣╣╣╣╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╢╢╢╢╢╢╢╢╢ ╣╣╣╣╣╣╣╢╢╢╢╣╣╣╣╣╣╣╢╢╣╢╢╢╣▓▓╣▓▓▓╣▓▓▓▓▓╣╣╣▓╣╢╢╢╣╣╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╣╣╢╢╢╢╢╢╢╢ ╣╣╣╣╣╣╣╢╢╢╢╣╣╣▓▓╣╣╢╣╣╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╢╢╣╢╢ ╣╣╣╣╣╢╢╣╣╢╢╢╣▓▓▓▓▓╣╣╢╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╣╣╣ ╢╣╣╣╢╣╣╢╣╢╢╢╢╣▓▓▓▓╣╣╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ╢╢╢╢╢╢╢╢▓▓╣╢╢╢▓▓▓▓▓╣╢╢╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓╣╣╢▓▓▓▓▓▓╣╢╢╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓╣╣▓▓▓▓▓▓▓▓╣╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓╣╢▓▓▓▓▓▓▓▓▓▓╣╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓╣▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓╢▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ ▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓ '@ } # Display the art directly Write-Host $moosArt -ForegroundColor Cyan } catch { Write-CCLSHost "moos no no no no no" -ForegroundColor Yellow -Log Write-CCLSHost "#Error details: $($_.Exception.Message)" -ForegroundColor Red -Log -NoConsole } } # Modified Start-CommandInterface function to include the secret command function Start-CommandInterface($username) { $running = $true while ($running) { Write-CCLSHost "CCLS>" -ForegroundColor Yellow -NoNewline -Log $command = Read-Host Write-CCLSHost "$command" -NoConsole -Log switch -Regex ($command.ToLower()) { "^exit|^quit" { $running = $false Write-CCLSHost "Thank you for using the CCLS Games CLI Tool. Goodbye!" -ForegroundColor Cyan -Log } "^clear|^cls" { # Call the clear screen function Clear-ConsoleScreen } # Secret command that isn't shown in help "^moos$" { # Call the moos function Show-Dirty-Secret } "^help" { Write-CCLSHost "Available Commands:" -ForegroundColor Green -Log Write-CCLSHost " help - Show this help message" -Log Write-CCLSHost " clear, cls - Clear the console screen" -Log Write-CCLSHost " setup - Configure download directories" -Log Write-CCLSHost " search - Search for game information by CG number" -Log Write-CCLSHost " search library - List all available games for download" -Log Write-CCLSHost " get - Download and install a game by CG number" -Log Write-CCLSHost " list games - List installed games (names only)" -Log Write-CCLSHost " list games -d - List installed games with sizes" -Log Write-CCLSHost " list game [name] - Show info about a specific game" -Log Write-CCLSHost " list game [name] -d - Show detailed info about a specific game with file tree" -Log Write-CCLSHost " del [name] - Delete a game (with confirmation)" -Log Write-CCLSHost " del [name] -y - Delete a game without confirmation" -Log Write-CCLSHost " exit, quit - Exit the application" -Log Write-CCLSHost " logout - Log out and exit" -Log Write-CCLSHost " forget - Remove stored credentials" -Log } "^setup" { Start-Setup } "^search$" { Write-CCLSHost "To use the search command please provide a valid CG number in this format 'search cg0000'" -ForegroundColor Cyan -Log Write-CCLSHost "To get the CG number of a game, go to the main games page and click on any game, then check" -ForegroundColor Cyan -Log Write-CCLSHost "the URL 'https://games.ccls.icu/game.php?id=cg0000' and the 'cg0000' part in URL is the CG number" -ForegroundColor Cyan -Log } "^search\s+(cg\d{4})$" { $cgNumber = $matches[1] Search-Game -cgNumber $cgNumber } "^get$" { Write-CCLSHost "To use the get command please provide a valid CG number in this format 'get cg0000'" -ForegroundColor Cyan -Log Write-CCLSHost "To get the CG number of a game, go to the main games page and click on any game, then check" -ForegroundColor Cyan -Log Write-CCLSHost "the URL 'https://games.ccls.icu/game.php?id=cg0000' and the 'cg0000' part in URL is the CG number." -ForegroundColor Cyan -Log Write-CCLSHost "ALERT, the get command will start the downloading process of the game specified, to stop it do 'Ctrl C'" -ForegroundColor Red -Log } "^get\s+(cg\d{4})$" { $cgNumber = $matches[1] Get-Game -cgNumber $cgNumber } "^search\s+library$|^library$" { Get-GamesList } "^list\s+games$" { # List games with minimal detail Get-InstalledGames } "^list\s+games\s+-d$" { # List games with detailed information Get-InstalledGames -Detailed } "^list\s+game\s+(.+?)(?:\s+-d)?$" { $gameName = $matches[1] $detailed = $command -match "-d$" # Show information about a specific game Get-GameInfo -GameName $gameName -Detailed:$detailed } "^del\s+(.+?)(?:\s+-y)?$" { $gameName = $matches[1] $force = $command -match "-y$" # Delete the specified game Remove-Game -GameName $gameName -Force:$force } "^logout" { $running = $false Write-CCLSHost "Logging out..." -ForegroundColor Cyan -Log # Clear the current session but keep credentials if they exist } "^forget" { if (Test-Path $credentialsFile) { Remove-Item -Path $credentialsFile -Force $settings = Initialize-Settings $settings.RememberLogin = $false Save-Settings -settings $settings Write-CCLSHost "Stored credentials have been removed." -ForegroundColor Green -Log } else { Write-CCLSHost "No stored credentials found." -ForegroundColor Yellow -Log } } default { Write-CCLSHost "Unknown command. Type 'help' for a list of available commands." -ForegroundColor Red -Log } } } } # Add a line to log script completion function End-Logging { $endTime = Get-Date "CCLS Games CLI Session ended at $endTime, duration: $(($endTime - [DateTime]::ParseExact($script:sessionStartTime, 'yyyy-MM-dd_HH-mm-ss', $null)).ToString())" | Out-File -FilePath $script:logFile -Append } # Register script exit event to ensure logging is completed Register-EngineEvent -SourceIdentifier ([System.Management.Automation.PsEngineEvent]::Exiting) -Action { End-Logging } | Out-Null # Start the application Try { Start-CclsCliTool } Finally { # Ensure logging is completed even if script exits unexpectedly End-Logging }