Private/Resolve-BotConfiguration.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Phase 4 of setup: the token, the server ID and the audio device - kept from the configuration that is already there, or asked for. .DESCRIPTION Every release that changes bot.py needs setup run again, and until 1.6.2 setup asked for all three values from scratch although phase 0 had just migrated them. Now, when the file holds all three, setup shows them and asks once whether to keep them; when it holds some, only the missing ones are asked for; when it holds none, the three questions are asked as before. A kept value is checked exactly like a typed one - the token against the Discord API, the device against what ffmpeg lists - and one that fails is asked for on its own. A token reset in the portal since the last setup is caught here rather than at the next Start-BATCRelayBot. The returned hashtable is keyed the way New-BotConfigFile expects: BotToken, GuildId, AudioDeviceName. The names mirror bot.py's config keys rather than the Discord UI wording; the old ServerId/ChannelId naming is what let the installer write server_id and channel_id for sixteen releases while bot.py read neither. #> function Resolve-BotConfiguration { <# .OUTPUTS Hashtable with BotToken, GuildId, AudioDeviceName - or $null when the user abandoned a prompt. #> [OutputType([hashtable])] param( [string]$ConfigPath, [string]$FFmpegPath, [switch]$SkipAudioDevice, [string]$LogPath ) $existing = Get-ExistingConfiguration -ConfigPath $ConfigPath $complete = $existing.BotToken -and $existing.GuildId -and ($SkipAudioDevice -or $existing.AudioDeviceName) # Complete and declined: nothing is kept, the three questions follow. # Complete and kept, or partial: what is there is a candidate, and each # candidate still has to pass the check a typed value would. if ($complete -and -not (Confirm-KeepConfiguration -Existing $existing -SkipAudioDevice:$SkipAudioDevice)) { $existing = @{ BotToken = $null; GuildId = $null; AudioDeviceName = $null } } $config = @{ BotToken = $null; GuildId = $null; AudioDeviceName = $null } # The heading a clean run has always had. A run that keeps something # already had its own heading from the keep question. if (-not $existing.BotToken -and -not $existing.GuildId) { Write-Host "Discord Configuration" -ForegroundColor White -BackgroundColor DarkBlue Write-Host "Two values from the Discord developer portal and your server." -ForegroundColor Gray Write-Host "" } if ($existing.BotToken) { Write-Host " Checking the stored token against the Discord API..." -ForegroundColor Gray $validation = Test-DiscordBotToken -Token $existing.BotToken if ($validation.Valid) { Write-Host " Token accepted. Bot: $($validation.BotName)" -ForegroundColor Green Write-InstallLog "Stored token validated for bot '$($validation.BotName)'" -LogPath $LogPath $config.BotToken = $existing.BotToken } else { Write-Host " The stored token was rejected: $($validation.Error)" -ForegroundColor Yellow Write-Host " It may have been reset in the developer portal. A new one is needed." -ForegroundColor Yellow Write-InstallLog "Stored token rejected: $($validation.Error)" -LogPath $LogPath -Level WARN } Write-Host "" } if (-not $config.BotToken) { $config.BotToken = Read-DiscordToken -LogPath $LogPath if (-not $config.BotToken) { return $null } } if ($existing.GuildId -and ([string]$existing.GuildId) -match '^\d{17,21}$') { $config.GuildId = [string]$existing.GuildId } else { $config.GuildId = Read-DiscordSnowflake ` -Label "Server ID (guild)" ` -Step "Step 2/2" ` -Hint "Discord: Settings > Advanced > Developer Mode, then right-click the server > Copy Server ID" ` -LogPath $LogPath if (-not $config.GuildId) { return $null } } if ($SkipAudioDevice) { $config.AudioDeviceName = "" Write-InstallLog "Audio device selection skipped by -SkipAudioDevice" -LogPath $LogPath -Level WARN return $config } if ($existing.AudioDeviceName) { $listed = @() if ($FFmpegPath) { $listed = @(Get-DshowAudioDevice -FFmpegPath $FFmpegPath) } if ($listed -contains $existing.AudioDeviceName) { $config.AudioDeviceName = $existing.AudioDeviceName Write-InstallLog "Stored audio device still listed by ffmpeg: $($existing.AudioDeviceName)" -LogPath $LogPath } else { Write-Host " The stored audio device is not in ffmpeg's list any more:" -ForegroundColor Yellow Write-Host " $($existing.AudioDeviceName)" -ForegroundColor Gray Write-Host " Is VoiceMeeter running? Pick again." -ForegroundColor Yellow Write-Host "" Write-InstallLog "Stored audio device no longer listed: $($existing.AudioDeviceName)" -LogPath $LogPath -Level WARN } } if (-not $config.AudioDeviceName) { $config.AudioDeviceName = Select-AudioDevice -FFmpegPath $FFmpegPath -LogPath $LogPath if (-not $config.AudioDeviceName) { return $null } } return $config } function Get-ExistingConfiguration { <# .SYNOPSIS The three asked-for values as config.json holds them after migration. Anything unreadable reads as absent; setup then asks, as it always did. #> [OutputType([hashtable])] param([string]$ConfigPath) $found = @{ BotToken = $null; GuildId = $null; AudioDeviceName = $null } if (-not $ConfigPath -or -not (Test-Path $ConfigPath)) { return $found } try { $raw = Get-Content $ConfigPath -Raw -Encoding UTF8 -ErrorAction Stop $json = $raw | ConvertFrom-Json -ErrorAction Stop } catch { return $found } foreach ($pair in @(@('BotToken', 'bot_token'), @('GuildId', 'guild_id'), @('AudioDeviceName', 'audio_device_name'))) { $value = $json.PSObject.Properties[$pair[1]].Value if ($null -ne $value -and -not [string]::IsNullOrWhiteSpace([string]$value)) { $found[$pair[0]] = [string]$value } } return $found } function Confirm-KeepConfiguration { <# .SYNOPSIS Shows the three stored values - token redacted, server ID masked - and asks once whether to keep them. Enter, y or yes keeps. #> [OutputType([bool])] param( [hashtable]$Existing, [switch]$SkipAudioDevice ) Write-Host "Existing configuration" -ForegroundColor White -BackgroundColor DarkBlue Write-Host "Setup found these values in config.json." -ForegroundColor Gray Write-Host "" Write-Host " Bot token [REDACTED]" -ForegroundColor Gray Write-Host " Server ID $(Format-Snowflake $Existing.GuildId)" -ForegroundColor Gray if (-not $SkipAudioDevice) { Write-Host " Audio device $($Existing.AudioDeviceName)" -ForegroundColor Gray } Write-Host "" $answer = Read-Host "Keep this configuration? [Y/n]" Write-Host "" return ([string]::IsNullOrWhiteSpace($answer) -or $answer.Trim() -match '^(y|yes)$') } Export-ModuleMember -Function @( 'Resolve-BotConfiguration', 'Get-ExistingConfiguration', 'Confirm-KeepConfiguration' ) |