mirror of
https://github.com/KRTirtho/spotube.git
synced 2026-05-06 15:24:36 +00:00
feat(windows): add GUI uninstaller script
Adds a Windows-specific uninstaller under windows/uninstaller/ that: - Shows a Yes/No confirmation dialog via Windows Forms - Displays a live progress window (no console) during removal - Removes app files, Start Menu/Desktop/Startup shortcuts, AppData configuration, and all registry entries - Mirrors paths/keys from the Inno Setup installer (inno_setup.iss) - Includes a Register-SpotubeUninstaller.ps1 helper to surface the uninstaller in Control Panel -> Programs and Features - Provides a .bat wrapper (WindowStyle Hidden) so only GUI dialogs show Closes: N/A
This commit is contained in:
parent
2cc8d2620d
commit
4b09d2133d
85
windows/uninstaller/Register-SpotubeUninstaller.ps1
Normal file
85
windows/uninstaller/Register-SpotubeUninstaller.ps1
Normal file
@ -0,0 +1,85 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
Registers the Spotube custom uninstaller in Windows Programs and Features.
|
||||
.DESCRIPTION
|
||||
Writes a registry entry to HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
|
||||
so that Spotube appears in Control Panel -> Programs and Features and in
|
||||
Settings -> Apps -> Installed Apps. The UninstallString points to Uninstall-Spotube.bat
|
||||
which must be in the same directory as this script.
|
||||
.NOTES
|
||||
Requires: Uninstall-Spotube.bat in the same folder.
|
||||
Run as Administrator.
|
||||
#>
|
||||
param()
|
||||
|
||||
# Re-elevate if not already running as Administrator.
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
|
||||
[Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
)
|
||||
if (-not $isAdmin) {
|
||||
Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs
|
||||
exit
|
||||
}
|
||||
|
||||
$scriptDir = Split-Path -Parent $PSCommandPath
|
||||
$uninstallBat = Join-Path $scriptDir "Uninstall-Spotube.bat"
|
||||
|
||||
if (-Not (Test-Path $uninstallBat)) {
|
||||
Write-Error "Uninstall-Spotube.bat not found in '$scriptDir'. Ensure all uninstaller files are kept together."
|
||||
pause
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Version sourced from pubspec.yaml (5.1.1+44). Override if the installed exe exposes a FileVersion.
|
||||
$displayVersion = "5.1.1"
|
||||
$iconPath = ""
|
||||
|
||||
foreach ($candidate in @(
|
||||
(Join-Path $env:ProgramFiles "Spotube\spotube.exe"),
|
||||
(Join-Path $env:LOCALAPPDATA "Programs\Spotube\spotube.exe")
|
||||
)) {
|
||||
if (Test-Path $candidate) {
|
||||
$fileVer = (Get-Item $candidate).VersionInfo.FileVersion
|
||||
if ($fileVer) { $displayVersion = $fileVer }
|
||||
$iconPath = $candidate
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\SpotubeCustomUninstaller"
|
||||
|
||||
if (-Not (Test-Path $regPath)) {
|
||||
New-Item -Path $regPath -Force | Out-Null
|
||||
}
|
||||
|
||||
# Registry values follow the standard Windows "Add/Remove Programs" schema.
|
||||
$stringValues = @{
|
||||
DisplayName = "Spotube"
|
||||
DisplayVersion = $displayVersion
|
||||
Publisher = "KRTirtho, OSS"
|
||||
URLInfoAbout = "https://github.com/KRTirtho/spotube"
|
||||
HelpLink = "https://github.com/KRTirtho/spotube/issues"
|
||||
UninstallString = "`"$uninstallBat`""
|
||||
InstallDate = (Get-Date -Format "yyyyMMdd")
|
||||
}
|
||||
$dwordValues = @{
|
||||
NoModify = 1
|
||||
NoRepair = 1
|
||||
EstimatedSize = 80000 # Approximate installed size in KB
|
||||
}
|
||||
|
||||
foreach ($kv in $stringValues.GetEnumerator()) {
|
||||
Set-ItemProperty -Path $regPath -Name $kv.Key -Value $kv.Value
|
||||
}
|
||||
foreach ($kv in $dwordValues.GetEnumerator()) {
|
||||
Set-ItemProperty -Path $regPath -Name $kv.Key -Value $kv.Value -Type DWord
|
||||
}
|
||||
if ($iconPath) {
|
||||
Set-ItemProperty -Path $regPath -Name "DisplayIcon" -Value "$iconPath,0"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Spotube registered in Programs and Features." -ForegroundColor Green
|
||||
Write-Host "Open Control Panel -> Programs and Features (or Settings -> Apps) to uninstall."
|
||||
Write-Host ""
|
||||
pause
|
||||
4
windows/uninstaller/Uninstall-Spotube.bat
Normal file
4
windows/uninstaller/Uninstall-Spotube.bat
Normal file
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
:: Launches the Spotube GUI uninstaller without showing a console window.
|
||||
:: -WindowStyle Hidden ensures only the WinForms dialogs are visible.
|
||||
powershell -NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File "%~dp0Uninstall-Spotube.ps1"
|
||||
203
windows/uninstaller/Uninstall-Spotube.ps1
Normal file
203
windows/uninstaller/Uninstall-Spotube.ps1
Normal file
@ -0,0 +1,203 @@
|
||||
<#
|
||||
.SYNOPSIS
|
||||
GUI-based uninstaller for Spotube on Windows.
|
||||
.DESCRIPTION
|
||||
Removes all Spotube installation artifacts: application files, shortcuts,
|
||||
user data, and registry entries. Mirrors what the Inno Setup installer
|
||||
creates (inno_setup.iss / make_config.yaml).
|
||||
.PARAMETER Silent
|
||||
Suppresses all GUI dialogs and runs non-interactively.
|
||||
#>
|
||||
param (
|
||||
[switch]$Silent
|
||||
)
|
||||
|
||||
# Application metadata — must match Inno Setup make_config.yaml
|
||||
$APP_NAME = "Spotube"
|
||||
$APP_ID = "80B901C8-D6FE-494E-8AF7-A2BD440E8644"
|
||||
$INNO_REG_KEY = "${APP_ID}_is1"
|
||||
$CUSTOM_REG_KEY = "SpotubeCustomUninstaller"
|
||||
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
Add-Type -AssemblyName System.Drawing
|
||||
|
||||
# Displays a standard Windows message box and returns the DialogResult.
|
||||
function Show-MessageBox {
|
||||
param(
|
||||
[string]$Message,
|
||||
[string]$Title = "Spotube Uninstaller",
|
||||
[System.Windows.Forms.MessageBoxButtons]$Buttons = [System.Windows.Forms.MessageBoxButtons]::OK,
|
||||
[System.Windows.Forms.MessageBoxIcon]$Icon = [System.Windows.Forms.MessageBoxIcon]::Information
|
||||
)
|
||||
return [System.Windows.Forms.MessageBox]::Show($Message, $Title, $Buttons, $Icon)
|
||||
}
|
||||
|
||||
# Creates and displays the progress window. Returns a hashtable of controls
|
||||
# so the caller can update label text, sub-label, and progress bar value.
|
||||
function Show-ProgressForm {
|
||||
$form = New-Object System.Windows.Forms.Form
|
||||
$form.Text = "Spotube Uninstaller"
|
||||
$form.Size = New-Object System.Drawing.Size(460, 200)
|
||||
$form.StartPosition = "CenterScreen"
|
||||
$form.FormBorderStyle = "FixedDialog"
|
||||
$form.MaximizeBox = $false
|
||||
$form.MinimizeBox = $false
|
||||
$form.ControlBox = $false # Disable X button during active uninstall
|
||||
$form.TopMost = $true
|
||||
|
||||
# Use the installed Spotube executable's icon if available
|
||||
foreach ($candidate in @(
|
||||
(Join-Path $env:ProgramFiles "Spotube\spotube.exe"),
|
||||
(Join-Path $env:LOCALAPPDATA "Programs\Spotube\spotube.exe")
|
||||
)) {
|
||||
if (Test-Path $candidate) {
|
||||
try { $form.Icon = [System.Drawing.Icon]::ExtractAssociatedIcon($candidate) } catch {}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
$lblStatus = New-Object System.Windows.Forms.Label
|
||||
$lblStatus.Location = New-Object System.Drawing.Point(16, 16)
|
||||
$lblStatus.Size = New-Object System.Drawing.Size(420, 20)
|
||||
$lblStatus.Text = "Preparing..."
|
||||
$lblStatus.Font = New-Object System.Drawing.Font("Segoe UI", 10)
|
||||
$form.Controls.Add($lblStatus)
|
||||
|
||||
$progressBar = New-Object System.Windows.Forms.ProgressBar
|
||||
$progressBar.Location = New-Object System.Drawing.Point(16, 48)
|
||||
$progressBar.Size = New-Object System.Drawing.Size(420, 22)
|
||||
$progressBar.Minimum = 0
|
||||
$progressBar.Maximum = 100
|
||||
$progressBar.Value = 0
|
||||
$form.Controls.Add($progressBar)
|
||||
|
||||
$lblDetail = New-Object System.Windows.Forms.Label
|
||||
$lblDetail.Location = New-Object System.Drawing.Point(16, 80)
|
||||
$lblDetail.Size = New-Object System.Drawing.Size(420, 16)
|
||||
$lblDetail.Text = ""
|
||||
$lblDetail.Font = New-Object System.Drawing.Font("Segoe UI", 8)
|
||||
$lblDetail.ForeColor = [System.Drawing.Color]::DimGray
|
||||
$form.Controls.Add($lblDetail)
|
||||
|
||||
$form.Show()
|
||||
$form.Refresh()
|
||||
|
||||
return @{
|
||||
Form = $form
|
||||
Status = $lblStatus
|
||||
Detail = $lblDetail
|
||||
Progress = $progressBar
|
||||
}
|
||||
}
|
||||
|
||||
# Re-elevate as Administrator if the script is not already running elevated.
|
||||
$isAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole(
|
||||
[Security.Principal.WindowsBuiltInRole]::Administrator
|
||||
)
|
||||
if (-not $isAdmin) {
|
||||
$relaunchArgs = "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`""
|
||||
if ($Silent) { $relaunchArgs += " -Silent" }
|
||||
Start-Process powershell -ArgumentList $relaunchArgs -Verb RunAs
|
||||
exit
|
||||
}
|
||||
|
||||
# Prompt the user before making any changes.
|
||||
if (-not $Silent) {
|
||||
$confirmMsg = @"
|
||||
Are you sure you want to uninstall Spotube?
|
||||
|
||||
This will permanently remove:
|
||||
• Application files
|
||||
• Desktop, Start Menu, and Startup shortcuts
|
||||
• User configuration and cached data
|
||||
• Windows registry entries
|
||||
"@
|
||||
$result = Show-MessageBox -Message $confirmMsg -Title "Uninstall Spotube" `
|
||||
-Buttons ([System.Windows.Forms.MessageBoxButtons]::YesNo) `
|
||||
-Icon ([System.Windows.Forms.MessageBoxIcon]::Question)
|
||||
|
||||
if ($result -ne [System.Windows.Forms.DialogResult]::Yes) {
|
||||
Show-MessageBox -Message "Uninstallation was cancelled. No changes were made." `
|
||||
-Title "Cancelled" -Icon ([System.Windows.Forms.MessageBoxIcon]::Information)
|
||||
exit
|
||||
}
|
||||
}
|
||||
|
||||
$ui = Show-ProgressForm
|
||||
|
||||
# Updates the progress window with new status text and a percentage value.
|
||||
function Update-Progress ([string]$status, [string]$detail, [int]$percent) {
|
||||
$ui.Status.Text = $status
|
||||
$ui.Detail.Text = $detail
|
||||
$ui.Progress.Value = [Math]::Min($percent, 100)
|
||||
$ui.Form.Refresh()
|
||||
}
|
||||
|
||||
# Silently removes a file or directory; no-ops if the path does not exist.
|
||||
function Safe-Remove ([string]$path) {
|
||||
if ($path -and (Test-Path $path)) {
|
||||
try { Remove-Item -Path $path -Recurse -Force -ErrorAction Stop } catch {}
|
||||
}
|
||||
}
|
||||
|
||||
# Step 1: Terminate any running Spotube processes before touching files.
|
||||
Update-Progress "Stopping Spotube..." "Terminating running processes" 5
|
||||
Get-Process -Name "spotube" -ErrorAction SilentlyContinue |
|
||||
Stop-Process -Force -ErrorAction SilentlyContinue
|
||||
Start-Sleep -Milliseconds 1500
|
||||
|
||||
# Step 2: Delete the installation directory.
|
||||
# Inno Setup installs to {autopf}\Spotube — covers both admin and per-user installs.
|
||||
Update-Progress "Removing application files..." "Deleting installation directory" 20
|
||||
@(
|
||||
(Join-Path $env:ProgramFiles $APP_NAME),
|
||||
(Join-Path $env:ProgramW6432 $APP_NAME),
|
||||
(Join-Path $env:LOCALAPPDATA "Programs\$APP_NAME")
|
||||
) | Select-Object -Unique | ForEach-Object { Safe-Remove $_ }
|
||||
|
||||
# Step 3: Remove shortcuts created by the Inno Setup [Icons] section.
|
||||
# Covers: {autoprograms} (Start Menu), {autodesktop} (Desktop), {userstartup} (Startup).
|
||||
Update-Progress "Removing shortcuts..." "Cleaning Start Menu, Desktop, and Startup" 40
|
||||
@(
|
||||
(Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$APP_NAME.lnk"),
|
||||
(Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\$APP_NAME.lnk"),
|
||||
(Join-Path $env:ProgramData "Microsoft\Windows\Start Menu\Programs\$APP_NAME"),
|
||||
(Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\$APP_NAME"),
|
||||
(Join-Path ([Environment]::GetFolderPath("CommonDesktopDirectory")) "$APP_NAME.lnk"),
|
||||
(Join-Path ([Environment]::GetFolderPath("Desktop")) "$APP_NAME.lnk"),
|
||||
(Join-Path $env:APPDATA "Microsoft\Windows\Start Menu\Programs\Startup\$APP_NAME.lnk")
|
||||
) | ForEach-Object { Safe-Remove $_ }
|
||||
|
||||
# Step 4: Remove Flutter application data stored in AppData.
|
||||
Update-Progress "Removing user data..." "Clearing configuration and cache" 60
|
||||
@(
|
||||
(Join-Path $env:APPDATA "com.krtirtho.spotube"),
|
||||
(Join-Path $env:LOCALAPPDATA "com.krtirtho.spotube"),
|
||||
(Join-Path $env:APPDATA "spotube"),
|
||||
(Join-Path $env:LOCALAPPDATA "spotube")
|
||||
) | ForEach-Object { Safe-Remove $_ }
|
||||
|
||||
# Step 5: Remove all Windows registry entries.
|
||||
# Targets the Inno Setup key ({AppId}_is1) and our custom Control Panel key.
|
||||
Update-Progress "Removing registry entries..." "Cleaning uninstall records" 80
|
||||
foreach ($root in @("HKLM:\SOFTWARE", "HKCU:\SOFTWARE", "HKLM:\SOFTWARE\WOW6432Node")) {
|
||||
foreach ($key in @($INNO_REG_KEY, $CUSTOM_REG_KEY)) {
|
||||
Safe-Remove "$root\Microsoft\Windows\CurrentVersion\Uninstall\$key"
|
||||
}
|
||||
}
|
||||
Safe-Remove "HKCU:\SOFTWARE\KRTirtho"
|
||||
Safe-Remove "HKCU:\SOFTWARE\Spotube"
|
||||
|
||||
Update-Progress "Complete" "Spotube has been removed." 100
|
||||
Start-Sleep -Milliseconds 500
|
||||
$ui.Form.Close()
|
||||
$ui.Form.Dispose()
|
||||
|
||||
# Show the final confirmation dialog with an OK button to dismiss.
|
||||
if (-not $Silent) {
|
||||
Show-MessageBox `
|
||||
-Message "Spotube has been successfully uninstalled.`n`nClick OK to close." `
|
||||
-Title "Uninstall Complete" `
|
||||
-Buttons ([System.Windows.Forms.MessageBoxButtons]::OK) `
|
||||
-Icon ([System.Windows.Forms.MessageBoxIcon]::Information)
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user