From b7e9cbe14f776d3e7db4ee190547890b59df3a96 Mon Sep 17 00:00:00 2001 From: amd64fox <62529699+amd64fox@users.noreply.github.com> Date: Fri, 16 May 2025 19:17:07 +0300 Subject: [PATCH] Added support for assemblies using snapshots #719 --- run.ps1 | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 161 insertions(+), 3 deletions(-) diff --git a/run.ps1 b/run.ps1 index 24121d3..48bf155 100644 --- a/run.ps1 +++ b/run.ps1 @@ -1613,6 +1613,92 @@ function injection { } +function Extract-WebpackModules { + param( + [Parameter(Mandatory = $true)] + [string]$InputFile + ) + + $scriptStart = Get-Date + Write-Debug "=== Script execution started ===" + Write-Debug "Input file: $InputFile" + + function Encode-UTF16LE { + param([byte[]]$Bytes) + $str = [System.Text.Encoding]::UTF8.GetString($Bytes) + [System.Text.Encoding]::Unicode.GetBytes($str) + } + + $StartMarker = [System.Text.Encoding]::UTF8.GetBytes("var __webpack_modules__={") + $EndMarker = [System.Text.Encoding]::UTF8.GetBytes("//# sourceMappingURL=xpui-modules.js.map") + + [byte[]]$fileContent = [System.IO.File]::ReadAllBytes($InputFile) + + $isUTF16LE = $false + if ($fileContent.Length -ge 2 -and $fileContent[0] -eq 0xFF -and $fileContent[1] -eq 0xFE) { + $isUTF16LE = $true + } + elseif ($fileContent.Length -gt 100 -and $fileContent[1] -eq 0x00) { + $isUTF16LE = $true + } + if (-not $isUTF16LE) { + Write-Error "File is not in UTF-16LE format: $InputFile" + exit 1 + } + + $searchStartMarker = Encode-UTF16LE -Bytes $StartMarker + $searchEndMarker = Encode-UTF16LE -Bytes $EndMarker + + function IndexOfBytes($haystack, $needle, [int]$startIndex = 0) { + if ($startIndex -lt 0) { $startIndex = 0 } + $haystackLength = $haystack.Length + $needleLength = $needle.Length + $searchLimit = $haystackLength - $needleLength + if ($searchLimit -lt $startIndex) { return -1 } + $firstNeedleByte = $needle[0] + for ($i = $startIndex; $i -le $searchLimit; $i++) { + if ($haystack[$i] -eq $firstNeedleByte) { + $found = $true + for ($j = 1; $j -lt $needleLength; $j++) { + if ($haystack[$i + $j] -ne $needle[$j]) { + $found = $false + break + } + } + if ($found) { return $i } + } + } + return -1 + } + + $startIdx = IndexOfBytes $fileContent $searchStartMarker 2 + if ($startIdx -eq -1) { + Write-Error "Start marker not found" + exit 1 + } + Write-Debug "Start marker found at index $startIdx" + + $endMarkerSearchOffset = $startIdx + $searchStartMarker.Length + $endIdx = IndexOfBytes $fileContent $searchEndMarker $endMarkerSearchOffset + if ($endIdx -eq -1) { + Write-Error "End marker not found after index $endMarkerSearchOffset" + exit 1 + } + Write-Debug "End marker found at absolute index $endIdx" + + $endDataIdx = $endIdx + $searchEndMarker.Length + $length = $endDataIdx - $startIdx + + Write-Debug "Decoding data from UTF-16LE..." + $decodedString = [System.Text.Encoding]::Unicode.GetString($fileContent, $startIdx, $length) + + $scriptEnd = Get-Date + $duration = [math]::Round(($scriptEnd - $scriptStart).TotalSeconds, 1) + Write-Debug "=== Execution completed in $duration seconds ===" + + return $decodedString +} + Write-Host ($lang).ModSpoti`n @@ -1663,13 +1749,85 @@ if (!($test_js) -and !($test_spa)) { Exit } -If ($test_spa) { +if ($test_spa) { + + Add-Type -Assembly 'System.IO.Compression.FileSystem' + + # Check for the presence of xpui.js in the xpui.spa archive + try { + $archive_spa = [System.IO.Compression.ZipFile]::OpenRead($xpui_spa_patch) + $xpuiJsEntry = $archive_spa.GetEntry('xpui.js') + $xpuiSnapshotEntry = $archive_spa.GetEntry('xpui-snapshot.js') + if (($null -eq $xpuiJsEntry) -and ($null -ne $xpuiSnapshotEntry)) { + + $snapshot_x64 = Join-Path $spotifyDirectory 'v8_context_snapshot.bin' + $snapshot_arm64 = Join-Path $spotifyDirectory 'v8_context_snapshot.arm64.bin' + + $v8_snapshot = switch ($true) { + { Test-Path $snapshot_x64 } { $snapshot_x64; break } + { Test-Path $snapshot_arm64 } { $snapshot_arm64; break } + default { $null } + } + if ($v8_snapshot) { + $modules = Extract-WebpackModules -InputFile $v8_snapshot + + function Update-ZipEntry { + param ( + [Parameter(Mandatory)] + $archive, + [Parameter(Mandatory)] + [string]$entryName, + [string]$newEntryName = $null, + [string]$prepend = $null, + [scriptblock]$contentTransform = $null + ) + $entry = $archive.GetEntry($entryName) + if ($entry) { + $tmpFile = [System.IO.Path]::GetTempFileName() + $reader = New-Object IO.StreamReader($entry.Open()) + $content = $reader.ReadToEnd() + $reader.Close() + $entry.Delete() + if ($prepend) { $content = "$prepend`n$content" } + if ($contentTransform) { $content = & $contentTransform $content } + [System.IO.File]::WriteAllText($tmpFile, $content) + [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($archive, $tmpFile, $(if ($newEntryName) { $newEntryName } else { $entryName })) | Out-Null + Remove-Item $tmpFile + } + } + + $firstLine = ($modules -split "`r?`n")[0] + + $archive_spa.Dispose() + $archive_spa = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, [System.IO.Compression.ZipArchiveMode]::Update) + + Update-ZipEntry -archive $archive_spa -entryName 'xpui-snapshot.js' -prepend $firstLine + Update-ZipEntry -archive $archive_spa -entryName 'xpui-snapshot.js' -newEntryName 'xpui.js' + Update-ZipEntry -archive $archive_spa -entryName 'xpui-snapshot.css' -newEntryName 'xpui.css' + Update-ZipEntry -archive $archive_spa -entryName 'index.html' -contentTransform { + param($c) + $c -replace 'xpui-snapshot.js', 'xpui.js' -replace 'xpui-snapshot.css', 'xpui.css' + } + } + else { + Write-Warning "v8_context_snapshot file not found" + } + + } + } + catch { + Write-Warning "Error: $($_.Exception.Message)" + } + finally { + if ($null -ne $archive_spa) { + $archive_spa.Dispose() + } + } $bak_spa = Join-Path (Join-Path $env:APPDATA 'Spotify\Apps') 'xpui.bak' $test_bak_spa = Test-Path -Path $bak_spa # Make a backup copy of xpui.spa if it is original - Add-Type -Assembly 'System.IO.Compression.FileSystem' $zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update') $entry = $zip.GetEntry('xpui.js') $reader = New-Object System.IO.StreamReader($entry.Open()) @@ -1771,7 +1929,7 @@ If ($test_spa) { if ([version]$offline -ge [version]"1.2.28.581" -and [version]$offline -le [version]"1.2.57.463") { - if ([version]$offline -ge [version]"1.2.45.454") { $typefile = "xpui.js"} + if ([version]$offline -ge [version]"1.2.45.454") { $typefile = "xpui.js" } else { $typefile = "xpui-routes-search.js" }