6 Commits

Author SHA1 Message Date
amd64fox
3bdfec03a8 Remove redacted host and user lines 2026-04-18 18:21:38 +03:00
amd64fox
2783cbe0c1 Move clipboard notice to end 2026-04-18 18:15:52 +03:00
amd64fox
f4279fb962 Add clipboard copy for diagnostics 2026-04-18 18:12:47 +03:00
amd64fox
ee5881572c Improve diagnostic output privacy 2026-04-18 18:05:50 +03:00
amd64fox
4f0706b010 Fix diagnostic launcher script path 2026-04-18 17:54:10 +03:00
amd64fox
4106903513 Add download diagnostics scripts 2026-04-18 17:50:05 +03:00
2 changed files with 410 additions and 0 deletions

22
scripts/DL_Diag.bat Normal file
View File

@@ -0,0 +1,22 @@
@echo off
setlocal
set "script_name=DL_Diag.ps1"
set "branch_name=dl-diag-scripts"
set "script_dir=%~dp0"
set "local_script=%script_dir%%script_name%"
set "branch_url=https://raw.githubusercontent.com/SpotX-Official/SpotX/refs/heads/%branch_name%/scripts/%script_name%"
set "main_url=https://raw.githubusercontent.com/SpotX-Official/SpotX/refs/heads/main/scripts/%script_name%"
set "temp_script=%TEMP%\SpotX-%script_name%"
set "ps=%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe"
if exist "%local_script%" (
%ps% -NoProfile -ExecutionPolicy Bypass -File "%local_script%"
) else (
%ps% -NoProfile -ExecutionPolicy Bypass ^
-Command "[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12; $out='%temp_script%'; $urls=@('%branch_url%','%main_url%'); $downloaded=$false; foreach ($url in $urls) { try { Invoke-WebRequest -UseBasicParsing -Uri $url -OutFile $out -ErrorAction Stop; $downloaded=$true; break } catch {} }; if (-not $downloaded) { throw 'Failed to download diagnostic script' }; & $out"
)
pause
endlocal
exit /b

388
scripts/DL_Diag.ps1 Normal file
View File

@@ -0,0 +1,388 @@
$rawScriptUrl = 'https://raw.githubusercontent.com/SpotX-Official/SpotX/refs/heads/main/run.ps1'
$mirrorScriptUrl = 'https://spotx-official.github.io/SpotX/run.ps1'
$downloadHost = 'loadspot.amd64fox1.workers.dev'
$defaultLatestFull = '1.2.86.502.g8cd7fb22'
$stableFull = '1.2.13.661.ga588f749'
$reportLines = New-Object 'System.Collections.Generic.List[string]'
$sensitivePatterns = New-Object 'System.Collections.Generic.List[object]'
function Add-SensitivePattern {
param(
[string]$Pattern,
[string]$Replacement = '[redacted]'
)
if (-not [string]::IsNullOrWhiteSpace($Pattern)) {
$script:sensitivePatterns.Add([PSCustomObject]@{
Pattern = $Pattern
Replacement = $Replacement
}) | Out-Null
}
}
function Protect-DiagnosticText {
param(
[AllowNull()]
[string]$Text
)
if ($null -eq $Text) {
return $null
}
$value = [string]$Text
foreach ($item in $script:sensitivePatterns) {
$value = [regex]::Replace($value, $item.Pattern, $item.Replacement)
}
$value
}
function Add-ReportLine {
param(
[AllowEmptyString()]
[string]$Line = ''
)
[void]$script:reportLines.Add((Protect-DiagnosticText -Text $Line))
}
function Add-ReportSection {
param(
[Parameter(Mandatory = $true)]
[string]$Title
)
if ($script:reportLines.Count -gt 0) {
Add-ReportLine
}
Add-ReportLine ("== {0} ==" -f $Title)
}
function Add-CommandOutput {
param(
[string[]]$Lines
)
foreach ($line in $Lines) {
Add-ReportLine ([string]$line)
}
}
function Invoke-WebRequestCompat {
param(
[Parameter(Mandatory = $true)]
[string]$Uri
)
$params = @{
Uri = $Uri
ErrorAction = 'Stop'
}
if ($PSVersionTable.PSVersion.Major -lt 6) {
$params.UseBasicParsing = $true
}
Invoke-WebRequest @params
}
function Invoke-WebClientStep {
param(
[Parameter(Mandatory = $true)]
[string]$Title,
[Parameter(Mandatory = $true)]
[string]$Uri
)
Invoke-PowerShellStep -Title $Title -Action {
$wc = New-Object System.Net.WebClient
$stream = $null
try {
$stream = $wc.OpenRead($Uri)
$buffer = New-Object byte[] 1
[void]$stream.Read($buffer, 0, 1)
$lines = New-Object 'System.Collections.Generic.List[string]'
$lines.Add('WEBCLIENT_OK') | Out-Null
$lines.Add(("Url: {0}" -f $Uri)) | Out-Null
if ($wc.ResponseHeaders) {
foreach ($headerName in $wc.ResponseHeaders.AllKeys) {
$lines.Add(("{0}: {1}" -f $headerName, $wc.ResponseHeaders[$headerName])) | Out-Null
}
}
$lines
}
finally {
if ($stream) {
$stream.Dispose()
}
$wc.Dispose()
}
}
}
function Copy-TextToClipboard {
param(
[Parameter(Mandatory = $true)]
[string]$Text
)
try {
if (Get-Command Set-Clipboard -ErrorAction SilentlyContinue) {
Set-Clipboard -Value $Text -ErrorAction Stop
return $true
}
if (Get-Command clip.exe -ErrorAction SilentlyContinue) {
$Text | clip.exe
return ($LASTEXITCODE -eq 0)
}
}
catch {
return $false
}
return $false
}
function Get-DiagnosticArchitecture {
$arch = $env:PROCESSOR_ARCHITEW6432
if ([string]::IsNullOrWhiteSpace($arch)) {
$arch = $env:PROCESSOR_ARCHITECTURE
}
switch -Regex ($arch) {
'ARM64' { return 'arm64' }
'64' { return 'x64' }
default { return 'x86' }
}
}
if (-not [string]::IsNullOrWhiteSpace($env:COMPUTERNAME)) {
Add-SensitivePattern -Pattern ([regex]::Escape($env:COMPUTERNAME)) -Replacement '[redacted-host]'
}
if (-not [string]::IsNullOrWhiteSpace($env:USERNAME)) {
Add-SensitivePattern -Pattern ([regex]::Escape($env:USERNAME)) -Replacement '[redacted-user]'
}
if (-not [string]::IsNullOrWhiteSpace($env:USERPROFILE)) {
Add-SensitivePattern -Pattern ([regex]::Escape($env:USERPROFILE)) -Replacement '[redacted-profile]'
}
Add-SensitivePattern -Pattern '(?<![\d.])(?:\d{1,3}\.){3}\d{1,3}(?![\d.])' -Replacement '[redacted-ipv4]'
Add-SensitivePattern -Pattern '(?i)(?<![0-9a-f:])((?:[0-9a-f]{1,4}:){7}[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,7}:|(?:[0-9a-f]{1,4}:){1,6}:[0-9a-f]{1,4}|(?:[0-9a-f]{1,4}:){1,5}(?::[0-9a-f]{1,4}){1,2}|(?:[0-9a-f]{1,4}:){1,4}(?::[0-9a-f]{1,4}){1,3}|(?:[0-9a-f]{1,4}:){1,3}(?::[0-9a-f]{1,4}){1,4}|(?:[0-9a-f]{1,4}:){1,2}(?::[0-9a-f]{1,4}){1,5}|[0-9a-f]{1,4}:(?:(?::[0-9a-f]{1,4}){1,6})|:(?:(?::[0-9a-f]{1,4}){1,7}|:))(?![0-9a-f:])' -Replacement '[redacted-ipv6]'
function Format-ExceptionDetails {
param(
[Parameter(Mandatory = $true)]
[System.Exception]$Exception
)
$details = New-Object 'System.Collections.Generic.List[string]'
$current = $Exception
while ($null -ne $current) {
[void]$details.Add($current.Message)
$current = $current.InnerException
}
$details
}
function Invoke-CurlStep {
param(
[Parameter(Mandatory = $true)]
[string]$Title,
[Parameter(Mandatory = $true)]
[string[]]$Arguments
)
Add-ReportSection -Title $Title
if (-not (Get-Command curl.exe -ErrorAction SilentlyContinue)) {
Add-ReportLine 'curl.exe not found'
return
}
try {
$output = & curl.exe '-sS' @Arguments 2>&1
Add-CommandOutput -Lines ($output | ForEach-Object { [string]$_ })
Add-ReportLine ("ExitCode: {0}" -f $LASTEXITCODE)
}
catch {
Add-CommandOutput -Lines (Format-ExceptionDetails -Exception $_.Exception)
}
}
function Invoke-PowerShellStep {
param(
[Parameter(Mandatory = $true)]
[string]$Title,
[Parameter(Mandatory = $true)]
[scriptblock]$Action
)
Add-ReportSection -Title $Title
try {
$result = & $Action
if ($null -eq $result) {
Add-ReportLine
return
}
if ($result -is [System.Array]) {
Add-CommandOutput -Lines ($result | ForEach-Object { [string]$_ })
return
}
Add-ReportLine ([string]$result)
}
catch {
Add-CommandOutput -Lines (Format-ExceptionDetails -Exception $_.Exception)
}
}
$architecture = Get-DiagnosticArchitecture
$latestFull = $defaultLatestFull
$bootstrapResults = New-Object 'System.Collections.Generic.List[object]'
foreach ($source in @(
[PSCustomObject]@{ Name = 'raw'; Url = $rawScriptUrl },
[PSCustomObject]@{ Name = 'mirror'; Url = $mirrorScriptUrl }
)) {
try {
$response = Invoke-WebRequestCompat -Uri $source.Url
$content = [string]$response.Content
if ($latestFull -eq $defaultLatestFull) {
$match = [regex]::Match($content, '\[string\]\$latest_full\s*=\s*"([^"]+)"')
if ($match.Success) {
$latestFull = $match.Groups[1].Value
}
}
$bootstrapResults.Add([PSCustomObject]@{
Name = $source.Name
Url = $source.Url
Success = $true
StatusCode = [int]$response.StatusCode
Length = $content.Length
}) | Out-Null
}
catch {
$bootstrapResults.Add([PSCustomObject]@{
Name = $source.Name
Url = $source.Url
Success = $false
StatusCode = $null
Length = $null
Error = $_.Exception.Message
}) | Out-Null
}
}
$tempUrl = if ($architecture -eq 'x64') {
'https://{0}/temporary-download/spotify_installer-{1}-x64.exe' -f $downloadHost, $latestFull
}
else {
$null
}
$directUrl = 'https://{0}/download/spotify_installer-{1}-{2}.exe' -f $downloadHost, $stableFull, $architecture
Add-ReportSection -Title 'Environment'
Add-ReportLine ("Date: {0}" -f (Get-Date).ToString('yyyy-MM-dd HH:mm:ss zzz'))
Add-ReportLine ("PowerShell: {0}" -f $PSVersionTable.PSVersion)
Add-ReportLine ("Architecture: {0}" -f $architecture)
Add-ReportLine ("LatestFull: {0}" -f $latestFull)
Add-ReportLine ("StableFull: {0}" -f $stableFull)
Add-ReportLine ("TempUrl: {0}" -f $(if ($tempUrl) { $tempUrl } else { 'skipped for non-x64 system' }))
Add-ReportLine ("DirectUrl: {0}" -f $directUrl)
Add-ReportSection -Title 'Bootstrap check'
foreach ($item in $bootstrapResults) {
Add-ReportLine ("Source: {0}" -f $item.Name)
Add-ReportLine ("Url: {0}" -f $item.Url)
Add-ReportLine ("Success: {0}" -f $item.Success)
if ($item.Success) {
Add-ReportLine ("StatusCode: {0}" -f $item.StatusCode)
Add-ReportLine ("ContentLength: {0}" -f $item.Length)
}
else {
Add-ReportLine ("Error: {0}" -f $item.Error)
}
Add-ReportLine
}
Invoke-CurlStep -Title 'curl version' -Arguments @('-V')
Invoke-PowerShellStep -Title 'DNS' -Action {
Resolve-DnsName $downloadHost | Format-Table -AutoSize | Out-String -Width 4096
}
if ($tempUrl) {
Invoke-CurlStep -Title 'HEAD temp' -Arguments @('-I', '-L', '-k', '--ssl-no-revoke', $tempUrl)
Invoke-CurlStep -Title '1MB temp' -Arguments @('-L', '-k', '--ssl-no-revoke', '--fail-with-body', '--connect-timeout', '15', '-r', '0-1048575', '-o', 'NUL', '-D', '-', '-w', "`nHTTP_STATUS:%{http_code}`n", $tempUrl)
}
else {
Add-ReportSection -Title 'HEAD temp'
Add-ReportLine 'Skipped because temporary route is only used for x64 latest build'
Add-ReportSection -Title '1MB temp'
Add-ReportLine 'Skipped because temporary route is only used for x64 latest build'
}
Invoke-CurlStep -Title 'HEAD direct stable' -Arguments @('-I', '-L', '-k', '--ssl-no-revoke', $directUrl)
Invoke-CurlStep -Title '1MB direct stable' -Arguments @('-L', '-k', '--ssl-no-revoke', '--fail-with-body', '--connect-timeout', '15', '-r', '0-1048575', '-o', 'NUL', '-D', '-', '-w', "`nHTTP_STATUS:%{http_code}`n", $directUrl)
if ($tempUrl) {
Invoke-WebClientStep -Title 'WebClient temp' -Uri $tempUrl
}
else {
Add-ReportSection -Title 'WebClient temp'
Add-ReportLine 'Skipped because temporary route is only used for x64 latest build'
}
Invoke-WebClientStep -Title 'WebClient direct stable' -Uri $directUrl
$finalOutputLines = New-Object 'System.Collections.Generic.List[string]'
$finalOutputLines.Add('----- BEGIN DIAGNOSTICS -----') | Out-Null
foreach ($line in $reportLines) {
$finalOutputLines.Add($line) | Out-Null
}
$finalOutputLines.Add('----- END DIAGNOSTICS -----') | Out-Null
$finalOutputText = [string]::Join([Environment]::NewLine, $finalOutputLines)
$clipboardCopied = Copy-TextToClipboard -Text $finalOutputText
Write-Host
Write-Host '----- BEGIN DIAGNOSTICS -----' -ForegroundColor Cyan
foreach ($line in $reportLines) {
Write-Output $line
}
Write-Host '----- END DIAGNOSTICS -----' -ForegroundColor Cyan
if ($clipboardCopied) {
Write-Host
Write-Host 'Diagnostics copied to clipboard' -ForegroundColor Green
}
else {
Write-Host
Write-Host 'Clipboard copy failed, copy the text above manually' -ForegroundColor Yellow
}