diff --git a/.github/workflows/org.yml b/.github/workflows/org.yml index 9645f52e..8f130826 100644 --- a/.github/workflows/org.yml +++ b/.github/workflows/org.yml @@ -4,7 +4,7 @@ on: workflow_dispatch: push: paths: - - 'Install.ps1' + - 'run.ps1' jobs: copy_file: @@ -23,14 +23,14 @@ jobs: path: spotx-official.github.io token: ${{ secrets.ORGPAT }} - - name: Copy Install.ps1 file - run: cp Install.ps1 spotx-official.github.io/Install.ps1 + - name: Copy run.ps1 file + run: cp run.ps1 spotx-official.github.io/run.ps1 - name: Push changes run: | cd spotx-official.github.io git config user.name "GitHub Actions" git config user.email "actions@github.com" - git add Install.ps1 - git commit -m "Update Install.ps1" + git add run.ps1 + git commit -m "Update run.ps1" git push diff --git a/Install_New_theme.bat b/Install_New_theme.bat index ef3d4572..b547526a 100644 --- a/Install_New_theme.bat +++ b/Install_New_theme.bat @@ -1,6 +1,6 @@ @echo off -%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/SpotX/Install.ps1')} -new_theme """" | Invoke-Expression" +%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/run.ps1')} -new_theme """" | Invoke-Expression" pause exit /b \ No newline at end of file diff --git a/Install_Old_theme.bat b/Install_Old_theme.bat index 00a8b9f2..63922f3c 100644 --- a/Install_Old_theme.bat +++ b/Install_Old_theme.bat @@ -1,6 +1,6 @@ @echo off -%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/SpotX/Install.ps1')} -v 1.2.13.661.ga588f749-4064 -confirm_spoti_recomended_over -block_update_on """" | Invoke-Expression" +%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/run.ps1')} -v 1.2.13.661.ga588f749-4064 -confirm_spoti_recomended_over -block_update_on """" | Invoke-Expression" pause exit /b \ No newline at end of file diff --git a/README.md b/README.md index 5a505266..de2c2dea 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ or #### Run The following command in PowerShell: ```ps1 -[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/SpotX/Install.ps1') } -new_theme" +[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/run.ps1') } -new_theme" ``` @@ -72,7 +72,7 @@ or #### Run The following command in PowerShell: ```ps1 -[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/SpotX/Install.ps1') } -v 1.2.13.661.ga588f749-4064 -confirm_spoti_recomended_over -block_update_on" +[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/run.ps1') } -v 1.2.13.661.ga588f749-4064 -confirm_spoti_recomended_over -block_update_on" ``` @@ -101,7 +101,7 @@ or #### Run The following command in PowerShell: ```ps1 -[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/SpotX/Install.ps1') } -confirm_uninstall_ms_spoti -confirm_spoti_recomended_over -podcasts_off -block_update_on -start_spoti -new_theme -adsections_off -lyrics_stat spotify" +[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/run.ps1') } -confirm_uninstall_ms_spoti -confirm_spoti_recomended_over -podcasts_off -block_update_on -start_spoti -new_theme -adsections_off -lyrics_stat spotify" ``` @@ -127,7 +127,7 @@ or #### Run The following command in PowerShell: ```ps1 -[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/SpotX/Install.ps1') } -premium -new_theme" +[Net.ServicePointManager]::SecurityProtocol = 3072; iex "& { $(iwr -useb 'https://spotx-official.github.io/run.ps1') } -premium -new_theme" ``` diff --git a/Install.ps1 b/run.ps1 similarity index 97% rename from Install.ps1 rename to run.ps1 index cb21008e..d8352e30 100644 --- a/Install.ps1 +++ b/run.ps1 @@ -1,1593 +1,1593 @@ -param -( - - [Parameter(HelpMessage = "Change recommended version of Spotify.")] - [Alias("v")] - [string]$version, - - [Parameter(HelpMessage = 'Hiding podcasts/episodes/audiobooks from homepage.')] - [switch]$podcasts_off, - - [Parameter(HelpMessage = 'Hiding Ad-like sections from the homepage')] - [switch]$adsections_off, - - [Parameter(HelpMessage = 'Do not hiding podcasts/episodes/audiobooks from homepage.')] - [switch]$podcasts_on, - - [Parameter(HelpMessage = 'Block Spotify automatic updates.')] - [switch]$block_update_on, - - [Parameter(HelpMessage = 'Do not block Spotify automatic updates.')] - [switch]$block_update_off, - - [Parameter(HelpMessage = 'Change limit for clearing audio cache.')] - [Alias('cl')] - [int]$cache_limit, - - [Parameter(HelpMessage = 'Automatic uninstallation of Spotify MS if it was found.')] - [switch]$confirm_uninstall_ms_spoti, - - [Parameter(HelpMessage = 'Overwrite outdated or unsupported version of Spotify with the recommended version.')] - [switch]$confirm_spoti_recomended_over, - - [Parameter(HelpMessage = 'Uninstall outdated or unsupported version of Spotify and install the recommended version.')] - [switch]$confirm_spoti_recomended_unistall, - - [Parameter(HelpMessage = 'Installation without ad blocking for premium accounts.')] - [switch]$premium, - - [Parameter(HelpMessage = 'Automatic launch of Spotify after installation is complete.')] - [switch]$start_spoti, - - [Parameter(HelpMessage = 'Experimental features operated by Spotify.')] - [switch]$exp_spotify, - - [Parameter(HelpMessage = 'Do not hide the icon of collaborations in playlists.')] - [switch]$hide_col_icon_off, - - [Parameter(HelpMessage = 'disable new right sidebar.')] - [switch]$rightsidebar_off, - - [Parameter(HelpMessage = 'Do not enable enhance playlist.')] - [switch]$enhance_playlist_off, - - [Parameter(HelpMessage = 'Do not enable enhance liked songs.')] - [switch]$enhance_like_off, - - [Parameter(HelpMessage = 'Disable smart shuffle in playlists.')] - [switch]$smartShuffle_off, - - [Parameter(HelpMessage = 'enable funny progress bar.')] - [switch]$funnyprogressBar, - - [Parameter(HelpMessage = 'New theme activated (new right and left sidebar, some cover change)')] - [switch]$new_theme, - - [Parameter(HelpMessage = 'enable right sidebar coloring to match cover color)')] - [switch]$rightsidebarcolor, - - [Parameter(HelpMessage = 'Returns old lyrics')] - [switch]$old_lyrics, - - [Parameter(HelpMessage = 'Do not create desktop shortcut.')] - [switch]$no_shortcut, - - [Parameter(HelpMessage = 'Static color for lyrics.')] - [ArgumentCompleter({ param($cmd, $param, $wordToComplete) - [array] $validValues = @('default', 'red', 'orange', 'yellow', 'spotify', 'blue', 'purple', 'strawberry', 'pumpkin', 'sandbar', 'radium', 'oceano', 'royal', 'github', 'discord', 'drot', 'forest', 'fresh', 'zing', 'pinkle', 'krux', 'blueberry', 'postlight', 'relish', 'turquoise') - $validValues -like "*$wordToComplete*" - })] - [string]$lyrics_stat, - - [Parameter(HelpMessage = 'Accumulation of track listening history with Goofy.')] - [string]$urlform_goofy = $null, - - [Parameter(HelpMessage = 'Accumulation of track listening history with Goofy.')] - [string]$idbox_goofy = $null, - - [Parameter(HelpMessage = 'Error log ru string.')] - [switch]$err_ru, - - [Parameter(HelpMessage = 'Select the desired language to use for installation. Default is the detected system language.')] - [Alias('l')] - [string]$Language -) - -# Ignore errors from `Stop-Process` -$PSDefaultParameterValues['Stop-Process:ErrorAction'] = [System.Management.Automation.ActionPreference]::SilentlyContinue - -function Format-LanguageCode { - - # Normalizes and confirms support of the selected language. - [CmdletBinding()] - [OutputType([string])] - param - ( - [string]$LanguageCode - ) - - - $supportLanguages = @( - 'en', 'ru', 'it', 'tr', 'ka', 'pl', 'es', 'fr', 'hi', 'pt', 'id', 'vi', 'ro', 'de', 'hu', 'zh', 'zh-TW', 'ko', 'ua', 'fa', 'sr', 'lv', 'bn', 'el', 'fi', 'ja', 'fil' - ) - - - # Trim the language code down to two letter code. - switch -Regex ($LanguageCode) { - '^en' { - $returnCode = 'en' - break - } - '^(ru|py)' { - $returnCode = 'ru' - break - } - '^it' { - $returnCode = 'it' - break - } - '^tr' { - $returnCode = 'tr' - break - } - '^ka' { - $returnCode = 'ka' - break - } - '^pl' { - $returnCode = 'pl' - break - } - '^es' { - $returnCode = 'es' - break - } - '^fr' { - $returnCode = 'fr' - break - } - '^hi' { - $returnCode = 'hi' - break - } - '^pt' { - $returnCode = 'pt' - break - } - '^id' { - $returnCode = 'id' - break - } - '^vi' { - $returnCode = 'vi' - break - } - '^ro' { - $returnCode = 'ro' - break - } - '^de' { - $returnCode = 'de' - break - } - '^hu' { - $returnCode = 'hu' - break - } - '^(zh|zh-CN)$' { - $returnCode = 'zh' - break - } - '^zh-TW' { - $returnCode = 'zh-TW' - break - } - '^ko' { - $returnCode = 'ko' - break - } - '^ua' { - $returnCode = 'ua' - break - } - '^fa' { - $returnCode = 'fa' - break - } - '^sr' { - $returnCode = 'sr' - break - } - '^lv' { - $returnCode = 'lv' - break - } - '^bn' { - $returnCode = 'bn' - break - } - '^el' { - $returnCode = 'el' - break - } - '^fi$' { - $returnCode = 'fi' - break - } - '^ja' { - $returnCode = 'ja' - break - - } - '^fil' { - $returnCode = 'fil' - break - } - Default { - $returnCode = $PSUICulture - $long_code = $true - break - } - } - - # Checking the long language code - if ($long_code -and $returnCode -NotIn $supportLanguages) { - $returnCode = $returnCode -split "-" | Select-Object -First 1 - } - # Checking the short language code - if ($returnCode -NotIn $supportLanguages) { - # If the language code is not supported default to English. - $returnCode = 'en' - } - return $returnCode -} - -$spotifyDirectory = Join-Path $env:APPDATA 'Spotify' -$spotifyDirectory2 = Join-Path $env:LOCALAPPDATA 'Spotify' -$spotifyExecutable = Join-Path $spotifyDirectory 'Spotify.exe' -$exe_bak = Join-Path $spotifyDirectory 'Spotify.bak' -$spotifyUninstall = Join-Path $env:TEMP 'SpotifyUninstall.exe' -$start_menu = Join-Path $env:APPDATA 'Microsoft\Windows\Start Menu\Programs\Spotify.lnk' - -$upgrade_client = $false - -# Check version Powershell -$psv = $PSVersionTable.PSVersion.major -if ($psv -ge 7) { - Import-Module Appx -UseWindowsPowerShell -WarningAction:SilentlyContinue -} - -# add Tls12 -[Net.ServicePointManager]::SecurityProtocol = 3072 - - -function CallLang($clg) { - - $urlLang = "https://spotx-official.github.io/SpotX/scripts/installer-lang/$clg.ps1" - $ProgressPreference = 'SilentlyContinue' - - try { - $response = (iwr -Uri $urlLang -UseBasicParsing).Content - $scriptContent = [System.Text.Encoding]::UTF8.GetString($response) - Invoke-Expression $scriptContent - } - catch { - Write-Host "Error loading $clg language" - Pause - Exit - } -} - - -# Set language code for script. -$langCode = Format-LanguageCode -LanguageCode $Language - -$lang = CallLang -clg $langCode - -# Set variable 'ru'. -if ($langCode -eq 'ru') { - $ru = $true - $urlru = "https://spotx-official.github.io/SpotX/patches/Augmented%20translation/ru.json" - $webjsonru = (Invoke-WebRequest -useb -Uri $urlru).Content | ConvertFrom-Json -} - -Write-Host ($lang).Welcome -Write-Host - -# Check version Windows -$os = Get-CimInstance -ClassName "Win32_OperatingSystem" -ErrorAction SilentlyContinue -if ($os) { - $osCaption = $os.Caption -} -else { - $osCaption = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName -} -$pattern = "\bWindows (7|8(\.1)?|10|11|12)\b" -$reg = [regex]::Matches($osCaption, $pattern) -$win_os = $reg.Value - -$win12 = $win_os -match "\windows 12\b" -$win11 = $win_os -match "\windows 11\b" -$win10 = $win_os -match "\windows 10\b" -$win8_1 = $win_os -match "\windows 8.1\b" -$win8 = $win_os -match "\windows 8\b" -$win7 = $win_os -match "\windows 7\b" - -$match_v = "^\d+\.\d+\.\d+\.\d+\.g[0-9a-f]{8}-\d+$" -if ($version) { - if ($version -match $match_v) { - $onlineFull = $version - } - else { - Write-Warning "Invalid $($version) format. Example: 1.2.13.661.ga588f749-4064" - Write-Host - } -} - -$old_os = $win7 -or $win8 -or $win8_1 - -# Recommended version for Win 7-8.1 -$last_win7_full = "1.2.5.1006.g22820f93-1078" - -if (!($version -and $version -match $match_v)) { - if ($old_os) { - $onlineFull = $last_win7_full - } - else { - # Recommended version for Win 10-12 - $onlineFull = "1.2.21.1104.g42cf0a50-303" - } -} -else { - if ($old_os) { - $last_win7 = "1.2.5.1006" - if ([version]($onlineFull -split ".g")[0] -gt [version]$last_win7) { - - Write-Warning ("Version {0} is only supported on Windows 10 and above" -f ($onlineFull -split ".g")[0]) - Write-Warning ("The recommended version has been automatically changed to {0}, the latest supported version for Windows 7-8.1" -f $last_win7) - Write-Host - $onlineFull = $last_win7_full - } - } -} -$online = ($onlineFull -split ".g")[0] - -# Sending a statistical web query to cutt.ly -$ErrorActionPreference = 'SilentlyContinue' -$cutt_url = "https://cutt.ly/8wv60QTL" -$retries = 0 - -while ($retries -lt 2) { - try { - $null = Invoke-WebRequest -useb -Uri $cutt_url - break - } - catch { - $retries++ - Start-Sleep -Seconds 2 - } -} - -function incorrectValue { - - Write-Host ($lang).Incorrect"" -ForegroundColor Red -NoNewline - Write-Host ($lang).Incorrect2"" -NoNewline - Start-Sleep -Milliseconds 1000 - Write-Host "3" -NoNewline - Start-Sleep -Milliseconds 1000 - Write-Host " 2" -NoNewline - Start-Sleep -Milliseconds 1000 - Write-Host " 1" - Start-Sleep -Milliseconds 1000 - Clear-Host -} - -function Unlock-Folder { - $blockFileUpdate = Join-Path $env:LOCALAPPDATA 'Spotify\Update' - - if (Test-Path $blockFileUpdate -PathType Container) { - $folderUpdateAccess = Get-Acl $blockFileUpdate - $hasDenyAccessRule = $false - - foreach ($accessRule in $folderUpdateAccess.Access) { - if ($accessRule.AccessControlType -eq 'Deny') { - $hasDenyAccessRule = $true - $folderUpdateAccess.RemoveAccessRule($accessRule) - } - } - - if ($hasDenyAccessRule) { - Set-Acl $blockFileUpdate $folderUpdateAccess - } - } -} -function Mod-F { - param( - [string] $template, - [object[]] $arguments - ) - - $result = $template - for ($i = 0; $i -lt $arguments.Length; $i++) { - $placeholder = "{${i}}" - $value = $arguments[$i] - $result = $result -replace [regex]::Escape($placeholder), $value - } - - return $result -} - -function downloadSp() { - - $webClient = New-Object -TypeName System.Net.WebClient - - Import-Module BitsTransfer - - $web_Url = "https://download.scdn.co/upgrade/client/win32-x86/spotify_installer-$onlineFull.exe" - $local_Url = "$PWD\SpotifySetup.exe" - $web_name_file = "SpotifySetup.exe" - - try { if (curl.exe -V) { $curl_check = $true } } - catch { $curl_check = $false } - - try { - if ($curl_check) { - $stcode = curl.exe -s -w "%{http_code}" -o /dev/null $web_Url --retry 2 --ssl-no-revoke - if ($stcode -ne "200") { - Write-Host "Curl error code: $stcode"; throw - } - curl.exe -q $web_Url -o $local_Url --progress-bar --retry 3 --ssl-no-revoke - return - } - if (!($curl_check ) -and $null -ne (Get-Module -Name BitsTransfer -ListAvailable)) { - $ProgressPreference = 'Continue' - Start-BitsTransfer -Source $web_Url -Destination $local_Url -DisplayName ($lang).Download5 -Description "$online " - return - } - if (!($curl_check ) -and $null -eq (Get-Module -Name BitsTransfer -ListAvailable)) { - $webClient.DownloadFile($web_Url, $local_Url) - return - } - } - - catch { - Write-Host - Write-Host ($lang).Download $web_name_file -ForegroundColor RED - $Error[0].Exception - Write-Host - Write-Host ($lang).Download2`n - Start-Sleep -Milliseconds 5000 - try { - - if ($curl_check) { - $stcode = curl.exe -s -w "%{http_code}" -o /dev/null $web_Url --retry 2 --ssl-no-revoke - if ($stcode -ne "200") { - Write-Host "Curl error code: $stcode"; throw - } - curl.exe -q $web_Url -o $local_Url --progress-bar --retry 3 --ssl-no-revoke - return - } - if (!($curl_check ) -and $null -ne (Get-Module -Name BitsTransfer -ListAvailable) -and !($curl_check )) { - Start-BitsTransfer -Source $web_Url -Destination $local_Url -DisplayName ($lang).Download5 -Description "$online " - return - } - if (!($curl_check ) -and $null -eq (Get-Module -Name BitsTransfer -ListAvailable) -and !($curl_check )) { - $webClient.DownloadFile($web_Url, $local_Url) - return - } - } - - catch { - Write-Host ($lang).Download3 -ForegroundColor RED - $Error[0].Exception - Write-Host - Write-Host ($lang).Download4`n - ($lang).StopScript - $tempDirectory = $PWD - Pop-Location - Start-Sleep -Milliseconds 200 - Remove-Item -Recurse -LiteralPath $tempDirectory - Pause - Exit - } - } -} - -function DesktopFolder { - - # If the default Dekstop folder does not exist, then try to find it through the registry. - $ErrorActionPreference = 'SilentlyContinue' - if (Test-Path "$env:USERPROFILE\Desktop") { - $desktop_folder = "$env:USERPROFILE\Desktop" - } - - $regedit_desktop_folder = Get-ItemProperty -Path "Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\" - $regedit_desktop = $regedit_desktop_folder.'{754AC886-DF64-4CBA-86B5-F7FBF4FBCEF5}' - - if (!(Test-Path "$env:USERPROFILE\Desktop")) { - $desktop_folder = $regedit_desktop - } - return $desktop_folder -} - -taskkill /f /im Spotify.exe /t > $null 2>&1 - -# Remove Spotify Windows Store If Any -if ($win10 -or $win11 -or $win8_1 -or $win8 -or $win12) { - - if (Get-AppxPackage -Name SpotifyAB.SpotifyMusic) { - Write-Host ($lang).MsSpoti`n - - if (!($confirm_uninstall_ms_spoti)) { - do { - $ch = Read-Host -Prompt ($lang).MsSpoti2 - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { - incorrectValue - } - } - - while ($ch -notmatch '^y$|^n$') - } - if ($confirm_uninstall_ms_spoti) { $ch = 'y' } - if ($ch -eq 'y') { - $ProgressPreference = 'SilentlyContinue' # Hiding Progress Bars - if ($confirm_uninstall_ms_spoti) { Write-Host ($lang).MsSpoti3`n } - if (!($confirm_uninstall_ms_spoti)) { Write-Host ($lang).MsSpoti4`n } - Get-AppxPackage -Name SpotifyAB.SpotifyMusic | Remove-AppxPackage - } - if ($ch -eq 'n') { - Read-Host ($lang).StopScript - Pause - Exit - } - } -} - -# Attempt to fix the hosts file -$hostsFilePath = Join-Path $Env:windir 'System32\Drivers\Etc\hosts' -$hostsBackupFilePath = Join-Path $Env:windir 'System32\Drivers\Etc\hosts.bak' - -if (Test-Path -Path $hostsFilePath) { - $hosts = Get-Content -Path $hostsFilePath - - if ($hosts -match '^[^\#|].+scdn.+|^[^\#|].+spotify.+') { - Write-Host ($lang).HostInfo - Write-Host ($lang).HostBak - - Copy-Item -Path $hostsFilePath -Destination $hostsBackupFilePath -ErrorAction SilentlyContinue - - if ($?) { - Write-Host ($lang).HostDel - try { - $hosts = $hosts -replace '^[^\#|].+scdn.+|^[^\#|].+spotify.+', '' - $hosts = $hosts | Where-Object { $_.trim() -ne "" } - Set-Content -Path $hostsFilePath -Value $hosts -Force - } - catch { - Write-Host ($lang).HostError -ForegroundColor Red - $copyError = $Error[0] - Write-Host "Error: $($copyError.Exception.Message)" -ForegroundColor Red - } - } - else { - Write-Host ($lang).HostError`n -ForegroundColor Red - $copyError = $Error[0] - Write-Host "Error: $($copyError.Exception.Message)`n" -ForegroundColor Red - } - } -} - -# Unique directory name based on time -Push-Location -LiteralPath $env:TEMP -New-Item -Type Directory -Name "SpotX_Temp-$(Get-Date -UFormat '%Y-%m-%d_%H-%M-%S')" | Convert-Path | Set-Location - -if ($premium) { - Write-Host ($lang).Prem`n -} - -$spotifyInstalled = (Test-Path -LiteralPath $spotifyExecutable) - -if ($spotifyInstalled) { - - # Check version Spotify offline - $offline = (Get-Item $spotifyExecutable).VersionInfo.FileVersion - - # Version comparison - # converting strings to arrays of numbers using the -split operator and a foreach loop - - $arr1 = $online -split '\.' | foreach { [int]$_ } - $arr2 = $offline -split '\.' | foreach { [int]$_ } - - # compare each element of the array in order from most significant to least significant. - for ($i = 0; $i -lt $arr1.Length; $i++) { - if ($arr1[$i] -gt $arr2[$i]) { - $oldversion = $true - break - } - elseif ($arr1[$i] -lt $arr2[$i]) { - $testversion = $true - break - } - } - - # Old version Spotify - if ($oldversion) { - if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { - Write-Host ($lang).OldV`n - } - if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { - do { - Write-Host (($lang).OldV2 -f $offline, $online) - $ch = Read-Host -Prompt ($lang).OldV3 - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { - incorrectValue - } - } - while ($ch -notmatch '^y$|^n$') - } - if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { - $ch = 'y' - Write-Host ($lang).AutoUpd`n - } - if ($ch -eq 'y') { - $upgrade_client = $true - - if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { - do { - $ch = Read-Host -Prompt (($lang).DelOrOver -f $offline) - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { - incorrectValue - } - } - while ($ch -notmatch '^y$|^n$') - } - if ($confirm_spoti_recomended_unistall) { $ch = 'y' } - if ($confirm_spoti_recomended_over) { $ch = 'n' } - if ($ch -eq 'y') { - Write-Host ($lang).DelOld`n - $null = Unlock-Folder - cmd /c $spotifyExecutable /UNINSTALL /SILENT - wait-process -name SpotifyUninstall - Start-Sleep -Milliseconds 200 - if (Test-Path $spotifyDirectory) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory } - if (Test-Path $spotifyDirectory2) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory2 } - if (Test-Path $spotifyUninstall ) { Remove-Item -Recurse -Force -LiteralPath $spotifyUninstall } - } - if ($ch -eq 'n') { $ch = $null } - } - if ($ch -eq 'n') { - $downgrading = $true - } - } - - # Unsupported version Spotify - if ($testversion) { - # Submit unsupported version of Spotify to google form for further processing - try { - - # Country check - $country = [System.Globalization.RegionInfo]::CurrentRegion.EnglishName - - $txt = [IO.File]::ReadAllText($spotifyExecutable) - $regex = "(\d+)\.(\d+)\.(\d+)\.(\d+)(\.g[0-9a-f]{8})" - $v = $txt | Select-String $regex -AllMatches - $ver = $v.Matches.Value[0] - if ($ver.Count -gt 1) { $ver = $ver[0] } - - $Parameters = @{ - Uri = 'https://docs.google.com/forms/d/e/1FAIpQLSegGsAgilgQ8Y36uw-N7zFF6Lh40cXNfyl1ecHPpZcpD8kdHg/formResponse' - Method = 'POST' - Body = @{ - 'entry.620327948' = $ver - 'entry.1951747592' = $country - 'entry.1402903593' = $win_os - 'entry.860691305' = $psv - 'entry.2067427976' = $online + " < " + $offline - } - } - $null = Invoke-WebRequest -useb @Parameters - } - catch { - Write-Host 'Unable to submit new version of Spotify' - Write-Host "error description: "$Error[0] - } - - if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { - Write-Host ($lang).NewV`n - } - if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { - do { - Write-Host (($lang).NewV2 -f $offline, $online) - $ch = Read-Host -Prompt (($lang).NewV3 -f $offline) - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { - incorrectValue - } - } - while ($ch -notmatch '^y$|^n$') - } - if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { $ch = 'n' } - if ($ch -eq 'y') { $upgrade_client = $false } - if ($ch -eq 'n') { - if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { - do { - $ch = Read-Host -Prompt (($lang).Recom -f $online) - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { - incorrectValue - } - } - while ($ch -notmatch '^y$|^n$') - } - if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { - $ch = 'y' - Write-Host ($lang).AutoUpd`n - } - if ($ch -eq 'y') { - $upgrade_client = $true - $downgrading = $true - if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { - do { - $ch = Read-Host -Prompt (($lang).DelOrOver -f $offline) - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { - incorrectValue - } - } - while ($ch -notmatch '^y$|^n$') - } - if ($confirm_spoti_recomended_unistall) { $ch = 'y' } - if ($confirm_spoti_recomended_over) { $ch = 'n' } - if ($ch -eq 'y') { - Write-Host ($lang).DelNew`n - $null = Unlock-Folder - cmd /c $spotifyExecutable /UNINSTALL /SILENT - wait-process -name SpotifyUninstall - Start-Sleep -Milliseconds 200 - if (Test-Path $spotifyDirectory) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory } - if (Test-Path $spotifyDirectory2) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory2 } - if (Test-Path $spotifyUninstall ) { Remove-Item -Recurse -Force -LiteralPath $spotifyUninstall } - } - if ($ch -eq 'n') { $ch = $null } - } - - if ($ch -eq 'n') { - Write-Host ($lang).StopScript - $tempDirectory = $PWD - Pop-Location - Start-Sleep -Milliseconds 200 - Remove-Item -Recurse -LiteralPath $tempDirectory - Pause - Exit - } - } - } -} -# If there is no client or it is outdated, then install -if (-not $spotifyInstalled -or $upgrade_client) { - - Write-Host ($lang).DownSpoti"" -NoNewline - Write-Host $online -ForegroundColor Green - Write-Host ($lang).DownSpoti2`n - - # Delete old version files of Spotify before installing, leave only profile files - $ErrorActionPreference = 'SilentlyContinue' - taskkill /f /im Spotify.exe /t > $null 2>&1 - Start-Sleep -Milliseconds 600 - $null = Unlock-Folder - Start-Sleep -Milliseconds 200 - Get-ChildItem $spotifyDirectory -Exclude 'Users', 'prefs' | Remove-Item -Recurse -Force - Start-Sleep -Milliseconds 200 - - # Client download - downloadSp - Write-Host - - Start-Sleep -Milliseconds 200 - - # Client installation - Start-Process -FilePath explorer.exe -ArgumentList $PWD\SpotifySetup.exe - while (-not (get-process | Where-Object { $_.ProcessName -eq 'SpotifySetup' })) {} - wait-process -name SpotifySetup - taskkill /f /im Spotify.exe /t > $null 2>&1 - - - # Upgrade check version Spotify offline - $offline = (Get-Item $spotifyExecutable).VersionInfo.FileVersion - - # Upgrade check version Spotify.bak - $offline_bak = (Get-Item $exe_bak).VersionInfo.FileVersion -} - - - -# Delete Spotify shortcut if it is on desktop -if ($no_shortcut) { - $ErrorActionPreference = 'SilentlyContinue' - $desktop_folder = DesktopFolder - Start-Sleep -Milliseconds 1000 - remove-item "$desktop_folder\Spotify.lnk" -Recurse -Force -} - -$ch = $null - -if ($podcasts_off) { - Write-Host ($lang).PodcatsOff`n - $ch = 'y' -} -if ($podcasts_on) { - Write-Host ($lang).PodcastsOn`n - $ch = 'n' -} -if (!($podcasts_off) -and !($podcasts_on)) { - - do { - $ch = Read-Host -Prompt ($lang).PodcatsSelect - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { incorrectValue } - } - while ($ch -notmatch '^y$|^n$') -} -if ($ch -eq 'y') { $podcast_off = $true } - -$ch = $null - -if ($downgrading) { $upd = "`n" + [string]($lang).DowngradeNote } - -else { $upd = "" } - -if ($block_update_on) { - Write-Host ($lang).UpdBlock`n - $ch = 'y' -} -if ($block_update_off) { - Write-Host ($lang).UpdUnblock`n - $ch = 'n' -} -if (!($block_update_on) -and !($block_update_off)) { - do { - $text_upd = [string]($lang).UpdSelect + $upd - $ch = Read-Host -Prompt $text_upd - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { incorrectValue } - } - while ($ch -notmatch '^y$|^n$') -} -if ($ch -eq 'y') { $block_update = $true } - -if (!($new_theme) -and [version]$offline -ge [version]"1.2.14.1141") { - Write-Warning "This version does not support the old theme, use version 1.2.13.661 or below" - Write-Host -} - -if ($ch -eq 'n') { - $ErrorActionPreference = 'SilentlyContinue' - if ((Test-Path -LiteralPath $exe_bak) -and $offline -eq $offline_bak) { - Remove-Item $spotifyExecutable -Recurse -Force - Rename-Item $exe_bak $spotifyExecutable - } -} - -$ch = $null - -$url = "https://spotx-official.github.io/SpotX/patches/patches.json" -$retries = 0 - -while ($retries -lt 3) { - try { - $webjson = Invoke-WebRequest -UseBasicParsing -Uri $url | ConvertFrom-Json - break - } - catch { - Write-Warning "Request failed: $_" - $retries++ - Start-Sleep -Seconds 3 - } -} - -if ($retries -eq 3) { - - Write-Host "Failed to get patches.json" -ForegroundColor Red - Write-Host ($lang).StopScript - $tempDirectory = $PWD - Pop-Location - Start-Sleep -Milliseconds 200 - Remove-Item -Recurse -LiteralPath $tempDirectory - Pause - Exit -} -function Helper($paramname) { - - switch ( $paramname ) { - "HtmlLicMin" { - # licenses.html minification - $name = "patches.json.others." - $n = "licenses.html" - $contents = "htmlmin" - $json = $webjson.others - } - "HtmlBlank" { - # htmlBlank minification - $name = "patches.json.others." - $n = "blank.html" - $contents = "blank.html" - $json = $webjson.others - } - "MinJs" { - # Minification of all *.js - $contents = "minjs" - $json = $webjson.others - } - "MinJson" { - # Minification of all *.json - $contents = "minjson" - $json = $webjson.others - } - "FixCss" { - # Remove indent for old theme xpui.css - $name = "patches.json.others." - $n = "xpui.css" - $json = $webjson.others - } - "RemovertlCssmin" { - # Remove RTL and minification of all *.css - $contents = "removertl-cssmin" - $json = $webjson.others - } - "DisableSentry" { - # Disable Sentry (vendor~xpui.js) - $name = "patches.json.others." - $n = "vendor~xpui.js" - $contents = "disablesentry" - $json = $webjson.others - } - "Lyrics-color" { - $pasttext = $webjson.others.themelyrics.theme.$lyrics_stat.pasttext - $current = $webjson.others.themelyrics.theme.$lyrics_stat.current - $next = $webjson.others.themelyrics.theme.$lyrics_stat.next - $background = $webjson.others.themelyrics.theme.$lyrics_stat.background - $hover = $webjson.others.themelyrics.theme.$lyrics_stat.hover - $maxmatch = $webjson.others.themelyrics.theme.$lyrics_stat.maxmatch - - if ([version]$offline -lt [version]"1.1.99.871") { $lyrics = "lyricscolor1"; $contents = $lyrics } - if ([version]$offline -ge [version]"1.1.99.871") { $lyrics = "lyricscolor2"; $contents = $lyrics } - - # xpui.js or xpui-routes-lyrics.js - if ([version]$offline -ge [version]"1.1.99.871") { - - $full_previous = Mod-F -template $webjson.others.$lyrics.add[0] -arguments $pasttext - $full_current = Mod-F -template $webjson.others.$lyrics.add[1] -arguments $current - $full_next = Mod-F -template $webjson.others.$lyrics.add[2] -arguments $next - $full_lyrics = Mod-F -template $webjson.others.$lyrics.add[3] -arguments $full_previous, $full_current, $full_next - $webjson.others.$lyrics.add[3] = $full_lyrics - $webjson.others.$lyrics.replace[1] = '$1' + '"' + $pasttext + '"' - $webjson.others.$lyrics.replace[2] = '$1' + '"' + $current + '"' - $webjson.others.$lyrics.replace[3] = '$1' + '"' + $next + '"' - $webjson.others.$lyrics.replace[4] = '$1' + '"' + $background + '"' - $webjson.others.$lyrics.replace[5] = '$1' + '"' + $hover + '"' - $webjson.others.$lyrics.replace[6] = '$1' + '"' + $maxmatch + '"' - if ([version]$offline -ge [version]"1.2.6.861") { - $webjson.others.$lyrics.replace[7] = '$1' + '"' + $maxmatch + '"' + '$3' - } - else { - $webjson.others.$lyrics.match = $webjson.others.$lyrics.match | Where-Object { $_ -ne $webjson.others.$lyrics.match[7] } - } - if ([version]$offline -ge [version]"1.2.3.1107") { - $webjson.others.$lyrics.replace[8] = $webjson.others.$lyrics.replace[8] -f $background - } - } - - # xpui-routes-lyrics.css - if ([version]$offline -lt [version]"1.1.99.871") { - $webjson.others.$lyrics.replace[0] = '$1' + $pasttext - $webjson.others.$lyrics.replace[1] = '$1' + $current - $webjson.others.$lyrics.replace[2] = '$1' + $next - $webjson.others.$lyrics.replace[3] = $background - $webjson.others.$lyrics.replace[4] = '$1' + $hover - $webjson.others.$lyrics.replace[5] = '$1' + $maxmatch - } - $name = "patches.json.others." - $n = $name_file - $json = $webjson.others - } - "Discriptions" { - # Add discriptions (xpui-desktop-modals.js) - - $svg_tg = $webjson.others.discriptions.svgtg - $svg_git = $webjson.others.discriptions.svggit - $svg_faq = $webjson.others.discriptions.svgfaq - $replace = $webjson.others.discriptions.replace - - $replacedText = $replace -f $svg_git, $svg_tg, $svg_faq - - $webjson.others.discriptions.replace = '$1"' + $replacedText + '"})' - - $name = "patches.json.others." - $n = "xpui-desktop-modals.js" - $contents = "discriptions" - $json = $webjson.others - } - "OffadsonFullscreen" { - # Full screen mode activation and removing "Upgrade to premium" menu, upgrade button, disabling a playlist sponsor - $name = "patches.json.free." - $n = "xpui.js" - $contents = $webjson.free.psobject.properties.name - $json = $webjson.free - } - "ForcedExp" { - # Forced disable some exp (xpui.js) - $offline_patch = $offline -replace '(\d+\.\d+\.\d+)(.\d+)', '$1' - $remEnable = $webjson.others.EnableExp.psobject.properties - $remCustom = $webjson.others.CustomExp.psobject.properties - - if ($enhance_like_off) { $remEnable.remove('EnhanceLikedSongs') } - if ($enhance_playlist_off) { $remEnable.remove('EnhancePlaylist') } - # if ($smartShuffle_off) { $remEnable.remove('SmartShuffle') } - $remEnable.remove('SmartShuffle') - $remEnable.remove('RecentlyPlayedShortcut') - $remEnable.remove('EncoreCards') - if (!($funnyprogressBar)) { $remEnable.remove('HeBringsNpb') } - # Old theme - if (!($new_theme) -and [version]$offline -le [version]"1.2.13.661") { - $LeftSidebar = $webjson.others.EnableExp.LeftSidebar - $RightSidebar = $webjson.others.EnableExp.RightSidebar - $webjson.others.DisableExp | Add-Member -MemberType NoteProperty -Name "LeftSidebar" -Value $LeftSidebar - $webjson.others.DisableExp | Add-Member -MemberType NoteProperty -Name "RightSidebar" -Value $RightSidebar - - $remCustom.remove('NavAlt'), $remCustom.remove('NavAlt2'), $remEnable.remove('RightSidebarLyrics'), $remEnable.remove('RightSidebarCredits'), - $remEnable.remove('RightSidebar'), $remEnable.remove('LeftSidebar'), $remEnable.remove('RightSidebarColors'); - } - # New theme - else { - if ($rightsidebar_off) { - $RightSidebar = $webjson.others.EnableExp.RightSidebar - $webjson.others.DisableExp | Add-Member -MemberType NoteProperty -Name "RightSidebar" -Value $RightSidebar - } - else { - if (!($rightsidebarcolor)) { $remEnable.remove('RightSidebarColors') } - if ($old_lyrics) { $remEnable.remove('RightSidebarLyrics') } - } - } - if (!$premium) { $remEnable.remove('RemoteDownloads') } - - # Disable unimportant exp - if ($exp_spotify) { - $objects = @( - @{ - Object = $webjson.others.CustomExp.psobject.properties - PropertiesToKeep = @('LyricsUpsell') - }, - @{ - Object = $webjson.others.EnableExp.psobject.properties - PropertiesToKeep = @('CarouselsOnHome') - } - ) - - foreach ($obj in $objects) { - $propertiesToRemove = $obj.Object.Name | Where-Object { $_ -notin $obj.PropertiesToKeep } - $propertiesToRemove | foreach { - $obj.Object.Remove($_) - } - } - - } - - $Exp = ($webjson.others.EnableExp, $webjson.others.DisableExp, $webjson.others.CustomExp) - - foreach ($item in $Exp) { - $itemProperties = $item | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name - - foreach ($key in $itemProperties) { - $vers = $item.$key.version - - if (!($vers.to -eq "" -or [version]$vers.to -ge [version]$offline_patch -and [version]$vers.fr -le [version]$offline_patch)) { - if ($item.PSObject.Properties.Name -contains $key) { - $item.PSObject.Properties.Remove($key) - } - } - } - } - - $enableExp = $webjson.others.EnableExp - $disableExp = $webjson.others.DisableExp - $CustomExp = $webjson.others.CustomExp - - $enableNames = foreach ($item in $enableExp.PSObject.Properties.Name) { - $webjson.others.EnableExp.$item.name - } - - $disableNames = foreach ($item in $disableExp.PSObject.Properties.Name) { - $webjson.others.DisableExp.$item.name - } - - $customNames = foreach ($item in $CustomExp.PSObject.Properties.Name) { - $custname = $webjson.others.CustomExp.$item.name - $custvalue = $webjson.others.CustomExp.$item.value - - # Create a string with the desired format - $objectString = "{name:'$custname',value:'$custvalue'}" - $objectString - } - - # Convert the strings of objects into a single text string - if ([string]::IsNullOrEmpty($customNames)) { $customTextVariable = '[]' } - else { $customTextVariable = "[" + ($customNames -join ',') + "]" } - if ([string]::IsNullOrEmpty($enableNames)) { $enableTextVariable = '[]' } - else { $enableTextVariable = "['" + ($enableNames -join "','") + "']" } - if ([string]::IsNullOrEmpty($disableNames)) { $disableTextVariable = '[]' } - else { $disableTextVariable = "['" + ($disableNames -join "','") + "']" } - - $replacements = @( - @("EnableExp=[]", "EnableExp=$enableTextVariable"), - @("DisableExp=[]", "DisableExp=$disableTextVariable"), - @("CustomExp=[]", "CustomExp=$customTextVariable") - ) - - foreach ($replacement in $replacements) { - $webjson.others.ForcedExp.replace = $webjson.others.ForcedExp.replace.Replace($replacement[0], $replacement[1]) - } - - $name = "patches.json.others." - $n = "xpui.js" - $contents = "ForcedExp" - $json = $webjson.others - } - "OffPodcasts" { - # Turn off podcasts - if ([version]$offline -le [version]"1.1.92.647") { $contents = "podcastsoff" } - if ([version]$offline -ge [version]"1.1.93.896") { $contents = "podcastsoff2" } - $n = $js - $name = "patches.json.others." - $json = $webjson.others - } - "OffAdSections" { - # Hiding Ad-like sections from the homepage - $n = $js - $name = "patches.json.others." - $contents = "adsectionsoff" - $json = $webjson.others - } - "RuTranslate" { - # Additional translation of some words for the Russian language - $n = "ru.json" - $contents = $webjsonru.psobject.properties.name - $json = $webjsonru - } - "PodcastAd" { - # Aodcast ad block - $name = "patches.json.others." - $n = "Spotify.exe" - $contents = "podcast_ad_block" - $json = $webjson.others - } - "BannerHome" { - # Remove banner on home page - $name = "patches.json.others." - $n = "home-hpto.js" - $contents = "BannerHome" - $json = $webjson.others - } - "BlockUpdate" { - # Block Spotify client updates - $name = "patches.json.others." - $n = "Spotify.exe" - $contents = "block_update" - $json = $webjson.others - } - "Collaborators" { - # Hide Collaborators icon - $name = "patches.json.others." - $n = "xpui-routes-playlist.js" - $contents = "collaboration" - $json = $webjson.others - } - "VariousofXpui-js" { - - $rem = $webjson.VariousJs.psobject.properties - - if ($urlform_goofy -and $idbox_goofy) { - $webjson.VariousJs.goofyhistory.replace = "`$1 const urlForm=" + '"' + $urlform_goofy + '"' + ";const idBox=" + '"' + $idbox_goofy + '"' + $webjson.VariousJs.goofyhistory.replace - } - else { $rem.remove('goofyhistory') } - - if (!($ru)) { $rem.remove('offrujs') } - - if (!($premium) -or ($cache_limit)) { - if (!($premium)) { - $adds += $webjson.VariousJs.product_state.add - } - - if ($cache_limit) { - - if ($cache_limit -lt 500) { $cache_limit = 500 } - if ($cache_limit -gt 20000) { $cache_limit = 20000 } - - $adds2 = $webjson.VariousJs.product_state.add2 - if (!([string]::IsNullOrEmpty($adds))) { $adds2 = ',' + $adds2 } - $adds += $adds2 -f $cache_limit - - } - $repl = $webjson.VariousJs.product_state.replace - $webjson.VariousJs.product_state.replace = $repl -f "{pairs:{$adds}}" - } - else { $rem.remove('product_state') } - - $name = "patches.json.VariousJs." - $n = "xpui.js" - $contents = $webjson.VariousJs.psobject.properties.name - $json = $webjson.VariousJs - } - } - $paramdata = $xpui - $novariable = "Didn't find variable " - $offline_patch = $offline -replace '(\d+\.\d+\.\d+)(.\d+)', '$1' - - $contents | foreach { - - if ( $json.$PSItem.version.to ) { $to = [version]$json.$PSItem.version.to -ge [version]$offline_patch } else { $to = $true } - if ( $json.$PSItem.version.fr ) { $fr = [version]$json.$PSItem.version.fr -le [version]$offline_patch } else { $fr = $false } - - $checkVer = $fr -and $to; $translate = $paramname -eq "RuTranslate" - - if ($checkVer -or $translate) { - - if ($json.$PSItem.match.Count -gt 1) { - - $count = $json.$PSItem.match.Count - 1 - $numbers = 0 - - While ($numbers -le $count) { - - if ($paramdata -match $json.$PSItem.match[$numbers]) { - $paramdata = $paramdata -replace $json.$PSItem.match[$numbers], $json.$PSItem.replace[$numbers] - } - else { - $notlog = "MinJs", "MinJson", "Removertl", "RemovertlCssmin" - if ($paramname -notin $notlog) { - - Write-Host $novariable -ForegroundColor red -NoNewline - Write-Host "$name$PSItem $numbers"'in'$n - } - } - $numbers++ - } - } - if ($json.$PSItem.match.Count -eq 1) { - if ($paramdata -match $json.$PSItem.match) { - $paramdata = $paramdata -replace $json.$PSItem.match, $json.$PSItem.replace - } - else { - if (!($translate) -or $err_ru) { - Write-Host $novariable -ForegroundColor red -NoNewline - Write-Host "$name$PSItem"'in'$n - } - } - } - } - } - $paramdata -} - -function extract ($counts, $method, $name, $helper, $add, $patch) { - switch ( $counts ) { - "one" { - if ($method -eq "zip") { - Add-Type -Assembly 'System.IO.Compression.FileSystem' - $xpui_spa_patch = Join-Path (Join-Path $env:APPDATA 'Spotify\Apps') 'xpui.spa' - $zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update') - $file = $zip.GetEntry($name) - $reader = New-Object System.IO.StreamReader($file.Open()) - } - if ($method -eq "nonezip") { - $file = get-item $env:APPDATA\Spotify\Apps\xpui\$name - $reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $file - } - $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 $env:APPDATA 'Spotify\Apps') 'xpui.spa' - $zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update') - $zip.Entries | Where-Object FullName -like $name | foreach { - $reader = New-Object System.IO.StreamReader($_.Open()) - $xpui = $reader.ReadToEnd() - $reader.Close() - $xpui = Helper -paramname $helper - $writer = New-Object System.IO.StreamWriter($_.Open()) - $writer.BaseStream.SetLength(0) - $writer.Write($xpui) - $writer.Close() - } - $zip.Dispose() - } - "exe" { - $ANSI = [Text.Encoding]::GetEncoding(1251) - $xpui = [IO.File]::ReadAllText($spotifyExecutable, $ANSI) - $xpui = Helper -paramname $helper - [IO.File]::WriteAllText($spotifyExecutable, $xpui, $ANSI) - } - } -} - -Write-Host ($lang).ModSpoti`n - -$tempDirectory = $PWD -Pop-Location - -Start-Sleep -Milliseconds 200 -Remove-Item -Recurse -LiteralPath $tempDirectory - -$xpui_spa_patch = Join-Path (Join-Path $env:APPDATA 'Spotify\Apps') 'xpui.spa' -$xpui_js_patch = Join-Path (Join-Path (Join-Path $env:APPDATA 'Spotify\Apps') 'xpui') 'xpui.js' -$test_spa = Test-Path -Path $xpui_spa_patch -$test_js = Test-Path -Path $xpui_js_patch -$spotify_exe_bak_patch = Join-Path $env:APPDATA 'Spotify\Spotify.bak' - - -if ($test_spa -and $test_js) { - Write-Host ($lang).Error -ForegroundColor Red - Write-Host ($lang).FileLocBroken - Write-Host ($lang).StopScript - pause - Exit -} - -if ($test_js) { - - do { - $ch = Read-Host -Prompt ($lang).Spicetify - Write-Host - if (!($ch -eq 'n' -or $ch -eq 'y')) { incorrectValue } - } - while ($ch -notmatch '^y$|^n$') - - if ($ch -eq 'y') { - $Url = "https://telegra.ph/SpotX-FAQ-09-19#Can-I-use-SpotX-and-Spicetify-together?" - Start-Process $Url - } - - Write-Host ($lang).StopScript - Pause - Exit -} - -if (!($test_js) -and !($test_spa)) { - Write-Host "xpui.spa not found, reinstall Spotify" - Write-Host ($lang).StopScript - Pause - Exit -} - -If ($test_spa) { - - $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()) - $patched_by_spotx = $reader.ReadToEnd() - $reader.Close() - - If ($patched_by_spotx -match 'patched by spotx') { - $zip.Dispose() - - if ($test_bak_spa) { - Remove-Item $xpui_spa_patch -Recurse -Force - Rename-Item $bak_spa $xpui_spa_patch - - $spotify_exe_bak_patch = Join-Path $env:APPDATA 'Spotify\Spotify.bak' - $test_spotify_exe_bak = Test-Path -Path $spotify_exe_bak_patch - if ($test_spotify_exe_bak) { - Remove-Item $spotifyExecutable -Recurse -Force - Rename-Item $spotify_exe_bak_patch $spotifyExecutable - } - } - else { - Write-Host ($lang).NoRestore`n - Pause - Exit - } - $spotify_exe_bak_patch = Join-Path $env:APPDATA 'Spotify\Spotify.bak' - $test_spotify_exe_bak = Test-Path -Path $spotify_exe_bak_patch - if ($test_spotify_exe_bak) { - Remove-Item $spotifyExecutable -Recurse -Force - Rename-Item $spotify_exe_bak_patch $spotifyExecutable - } - } - $zip.Dispose() - Copy-Item $xpui_spa_patch $env:APPDATA\Spotify\Apps\xpui.bak - - # Remove all languages except En and Ru from xpui.spa - if ($ru) { - $null = [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression') - $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.Entries | Where-Object { $_.FullName -match "i18n" -and $_.FullName -inotmatch "(ru|en.json|longest)" }) | foreach { $_.Delete() } - - $zip_xpui.Dispose() - $stream.Close() - $stream.Dispose() - } - - # Full screen mode activation and removing "Upgrade to premium" menu, upgrade button, disabling a playlist sponsor - if (!($premium)) { - extract -counts 'one' -method 'zip' -name 'xpui.js' -helper 'OffadsonFullscreen' - } - - # Forced disable some exp - extract -counts 'one' -method 'zip' -name 'xpui.js' -helper 'ForcedExp' -add $webjson.others.byspotx.add - - # Experimental Feature - extract -counts 'one' -method 'zip' -name 'xpui.js' -helper 'VariousofXpui-js' - - # Turn off podcasts - if ($podcast_off) { - if ([version]$offline -ge [version]"1.1.93.896" -and [version]$offline -le [version]"1.1.97.962") { $js = 'home-v2.js' } - if ([version]$offline -le [version]"1.1.92.647" -or [version]$offline -ge [version]"1.1.98.683") { $js = 'xpui.js' } - extract -counts 'one' -method 'zip' -name $js -helper 'OffPodcasts' - } - - # Hiding Ad-like sections from the homepage - if ($adsections_off) { - if ([version]$offline -ge [version]"1.1.93.896" -and [version]$offline -le [version]"1.1.97.962") { $js = 'home-v2.js' } - if ([version]$offline -ge [version]"1.1.98.683") { $js = 'xpui.js' } - extract -counts 'one' -method 'zip' -name $js -helper 'OffAdSections' - } - - # Remove banner on home page - extract -counts 'one' -method 'zip' -name 'home-hpto.js' -helper 'BannerHome' - - # Hide Collaborators icon - if (!($hide_col_icon_off) -and !($exp_spotify)) { - extract -counts 'one' -method 'zip' -name 'xpui-routes-playlist.js' -helper 'Collaborators' - } - - - # Static color for lyrics - if ($lyrics_stat) { - # old - if ([version]$offline -lt [version]"1.1.99.871") { - $name_file = 'xpui-routes-lyrics.css' - extract -counts 'one' -method 'zip' -name $name_file -helper 'Lyrics-color' - } - # new - if ([version]$offline -ge [version]"1.1.99.871") { - $contents = "fixcsslyricscolor2" - extract -counts 'one' -method 'zip' -name 'xpui.css' -helper 'FixCss' - if ([version]$offline -le [version]"1.2.2.582") { - $name_file = 'xpui-routes-lyrics.js' - extract -counts 'one' -method 'zip' -name $name_file -helper 'Lyrics-color' - } - } - # mini lyrics - if ([version]$offline -ge [version]"1.2.0.1155") { - $name_file = 'xpui.js' - extract -counts 'one' -method 'zip' -name $name_file -helper 'Lyrics-color' - } - } - - # Add discriptions (xpui-desktop-modals.js) - extract -counts 'one' -method 'zip' -name 'xpui-desktop-modals.js' -helper 'Discriptions' - - # Disable Sentry (vendor~xpui.js) - extract -counts 'one' -method 'zip' -name 'vendor~xpui.js' -helper 'DisableSentry' - - # Minification of all *.js - extract -counts 'more' -name '*.js' -helper 'MinJs' - - # xpui.css - if (!($premium)) { - # Hide download icon on different pages - $css += $webjson.others.downloadicon.add - # Hide submenu item "download" - $css += $webjson.others.submenudownload.add - # Hide very high quality streaming - $css += $webjson.others.veryhighstream.add - } - # Full screen lyrics - if ($lyrics_stat -and [version]$offline -ge [version]"1.2.3.1107") { - $css += $webjson.others.lyricscolor2.add[3] - } - if ($null -ne $css ) { extract -counts 'one' -method 'zip' -name 'xpui.css' -add $css } - - - # Old UI fix - $contents = "fix-old-theme" - extract -counts 'one' -method 'zip' -name 'xpui.css' -helper "FixCss" - - # Remove RTL and minification of all *.css - extract -counts 'more' -name '*.css' -helper 'RemovertlCssmin' - - # licenses.html minification - - extract -counts 'one' -method 'zip' -name 'licenses.html' -helper 'HtmlLicMin' - # blank.html minification - extract -counts 'one' -method 'zip' -name 'blank.html' -helper 'HtmlBlank' - - if ($ru) { - # Additional translation of the ru.json file - extract -counts 'more' -name '*ru.json' -helper 'RuTranslate' - } - # Minification of all *.json - extract -counts 'more' -name '*.json' -helper 'MinJson' -} - -# Delete all files except "en" and "ru" -if ($ru) { - $patch_lang = "$spotifyDirectory\locales" - Remove-Item $patch_lang -Exclude *en*, *ru* -Recurse -} - -# Create a desktop shortcut -$ErrorActionPreference = 'SilentlyContinue' - -if (!($no_shortcut)) { - - $desktop_folder = DesktopFolder - - If (!(Test-Path $desktop_folder\Spotify.lnk)) { - $source = Join-Path $env:APPDATA 'Spotify\Spotify.exe' - $target = "$desktop_folder\Spotify.lnk" - $WorkingDir = "$env:APPDATA\Spotify" - $WshShell = New-Object -comObject WScript.Shell - $Shortcut = $WshShell.CreateShortcut($target) - $Shortcut.WorkingDirectory = $WorkingDir - $Shortcut.TargetPath = $source - $Shortcut.Save() - } -} - -# Create shortcut in start menu -If (!(Test-Path $start_menu)) { - $source = Join-Path $env:APPDATA 'Spotify\Spotify.exe' - $target = $start_menu - $WorkingDir = "$env:APPDATA\Spotify" - $WshShell = New-Object -comObject WScript.Shell - $Shortcut = $WshShell.CreateShortcut($target) - $Shortcut.WorkingDirectory = $WorkingDir - $Shortcut.TargetPath = $source - $Shortcut.Save() -} - -$ANSI = [Text.Encoding]::GetEncoding(1251) -$old = [IO.File]::ReadAllText($spotifyExecutable, $ANSI) - -$rexex1 = $old -notmatch $webjson.others.block_update.add -$rexex2 = $old -notmatch $webjson.others.podcast_ad_block.add - -if ($rexex1 -and $rexex2 ) { - - if (Test-Path -LiteralPath $exe_bak) { - Remove-Item $exe_bak -Recurse -Force - Start-Sleep -Milliseconds 150 - } - copy-Item $spotifyExecutable $exe_bak -} - -# Podcast ad block -extract -counts 'exe' -helper 'PodcastAd' - -# Block updates -if ($block_update) { extract -counts 'exe' -helper 'BlockUpdate' } - -# Start Spotify -if ($start_spoti) { Start-Process -WorkingDirectory $spotifyDirectory -FilePath $spotifyExecutable } - -Write-Host ($lang).InstallComplete`n -ForegroundColor Green +param +( + + [Parameter(HelpMessage = "Change recommended version of Spotify.")] + [Alias("v")] + [string]$version, + + [Parameter(HelpMessage = 'Hiding podcasts/episodes/audiobooks from homepage.')] + [switch]$podcasts_off, + + [Parameter(HelpMessage = 'Hiding Ad-like sections from the homepage')] + [switch]$adsections_off, + + [Parameter(HelpMessage = 'Do not hiding podcasts/episodes/audiobooks from homepage.')] + [switch]$podcasts_on, + + [Parameter(HelpMessage = 'Block Spotify automatic updates.')] + [switch]$block_update_on, + + [Parameter(HelpMessage = 'Do not block Spotify automatic updates.')] + [switch]$block_update_off, + + [Parameter(HelpMessage = 'Change limit for clearing audio cache.')] + [Alias('cl')] + [int]$cache_limit, + + [Parameter(HelpMessage = 'Automatic uninstallation of Spotify MS if it was found.')] + [switch]$confirm_uninstall_ms_spoti, + + [Parameter(HelpMessage = 'Overwrite outdated or unsupported version of Spotify with the recommended version.')] + [switch]$confirm_spoti_recomended_over, + + [Parameter(HelpMessage = 'Uninstall outdated or unsupported version of Spotify and install the recommended version.')] + [switch]$confirm_spoti_recomended_unistall, + + [Parameter(HelpMessage = 'Installation without ad blocking for premium accounts.')] + [switch]$premium, + + [Parameter(HelpMessage = 'Automatic launch of Spotify after installation is complete.')] + [switch]$start_spoti, + + [Parameter(HelpMessage = 'Experimental features operated by Spotify.')] + [switch]$exp_spotify, + + [Parameter(HelpMessage = 'Do not hide the icon of collaborations in playlists.')] + [switch]$hide_col_icon_off, + + [Parameter(HelpMessage = 'disable new right sidebar.')] + [switch]$rightsidebar_off, + + [Parameter(HelpMessage = 'Do not enable enhance playlist.')] + [switch]$enhance_playlist_off, + + [Parameter(HelpMessage = 'Do not enable enhance liked songs.')] + [switch]$enhance_like_off, + + [Parameter(HelpMessage = 'Disable smart shuffle in playlists.')] + [switch]$smartShuffle_off, + + [Parameter(HelpMessage = 'enable funny progress bar.')] + [switch]$funnyprogressBar, + + [Parameter(HelpMessage = 'New theme activated (new right and left sidebar, some cover change)')] + [switch]$new_theme, + + [Parameter(HelpMessage = 'enable right sidebar coloring to match cover color)')] + [switch]$rightsidebarcolor, + + [Parameter(HelpMessage = 'Returns old lyrics')] + [switch]$old_lyrics, + + [Parameter(HelpMessage = 'Do not create desktop shortcut.')] + [switch]$no_shortcut, + + [Parameter(HelpMessage = 'Static color for lyrics.')] + [ArgumentCompleter({ param($cmd, $param, $wordToComplete) + [array] $validValues = @('default', 'red', 'orange', 'yellow', 'spotify', 'blue', 'purple', 'strawberry', 'pumpkin', 'sandbar', 'radium', 'oceano', 'royal', 'github', 'discord', 'drot', 'forest', 'fresh', 'zing', 'pinkle', 'krux', 'blueberry', 'postlight', 'relish', 'turquoise') + $validValues -like "*$wordToComplete*" + })] + [string]$lyrics_stat, + + [Parameter(HelpMessage = 'Accumulation of track listening history with Goofy.')] + [string]$urlform_goofy = $null, + + [Parameter(HelpMessage = 'Accumulation of track listening history with Goofy.')] + [string]$idbox_goofy = $null, + + [Parameter(HelpMessage = 'Error log ru string.')] + [switch]$err_ru, + + [Parameter(HelpMessage = 'Select the desired language to use for installation. Default is the detected system language.')] + [Alias('l')] + [string]$Language +) + +# Ignore errors from `Stop-Process` +$PSDefaultParameterValues['Stop-Process:ErrorAction'] = [System.Management.Automation.ActionPreference]::SilentlyContinue + +function Format-LanguageCode { + + # Normalizes and confirms support of the selected language. + [CmdletBinding()] + [OutputType([string])] + param + ( + [string]$LanguageCode + ) + + + $supportLanguages = @( + 'en', 'ru', 'it', 'tr', 'ka', 'pl', 'es', 'fr', 'hi', 'pt', 'id', 'vi', 'ro', 'de', 'hu', 'zh', 'zh-TW', 'ko', 'ua', 'fa', 'sr', 'lv', 'bn', 'el', 'fi', 'ja', 'fil' + ) + + + # Trim the language code down to two letter code. + switch -Regex ($LanguageCode) { + '^en' { + $returnCode = 'en' + break + } + '^(ru|py)' { + $returnCode = 'ru' + break + } + '^it' { + $returnCode = 'it' + break + } + '^tr' { + $returnCode = 'tr' + break + } + '^ka' { + $returnCode = 'ka' + break + } + '^pl' { + $returnCode = 'pl' + break + } + '^es' { + $returnCode = 'es' + break + } + '^fr' { + $returnCode = 'fr' + break + } + '^hi' { + $returnCode = 'hi' + break + } + '^pt' { + $returnCode = 'pt' + break + } + '^id' { + $returnCode = 'id' + break + } + '^vi' { + $returnCode = 'vi' + break + } + '^ro' { + $returnCode = 'ro' + break + } + '^de' { + $returnCode = 'de' + break + } + '^hu' { + $returnCode = 'hu' + break + } + '^(zh|zh-CN)$' { + $returnCode = 'zh' + break + } + '^zh-TW' { + $returnCode = 'zh-TW' + break + } + '^ko' { + $returnCode = 'ko' + break + } + '^ua' { + $returnCode = 'ua' + break + } + '^fa' { + $returnCode = 'fa' + break + } + '^sr' { + $returnCode = 'sr' + break + } + '^lv' { + $returnCode = 'lv' + break + } + '^bn' { + $returnCode = 'bn' + break + } + '^el' { + $returnCode = 'el' + break + } + '^fi$' { + $returnCode = 'fi' + break + } + '^ja' { + $returnCode = 'ja' + break + + } + '^fil' { + $returnCode = 'fil' + break + } + Default { + $returnCode = $PSUICulture + $long_code = $true + break + } + } + + # Checking the long language code + if ($long_code -and $returnCode -NotIn $supportLanguages) { + $returnCode = $returnCode -split "-" | Select-Object -First 1 + } + # Checking the short language code + if ($returnCode -NotIn $supportLanguages) { + # If the language code is not supported default to English. + $returnCode = 'en' + } + return $returnCode +} + +$spotifyDirectory = Join-Path $env:APPDATA 'Spotify' +$spotifyDirectory2 = Join-Path $env:LOCALAPPDATA 'Spotify' +$spotifyExecutable = Join-Path $spotifyDirectory 'Spotify.exe' +$exe_bak = Join-Path $spotifyDirectory 'Spotify.bak' +$spotifyUninstall = Join-Path $env:TEMP 'SpotifyUninstall.exe' +$start_menu = Join-Path $env:APPDATA 'Microsoft\Windows\Start Menu\Programs\Spotify.lnk' + +$upgrade_client = $false + +# Check version Powershell +$psv = $PSVersionTable.PSVersion.major +if ($psv -ge 7) { + Import-Module Appx -UseWindowsPowerShell -WarningAction:SilentlyContinue +} + +# add Tls12 +[Net.ServicePointManager]::SecurityProtocol = 3072 + + +function CallLang($clg) { + + $urlLang = "https://spotx-official.github.io/SpotX/scripts/installer-lang/$clg.ps1" + $ProgressPreference = 'SilentlyContinue' + + try { + $response = (iwr -Uri $urlLang -UseBasicParsing).Content + $scriptContent = [System.Text.Encoding]::UTF8.GetString($response) + Invoke-Expression $scriptContent + } + catch { + Write-Host "Error loading $clg language" + Pause + Exit + } +} + + +# Set language code for script. +$langCode = Format-LanguageCode -LanguageCode $Language + +$lang = CallLang -clg $langCode + +# Set variable 'ru'. +if ($langCode -eq 'ru') { + $ru = $true + $urlru = "https://spotx-official.github.io/SpotX/patches/Augmented%20translation/ru.json" + $webjsonru = (Invoke-WebRequest -useb -Uri $urlru).Content | ConvertFrom-Json +} + +Write-Host ($lang).Welcome +Write-Host + +# Check version Windows +$os = Get-CimInstance -ClassName "Win32_OperatingSystem" -ErrorAction SilentlyContinue +if ($os) { + $osCaption = $os.Caption +} +else { + $osCaption = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName).ProductName +} +$pattern = "\bWindows (7|8(\.1)?|10|11|12)\b" +$reg = [regex]::Matches($osCaption, $pattern) +$win_os = $reg.Value + +$win12 = $win_os -match "\windows 12\b" +$win11 = $win_os -match "\windows 11\b" +$win10 = $win_os -match "\windows 10\b" +$win8_1 = $win_os -match "\windows 8.1\b" +$win8 = $win_os -match "\windows 8\b" +$win7 = $win_os -match "\windows 7\b" + +$match_v = "^\d+\.\d+\.\d+\.\d+\.g[0-9a-f]{8}-\d+$" +if ($version) { + if ($version -match $match_v) { + $onlineFull = $version + } + else { + Write-Warning "Invalid $($version) format. Example: 1.2.13.661.ga588f749-4064" + Write-Host + } +} + +$old_os = $win7 -or $win8 -or $win8_1 + +# Recommended version for Win 7-8.1 +$last_win7_full = "1.2.5.1006.g22820f93-1078" + +if (!($version -and $version -match $match_v)) { + if ($old_os) { + $onlineFull = $last_win7_full + } + else { + # Recommended version for Win 10-12 + $onlineFull = "1.2.21.1104.g42cf0a50-303" + } +} +else { + if ($old_os) { + $last_win7 = "1.2.5.1006" + if ([version]($onlineFull -split ".g")[0] -gt [version]$last_win7) { + + Write-Warning ("Version {0} is only supported on Windows 10 and above" -f ($onlineFull -split ".g")[0]) + Write-Warning ("The recommended version has been automatically changed to {0}, the latest supported version for Windows 7-8.1" -f $last_win7) + Write-Host + $onlineFull = $last_win7_full + } + } +} +$online = ($onlineFull -split ".g")[0] + +# Sending a statistical web query to cutt.ly +$ErrorActionPreference = 'SilentlyContinue' +$cutt_url = "https://cutt.ly/8wv60QTL" +$retries = 0 + +while ($retries -lt 2) { + try { + $null = Invoke-WebRequest -useb -Uri $cutt_url + break + } + catch { + $retries++ + Start-Sleep -Seconds 2 + } +} + +function incorrectValue { + + Write-Host ($lang).Incorrect"" -ForegroundColor Red -NoNewline + Write-Host ($lang).Incorrect2"" -NoNewline + Start-Sleep -Milliseconds 1000 + Write-Host "3" -NoNewline + Start-Sleep -Milliseconds 1000 + Write-Host " 2" -NoNewline + Start-Sleep -Milliseconds 1000 + Write-Host " 1" + Start-Sleep -Milliseconds 1000 + Clear-Host +} + +function Unlock-Folder { + $blockFileUpdate = Join-Path $env:LOCALAPPDATA 'Spotify\Update' + + if (Test-Path $blockFileUpdate -PathType Container) { + $folderUpdateAccess = Get-Acl $blockFileUpdate + $hasDenyAccessRule = $false + + foreach ($accessRule in $folderUpdateAccess.Access) { + if ($accessRule.AccessControlType -eq 'Deny') { + $hasDenyAccessRule = $true + $folderUpdateAccess.RemoveAccessRule($accessRule) + } + } + + if ($hasDenyAccessRule) { + Set-Acl $blockFileUpdate $folderUpdateAccess + } + } +} +function Mod-F { + param( + [string] $template, + [object[]] $arguments + ) + + $result = $template + for ($i = 0; $i -lt $arguments.Length; $i++) { + $placeholder = "{${i}}" + $value = $arguments[$i] + $result = $result -replace [regex]::Escape($placeholder), $value + } + + return $result +} + +function downloadSp() { + + $webClient = New-Object -TypeName System.Net.WebClient + + Import-Module BitsTransfer + + $web_Url = "https://download.scdn.co/upgrade/client/win32-x86/spotify_installer-$onlineFull.exe" + $local_Url = "$PWD\SpotifySetup.exe" + $web_name_file = "SpotifySetup.exe" + + try { if (curl.exe -V) { $curl_check = $true } } + catch { $curl_check = $false } + + try { + if ($curl_check) { + $stcode = curl.exe -s -w "%{http_code}" -o /dev/null $web_Url --retry 2 --ssl-no-revoke + if ($stcode -ne "200") { + Write-Host "Curl error code: $stcode"; throw + } + curl.exe -q $web_Url -o $local_Url --progress-bar --retry 3 --ssl-no-revoke + return + } + if (!($curl_check ) -and $null -ne (Get-Module -Name BitsTransfer -ListAvailable)) { + $ProgressPreference = 'Continue' + Start-BitsTransfer -Source $web_Url -Destination $local_Url -DisplayName ($lang).Download5 -Description "$online " + return + } + if (!($curl_check ) -and $null -eq (Get-Module -Name BitsTransfer -ListAvailable)) { + $webClient.DownloadFile($web_Url, $local_Url) + return + } + } + + catch { + Write-Host + Write-Host ($lang).Download $web_name_file -ForegroundColor RED + $Error[0].Exception + Write-Host + Write-Host ($lang).Download2`n + Start-Sleep -Milliseconds 5000 + try { + + if ($curl_check) { + $stcode = curl.exe -s -w "%{http_code}" -o /dev/null $web_Url --retry 2 --ssl-no-revoke + if ($stcode -ne "200") { + Write-Host "Curl error code: $stcode"; throw + } + curl.exe -q $web_Url -o $local_Url --progress-bar --retry 3 --ssl-no-revoke + return + } + if (!($curl_check ) -and $null -ne (Get-Module -Name BitsTransfer -ListAvailable) -and !($curl_check )) { + Start-BitsTransfer -Source $web_Url -Destination $local_Url -DisplayName ($lang).Download5 -Description "$online " + return + } + if (!($curl_check ) -and $null -eq (Get-Module -Name BitsTransfer -ListAvailable) -and !($curl_check )) { + $webClient.DownloadFile($web_Url, $local_Url) + return + } + } + + catch { + Write-Host ($lang).Download3 -ForegroundColor RED + $Error[0].Exception + Write-Host + Write-Host ($lang).Download4`n + ($lang).StopScript + $tempDirectory = $PWD + Pop-Location + Start-Sleep -Milliseconds 200 + Remove-Item -Recurse -LiteralPath $tempDirectory + Pause + Exit + } + } +} + +function DesktopFolder { + + # If the default Dekstop folder does not exist, then try to find it through the registry. + $ErrorActionPreference = 'SilentlyContinue' + if (Test-Path "$env:USERPROFILE\Desktop") { + $desktop_folder = "$env:USERPROFILE\Desktop" + } + + $regedit_desktop_folder = Get-ItemProperty -Path "Registry::HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\" + $regedit_desktop = $regedit_desktop_folder.'{754AC886-DF64-4CBA-86B5-F7FBF4FBCEF5}' + + if (!(Test-Path "$env:USERPROFILE\Desktop")) { + $desktop_folder = $regedit_desktop + } + return $desktop_folder +} + +taskkill /f /im Spotify.exe /t > $null 2>&1 + +# Remove Spotify Windows Store If Any +if ($win10 -or $win11 -or $win8_1 -or $win8 -or $win12) { + + if (Get-AppxPackage -Name SpotifyAB.SpotifyMusic) { + Write-Host ($lang).MsSpoti`n + + if (!($confirm_uninstall_ms_spoti)) { + do { + $ch = Read-Host -Prompt ($lang).MsSpoti2 + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { + incorrectValue + } + } + + while ($ch -notmatch '^y$|^n$') + } + if ($confirm_uninstall_ms_spoti) { $ch = 'y' } + if ($ch -eq 'y') { + $ProgressPreference = 'SilentlyContinue' # Hiding Progress Bars + if ($confirm_uninstall_ms_spoti) { Write-Host ($lang).MsSpoti3`n } + if (!($confirm_uninstall_ms_spoti)) { Write-Host ($lang).MsSpoti4`n } + Get-AppxPackage -Name SpotifyAB.SpotifyMusic | Remove-AppxPackage + } + if ($ch -eq 'n') { + Read-Host ($lang).StopScript + Pause + Exit + } + } +} + +# Attempt to fix the hosts file +$hostsFilePath = Join-Path $Env:windir 'System32\Drivers\Etc\hosts' +$hostsBackupFilePath = Join-Path $Env:windir 'System32\Drivers\Etc\hosts.bak' + +if (Test-Path -Path $hostsFilePath) { + $hosts = Get-Content -Path $hostsFilePath + + if ($hosts -match '^[^\#|].+scdn.+|^[^\#|].+spotify.+') { + Write-Host ($lang).HostInfo + Write-Host ($lang).HostBak + + Copy-Item -Path $hostsFilePath -Destination $hostsBackupFilePath -ErrorAction SilentlyContinue + + if ($?) { + Write-Host ($lang).HostDel + try { + $hosts = $hosts -replace '^[^\#|].+scdn.+|^[^\#|].+spotify.+', '' + $hosts = $hosts | Where-Object { $_.trim() -ne "" } + Set-Content -Path $hostsFilePath -Value $hosts -Force + } + catch { + Write-Host ($lang).HostError -ForegroundColor Red + $copyError = $Error[0] + Write-Host "Error: $($copyError.Exception.Message)" -ForegroundColor Red + } + } + else { + Write-Host ($lang).HostError`n -ForegroundColor Red + $copyError = $Error[0] + Write-Host "Error: $($copyError.Exception.Message)`n" -ForegroundColor Red + } + } +} + +# Unique directory name based on time +Push-Location -LiteralPath $env:TEMP +New-Item -Type Directory -Name "SpotX_Temp-$(Get-Date -UFormat '%Y-%m-%d_%H-%M-%S')" | Convert-Path | Set-Location + +if ($premium) { + Write-Host ($lang).Prem`n +} + +$spotifyInstalled = (Test-Path -LiteralPath $spotifyExecutable) + +if ($spotifyInstalled) { + + # Check version Spotify offline + $offline = (Get-Item $spotifyExecutable).VersionInfo.FileVersion + + # Version comparison + # converting strings to arrays of numbers using the -split operator and a foreach loop + + $arr1 = $online -split '\.' | foreach { [int]$_ } + $arr2 = $offline -split '\.' | foreach { [int]$_ } + + # compare each element of the array in order from most significant to least significant. + for ($i = 0; $i -lt $arr1.Length; $i++) { + if ($arr1[$i] -gt $arr2[$i]) { + $oldversion = $true + break + } + elseif ($arr1[$i] -lt $arr2[$i]) { + $testversion = $true + break + } + } + + # Old version Spotify + if ($oldversion) { + if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { + Write-Host ($lang).OldV`n + } + if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { + do { + Write-Host (($lang).OldV2 -f $offline, $online) + $ch = Read-Host -Prompt ($lang).OldV3 + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { + incorrectValue + } + } + while ($ch -notmatch '^y$|^n$') + } + if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { + $ch = 'y' + Write-Host ($lang).AutoUpd`n + } + if ($ch -eq 'y') { + $upgrade_client = $true + + if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { + do { + $ch = Read-Host -Prompt (($lang).DelOrOver -f $offline) + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { + incorrectValue + } + } + while ($ch -notmatch '^y$|^n$') + } + if ($confirm_spoti_recomended_unistall) { $ch = 'y' } + if ($confirm_spoti_recomended_over) { $ch = 'n' } + if ($ch -eq 'y') { + Write-Host ($lang).DelOld`n + $null = Unlock-Folder + cmd /c $spotifyExecutable /UNINSTALL /SILENT + wait-process -name SpotifyUninstall + Start-Sleep -Milliseconds 200 + if (Test-Path $spotifyDirectory) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory } + if (Test-Path $spotifyDirectory2) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory2 } + if (Test-Path $spotifyUninstall ) { Remove-Item -Recurse -Force -LiteralPath $spotifyUninstall } + } + if ($ch -eq 'n') { $ch = $null } + } + if ($ch -eq 'n') { + $downgrading = $true + } + } + + # Unsupported version Spotify + if ($testversion) { + # Submit unsupported version of Spotify to google form for further processing + try { + + # Country check + $country = [System.Globalization.RegionInfo]::CurrentRegion.EnglishName + + $txt = [IO.File]::ReadAllText($spotifyExecutable) + $regex = "(\d+)\.(\d+)\.(\d+)\.(\d+)(\.g[0-9a-f]{8})" + $v = $txt | Select-String $regex -AllMatches + $ver = $v.Matches.Value[0] + if ($ver.Count -gt 1) { $ver = $ver[0] } + + $Parameters = @{ + Uri = 'https://docs.google.com/forms/d/e/1FAIpQLSegGsAgilgQ8Y36uw-N7zFF6Lh40cXNfyl1ecHPpZcpD8kdHg/formResponse' + Method = 'POST' + Body = @{ + 'entry.620327948' = $ver + 'entry.1951747592' = $country + 'entry.1402903593' = $win_os + 'entry.860691305' = $psv + 'entry.2067427976' = $online + " < " + $offline + } + } + $null = Invoke-WebRequest -useb @Parameters + } + catch { + Write-Host 'Unable to submit new version of Spotify' + Write-Host "error description: "$Error[0] + } + + if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { + Write-Host ($lang).NewV`n + } + if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { + do { + Write-Host (($lang).NewV2 -f $offline, $online) + $ch = Read-Host -Prompt (($lang).NewV3 -f $offline) + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { + incorrectValue + } + } + while ($ch -notmatch '^y$|^n$') + } + if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { $ch = 'n' } + if ($ch -eq 'y') { $upgrade_client = $false } + if ($ch -eq 'n') { + if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { + do { + $ch = Read-Host -Prompt (($lang).Recom -f $online) + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { + incorrectValue + } + } + while ($ch -notmatch '^y$|^n$') + } + if ($confirm_spoti_recomended_over -or $confirm_spoti_recomended_unistall) { + $ch = 'y' + Write-Host ($lang).AutoUpd`n + } + if ($ch -eq 'y') { + $upgrade_client = $true + $downgrading = $true + if (!($confirm_spoti_recomended_over) -and !($confirm_spoti_recomended_unistall)) { + do { + $ch = Read-Host -Prompt (($lang).DelOrOver -f $offline) + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { + incorrectValue + } + } + while ($ch -notmatch '^y$|^n$') + } + if ($confirm_spoti_recomended_unistall) { $ch = 'y' } + if ($confirm_spoti_recomended_over) { $ch = 'n' } + if ($ch -eq 'y') { + Write-Host ($lang).DelNew`n + $null = Unlock-Folder + cmd /c $spotifyExecutable /UNINSTALL /SILENT + wait-process -name SpotifyUninstall + Start-Sleep -Milliseconds 200 + if (Test-Path $spotifyDirectory) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory } + if (Test-Path $spotifyDirectory2) { Remove-Item -Recurse -Force -LiteralPath $spotifyDirectory2 } + if (Test-Path $spotifyUninstall ) { Remove-Item -Recurse -Force -LiteralPath $spotifyUninstall } + } + if ($ch -eq 'n') { $ch = $null } + } + + if ($ch -eq 'n') { + Write-Host ($lang).StopScript + $tempDirectory = $PWD + Pop-Location + Start-Sleep -Milliseconds 200 + Remove-Item -Recurse -LiteralPath $tempDirectory + Pause + Exit + } + } + } +} +# If there is no client or it is outdated, then install +if (-not $spotifyInstalled -or $upgrade_client) { + + Write-Host ($lang).DownSpoti"" -NoNewline + Write-Host $online -ForegroundColor Green + Write-Host ($lang).DownSpoti2`n + + # Delete old version files of Spotify before installing, leave only profile files + $ErrorActionPreference = 'SilentlyContinue' + taskkill /f /im Spotify.exe /t > $null 2>&1 + Start-Sleep -Milliseconds 600 + $null = Unlock-Folder + Start-Sleep -Milliseconds 200 + Get-ChildItem $spotifyDirectory -Exclude 'Users', 'prefs' | Remove-Item -Recurse -Force + Start-Sleep -Milliseconds 200 + + # Client download + downloadSp + Write-Host + + Start-Sleep -Milliseconds 200 + + # Client installation + Start-Process -FilePath explorer.exe -ArgumentList $PWD\SpotifySetup.exe + while (-not (get-process | Where-Object { $_.ProcessName -eq 'SpotifySetup' })) {} + wait-process -name SpotifySetup + taskkill /f /im Spotify.exe /t > $null 2>&1 + + + # Upgrade check version Spotify offline + $offline = (Get-Item $spotifyExecutable).VersionInfo.FileVersion + + # Upgrade check version Spotify.bak + $offline_bak = (Get-Item $exe_bak).VersionInfo.FileVersion +} + + + +# Delete Spotify shortcut if it is on desktop +if ($no_shortcut) { + $ErrorActionPreference = 'SilentlyContinue' + $desktop_folder = DesktopFolder + Start-Sleep -Milliseconds 1000 + remove-item "$desktop_folder\Spotify.lnk" -Recurse -Force +} + +$ch = $null + +if ($podcasts_off) { + Write-Host ($lang).PodcatsOff`n + $ch = 'y' +} +if ($podcasts_on) { + Write-Host ($lang).PodcastsOn`n + $ch = 'n' +} +if (!($podcasts_off) -and !($podcasts_on)) { + + do { + $ch = Read-Host -Prompt ($lang).PodcatsSelect + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { incorrectValue } + } + while ($ch -notmatch '^y$|^n$') +} +if ($ch -eq 'y') { $podcast_off = $true } + +$ch = $null + +if ($downgrading) { $upd = "`n" + [string]($lang).DowngradeNote } + +else { $upd = "" } + +if ($block_update_on) { + Write-Host ($lang).UpdBlock`n + $ch = 'y' +} +if ($block_update_off) { + Write-Host ($lang).UpdUnblock`n + $ch = 'n' +} +if (!($block_update_on) -and !($block_update_off)) { + do { + $text_upd = [string]($lang).UpdSelect + $upd + $ch = Read-Host -Prompt $text_upd + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { incorrectValue } + } + while ($ch -notmatch '^y$|^n$') +} +if ($ch -eq 'y') { $block_update = $true } + +if (!($new_theme) -and [version]$offline -ge [version]"1.2.14.1141") { + Write-Warning "This version does not support the old theme, use version 1.2.13.661 or below" + Write-Host +} + +if ($ch -eq 'n') { + $ErrorActionPreference = 'SilentlyContinue' + if ((Test-Path -LiteralPath $exe_bak) -and $offline -eq $offline_bak) { + Remove-Item $spotifyExecutable -Recurse -Force + Rename-Item $exe_bak $spotifyExecutable + } +} + +$ch = $null + +$url = "https://spotx-official.github.io/SpotX/patches/patches.json" +$retries = 0 + +while ($retries -lt 3) { + try { + $webjson = Invoke-WebRequest -UseBasicParsing -Uri $url | ConvertFrom-Json + break + } + catch { + Write-Warning "Request failed: $_" + $retries++ + Start-Sleep -Seconds 3 + } +} + +if ($retries -eq 3) { + + Write-Host "Failed to get patches.json" -ForegroundColor Red + Write-Host ($lang).StopScript + $tempDirectory = $PWD + Pop-Location + Start-Sleep -Milliseconds 200 + Remove-Item -Recurse -LiteralPath $tempDirectory + Pause + Exit +} +function Helper($paramname) { + + switch ( $paramname ) { + "HtmlLicMin" { + # licenses.html minification + $name = "patches.json.others." + $n = "licenses.html" + $contents = "htmlmin" + $json = $webjson.others + } + "HtmlBlank" { + # htmlBlank minification + $name = "patches.json.others." + $n = "blank.html" + $contents = "blank.html" + $json = $webjson.others + } + "MinJs" { + # Minification of all *.js + $contents = "minjs" + $json = $webjson.others + } + "MinJson" { + # Minification of all *.json + $contents = "minjson" + $json = $webjson.others + } + "FixCss" { + # Remove indent for old theme xpui.css + $name = "patches.json.others." + $n = "xpui.css" + $json = $webjson.others + } + "RemovertlCssmin" { + # Remove RTL and minification of all *.css + $contents = "removertl-cssmin" + $json = $webjson.others + } + "DisableSentry" { + # Disable Sentry (vendor~xpui.js) + $name = "patches.json.others." + $n = "vendor~xpui.js" + $contents = "disablesentry" + $json = $webjson.others + } + "Lyrics-color" { + $pasttext = $webjson.others.themelyrics.theme.$lyrics_stat.pasttext + $current = $webjson.others.themelyrics.theme.$lyrics_stat.current + $next = $webjson.others.themelyrics.theme.$lyrics_stat.next + $background = $webjson.others.themelyrics.theme.$lyrics_stat.background + $hover = $webjson.others.themelyrics.theme.$lyrics_stat.hover + $maxmatch = $webjson.others.themelyrics.theme.$lyrics_stat.maxmatch + + if ([version]$offline -lt [version]"1.1.99.871") { $lyrics = "lyricscolor1"; $contents = $lyrics } + if ([version]$offline -ge [version]"1.1.99.871") { $lyrics = "lyricscolor2"; $contents = $lyrics } + + # xpui.js or xpui-routes-lyrics.js + if ([version]$offline -ge [version]"1.1.99.871") { + + $full_previous = Mod-F -template $webjson.others.$lyrics.add[0] -arguments $pasttext + $full_current = Mod-F -template $webjson.others.$lyrics.add[1] -arguments $current + $full_next = Mod-F -template $webjson.others.$lyrics.add[2] -arguments $next + $full_lyrics = Mod-F -template $webjson.others.$lyrics.add[3] -arguments $full_previous, $full_current, $full_next + $webjson.others.$lyrics.add[3] = $full_lyrics + $webjson.others.$lyrics.replace[1] = '$1' + '"' + $pasttext + '"' + $webjson.others.$lyrics.replace[2] = '$1' + '"' + $current + '"' + $webjson.others.$lyrics.replace[3] = '$1' + '"' + $next + '"' + $webjson.others.$lyrics.replace[4] = '$1' + '"' + $background + '"' + $webjson.others.$lyrics.replace[5] = '$1' + '"' + $hover + '"' + $webjson.others.$lyrics.replace[6] = '$1' + '"' + $maxmatch + '"' + if ([version]$offline -ge [version]"1.2.6.861") { + $webjson.others.$lyrics.replace[7] = '$1' + '"' + $maxmatch + '"' + '$3' + } + else { + $webjson.others.$lyrics.match = $webjson.others.$lyrics.match | Where-Object { $_ -ne $webjson.others.$lyrics.match[7] } + } + if ([version]$offline -ge [version]"1.2.3.1107") { + $webjson.others.$lyrics.replace[8] = $webjson.others.$lyrics.replace[8] -f $background + } + } + + # xpui-routes-lyrics.css + if ([version]$offline -lt [version]"1.1.99.871") { + $webjson.others.$lyrics.replace[0] = '$1' + $pasttext + $webjson.others.$lyrics.replace[1] = '$1' + $current + $webjson.others.$lyrics.replace[2] = '$1' + $next + $webjson.others.$lyrics.replace[3] = $background + $webjson.others.$lyrics.replace[4] = '$1' + $hover + $webjson.others.$lyrics.replace[5] = '$1' + $maxmatch + } + $name = "patches.json.others." + $n = $name_file + $json = $webjson.others + } + "Discriptions" { + # Add discriptions (xpui-desktop-modals.js) + + $svg_tg = $webjson.others.discriptions.svgtg + $svg_git = $webjson.others.discriptions.svggit + $svg_faq = $webjson.others.discriptions.svgfaq + $replace = $webjson.others.discriptions.replace + + $replacedText = $replace -f $svg_git, $svg_tg, $svg_faq + + $webjson.others.discriptions.replace = '$1"' + $replacedText + '"})' + + $name = "patches.json.others." + $n = "xpui-desktop-modals.js" + $contents = "discriptions" + $json = $webjson.others + } + "OffadsonFullscreen" { + # Full screen mode activation and removing "Upgrade to premium" menu, upgrade button, disabling a playlist sponsor + $name = "patches.json.free." + $n = "xpui.js" + $contents = $webjson.free.psobject.properties.name + $json = $webjson.free + } + "ForcedExp" { + # Forced disable some exp (xpui.js) + $offline_patch = $offline -replace '(\d+\.\d+\.\d+)(.\d+)', '$1' + $remEnable = $webjson.others.EnableExp.psobject.properties + $remCustom = $webjson.others.CustomExp.psobject.properties + + if ($enhance_like_off) { $remEnable.remove('EnhanceLikedSongs') } + if ($enhance_playlist_off) { $remEnable.remove('EnhancePlaylist') } + # if ($smartShuffle_off) { $remEnable.remove('SmartShuffle') } + $remEnable.remove('SmartShuffle') + $remEnable.remove('RecentlyPlayedShortcut') + $remEnable.remove('EncoreCards') + if (!($funnyprogressBar)) { $remEnable.remove('HeBringsNpb') } + # Old theme + if (!($new_theme) -and [version]$offline -le [version]"1.2.13.661") { + $LeftSidebar = $webjson.others.EnableExp.LeftSidebar + $RightSidebar = $webjson.others.EnableExp.RightSidebar + $webjson.others.DisableExp | Add-Member -MemberType NoteProperty -Name "LeftSidebar" -Value $LeftSidebar + $webjson.others.DisableExp | Add-Member -MemberType NoteProperty -Name "RightSidebar" -Value $RightSidebar + + $remCustom.remove('NavAlt'), $remCustom.remove('NavAlt2'), $remEnable.remove('RightSidebarLyrics'), $remEnable.remove('RightSidebarCredits'), + $remEnable.remove('RightSidebar'), $remEnable.remove('LeftSidebar'), $remEnable.remove('RightSidebarColors'); + } + # New theme + else { + if ($rightsidebar_off) { + $RightSidebar = $webjson.others.EnableExp.RightSidebar + $webjson.others.DisableExp | Add-Member -MemberType NoteProperty -Name "RightSidebar" -Value $RightSidebar + } + else { + if (!($rightsidebarcolor)) { $remEnable.remove('RightSidebarColors') } + if ($old_lyrics) { $remEnable.remove('RightSidebarLyrics') } + } + } + if (!$premium) { $remEnable.remove('RemoteDownloads') } + + # Disable unimportant exp + if ($exp_spotify) { + $objects = @( + @{ + Object = $webjson.others.CustomExp.psobject.properties + PropertiesToKeep = @('LyricsUpsell') + }, + @{ + Object = $webjson.others.EnableExp.psobject.properties + PropertiesToKeep = @('CarouselsOnHome') + } + ) + + foreach ($obj in $objects) { + $propertiesToRemove = $obj.Object.Name | Where-Object { $_ -notin $obj.PropertiesToKeep } + $propertiesToRemove | foreach { + $obj.Object.Remove($_) + } + } + + } + + $Exp = ($webjson.others.EnableExp, $webjson.others.DisableExp, $webjson.others.CustomExp) + + foreach ($item in $Exp) { + $itemProperties = $item | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name + + foreach ($key in $itemProperties) { + $vers = $item.$key.version + + if (!($vers.to -eq "" -or [version]$vers.to -ge [version]$offline_patch -and [version]$vers.fr -le [version]$offline_patch)) { + if ($item.PSObject.Properties.Name -contains $key) { + $item.PSObject.Properties.Remove($key) + } + } + } + } + + $enableExp = $webjson.others.EnableExp + $disableExp = $webjson.others.DisableExp + $CustomExp = $webjson.others.CustomExp + + $enableNames = foreach ($item in $enableExp.PSObject.Properties.Name) { + $webjson.others.EnableExp.$item.name + } + + $disableNames = foreach ($item in $disableExp.PSObject.Properties.Name) { + $webjson.others.DisableExp.$item.name + } + + $customNames = foreach ($item in $CustomExp.PSObject.Properties.Name) { + $custname = $webjson.others.CustomExp.$item.name + $custvalue = $webjson.others.CustomExp.$item.value + + # Create a string with the desired format + $objectString = "{name:'$custname',value:'$custvalue'}" + $objectString + } + + # Convert the strings of objects into a single text string + if ([string]::IsNullOrEmpty($customNames)) { $customTextVariable = '[]' } + else { $customTextVariable = "[" + ($customNames -join ',') + "]" } + if ([string]::IsNullOrEmpty($enableNames)) { $enableTextVariable = '[]' } + else { $enableTextVariable = "['" + ($enableNames -join "','") + "']" } + if ([string]::IsNullOrEmpty($disableNames)) { $disableTextVariable = '[]' } + else { $disableTextVariable = "['" + ($disableNames -join "','") + "']" } + + $replacements = @( + @("EnableExp=[]", "EnableExp=$enableTextVariable"), + @("DisableExp=[]", "DisableExp=$disableTextVariable"), + @("CustomExp=[]", "CustomExp=$customTextVariable") + ) + + foreach ($replacement in $replacements) { + $webjson.others.ForcedExp.replace = $webjson.others.ForcedExp.replace.Replace($replacement[0], $replacement[1]) + } + + $name = "patches.json.others." + $n = "xpui.js" + $contents = "ForcedExp" + $json = $webjson.others + } + "OffPodcasts" { + # Turn off podcasts + if ([version]$offline -le [version]"1.1.92.647") { $contents = "podcastsoff" } + if ([version]$offline -ge [version]"1.1.93.896") { $contents = "podcastsoff2" } + $n = $js + $name = "patches.json.others." + $json = $webjson.others + } + "OffAdSections" { + # Hiding Ad-like sections from the homepage + $n = $js + $name = "patches.json.others." + $contents = "adsectionsoff" + $json = $webjson.others + } + "RuTranslate" { + # Additional translation of some words for the Russian language + $n = "ru.json" + $contents = $webjsonru.psobject.properties.name + $json = $webjsonru + } + "PodcastAd" { + # Aodcast ad block + $name = "patches.json.others." + $n = "Spotify.exe" + $contents = "podcast_ad_block" + $json = $webjson.others + } + "BannerHome" { + # Remove banner on home page + $name = "patches.json.others." + $n = "home-hpto.js" + $contents = "BannerHome" + $json = $webjson.others + } + "BlockUpdate" { + # Block Spotify client updates + $name = "patches.json.others." + $n = "Spotify.exe" + $contents = "block_update" + $json = $webjson.others + } + "Collaborators" { + # Hide Collaborators icon + $name = "patches.json.others." + $n = "xpui-routes-playlist.js" + $contents = "collaboration" + $json = $webjson.others + } + "VariousofXpui-js" { + + $rem = $webjson.VariousJs.psobject.properties + + if ($urlform_goofy -and $idbox_goofy) { + $webjson.VariousJs.goofyhistory.replace = "`$1 const urlForm=" + '"' + $urlform_goofy + '"' + ";const idBox=" + '"' + $idbox_goofy + '"' + $webjson.VariousJs.goofyhistory.replace + } + else { $rem.remove('goofyhistory') } + + if (!($ru)) { $rem.remove('offrujs') } + + if (!($premium) -or ($cache_limit)) { + if (!($premium)) { + $adds += $webjson.VariousJs.product_state.add + } + + if ($cache_limit) { + + if ($cache_limit -lt 500) { $cache_limit = 500 } + if ($cache_limit -gt 20000) { $cache_limit = 20000 } + + $adds2 = $webjson.VariousJs.product_state.add2 + if (!([string]::IsNullOrEmpty($adds))) { $adds2 = ',' + $adds2 } + $adds += $adds2 -f $cache_limit + + } + $repl = $webjson.VariousJs.product_state.replace + $webjson.VariousJs.product_state.replace = $repl -f "{pairs:{$adds}}" + } + else { $rem.remove('product_state') } + + $name = "patches.json.VariousJs." + $n = "xpui.js" + $contents = $webjson.VariousJs.psobject.properties.name + $json = $webjson.VariousJs + } + } + $paramdata = $xpui + $novariable = "Didn't find variable " + $offline_patch = $offline -replace '(\d+\.\d+\.\d+)(.\d+)', '$1' + + $contents | foreach { + + if ( $json.$PSItem.version.to ) { $to = [version]$json.$PSItem.version.to -ge [version]$offline_patch } else { $to = $true } + if ( $json.$PSItem.version.fr ) { $fr = [version]$json.$PSItem.version.fr -le [version]$offline_patch } else { $fr = $false } + + $checkVer = $fr -and $to; $translate = $paramname -eq "RuTranslate" + + if ($checkVer -or $translate) { + + if ($json.$PSItem.match.Count -gt 1) { + + $count = $json.$PSItem.match.Count - 1 + $numbers = 0 + + While ($numbers -le $count) { + + if ($paramdata -match $json.$PSItem.match[$numbers]) { + $paramdata = $paramdata -replace $json.$PSItem.match[$numbers], $json.$PSItem.replace[$numbers] + } + else { + $notlog = "MinJs", "MinJson", "Removertl", "RemovertlCssmin" + if ($paramname -notin $notlog) { + + Write-Host $novariable -ForegroundColor red -NoNewline + Write-Host "$name$PSItem $numbers"'in'$n + } + } + $numbers++ + } + } + if ($json.$PSItem.match.Count -eq 1) { + if ($paramdata -match $json.$PSItem.match) { + $paramdata = $paramdata -replace $json.$PSItem.match, $json.$PSItem.replace + } + else { + if (!($translate) -or $err_ru) { + Write-Host $novariable -ForegroundColor red -NoNewline + Write-Host "$name$PSItem"'in'$n + } + } + } + } + } + $paramdata +} + +function extract ($counts, $method, $name, $helper, $add, $patch) { + switch ( $counts ) { + "one" { + if ($method -eq "zip") { + Add-Type -Assembly 'System.IO.Compression.FileSystem' + $xpui_spa_patch = Join-Path (Join-Path $env:APPDATA 'Spotify\Apps') 'xpui.spa' + $zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update') + $file = $zip.GetEntry($name) + $reader = New-Object System.IO.StreamReader($file.Open()) + } + if ($method -eq "nonezip") { + $file = get-item $env:APPDATA\Spotify\Apps\xpui\$name + $reader = New-Object -TypeName System.IO.StreamReader -ArgumentList $file + } + $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 $env:APPDATA 'Spotify\Apps') 'xpui.spa' + $zip = [System.IO.Compression.ZipFile]::Open($xpui_spa_patch, 'update') + $zip.Entries | Where-Object FullName -like $name | foreach { + $reader = New-Object System.IO.StreamReader($_.Open()) + $xpui = $reader.ReadToEnd() + $reader.Close() + $xpui = Helper -paramname $helper + $writer = New-Object System.IO.StreamWriter($_.Open()) + $writer.BaseStream.SetLength(0) + $writer.Write($xpui) + $writer.Close() + } + $zip.Dispose() + } + "exe" { + $ANSI = [Text.Encoding]::GetEncoding(1251) + $xpui = [IO.File]::ReadAllText($spotifyExecutable, $ANSI) + $xpui = Helper -paramname $helper + [IO.File]::WriteAllText($spotifyExecutable, $xpui, $ANSI) + } + } +} + +Write-Host ($lang).ModSpoti`n + +$tempDirectory = $PWD +Pop-Location + +Start-Sleep -Milliseconds 200 +Remove-Item -Recurse -LiteralPath $tempDirectory + +$xpui_spa_patch = Join-Path (Join-Path $env:APPDATA 'Spotify\Apps') 'xpui.spa' +$xpui_js_patch = Join-Path (Join-Path (Join-Path $env:APPDATA 'Spotify\Apps') 'xpui') 'xpui.js' +$test_spa = Test-Path -Path $xpui_spa_patch +$test_js = Test-Path -Path $xpui_js_patch +$spotify_exe_bak_patch = Join-Path $env:APPDATA 'Spotify\Spotify.bak' + + +if ($test_spa -and $test_js) { + Write-Host ($lang).Error -ForegroundColor Red + Write-Host ($lang).FileLocBroken + Write-Host ($lang).StopScript + pause + Exit +} + +if ($test_js) { + + do { + $ch = Read-Host -Prompt ($lang).Spicetify + Write-Host + if (!($ch -eq 'n' -or $ch -eq 'y')) { incorrectValue } + } + while ($ch -notmatch '^y$|^n$') + + if ($ch -eq 'y') { + $Url = "https://telegra.ph/SpotX-FAQ-09-19#Can-I-use-SpotX-and-Spicetify-together?" + Start-Process $Url + } + + Write-Host ($lang).StopScript + Pause + Exit +} + +if (!($test_js) -and !($test_spa)) { + Write-Host "xpui.spa not found, reinstall Spotify" + Write-Host ($lang).StopScript + Pause + Exit +} + +If ($test_spa) { + + $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()) + $patched_by_spotx = $reader.ReadToEnd() + $reader.Close() + + If ($patched_by_spotx -match 'patched by spotx') { + $zip.Dispose() + + if ($test_bak_spa) { + Remove-Item $xpui_spa_patch -Recurse -Force + Rename-Item $bak_spa $xpui_spa_patch + + $spotify_exe_bak_patch = Join-Path $env:APPDATA 'Spotify\Spotify.bak' + $test_spotify_exe_bak = Test-Path -Path $spotify_exe_bak_patch + if ($test_spotify_exe_bak) { + Remove-Item $spotifyExecutable -Recurse -Force + Rename-Item $spotify_exe_bak_patch $spotifyExecutable + } + } + else { + Write-Host ($lang).NoRestore`n + Pause + Exit + } + $spotify_exe_bak_patch = Join-Path $env:APPDATA 'Spotify\Spotify.bak' + $test_spotify_exe_bak = Test-Path -Path $spotify_exe_bak_patch + if ($test_spotify_exe_bak) { + Remove-Item $spotifyExecutable -Recurse -Force + Rename-Item $spotify_exe_bak_patch $spotifyExecutable + } + } + $zip.Dispose() + Copy-Item $xpui_spa_patch $env:APPDATA\Spotify\Apps\xpui.bak + + # Remove all languages except En and Ru from xpui.spa + if ($ru) { + $null = [Reflection.Assembly]::LoadWithPartialName('System.IO.Compression') + $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.Entries | Where-Object { $_.FullName -match "i18n" -and $_.FullName -inotmatch "(ru|en.json|longest)" }) | foreach { $_.Delete() } + + $zip_xpui.Dispose() + $stream.Close() + $stream.Dispose() + } + + # Full screen mode activation and removing "Upgrade to premium" menu, upgrade button, disabling a playlist sponsor + if (!($premium)) { + extract -counts 'one' -method 'zip' -name 'xpui.js' -helper 'OffadsonFullscreen' + } + + # Forced disable some exp + extract -counts 'one' -method 'zip' -name 'xpui.js' -helper 'ForcedExp' -add $webjson.others.byspotx.add + + # Experimental Feature + extract -counts 'one' -method 'zip' -name 'xpui.js' -helper 'VariousofXpui-js' + + # Turn off podcasts + if ($podcast_off) { + if ([version]$offline -ge [version]"1.1.93.896" -and [version]$offline -le [version]"1.1.97.962") { $js = 'home-v2.js' } + if ([version]$offline -le [version]"1.1.92.647" -or [version]$offline -ge [version]"1.1.98.683") { $js = 'xpui.js' } + extract -counts 'one' -method 'zip' -name $js -helper 'OffPodcasts' + } + + # Hiding Ad-like sections from the homepage + if ($adsections_off) { + if ([version]$offline -ge [version]"1.1.93.896" -and [version]$offline -le [version]"1.1.97.962") { $js = 'home-v2.js' } + if ([version]$offline -ge [version]"1.1.98.683") { $js = 'xpui.js' } + extract -counts 'one' -method 'zip' -name $js -helper 'OffAdSections' + } + + # Remove banner on home page + extract -counts 'one' -method 'zip' -name 'home-hpto.js' -helper 'BannerHome' + + # Hide Collaborators icon + if (!($hide_col_icon_off) -and !($exp_spotify)) { + extract -counts 'one' -method 'zip' -name 'xpui-routes-playlist.js' -helper 'Collaborators' + } + + + # Static color for lyrics + if ($lyrics_stat) { + # old + if ([version]$offline -lt [version]"1.1.99.871") { + $name_file = 'xpui-routes-lyrics.css' + extract -counts 'one' -method 'zip' -name $name_file -helper 'Lyrics-color' + } + # new + if ([version]$offline -ge [version]"1.1.99.871") { + $contents = "fixcsslyricscolor2" + extract -counts 'one' -method 'zip' -name 'xpui.css' -helper 'FixCss' + if ([version]$offline -le [version]"1.2.2.582") { + $name_file = 'xpui-routes-lyrics.js' + extract -counts 'one' -method 'zip' -name $name_file -helper 'Lyrics-color' + } + } + # mini lyrics + if ([version]$offline -ge [version]"1.2.0.1155") { + $name_file = 'xpui.js' + extract -counts 'one' -method 'zip' -name $name_file -helper 'Lyrics-color' + } + } + + # Add discriptions (xpui-desktop-modals.js) + extract -counts 'one' -method 'zip' -name 'xpui-desktop-modals.js' -helper 'Discriptions' + + # Disable Sentry (vendor~xpui.js) + extract -counts 'one' -method 'zip' -name 'vendor~xpui.js' -helper 'DisableSentry' + + # Minification of all *.js + extract -counts 'more' -name '*.js' -helper 'MinJs' + + # xpui.css + if (!($premium)) { + # Hide download icon on different pages + $css += $webjson.others.downloadicon.add + # Hide submenu item "download" + $css += $webjson.others.submenudownload.add + # Hide very high quality streaming + $css += $webjson.others.veryhighstream.add + } + # Full screen lyrics + if ($lyrics_stat -and [version]$offline -ge [version]"1.2.3.1107") { + $css += $webjson.others.lyricscolor2.add[3] + } + if ($null -ne $css ) { extract -counts 'one' -method 'zip' -name 'xpui.css' -add $css } + + + # Old UI fix + $contents = "fix-old-theme" + extract -counts 'one' -method 'zip' -name 'xpui.css' -helper "FixCss" + + # Remove RTL and minification of all *.css + extract -counts 'more' -name '*.css' -helper 'RemovertlCssmin' + + # licenses.html minification + + extract -counts 'one' -method 'zip' -name 'licenses.html' -helper 'HtmlLicMin' + # blank.html minification + extract -counts 'one' -method 'zip' -name 'blank.html' -helper 'HtmlBlank' + + if ($ru) { + # Additional translation of the ru.json file + extract -counts 'more' -name '*ru.json' -helper 'RuTranslate' + } + # Minification of all *.json + extract -counts 'more' -name '*.json' -helper 'MinJson' +} + +# Delete all files except "en" and "ru" +if ($ru) { + $patch_lang = "$spotifyDirectory\locales" + Remove-Item $patch_lang -Exclude *en*, *ru* -Recurse +} + +# Create a desktop shortcut +$ErrorActionPreference = 'SilentlyContinue' + +if (!($no_shortcut)) { + + $desktop_folder = DesktopFolder + + If (!(Test-Path $desktop_folder\Spotify.lnk)) { + $source = Join-Path $env:APPDATA 'Spotify\Spotify.exe' + $target = "$desktop_folder\Spotify.lnk" + $WorkingDir = "$env:APPDATA\Spotify" + $WshShell = New-Object -comObject WScript.Shell + $Shortcut = $WshShell.CreateShortcut($target) + $Shortcut.WorkingDirectory = $WorkingDir + $Shortcut.TargetPath = $source + $Shortcut.Save() + } +} + +# Create shortcut in start menu +If (!(Test-Path $start_menu)) { + $source = Join-Path $env:APPDATA 'Spotify\Spotify.exe' + $target = $start_menu + $WorkingDir = "$env:APPDATA\Spotify" + $WshShell = New-Object -comObject WScript.Shell + $Shortcut = $WshShell.CreateShortcut($target) + $Shortcut.WorkingDirectory = $WorkingDir + $Shortcut.TargetPath = $source + $Shortcut.Save() +} + +$ANSI = [Text.Encoding]::GetEncoding(1251) +$old = [IO.File]::ReadAllText($spotifyExecutable, $ANSI) + +$rexex1 = $old -notmatch $webjson.others.block_update.add +$rexex2 = $old -notmatch $webjson.others.podcast_ad_block.add + +if ($rexex1 -and $rexex2 ) { + + if (Test-Path -LiteralPath $exe_bak) { + Remove-Item $exe_bak -Recurse -Force + Start-Sleep -Milliseconds 150 + } + copy-Item $spotifyExecutable $exe_bak +} + +# Podcast ad block +extract -counts 'exe' -helper 'PodcastAd' + +# Block updates +if ($block_update) { extract -counts 'exe' -helper 'BlockUpdate' } + +# Start Spotify +if ($start_spoti) { Start-Process -WorkingDirectory $spotifyDirectory -FilePath $spotifyExecutable } + +Write-Host ($lang).InstallComplete`n -ForegroundColor Green diff --git a/scripts/Install_Auto.bat b/scripts/Install_Auto.bat index f0176937..77eaf4d6 100644 --- a/scripts/Install_Auto.bat +++ b/scripts/Install_Auto.bat @@ -1,6 +1,6 @@ @echo off -%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/SpotX/Install.ps1')} -confirm_uninstall_ms_spoti -confirm_spoti_recomended_over -podcasts_off -block_update_on -start_spoti -new_theme -adsections_off -lyrics_stat spotify """" | Invoke-Expression" +%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/run.ps1')} -confirm_uninstall_ms_spoti -confirm_spoti_recomended_over -podcasts_off -block_update_on -start_spoti -new_theme -adsections_off -lyrics_stat spotify """" | Invoke-Expression" pause exit /b \ No newline at end of file diff --git a/scripts/Install_Prem.bat b/scripts/Install_Prem.bat index 69b91898..e2550055 100644 --- a/scripts/Install_Prem.bat +++ b/scripts/Install_Prem.bat @@ -1,6 +1,6 @@ @echo off -%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/SpotX/Install.ps1')} -premium -new_theme """" | Invoke-Expression" +%SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -Command "&{[Net.ServicePointManager]::SecurityProtocol = 3072}; """"& { $(Invoke-WebRequest -UseBasicParsing 'https://spotx-official.github.io/run.ps1')} -premium -new_theme """" | Invoke-Expression" pause exit /b \ No newline at end of file