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 "