diff --git a/js-helper/sectionBlock.js b/js-helper/sectionBlock.js
new file mode 100644
index 00000000..63a00d52
--- /dev/null
+++ b/js-helper/sectionBlock.js
@@ -0,0 +1,71 @@
+function sectionBlock(e, type) {
+
+ const body = e?.data?.home;
+ const sections = body?.sectionContainer?.sections?.items;
+
+ function removeSections() {
+
+ const sectionsData = [
+ { id: '0JQ5IMCbQBLupUQrQFeCzx', name: 'Best of the Year' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3C', name: 'Best of Artists / Tracks' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu4w', name: 'Best of songwriters' },
+ { id: '0JQ5DAob0KOew1FBAMSmBz', name: 'Featured Charts' },
+ { id: '0JQ5DAob0JCuWaGLU6ntFY', name: 'Focus' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3s', name: 'Fresh new music' },
+ { id: '0JQ5DAob0LaV9FOMJ9utY5', name: 'Gaming music' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3q', name: 'Happy' },
+ { id: '0JQ5DAnM3wGh0gz1MXnucG', name: 'Mood' },
+ { id: '0JQ5DAob0JCuWaGLU6ntFT', name: 'Mood' },
+ { id: '0JQ5DAob0Jr9ClCbkV4pZD', name: 'Music to game to' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3B', name: 'Popular Albums / Artists' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3D', name: 'Popular new releases' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu4h', name: 'Popular radio' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3u', name: 'Sad' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3w', name: 'Throwback' },
+ { id: '0JQ5DAuChZYPe9iDhh2mJz', name: 'Throwback Thursday' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3M', name: 'Today`s biggest hits' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3E', name: 'Trending now' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu3x', name: 'Workout' },
+ { id: '0JQ5IMCbQBLqTJyy28YCa9', name: '?' },
+ { id: '0JQ5IMCbQBLlC31GvtaB6w', name: '?' },
+ { id: '0JQ5DAnM3wGh0gz1MXnu7R', name: '?' }
+ ]
+ const sectionIdsRegex = new RegExp(sectionsData.map(section => section.id).join('|'));
+
+ for (let i = sections.length - 1; i >= 0; i--) {
+ const uri = sections[i]?.uri;
+ if (uri && uri.match(sectionIdsRegex)) {
+ sections.splice(i, 1);
+ }
+ }
+ }
+
+ function removePodcasts() {
+ if (Array.isArray(sections)) {
+ for (let i = 0; i < sections.length; i++) {
+ const sectionItems = sections[i]?.sectionItems?.items;
+
+ if (Array.isArray(sectionItems)) {
+ for (let j = 0; j < sectionItems.length; j++) {
+ const contentData = sectionItems[j]?.content?.data;
+
+ if (contentData && ["Podcast", "Audiobook", "Episode"].includes(contentData.__typename)) {
+ sectionItems.splice(j, 1);
+ j--;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (body?.greeting && sections) {
+ if (type === "section" || type === "all") {
+ removeSections();
+ }
+
+ if (type === "podcast" || type === "all") {
+ removePodcasts();
+ }
+ }
+}
diff --git a/patches/patches.json b/patches/patches.json
index 374024b0..ee8bc0b6 100644
--- a/patches/patches.json
+++ b/patches/patches.json
@@ -421,6 +421,24 @@
}
},
"EnableExp": {
+ "HomeViaGraphQLV2": {
+ "name": "enableHomeViaGraphQLV2",
+ "description": "Enable fetching Home via GraphQL",
+ "native_description": "Enable fetching Home via GraphQL",
+ "version": {
+ "fr": "1.1.86",
+ "to": "1.1.92"
+ }
+ },
+ "BrowseViaPathfinder": {
+ "name": "enableBrowseViaPathfinder",
+ "description": "Fixes a bug on the genres page",
+ "native_description": "Fetch Browse data from Pathfinder",
+ "version": {
+ "fr": "1.1.88",
+ "to": "1.2.24"
+ }
+ },
"EnhanceLikedSongs": {
"name": "enableEnhanceLikedSongs",
"description": "Enable Enhance Liked Songs UI and functionality",
@@ -862,15 +880,6 @@
"to": "1.2.29"
}
},
- "BrowseViaPathfinder": {
- "name": "enableBrowseViaPathfinder",
- "description": "Fixes a bug on the genres page",
- "native_description": "Fetch Browse data from Pathfinder",
- "version": {
- "fr": "1.1.70",
- "to": "1.2.24"
- }
- },
"NotificationCenter": {
"name": "enableNotificationCenter",
"description": "Enables notification center for desktop & web",
@@ -1130,30 +1139,6 @@
"replace": "dodo"
}
},
- "podcastsoff": {
- "version": {
- "fr": "1.1.70",
- "to": "1.1.92"
- },
- "match": "withQueryParameters\\(.\\){return this.queryParameters=.,this}",
- "replace": "withQueryParameters(e){return this.queryParameters=(e.types?{...e, types: e.types.split(\",\").filter(_ => ![\"episode\",\"show\"].includes(_)).join(\",\")}:e),this}"
- },
- "podcastsoff2": {
- "version": {
- "fr": "1.1.93",
- "to": ""
- },
- "match": "(\\!?Array.isArray\\(.\\)[\\|&]{2}.===(.).length\\)return null;)",
- "replace": "$1 let as=$2;if(!Array.isArray(as)){as=e;}for(let q=0;q<(as.children?as.children.length:as.length);q++){const key=(as.children?.[q]||as[q])?.key;if(!key||as[q].props?.value===\"search-history\"){continue;}if(key.match(/(episode|show)/)||(as.title)?.match(/podcasts/i)){return null;}}"
- },
- "adsectionsoff": {
- "version": {
- "fr": "1.1.93",
- "to": ""
- },
- "match": "((\"Carousel\".+?|onClickCarouselControls:.,spec:.[\\{\\}\\(\\)]{3,8})seeAllUri:(.),index.+?(UBIWrapper|id:.}\\)|\\.spec);)",
- "replace": "$1 if ($3 && $3.match && $3.match(/(0JQ5DAnM3wGh0gz1MXnu3B|0JQ5DAnM3wGh0gz1MXnu3D|0JQ5IMCbQBLupUQrQFeCzx|0JQ5IMCbQBLqTJyy28YCa9|0JQ5IMCbQBLlC31GvtaB6w|0JQ5DAob0KOew1FBAMSmBz|0JQ5DAnM3wGh0gz1MXnu4w|0JQ5DAnM3wGh0gz1MXnu3C|0JQ5DAnM3wGh0gz1MXnu3s|0JQ5DAnM3wGh0gz1MXnu3M|0JQ5DAob0JCuWaGLU6ntFT|0JQ5DAnM3wGh0gz1MXnucG|0JQ5DAnM3wGh0gz1MXnu3E|0JQ5DAnM3wGh0gz1MXnu4h|0JQ5DAnM3wGh0gz1MXnu7R|0JQ5DAnM3wGh0gz1MXnu3w|0JQ5DAuChZYPe9iDhh2mJz|0JQ5DAnM3wGh0gz1MXnu3x|0JQ5DAob0JCuWaGLU6ntFY|0JQ5DAnM3wGh0gz1MXnu3u|0JQ5DAnM3wGh0gz1MXnu3q|0JQ5DAob0Jr9ClCbkV4pZD|0JQ5DAob0LaV9FOMJ9utY5)/)) {return null};"
- },
"themelyrics": {
"theme": {
"default": {
@@ -1626,6 +1611,14 @@
"true$2"
]
},
+ "block_section": {
+ "version": {
+ "fr": "1.1.86",
+ "to": ""
+ },
+ "match": "(case 6:|const .=await .\\(.,.\\);)((return .\\.abrupt\\(\"|return[ \"],?)(null!=n&&|return\",)?(.)(\\);case 9|\\??.errors\\?Promise.reject.+?errors\\):.))",
+ "replace": "$1sectionBlock($5,\"{0}\");$2"
+ },
"banner_home": {
"version": {
"fr": "1.1.70",
diff --git a/run.ps1 b/run.ps1
index 92f9f88d..60c02c71 100644
--- a/run.ps1
+++ b/run.ps1
@@ -54,6 +54,9 @@ param
[Parameter(HelpMessage = 'Enable top search bar.')]
[switch]$topsearchbar,
+
+ [Parameter(HelpMessage = 'disable subfeed filter chips on home.')]
+ [switch]$homesub_off,
[Parameter(HelpMessage = 'Do not hide the icon of collaborations in playlists.')]
[switch]$hide_col_icon_off,
@@ -291,10 +294,10 @@ if ($psv -ge 7) {
function CallLang($clg) {
- if ($mirror) {
- $urlLang = "https://spotx-official.github.io/SpotX/scripts/installer-lang/$clg.ps1"
+ $urlLang = switch ($mirror) {
+ $true { "https://spotx-official.github.io/SpotX/scripts/installer-lang/$clg.ps1" }
+ default { "https://raw.githubusercontent.com/SpotX-Official/SpotX/main/scripts/installer-lang/$clg.ps1" }
}
- else { $urlLang = "https://raw.githubusercontent.com/SpotX-Official/SpotX/main/scripts/installer-lang/$clg.ps1" }
$ProgressPreference = 'SilentlyContinue'
@@ -377,6 +380,33 @@ else {
$online = ($onlineFull -split ".g")[0]
+function Get {
+ param (
+ [string]$Url,
+ [int]$MaxRetries = 3,
+ [int]$RetrySeconds = 3
+ )
+
+ $retries = 0
+
+ while ($retries -lt $MaxRetries) {
+ try {
+ return Invoke-RestMethod -Uri $Url
+ }
+ catch {
+ Write-Warning "Request failed: $_"
+ $retries++
+ Start-Sleep -Seconds $RetrySeconds
+ }
+ }
+ Write-Host
+ Write-Host "ERROR: " -ForegroundColor Red -NoNewline; Write-Host "Failed to retrieve data from $Url" -ForegroundColor White
+ Write-Host
+
+ return $null
+
+}
+
function incorrectValue {
Write-Host ($lang).Incorrect"" -ForegroundColor Red -NoNewline
@@ -826,14 +856,18 @@ $ch = $null
# updated Russian translation
if ($langCode -eq 'ru' -and [version]$offline -ge [version]"1.1.92.644") {
- $ru = $true
-
- if ($mirror) {
- $urlru = "https://spotx-official.github.io/SpotX/patches/Augmented%20translation/ru.json"
+
+ $urlru = switch ($mirror) {
+ $true { "https://spotx-official.github.io/SpotX/patches/Augmented%20translation/ru.json" }
+ default { "https://raw.githubusercontent.com/SpotX-Official/SpotX/main/patches/Augmented%20translation/ru.json" }
}
- else { $urlru = "https://raw.githubusercontent.com/SpotX-Official/SpotX/main/patches/Augmented%20translation/ru.json" }
- $webjsonru = (Invoke-WebRequest -useb -Uri $urlru).Content | ConvertFrom-Json
+ $webjsonru = Get -Url $urlru
+
+ if ($webjsonru -ne $null) {
+
+ $ru = $true
+ }
}
if ($podcasts_off) {
@@ -897,28 +931,15 @@ if ($ch -eq 'n') {
$ch = $null
-if ($mirror) {
-
- $url = "https://spotx-official.github.io/SpotX/patches/patches.json"
-}
-else { $url = "https://raw.githubusercontent.com/SpotX-Official/SpotX/main/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
- }
+$url = switch ($mirror) {
+ $true { "https://spotx-official.github.io/SpotX/patches/patches.json" }
+ default { "https://raw.githubusercontent.com/SpotX-Official/SpotX/main/patches/patches.json" }
}
-if ($retries -eq 3) {
-
+$webjson = Get -Url $url -RetrySeconds 5
+
+if ($webjson -eq $null) {
+ Write-Host
Write-Host "Failed to get patches.json" -ForegroundColor Red
Write-Host ($lang).StopScript
$tempDirectory = $PWD
@@ -927,7 +948,10 @@ if ($retries -eq 3) {
Remove-Item -Recurse -LiteralPath $tempDirectory
Pause
Exit
+
}
+
+
function Helper($paramname) {
@@ -1115,15 +1139,9 @@ function Helper($paramname) {
if (!($funnyprogressbar)) { Move-Json -n 'HeBringsNpb' -t $Enable -f $Disable }
- # disable homesub if the patch for disabling podcasts on the home page is applied
- $homesub = "HomeSubfeeds"
-
- if ($podcasts_off) {
- Move-Json -n $homesub -t $Enable -f $Disable
- }
-
- else {
- Remove-Json -j $Enable -p $homesub
+ # disable subfeed filter chips on home
+ if ($homesub_off) {
+ Move-Json -n "HomeSubfeeds" -t $Enable -f $Disable
}
# Old theme
@@ -1155,7 +1173,7 @@ function Helper($paramname) {
},
@{
Object = $webjson.others.EnableExp.psobject.properties
- PropertiesToKeep = @('CarouselsOnHome', 'BrowseViaPathfinder')
+ PropertiesToKeep = @('BrowseViaPathfinder', 'HomeViaGraphQLV2')
}
)
@@ -1228,21 +1246,6 @@ function Helper($paramname) {
$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"
@@ -1300,6 +1303,19 @@ function Helper($paramname) {
}
else { Remove-Json -j $VarJs -p 'product_state' }
+
+ if ($podcast_off -or $adsections_off) {
+ $type = switch ($true) {
+ { $podcast_off -and $adsections_off } { "all" }
+ { $podcast_off -and -not $adsections_off } { "podcast" }
+ { -not $podcast_off -and $adsections_off } { "section" }
+ }
+ $webjson.VariousJs.block_section.replace = $webjson.VariousJs.block_section.replace -f $type
+ }
+ else {
+ Remove-Json -j $VarJs -p 'block_section'
+ }
+
$name = "patches.json.VariousJs."
$n = "xpui.js"
$contents = $webjson.VariousJs.psobject.properties.name
@@ -1385,7 +1401,7 @@ function extract ($counts, $method, $name, $helper, $add, $patch) {
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 {
+ $zip.Entries | Where-Object { $_.FullName -like $name -and $_.FullName.Split('/') -notcontains 'spotx-helper' } | foreach {
$reader = New-Object System.IO.StreamReader($_.Open())
$xpui = $reader.ReadToEnd()
$reader.Close()
@@ -1406,6 +1422,79 @@ function extract ($counts, $method, $name, $helper, $add, $patch) {
}
}
+function injection {
+ param(
+ [Alias("p")]
+ [string]$ArchivePath,
+
+ [Alias("f")]
+ [string]$FolderInArchive,
+
+ [Alias("n")]
+ [string]$FileName,
+
+ [Alias("c")]
+ [string]$FileContent
+ )
+
+ $folderPathInArchive = "$($FolderInArchive)/"
+
+ Add-Type -AssemblyName System.IO.Compression.FileSystem
+ $archive = [System.IO.Compression.ZipFile]::Open($ArchivePath, 'Update')
+ $stream = $null
+ try {
+ $entry = $archive.GetEntry($folderPathInArchive + $FileName)
+ if ($entry -eq $null) {
+ $stream = $archive.CreateEntry($folderPathInArchive + $FileName).Open()
+ }
+ else {
+ $stream = $entry.Open()
+ }
+
+ $writer = [System.IO.StreamWriter]::new($stream)
+ $writer.Write($FileContent)
+
+ $writer.Dispose()
+ $stream.Dispose()
+
+ $indexEntry = $archive.Entries | Where-Object { $_.FullName -eq "index.html" }
+ if ($indexEntry -ne $null) {
+ $indexStream = $indexEntry.Open()
+ $reader = [System.IO.StreamReader]::new($indexStream)
+ $indexContent = $reader.ReadToEnd()
+ $reader.Dispose()
+ $indexStream.Dispose()
+
+ $scriptTagIndex = $indexContent.IndexOf("")
+
+ $indexEntry.Delete()
+ $newIndexEntry = $archive.CreateEntry("index.html").Open()
+ $indexWriter = [System.IO.StreamWriter]::new($newIndexEntry)
+ $indexWriter.Write($modifiedIndexContent)
+ $indexWriter.Dispose()
+ $newIndexEntry.Dispose()
+
+ }
+ else {
+ Write-Warning "