Compare commits

...
3 Commits
Author SHA1 Message Date
jetfir3 03207b6117 Add binary validation 2026-07-29 15:38:54 -04:00
jetfir3 b6df3cdcc5 Fix typos 2026-07-29 15:20:56 -04:00
jetfir3 876e4dc0cd Improve macOS installation and codesigning 2026-07-29 14:53:59 -04:00
+66 -15
View File
@@ -764,6 +764,13 @@ sudo_check() {
}
cleanup_temp_dirs() {
[[ -n "${macInstallOld:-}" && -d "${macInstallOld}" && "${macInstallOld%/*}" == "${installPath:-}" && "${macInstallOld##*/}" == .spotx-previous.* ]] && {
[[ "${macInstallOldMoved:-}" && -z "${macInstallCommitted:-}" && ! -e "${appPath:-}" ]] && mv -- "${macInstallOld}" "${appPath}"
[[ -z "${macInstallOldMoved:-}" && -d "${macInstallOld}" ]] && rm -rf -- "${macInstallOld}"
[[ "${macInstallCommitted:-}" && -d "${macInstallOld}" ]] && rm -rf -- "${macInstallOld}"
}
[[ -n "${macInstallTemp:-}" && -d "${macInstallTemp}" && "${macInstallTemp%/*}" == "${installPath:-}" && "${macInstallTemp##*/}" == .spotx-install.* ]] && rm -rf -- "${macInstallTemp}"
[[ -n "${macDownloadPath:-}" && -f "${macDownloadPath}" && "${macDownloadPath%/*}" == "${HOME}/Downloads" && "${macDownloadPath##*/}" == "${fileVar:-}" ]] && rm -f -- "${macDownloadPath}"
[[ -n "${workDir:-}" && -d "${workDir}" && "${workDir##*/}" == spotx-bash.* ]] && rm -rf -- "${workDir}"
[[ -n "${copyTempDir:-}" && -d "${copyTempDir}" && "${copyTempDir##*/}" == *.spotx.* ]] && rm -rf -- "${copyTempDir}"
[[ -n "${spaTempDir:-}" && -d "${spaTempDir}" && "${spaTempDir##*/}" == .spotx-spa.* ]] && rm -rf -- "${spaTempDir}"
@@ -828,6 +835,7 @@ linux_deb_install() {
}
macos_client_install() {
local downloadPath="${HOME}/Downloads/${fileVar}" stagedApp
[[ ! -w "${installPath}" ]] && {
echo -e "${red}Error:${clr} SpotX-Bash does not have write permission in ${installOutput}.\nConfirm permissions or set custom install path to writable directory.\n" >&2
exit 1
@@ -846,22 +854,54 @@ macos_client_install() {
"alHZyIWeChFT0F0UjRXQDJWeWNTW" \
| rev | base64 --decode | base64 --decode)
eval "${mc01}"; eval "${mc02}"
tar -tf "$HOME/Downloads/${fileVar}" >/dev/null 2>&1 || {
rm "$HOME/Downloads/${fileVar}" 2>/dev/null
tar -tf "${downloadPath}" >/dev/null 2>&1 || {
rm "${downloadPath}" 2>/dev/null
echo -e "\n${red}Error:${clr} Downloaded client archive is corrupt or incomplete. Exiting...\n" >&2
exit 1
}
macDownloadPath="${downloadPath}"
printf "\xE2\x9C\x94\x20\x44\x6F\x77\x6E\x6C\x6F\x61\x64\x65\x64\x20\x61\x6E\x64\x20\x69\x6E\x73\x74\x61\x6C\x6C\x69\x6E\x67\x20\x53\x70\x6F\x74\x69\x66\x79\n"
rm -rf "${appPath}" 2>/dev/null
mkdir -p "${appPath}"
tar -xpf "$HOME/Downloads/${fileVar}" -C "${appPath}" && unset notInstalled versionFailed || {
rm "$HOME/Downloads/${fileVar}" 2>/dev/null
macInstallTemp=$(mktemp -d "${installPath}/.spotx-install.XXXXXXXX") || {
rm "${downloadPath}" 2>/dev/null
echo -e "\n${red}Error:${clr} Client install failed. Exiting...\n" >&2
exit 1
}
stagedApp="${macInstallTemp}/Spotify.app"
mkdir -p "${stagedApp}" &&
tar -xpf "${downloadPath}" -C "${stagedApp}" &&
[[ -x "${stagedApp}/Contents/MacOS/Spotify" ]] &&
[[ -f "${stagedApp}/Contents/Info.plist" ]] &&
[[ -f "${stagedApp}/Contents/Resources/Apps/xpui.spa" ]] || {
rm "${downloadPath}" 2>/dev/null
echo -e "\n${red}Error:${clr} Client install failed. Exiting...\n" >&2
exit 1
}
[[ -e "${appPath}" ]] && {
macInstallOld=$(mktemp -d "${installPath}/.spotx-previous.XXXXXXXX") || {
rm "${downloadPath}" 2>/dev/null
echo -e "\n${red}Error:${clr} Client install failed. Exiting...\n" >&2
exit 1
}
rmdir "${macInstallOld}" && macInstallOldMoved='true' && mv "${appPath}" "${macInstallOld}" || {
rm "${downloadPath}" 2>/dev/null
echo -e "\n${red}Error:${clr} Client install failed. Exiting...\n" >&2
exit 1
}
}
mv "${stagedApp}" "${appPath}" && macInstallCommitted='true' || {
[[ -n "${macInstallOld:-}" && -d "${macInstallOld}" && ! -e "${appPath}" ]] && mv "${macInstallOld}" "${appPath}"
rm "${downloadPath}" 2>/dev/null
echo -e "\n${red}Error:${clr} Client install failed. Exiting...\n" >&2
exit 1
}
rm -rf "${macInstallTemp}"
[[ ! -d "${macInstallTemp}" ]] && unset macInstallTemp
[[ -n "${macInstallOld:-}" ]] && rm -rf "${macInstallOld}"
[[ -z "${macInstallOld:-}" || ! -d "${macInstallOld}" ]] && unset macInstallOld macInstallOldMoved macInstallCommitted
printf "\xE2\x9C\x94\x20\x49\x6E\x73\x74\x61\x6C\x6C\x65\x64\x20\x69\x6E\x20'"${installOutput}"'\n"
rm "$HOME/Downloads/${fileVar}"
rm "${downloadPath}" && unset macDownloadPath
clientVer=$(echo "${fileVar}" | perl -ne '/te-(.*)\..*\./ && print "$1"')
unset notInstalled versionFailed
}
run_install_check() {
@@ -871,6 +911,20 @@ run_install_check() {
}
}
macos_codesign() {
/usr/bin/xattr -cr "${appPath}" 2>/dev/null || {
echo -e "\n${red}Error:${clr} Failed to clear Spotify security attributes. Exiting...\n" >&2
exit 1
}
[[ "${skipCodesign}" ]] && return
codesign -f --deep -s - "${appPath}" >/dev/null 2>&1 &&
codesign --verify --deep --strict "${appPath}" >/dev/null 2>&1 || {
echo -e "\n${red}Error:${clr} Failed to codesign Spotify. Exiting...\n" >&2
exit 1
}
printf "\xE2\x9C\x94\x20\x43\x6F\x64\x65\x73\x69\x67\x6E\x65\x64\x20\x53\x70\x6F\x74\x69\x66\x79\n"
}
run_cache_check() {
[[ "${clearCache}" ]] && {
[[ -n "${cachePath}" && -d "${cachePath}" ]] && {
@@ -886,6 +940,7 @@ run_cache_check() {
final_setup_check() {
[[ "${notInstalled}" ]] && { echo -e "${red}Error:${clr} Client not found\n" >&2; exit 1; }
[[ ! -f "${appBinary}" || ! -s "${appBinary}" || ! -r "${appBinary}" || ! -x "${appBinary}" ]] && { echo -e "${red}Error:${clr} Client executable not found or invalid.\nReinstall client then try again.\n" >&2; exit 1; }
[[ ! -f "${xpuiSpa}" ]] && { echo -e "${red}Error:${clr} Detected a modified client installation!\nReinstall client then try again.\n" >&2; exit 1; }
[[ "${clientVer}" ]] && (($(ver "${clientVer}") < $(ver "1.1.59.710"))) && { echo -e "${red}Error:${clr} ${clientVer} not supported by SpotX-Bash\n" >&2; exit 1; }
}
@@ -1124,11 +1179,7 @@ run_finish() {
}
}
[[ "${platformType}" == "macOS" ]] && {
[[ "${skipCodesign}" ]] && /usr/bin/xattr -cr "${appPath}" 2>/dev/null || {
/usr/bin/xattr -cr "${appPath}" 2>/dev/null
codesign -f --deep -s - "${appPath}" 2>/dev/null
printf "\xE2\x9C\x94\x20\x43\x6F\x64\x65\x73\x69\x67\x6E\x65\x64\x20\x53\x70\x6F\x74\x69\x66\x79\n"
}
macos_codesign
}
}
@@ -1183,7 +1234,7 @@ newUiEx=(
'enableNavAltExperiment&Enable the new home structure and navigation",values:.,default:\K..DISABLED&true&&xpuiJs&1.1.94.864&1.1.96.785'
'enableNavAltExperiment2&Enable the new home structure and navigation",values:.,default:.\K.DISABLED&.ENABLED_CENTER&&xpuiJs&1.1.97.956&1.2.2.582'
'enablePanelSizeCoordination&Enable Panel Size Coordination between the left sidebar, the main view and the right sidebar",default:\K!.(?=})&true&s&xpuiJs&1.2.7.1264&1.2.50.335'
'enableRightSidebar&Enable the view on the right sidebar",default:\K!1&true&s&xpuiJs&1.1.98.683&1.2.23.1125&1.2.93.667'
'enableRightSidebar&Enable the view on the right sidebar",default:\K!1&true&s&xpuiJs&1.1.98.683&1.2.93.667'
'enableRightSidebarLyrics&Show lyrics in the right sidebar",default:\K!1&true&s&xpuiJs&1.2.0.1165'
'enableYLXSidebar&Enable Your Library X view of the left sidebar",default:\K!1&true&s&xpuiJs&1.1.97.962&1.2.13.661'
)
@@ -1354,7 +1405,7 @@ expEx=(
'enableMoreLikeThisPlaylist&More Like This playlist for playlists the user cannot edit",default:\K!1&true&s&xpuiJs&1.2.32.985&1.2.73.474'
'enableNearbyJams&support for Nearby Jams feature in the Device Picker",default:\K!1&true&s&xpuiJs&1.2.52.442'
'enableNewArtistEventsPage&Display the new Artist events page",default:\K!1&true&s&xpuiJs&1.2.18.997&1.2.32.997'
'enableNewConcertFeed&Enables new concert feed experience",default:\K!1&true&s&xpuiJs&1.2.37.701&1.2.42.290&1.2.50.335'
'enableNewConcertFeed&Enables new concert feed experience",default:\K!1&true&s&xpuiJs&1.2.37.701&1.2.50.335'
'enableNewConcertLocationExperience&new concert location experience modal selector.",default:\K!1&true&s&xpuiJs&1.2.34.783&1.2.42.290'
'enableNewEntityHeaders&New Entity Headers",default:\K!1&true&s&xpuiJs&1.2.15.826&1.2.28.0'
'enableNewEpisodes&new episodes view",default:\K!1&true&s&xpuiJs&1.1.84.716&1.2.62.580'
@@ -1383,7 +1434,7 @@ expEx=(
'enablePremiumUserForMiniPlayer&premium user flag for mini player",default:\K!1&true&s&xpuiJs&1.2.32.985'
'enablePrereleaseRadar&Show a curated list of upcoming albums to a user",default:\K!1&true&s&xpuiJs&1.2.39.578&1.2.45.454'
'enableProfileVisibilityControls&profile visibility controls in the settings . profile page",default:\K!1&true&s&xpuiJs&1.2.74.462&1.2.85.519'
'enableProgressBarEpisodeChapters&pisode chapters markers in the progress bar",default:\K!1&true&s&xpuiJs&1.2.68.525&1.2.74&1.2.74.477'
'enableProgressBarEpisodeChapters&pisode chapters markers in the progress bar",default:\K!1&true&s&xpuiJs&1.2.68.525&1.2.74.477'
'enableProgressBarRefactorWithChapters&refactored ProgressBar implementation with chapter support",default:\K!1&true&s&xpuiJs&1.2.74.462&1.2.82.428'
'enableQueueOnRightPanel&Enable Queue on the right panel.",default:\K!.(?=})&true&s&xpuiJs&1.2.26.1180&1.2.61.443'
'enableQueueOnRightPanelAnimations&animations for Queue on the right panel.",default:\K!.(?=})&true&s&xpuiJs&1.2.32.985&1.2.50.335'