Files
JakeBreath bf1d75aca8
CI / Backend tests (push) Successful in 2m15s
CI / Frontend build & lint (push) Successful in 22s
Update
2026-10-02 00:34:05 -05:00

220 lines
9.4 KiB
PowerShell

# 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 <api-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
# Ignore commented-out lines: the config ships an example token line, and
# matching it would make us probe with the placeholder as a real token.
$content = (@($content -split "`r?`n") | Where-Object { $_ -notmatch '^\s*#' }) -join "`n"
$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) { . $j621GreetingScript }',
'# Run it again any time with: greeting',
'function greeting {',
' if (-not (Get-Command Show-J621Greeting -ErrorAction Ignore) -and (Test-Path -LiteralPath $j621GreetingScript)) { . $j621GreetingScript }',
' Show-J621Greeting',
'}',
'if ((Test-Path -LiteralPath $j621GreetingScript) -and [Environment]::UserInteractive -and -not [Console]::IsOutputRedirected) {',
' 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