# Install the J621 PowerShell greeting: # * copies J621Greeting.ps1 into %APPDATA%\j621Greeting\ # * writes %APPDATA%\j621Greeting\config.ps1 (asks for the API origin and an # optional token, or takes them as parameters) # * wires the greeting into your PowerShell profile (marker block, once) # * checks the tools it needs and probes the configured backend # # Usage: # .\install.ps1 # .\install.ps1 -Url https://j621.example.ts.net -Token # .\install.ps1 -NoPrompt # never ask, keep/derive defaults # .\install.ps1 -Force # rewrite an existing config # .\install.ps1 -NoProfilePatch # do not touch your PowerShell profile # .\install.ps1 -Uninstall # remove the profile block + installed script [CmdletBinding()] param( [string]$Url, [string]$Token, [switch]$NoPrompt, [switch]$Force, [switch]$NoProfilePatch, [switch]$Uninstall ) $ErrorActionPreference = 'Stop' $here = $PSScriptRoot if (-not $here) { $here = Split-Path -Parent $MyInvocation.MyCommand.Path } $configDir = Join-Path $env:APPDATA 'j621Greeting' $configFile = Join-Path $configDir 'config.ps1' $installedScript = Join-Path $configDir 'J621Greeting.ps1' $defaultUrl = 'https://j621.rainbow-herring.ts.net' $markerBegin = '# >>> J621 greeting >>>' $markerEnd = '# <<< J621 greeting <<<' $profilePath = $PROFILE function Get-InstalledConfigValue { param([string]$Name) if (-not (Test-Path -LiteralPath $configFile)) { return $null } $content = Get-Content -LiteralPath $configFile -Raw $rx = '\$env:' + $Name + ' = ''([^'']*)''' if ($content -match $rx) { return $Matches[1] } return $null } function Remove-ProfileBlock { if (-not (Test-Path -LiteralPath $profilePath)) { return } $lines = @(Get-Content -LiteralPath $profilePath) if (-not ($lines -contains $markerBegin)) { return } $out = New-Object System.Collections.Generic.List[string] $inside = $false foreach ($line in $lines) { if ($line.Trim() -eq $markerBegin) { $inside = $true; continue } if ($line.Trim() -eq $markerEnd) { $inside = $false; continue } if (-not $inside) { $out.Add($line) } } while ($out.Count -gt 0 -and [string]::IsNullOrWhiteSpace($out[$out.Count - 1])) { $out.RemoveAt($out.Count - 1) } Set-Content -LiteralPath $profilePath -Value ($out -join "`r`n") -Encoding ASCII } # --- Uninstall ----------------------------------------------------------------- if ($Uninstall) { Remove-ProfileBlock if (Test-Path -LiteralPath $installedScript) { Remove-Item -LiteralPath $installedScript -Force } Write-Host "Removed the J621 greeting from the profile and $installedScript" Write-Host "Your config and logs were left in place: $configDir" exit 0 } # --- Install the function ------------------------------------------------------ New-Item -ItemType Directory -Path $configDir -Force | Out-Null $source = Join-Path $here 'J621Greeting.ps1' if (-not (Test-Path -LiteralPath $source)) { throw "J621Greeting.ps1 not found next to this installer ($source)" } Copy-Item -LiteralPath $source -Destination $installedScript -Force Write-Host "Installed $installedScript" # --- Configuration ------------------------------------------------------------- $writeConfig = $false if (-not (Test-Path -LiteralPath $configFile)) { $writeConfig = $true } elseif ($Force -or $PSBoundParameters.ContainsKey('Url')) { $writeConfig = $true } else { Write-Host "Keeping existing $configFile (use -Force to rewrite it)" $current = Get-InstalledConfigValue -Name 'J621_BASE' if ($current) { $Url = $current } if (-not $Token) { $Token = Get-InstalledConfigValue -Name 'J621_TOKEN' } } if ($writeConfig) { if (-not $NoPrompt) { if (-not $Url) { $answer = Read-Host "API origin [$defaultUrl]" if ($answer) { $Url = $answer } } if (-not $Token) { $answer = Read-Host 'API token (optional, Enter to run as a guest)' if ($answer) { $Token = $answer } } } if (-not $Url) { $Url = $defaultUrl } $Url = $Url.Trim().TrimEnd('/').Replace("'", "") if ($Token) { $Token = $Token.Trim().Replace("'", "") } $lines = New-Object System.Collections.Generic.List[string] $lines.Add('# J621 greeting configuration - written by install.ps1 on ' + (Get-Date -Format 'yyyy-MM-dd')) $lines.Add('# Values here are defaults; an environment variable already set in your') $lines.Add('# session wins over them.') $lines.Add('if (-not $env:J621_BASE) { $env:J621_BASE = ''' + $Url + ''' }') if ($Token) { $lines.Add('if (-not $env:J621_TOKEN) { $env:J621_TOKEN = ''' + $Token + ''' }') } else { $lines.Add('# if (-not $env:J621_TOKEN) { $env:J621_TOKEN = ''paste-a-token-here'' }') } $lines.Add('# if (-not $env:J621_WEB) { $env:J621_WEB = ''' + $Url + ''' }') $lines.Add('# if (-not $env:J621_FASTFETCH_CONFIG) { $env:J621_FASTFETCH_CONFIG = ''jake'' }') Set-Content -LiteralPath $configFile -Value $lines -Encoding ASCII Write-Host "Wrote $configFile" } # --- Profile ------------------------------------------------------------------- if (-not $NoProfilePatch) { $existing = '' if (Test-Path -LiteralPath $profilePath) { $existing = Get-Content -LiteralPath $profilePath -Raw } if ($existing -match [regex]::Escape($markerBegin)) { Write-Host 'Profile already sources the greeting (marker present)' } else { $normalized = $existing -replace "`r`n", "`n" $legacy = @( '# Fastfetch greeting on interactive PowerShell start', 'if ([Environment]::UserInteractive -and -not [Console]::IsOutputRedirected) {', ' fastfetch', '}' ) -join "`n" if ($normalized.Contains($legacy)) { $normalized = $normalized.Replace($legacy, '').TrimEnd() + "`n" Write-Host 'Replaced the plain fastfetch block in your profile' } $block = @( $markerBegin, '# Random J621 library image as the fastfetch logo (extras/powershell_greeting).', '$j621GreetingScript = "$env:APPDATA\j621Greeting\J621Greeting.ps1"', 'if ((Test-Path -LiteralPath $j621GreetingScript) -and [Environment]::UserInteractive -and -not [Console]::IsOutputRedirected) {', ' . $j621GreetingScript', ' Show-J621Greeting', '}', $markerEnd ) -join "`r`n" $profileDir = Split-Path -Parent $profilePath if (-not (Test-Path -LiteralPath $profileDir)) { New-Item -ItemType Directory -Path $profileDir -Force | Out-Null } Set-Content -LiteralPath $profilePath -Value ($normalized.TrimEnd() + "`r`n`r`n" + $block + "`r`n") -Encoding ASCII Write-Host "Added the J621 greeting to $profilePath" } } # --- Dependencies -------------------------------------------------------------- $problems = 0 foreach ($tool in 'fastfetch', 'curl.exe') { if (-not (Get-Command $tool -ErrorAction SilentlyContinue)) { $problems = 1 Write-Host "Missing required tool: $tool" } } if (-not ($env:WT_SESSION -or $env:WEZTERM_PANE)) { Write-Host 'Note: image logos need Windows Terminal 1.22+ (sixel) or WezTerm (kitty graphics);' Write-Host 'other terminals fall back to a plain fastfetch.' } # --- Probe the configured backend ----------------------------------------------- Write-Host '' $probeUrl = $Url $probeToken = $Token if (-not $probeUrl) { $probeUrl = $defaultUrl } Write-Host "Checking $probeUrl ..." $health = & curl.exe -s -m 10 ($probeUrl + '/health') 2>$null | Out-String if ($health -match '"status"\s*:\s*"ok"') { Write-Host ' backend: ok' $probeArgs = @('-s', '-m', '10') if ($probeToken) { $probeArgs += @('-H', "Authorization: Token $probeToken") } $probe = & curl.exe @probeArgs ($probeUrl + '/api/random/?fastfetch=1') 2>$null | Out-String $detail = $null try { $parsed = $probe | ConvertFrom-Json if ($parsed.detail) { $detail = [string]$parsed.detail } } catch { } if ($detail) { Write-Host " random: $detail" if (-not $probeToken) { Write-Host ' (a token would also let you see items that are hidden from guests)' } } else { Write-Host ' random: ok' } } else { $problems = 1 Write-Host " backend did not answer at $probeUrl/health" Write-Host " got: $health" Write-Host " Fix J621_BASE in $configFile (or pass -Url) and run again." } # --- Wrap up -------------------------------------------------------------------- Write-Host '' if ($problems -eq 0) { Write-Host 'Done. Test it now with: Show-J621Greeting' } else { Write-Host 'Finished with problems above; the greeting will report them too.' } Write-Host ('Rating mode lives in ' + (Join-Path $configDir 'greeting_mode') + ' (0=NSFW, 1=SFW, 2=Questionable).') Write-Host 'gm-switch.exe and its Start Menu shortcuts write that same file.' exit $problems