diff --git a/scripts/README.md b/scripts/README.md index 4409d9b..3138e3e 100644 --- a/scripts/README.md +++ b/scripts/README.md @@ -8,6 +8,8 @@ Paketbau, Installation und Start. |---|---|---| | `build-package.ts` | Entwicklungsrechner / CI | Baut `dist/abdulive--win-x64.zip` samt Updater-Manifest | | `install.ps1` | Stream-PC | Installiert Programm, Daten und Autostart. Ohne Administratorrechte | +| `uninstall.ps1` | Stream-PC | Entfernt Programm und Autostart. `-AuchDaten` loescht auch Datenbank, Clips und Modell | +| `uninstall.ps1` | Stream-PC | Entfernt Programm und Autostart. `-AuchDaten` loescht auch Datenbank, Clips und Modell | | `launcher.ps1` | Stream-PC | Vom Aufgabenplaner gestartet: Update anwenden, dann Daemon starten | | `check-env` | Stream-PC | Prueft ffmpeg, whisper-cli, Schriften, Sprachmodell, Verzeichnisse, OBS | | `auth` | Stream-PC | OAuth-Flow fuer Broadcaster- und Bot-Token | diff --git a/scripts/build-package.ts b/scripts/build-package.ts index df01e45..bac1379 100644 --- a/scripts/build-package.ts +++ b/scripts/build-package.ts @@ -168,7 +168,7 @@ async function main(): Promise { for (const rel of await walk(path.join(repo, 'assets', 'fonts'))) { files.push({ name: `fonts/${rel}`, data: await fs.readFile(path.join(repo, 'assets/fonts', rel)) }); } - for (const f of ['launcher.ps1', 'install.ps1', 'backup.ps1']) { + for (const f of ['launcher.ps1', 'install.ps1', 'uninstall.ps1', 'backup.ps1']) { files.push({ name: f, data: await fs.readFile(path.join(repo, 'scripts', f)) }); } console.log(` ${files.filter((f) => f.name.startsWith('app/')).length} Quelldateien`); diff --git a/scripts/install.ps1 b/scripts/install.ps1 index 7c0c0bf..4a33115 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -133,7 +133,7 @@ Get-Process node -ErrorAction SilentlyContinue | New-Item -ItemType Directory -Force -Path $Ziel | Out-Null foreach ($item in @('app', 'bin', 'fonts', 'node.exe', 'version.json', - 'abdulive.cmd', 'launcher.ps1', 'install.ps1', 'backup.ps1')) { + 'abdulive.cmd', 'launcher.ps1', 'install.ps1', 'uninstall.ps1', 'backup.ps1')) { $von = Join-Path $quellordner $item if (-not (Test-Path $von)) { continue } $nach = Join-Path $Ziel $item @@ -249,3 +249,6 @@ Write-Host '' Write-Host 'Dort eintragen: die beiden Twitch-Apps und das OBS-Passwort.' Write-Host 'Danach ist alles beisammen.' Write-Host '' +Write-Host 'Wieder loswerden:' -ForegroundColor DarkGray +Write-Host " & '$Ziel\uninstall.ps1'" -ForegroundColor DarkGray +Write-Host '' diff --git a/scripts/launcher.ps1 b/scripts/launcher.ps1 index cd0086b..c4a0d1d 100644 --- a/scripts/launcher.ps1 +++ b/scripts/launcher.ps1 @@ -36,7 +36,7 @@ if (Test-Path $pending) { Start-Sleep -Milliseconds 500 foreach ($item in @('app', 'bin', 'fonts', 'node.exe', 'version.json', - 'abdulive.cmd', 'launcher.ps1', 'install.ps1', 'backup.ps1')) { + 'abdulive.cmd', 'launcher.ps1', 'install.ps1', 'uninstall.ps1', 'backup.ps1')) { $new = Join-Path $pending $item if (-not (Test-Path $new)) { continue } $old = Join-Path $root $item diff --git a/scripts/uninstall.ps1 b/scripts/uninstall.ps1 new file mode 100644 index 0000000..59703c8 --- /dev/null +++ b/scripts/uninstall.ps1 @@ -0,0 +1,78 @@ +# Entfernt abdulive wieder. +# +# .\uninstall.ps1 Programm und Autostart weg, Daten bleiben +# .\uninstall.ps1 -AuchDaten alles weg, auch Datenbank und Clips +# +# Die Daten bleiben absichtlich per Vorgabe stehen: in der Datenbank liegen +# Chatverlaeufe, und die sind nach einer versehentlichen Deinstallation nicht +# wiederherstellbar. Wer neu installiert, findet seine Einrichtung wieder. + +[CmdletBinding()] +param( + [string]$Ziel = (Join-Path $env:LOCALAPPDATA 'Programs\abdulive'), + [switch]$AuchDaten +) + +$ErrorActionPreference = 'Stop' +$daten = Join-Path $env:LOCALAPPDATA 'abdulive' + +function Schritt($text) { Write-Host "==> $text" -ForegroundColor Cyan } +function Hinweis($text) { Write-Host " $text" -ForegroundColor DarkGray } + +Schritt 'Autostart entfernen' +$aufgaben = Get-ScheduledTask -TaskName 'abdulive', 'abdulive-update' -ErrorAction SilentlyContinue +if ($aufgaben) { + foreach ($a in $aufgaben) { + try { Stop-ScheduledTask -TaskName $a.TaskName -ErrorAction SilentlyContinue } catch { } + Unregister-ScheduledTask -TaskName $a.TaskName -Confirm:$false + Hinweis "Aufgabe `"$($a.TaskName)`" entfernt." + } +} else { + Hinweis 'Keine Aufgaben gefunden.' +} + +Schritt 'Laufenden Daemon beenden' +$prozesse = Get-Process node -ErrorAction SilentlyContinue | + Where-Object { $_.Path -and $_.Path.StartsWith($Ziel, 'OrdinalIgnoreCase') } +if ($prozesse) { + foreach ($p in $prozesse) { + Stop-Process -Id $p.Id -Force + Hinweis "node.exe (PID $($p.Id)) beendet." + } + # Windows gibt die Dateisperren nicht sofort frei + Start-Sleep -Milliseconds 800 +} else { + Hinweis 'Lief nicht.' +} + +Schritt 'Programm entfernen' +if (Test-Path $Ziel) { + Remove-Item -Recurse -Force $Ziel + Hinweis $Ziel +} else { + Hinweis 'War nicht installiert.' +} + +if ($AuchDaten) { + Schritt 'Daten entfernen' + if (Test-Path $daten) { + Remove-Item -Recurse -Force $daten + Hinweis "$daten (Datenbank, Clips, Sprachmodell, Protokolle)" + } else { + Hinweis 'Nichts da.' + } +} elseif (Test-Path $daten) { + $mb = [math]::Round((Get-ChildItem $daten -Recurse -File -ErrorAction SilentlyContinue | + Measure-Object Length -Sum).Sum / 1MB) + Write-Host '' + Write-Host "Die Daten bleiben liegen ($mb MB):" -ForegroundColor Yellow + Write-Host " $daten" + Write-Host ' Darin: Datenbank mit Chatverlaeufen, Clips, Sprachmodell, Einrichtung.' + Write-Host '' + Write-Host 'Auch die weg:' + Write-Host " Remove-Item -Recurse -Force '$daten'" +} + +Write-Host '' +Write-Host 'abdulive ist entfernt.' -ForegroundColor Green +Write-Host ''