Fix strict-mode installer state initialization (#859)

* fix: initialize version comparison flags

* fix: initialize installer state defaults

* docs: explain installer state defaults

* fix: initialize remaining runtime state

* initialize curl capability cache and local patch accumulator before they are read

* this fixes StrictMode failures in curl download detection and product_state patch assembly

---------

Co-authored-by: amd64fox <62529699+amd64fox@users.noreply.github.com>
This commit is contained in:
Mark Siazon
2026-05-26 23:08:00 +08:00
committed by GitHub
parent 0154f9b353
commit 49d6db9448
+183 -72
View File
@@ -340,6 +340,13 @@ $spotifyUninstall = Join-Path ([System.IO.Path]::GetTempPath()) 'SpotifyUninstal
$start_menu = Join-Path $env:APPDATA 'Microsoft\Windows\Start Menu\Programs\Spotify.lnk' $start_menu = Join-Path $env:APPDATA 'Microsoft\Windows\Start Menu\Programs\Spotify.lnk'
$upgrade_client = $false $upgrade_client = $false
$downgrading = $false
$ru = $false
$podcast_off = $false
$css = $null
$calltype = $null
$tempDirectory = $null
$script:curlSupportsFailWithBody = $null
# Check version Powershell # Check version Powershell
$psv = $PSVersionTable.PSVersion.major $psv = $PSVersionTable.PSVersion.major
@@ -370,6 +377,18 @@ function Stop-Script {
} }
Exit Exit
} }
function Stop-BrokenSpotifyFiles {
param(
[string]$Details
)
if ($Details) { Write-Warning $Details }
Write-Host ($lang).Error -ForegroundColor Red
Write-Host ($lang).FileLocBroken
Stop-Script
}
function Get-Link { function Get-Link {
param ( param (
[Alias("e")] [Alias("e")]
@@ -1581,6 +1600,8 @@ if ($spotifyInstalled) {
$arr1 = $online -split '\.' | foreach { [int]$_ } $arr1 = $online -split '\.' | foreach { [int]$_ }
$arr2 = $offline -split '\.' | foreach { [int]$_ } $arr2 = $offline -split '\.' | foreach { [int]$_ }
$oldversion = $false
$testversion = $false
# compare each element of the array in order from most significant to least significant. # compare each element of the array in order from most significant to least significant.
for ($i = 0; $i -lt $arr1.Length; $i++) { for ($i = 0; $i -lt $arr1.Length; $i++) {
@@ -1871,6 +1892,20 @@ function Helper($paramname) {
Remove-Json -j $to -p $propertyName Remove-Json -j $to -p $propertyName
} }
} }
function Get-JsonValue {
param (
[AllowNull()]
[object]$Object,
[Parameter(Mandatory = $true)]
[string]$Name
)
if ($null -eq $Object) { return $null }
$property = $Object.PSObject.Properties[$Name]
if ($null -eq $property) { return $null }
return $property.Value
}
switch ( $paramname ) { switch ( $paramname ) {
"HtmlLicMin" { "HtmlLicMin" {
@@ -2189,6 +2224,7 @@ function Helper($paramname) {
if (!($ru)) { Remove-Json -j $VarJs -p "offrujs" } if (!($ru)) { Remove-Json -j $VarJs -p "offrujs" }
$adds = $null
if (!($premium) -or ($cache_limit)) { if (!($premium) -or ($cache_limit)) {
if (!($premium)) { if (!($premium)) {
$adds += $webjson.VariousJs.product_state.add $adds += $webjson.VariousJs.product_state.add
@@ -2222,46 +2258,65 @@ function Helper($paramname) {
$contents | foreach { $contents | foreach {
if ($json.$PSItem.disable -eq $true) { $contentName = $PSItem
$contentPatch = Get-JsonValue -Object $json -Name $contentName
if ($null -eq $contentPatch) {
return return
} }
if ( $json.$PSItem.version.to ) { $to = [version]$json.$PSItem.version.to -ge [version]$offline_patch } else { $to = $true } if ((Get-JsonValue -Object $contentPatch -Name 'disable') -eq $true) {
if ( $json.$PSItem.version.fr ) { $fr = [version]$json.$PSItem.version.fr -le [version]$offline_patch } else { $fr = $false } return
}
$version = Get-JsonValue -Object $contentPatch -Name 'version'
$versionTo = Get-JsonValue -Object $version -Name 'to'
$versionFr = Get-JsonValue -Object $version -Name 'fr'
if ($versionTo) { $to = [version]$versionTo -ge [version]$offline_patch } else { $to = $true }
if ($versionFr) { $fr = [version]$versionFr -le [version]$offline_patch } else { $fr = $false }
$checkVer = $fr -and $to; $translate = $paramname -eq "RuTranslate" $checkVer = $fr -and $to; $translate = $paramname -eq "RuTranslate"
if ($checkVer -or $translate) { if ($checkVer -or $translate) {
if ($json.$PSItem.match.Count -gt 1) { $matchValue = Get-JsonValue -Object $contentPatch -Name 'match'
$replaceValue = Get-JsonValue -Object $contentPatch -Name 'replace'
if ($null -eq $matchValue -or $null -eq $replaceValue) {
return
}
$count = $json.$PSItem.match.Count - 1 $matchPatterns = @($matchValue)
$replacements = @($replaceValue)
if ($matchPatterns.Count -gt 1) {
$count = $matchPatterns.Count - 1
$numbers = 0 $numbers = 0
While ($numbers -le $count) { While ($numbers -le $count) {
if ($paramdata -match $json.$PSItem.match[$numbers]) { if ($paramdata -match $matchPatterns[$numbers]) {
$paramdata = $paramdata -replace $json.$PSItem.match[$numbers], $json.$PSItem.replace[$numbers] $paramdata = $paramdata -replace $matchPatterns[$numbers], $replacements[$numbers]
} }
else { else {
$notlog = "MinJs", "MinJson", "Cssmin" $notlog = "MinJs", "MinJson", "Cssmin"
if ($paramname -notin $notlog) { if ($paramname -notin $notlog) {
Write-Host $novariable -ForegroundColor red -NoNewline Write-Host $novariable -ForegroundColor red -NoNewline
Write-Host "$name$PSItem $numbers"'in'$n Write-Host "$name$contentName $numbers"'in'$n
} }
} }
$numbers++ $numbers++
} }
} }
if ($json.$PSItem.match.Count -eq 1) { if ($matchPatterns.Count -eq 1) {
if ($paramdata -match $json.$PSItem.match) { if ($paramdata -match $matchPatterns[0]) {
$paramdata = $paramdata -replace $json.$PSItem.match, $json.$PSItem.replace $paramdata = $paramdata -replace $matchPatterns[0], $replacements[0]
} }
else { else {
if (!($translate) -or $err_ru) { if (!($translate) -or $err_ru) {
Write-Host $novariable -ForegroundColor red -NoNewline Write-Host $novariable -ForegroundColor red -NoNewline
Write-Host "$name$PSItem"'in'$n Write-Host "$name$contentName"'in'$n
} }
} }
} }
@@ -2271,53 +2326,78 @@ function Helper($paramname) {
} }
function extract ($counts, $method, $name, $helper, $add, $patch) { function extract ($counts, $method, $name, $helper, $add, $patch) {
switch ( $counts ) { $zip = $null
"one" { $reader = $null
if ($method -eq "zip") { $writer = $null
try {
switch ( $counts ) {
"one" {
if ($method -eq "zip") {
Add-Type -Assembly 'System.IO.Compression.FileSystem'
$xpui_spa_patch = Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui.spa'
$zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update')
$file = $zip.GetEntry($name)
if ($null -eq $file) { throw "Archive entry not found: $name" }
$reader = New-Object System.IO.StreamReader($file.Open())
}
elseif ($method -eq "nonezip") {
$file = Get-Item (Join-Path (Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui') $name) -ErrorAction Stop
$reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $file
}
else {
throw "Unsupported extraction method: $method"
}
$xpui = $reader.ReadToEnd()
$reader.Dispose()
$reader = $null
if ($helper) { $xpui = Helper -paramname $helper }
if ($method -eq "zip") { $writer = New-Object System.IO.StreamWriter($file.Open()) }
if ($method -eq "nonezip") { $writer = New-Object System.IO.StreamWriter -ArgumentList $file }
$writer.BaseStream.SetLength(0)
$writer.Write($xpui)
if ($add) { $add | foreach { $writer.Write([System.Environment]::NewLine + $PSItem ) } }
$writer.Dispose()
$writer = $null
}
"more" {
Add-Type -Assembly 'System.IO.Compression.FileSystem' Add-Type -Assembly 'System.IO.Compression.FileSystem'
$xpui_spa_patch = Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui.spa' $xpui_spa_patch = Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui.spa'
$zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update') $zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update')
$file = $zip.GetEntry($name) $entries = @($zip.Entries | Where-Object { $_.FullName -like $name -and $_.FullName.Split('/') -notcontains 'spotx-helper' })
$reader = New-Object System.IO.StreamReader($file.Open())
foreach ($entry in $entries) {
$reader = New-Object System.IO.StreamReader($entry.Open())
$xpui = $reader.ReadToEnd()
$reader.Dispose()
$reader = $null
$xpui = Helper -paramname $helper
$writer = New-Object System.IO.StreamWriter($entry.Open())
$writer.BaseStream.SetLength(0)
$writer.Write($xpui)
$writer.Dispose()
$writer = $null
}
} }
if ($method -eq "nonezip") { "exe" {
$file = Get-Item (Join-Path (Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui') $name) $ANSI = [Text.Encoding]::GetEncoding(1251)
$reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $file $xpui = [IO.File]::ReadAllText($spotify_binary, $ANSI)
}
$xpui = $reader.ReadToEnd()
$reader.Close()
if ($helper) { $xpui = Helper -paramname $helper }
if ($method -eq "zip") { $writer = New-Object System.IO.StreamWriter($file.Open()) }
if ($method -eq "nonezip") { $writer = New-Object System.IO.StreamWriter -ArgumentList $file }
$writer.BaseStream.SetLength(0)
$writer.Write($xpui)
if ($add) { $add | foreach { $writer.Write([System.Environment]::NewLine + $PSItem ) } }
$writer.Close()
if ($method -eq "zip") { $zip.Dispose() }
}
"more" {
Add-Type -Assembly 'System.IO.Compression.FileSystem'
$xpui_spa_patch = Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui.spa'
$zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update')
$zip.Entries | Where-Object { $_.FullName -like $name -and $_.FullName.Split('/') -notcontains 'spotx-helper' } | foreach {
$reader = New-Object System.IO.StreamReader($_.Open())
$xpui = $reader.ReadToEnd()
$reader.Close()
$xpui = Helper -paramname $helper $xpui = Helper -paramname $helper
$writer = New-Object System.IO.StreamWriter($_.Open()) [IO.File]::WriteAllText($spotify_binary, $xpui, $ANSI)
$writer.BaseStream.SetLength(0)
$writer.Write($xpui)
$writer.Close()
} }
$zip.Dispose()
}
"exe" {
$ANSI = [Text.Encoding]::GetEncoding(1251)
$xpui = [IO.File]::ReadAllText($spotify_binary, $ANSI)
$xpui = Helper -paramname $helper
[IO.File]::WriteAllText($spotify_binary, $xpui, $ANSI)
} }
} }
catch {
Stop-BrokenSpotifyFiles -Details "Error: $($_.Exception.Message)"
}
finally {
if ($null -ne $reader) { $reader.Dispose() }
if ($null -ne $writer) { $writer.Dispose() }
if ($null -ne $zip) { $zip.Dispose() }
}
} }
function injection { function injection {
@@ -2341,9 +2421,11 @@ function injection {
$folderPathInArchive = "$($FolderInArchive)/" $folderPathInArchive = "$($FolderInArchive)/"
Add-Type -AssemblyName System.IO.Compression.FileSystem Add-Type -AssemblyName System.IO.Compression.FileSystem
$archive = [System.IO.Compression.ZipFile]::Open($ArchivePath, 'Update') $archive = $null
try { try {
$archive = [System.IO.Compression.ZipFile]::Open($ArchivePath, 'Update')
for ($i = 0; $i -lt $FileNames.Length; $i++) { for ($i = 0; $i -lt $FileNames.Length; $i++) {
$fileName = $FileNames[$i] $fileName = $FileNames[$i]
$fileContent = $FileContents[$i] $fileContent = $FileContents[$i]
@@ -2404,6 +2486,9 @@ function injection {
Write-Warning "index.html not found in xpui.spa" Write-Warning "index.html not found in xpui.spa"
} }
} }
catch {
Stop-BrokenSpotifyFiles -Details "Error: $($_.Exception.Message)"
}
finally { finally {
if ($archive -ne $null) { if ($archive -ne $null) {
$archive.Dispose() $archive.Dispose()
@@ -2891,6 +2976,9 @@ if ($test_spa) {
# Check for the presence of xpui.js in the xpui.spa archive # Check for the presence of xpui.js in the xpui.spa archive
$archive_spa = $null $archive_spa = $null
$xpuiJsEntry = $null
$v8_snapshot = $null
$archiveError = $null
try { try {
$archive_spa = [System.IO.Compression.ZipFile]::OpenRead($xpui_spa_patch) $archive_spa = [System.IO.Compression.ZipFile]::OpenRead($xpui_spa_patch)
@@ -2929,27 +3017,45 @@ if ($test_spa) {
} }
} }
catch { catch {
Write-Warning "Error: $($_.Exception.Message)" $archiveError = $_.Exception
} }
finally { finally {
if ($null -ne $archive_spa) { if ($null -ne $archive_spa) {
$archive_spa.Dispose() $archive_spa.Dispose()
} }
if (-not $v8_snapshot -and $null -eq $xpuiJsEntry) { }
Write-Warning "v8_context_snapshot file not found, cannot create xpui.js"
Stop-Script if ($archiveError) {
} Stop-BrokenSpotifyFiles -Details "Error: $($archiveError.Message)"
}
if (-not $v8_snapshot -and $null -eq $xpuiJsEntry) {
Write-Warning "v8_context_snapshot file not found, cannot create xpui.js"
Stop-Script
} }
$bak_spa = Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui.bak' $bak_spa = Join-Path (Join-Path $spotifyDirectory 'Apps') 'xpui.bak'
$test_bak_spa = Test-Path -Path $bak_spa $test_bak_spa = Test-Path -Path $bak_spa
# Make a backup copy of xpui.spa if it is original # Make a backup copy of xpui.spa if it is original
$zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update') $zip = $null
$entry = $zip.GetEntry('xpui.js') $reader = $null
$reader = New-Object System.IO.StreamReader($entry.Open())
$patched_by_spotx = $reader.ReadToEnd() try {
$reader.Close() $zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update')
$entry = $zip.GetEntry('xpui.js')
if ($null -eq $entry) { throw "Archive entry not found: xpui.js" }
$reader = New-Object System.IO.StreamReader($entry.Open())
$patched_by_spotx = $reader.ReadToEnd()
}
catch {
Stop-BrokenSpotifyFiles -Details "Error: $($_.Exception.Message)"
}
finally {
if ($null -ne $reader) { $reader.Dispose() }
if ($null -ne $zip) { $zip.Dispose() }
}
if ($offline -ge [version]'1.2.70.253') { if ($offline -ge [version]'1.2.70.253') {
@@ -2963,8 +3069,6 @@ if ($test_spa) {
} }
If ($patched_by_spotx -match 'patched by spotx') { If ($patched_by_spotx -match 'patched by spotx') {
$zip.Dispose()
if ($test_bak_spa) { if ($test_bak_spa) {
Remove-Item $xpui_spa_patch -Recurse -Force Remove-Item $xpui_spa_patch -Recurse -Force
Rename-Item $bak_spa $xpui_spa_patch Rename-Item $bak_spa $xpui_spa_patch
@@ -3006,7 +3110,6 @@ if ($test_spa) {
} }
} }
$zip.Dispose()
Copy-Item $xpui_spa_patch $bak_spa Copy-Item $xpui_spa_patch $bak_spa
if ($spotify_binary_bak -eq $dll_bak) { if ($spotify_binary_bak -eq $dll_bak) {
@@ -3018,15 +3121,23 @@ if ($test_spa) {
# Remove all languages except En and Ru from xpui.spa # Remove all languages except En and Ru from xpui.spa
if ($ru) { if ($ru) {
$null = [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression') $null = [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression')
$stream = New-Object IO.FileStream($xpui_spa_patch, [IO.FileMode]::Open) $stream = $null
$mode = [IO.Compression.ZipArchiveMode]::Update $zip_xpui = $null
$zip_xpui = New-Object IO.Compression.ZipArchive($stream, $mode)
($zip_xpui.Entries | Where-Object { $_.FullName -match "i18n" -and $_.FullName -inotmatch "(ru|en.json|longest)" }) | foreach { $_.Delete() } try {
$stream = New-Object IO.FileStream($xpui_spa_patch, [IO.FileMode]::Open)
$mode = [IO.Compression.ZipArchiveMode]::Update
$zip_xpui = New-Object IO.Compression.ZipArchive($stream, $mode)
$zip_xpui.Dispose() ($zip_xpui.Entries | Where-Object { $_.FullName -match "i18n" -and $_.FullName -inotmatch "(ru|en.json|longest)" }) | foreach { $_.Delete() }
$stream.Close() }
$stream.Dispose() catch {
Stop-BrokenSpotifyFiles -Details "Error: $($_.Exception.Message)"
}
finally {
if ($null -ne $zip_xpui) { $zip_xpui.Dispose() }
if ($null -ne $stream) { $stream.Dispose() }
}
} }
# Full screen mode activation and removing "Upgrade to premium" menu, upgrade button, disabling a playlist sponsor # Full screen mode activation and removing "Upgrade to premium" menu, upgrade button, disabling a playlist sponsor