Skip to content

Instantly share code, notes, and snippets.

@zaxbux
Created May 15, 2024 05:01
Show Gist options
  • Save zaxbux/2ede5e3bc73156df63224bf8cd35f075 to your computer and use it in GitHub Desktop.
Save zaxbux/2ede5e3bc73156df63224bf8cd35f075 to your computer and use it in GitHub Desktop.
#!/bin/bash
indent() { sed 's/^/ /'; }
urldecode() { : "${*//+/ }"; echo -e "${_//%/\\x}"; }
# encode special characters per RFC 3986
urlencode() {
local LC_ALL=C # support unicode = loop bytes, not characters
local c i n=${#1}
for (( i=0; i<n; i++ )); do
c="${1:i:1}"
case "$c" in
#[-_.~A-Za-z0-9]) # also encode ;,/?:@&=+$!*'()# == encodeURIComponent in javascript
[-_.~A-Za-z0-9\;,/?:@\&=+\$!*\'\(\)#]) # dont encode ;,/?:@&=+$!*'()# == encodeURI in javascript
printf '%s' "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done
echo
}
plistExtractFmt() { plutil -extract "$1" "$2" -o - "$3"; }
plistDecodeBase64() { printf '%s' "$1" | base64 -d -i - ; }
plistExtractBase64() { plistDecodeBase64 "$1" | plutil -extract "$2" raw -o - -; }
getUserDefaultsExport() { sudo -u "$1" /usr/bin/defaults -currentHost export "$2" -; }
getUserDefaultsRead() { sudo -u "$1" /usr/bin/defaults -currentHost read "$2" "$3" -; }
getIdleTime() { sudo -u "$1" /usr/bin/defaults -currentHost read "com.apple.screensaver" idleTime; }
getBundleID() { mdls -name kMDItemCFBundleIdentifier -r "$1"; }
GetScreensaverModuleName() {
bundle_id=$1
case $bundle_id in
"com.apple.ScreenSaver.Ventura") printf "Ventura";;
"com.apple.ScreenSaver.Monterey") printf "Monterey";;
"com.apple.ScreenSaver.iLife-Slideshow-Extension") printf "iLifeSlideshows";;
"com.apple.screensaver.AlbumArtwork") printf "Album Artwork";;
"com.apple.Arabesque") printf "Arabesque";;
"com.apple.ScreenSaver.Drift") printf "Drift";;
"com.apple.Flurry") printf "Flurry";;
"com.apple.ScreenSaver.Hello") printf "Hello";;
"com.apple.Shell") printf "Shell";;
"com.apple.ScreenSaver.Computer-Name") printf "Computer Name";;
"com.apple.WordOfTheDay") printf "Word of the Day";;
"com.apple.ScreenSaver.Random") printf "Random";;
"com.apple.ScreenSaver.FloatingMessage") printf "Floating Message";;
esac
}
GetScreensaverSonoma() (
section=$1
sub_section=$2
wallpaper_store="/Users/${user}/Library/Application Support/com.apple.wallpaper/Store/Index.plist"
log "%s %s\n" "$wallpaper_store" "$(plutil -p "$wallpaper_store")"
GetSonomaAerialName() {
asset_id=$1
if [ "$asset_id" = "shuffle-all-aerials" ]; then echo "shuffle"; return; fi
entries=$(cat "$idleassetsd_path/Customer/entries.json")
read -r -d '' JXA <<-EOF
function run() {
var entries = JSON.parse(\`$entries\`);
var entry = entries.assets.find((asset) => asset.id === \`$asset_id\`) || entries.categories.find((asset) => asset.id === \`$asset_id\`);
return entry.localizedNameKey;
}
EOF
plistExtractFmt "$( osascript -l 'JavaScript' <<< "${JXA}" )" raw "$idleassetsd_path/Customer/TVIdleScreenStrings.bundle/en.lproj/Localizable.nocache.strings"
}
type=$(plistExtractFmt "${section}.Type" raw "$wallpaper_store")
case $type in
idle) section_full="${section}.Idle";;
individual) section_full="${section}.${sub_section}";;
linked) section_full="${section}.Linked";;
*) log "Unknown type: %s" "$type"; return;;
esac
content_choice_provider=$(plistExtractFmt "${section_full}.Content.Choices.0.Provider" raw "${wallpaper_store}")
content_choice_configuration=$(plistExtractFmt "${section_full}.Content.Choices.0.Configuration" raw "${wallpaper_store}")
log "%s.Content.Choices.0.Configuration %s\n" "${section_full}" "$( plistDecodeBase64 "$content_choice_configuration" | plutil -p - )"
GetSonomaAerialShuffle() {
section_type_shuffle="${section_full}.Content.Shuffle"
shuffle=$(plistExtractFmt "${section_type_shuffle}" raw "$wallpaper_store")
if [ "$shuffle" != "\$null" ]; then
shuffle=$(plistExtractFmt "${section_type_shuffle}.Type" raw "$wallpaper_store")
fi
case $shuffle in
afterDuration)
duration0=$(plistExtractFmt "${section_type_shuffle}.Duration.0" raw "$wallpaper_store")
duration1=$(plistExtractFmt "${section_type_shuffle}.Duration.1" raw "$wallpaper_store")
printf "afterDuration [%s, %s]" "$duration0" "$duration1"
;;
continuous) printf "%s" "continuous";;
"\$null") printf "%s" "null";;
*) printf "%s" "$shuffle";;
esac
}
GetAerialsProviderConfig() {
asset_id=$( plistExtractBase64 "$content_choice_configuration" assetID )
printf "Aerial: %s (%s)\n" "$(GetSonomaAerialName "$asset_id")" "$asset_id"
printf "Shuffle: %s\n" "$(GetSonomaAerialShuffle)"
}
GetScreenSaverProviderConfig() {
file=$(plistExtractBase64 "$content_choice_configuration" module.relative)
path=$(urldecode "$(echo "$file" | sed -E 's/^\s*.*:\/\///g')")
bundle_id=$(getBundleID "$path")
printf "Module: %s\n" "$(GetScreensaverModuleName "$bundle_id")"
printf "Settings:\n%s\n" "$(GetScreensaverSettings "$bundle_id")"
}
GetSonomaProviderConfig() {
printf "Screen Saver: Sonoma\n"
style=$(plistExtractBase64 "$content_choice_configuration" style)
printf "Style: ";
case $style in
0) printf "Automatic";;
2) printf "Light";;
3) printf "Dark";;
esac
printf " (%s)\n" "$style";
}
GetImageProviderConfig() {
file=$(plistExtractFmt "${section_full}.Content.Choices.0.Files.0.relative" raw "${wallpaper_store}")
path=$(urldecode "$(echo "$file" | sed -E 's/^\s*.*:\/\///g')")
printf "File: %s\n" "$path"
}
case $content_choice_provider in
"com.apple.wallpaper.choice.aerials") GetAerialsProviderConfig;;
"com.apple.wallpaper.choice.screen-saver") GetScreenSaverProviderConfig;;
"com.apple.wallpaper.choice.sonoma") GetSonomaProviderConfig;;
"com.apple.wallpaper.choice.image") GetImageProviderConfig;;
*) ;;
esac
)
GetScreensaverSettings() {
bundle_id=$1
case $bundle_id in
"com.apple.ScreenSaver.Ventura");;
"com.apple.ScreenSaver.Monterey");;
"com.apple.ScreenSaver.iLife-Slideshow-Extension")
selected_source=$(getUserDefaultsRead "$user" "com.apple.ScreenSaverPhotoChooser" "SelectedSource")
printf " Style: %s\n" "$(getUserDefaultsRead "$user" "com.apple.ScreenSaver.iLifeSlideshows" "styleKey")"
printf " Shuffle: %s\n" "$(getUserDefaultsRead "$user" "com.apple.ScreenSaverPhotoChooser" "ShufflesPhotos")"
case $selected_source in
3) printf " Source: Colors\n";;
4) printf " Source: Folder (%s)\n" "$(getUserDefaultsRead "$user" "com.apple.ScreenSaverPhotoChooser" "SelectedFolderPath")";;
6) printf " Source: iPhoto (%s)\n" "$(getUserDefaultsRead "$user" "com.apple.ScreenSaverPhotoChooser" "SelectedMediaGroup")";;
*) getUserDefaultsExport "$user" "com.apple.ScreenSaverPhotoChooser" | plutil -p -;;
esac
;;
#"com.apple.screensaver.AlbumArtwork");;
"com.apple.Arabesque");;
#"com.apple.ScreenSaver.Drift");;
#"com.apple.Flurry");;
#"com.apple.ScreenSaver.Hello");;
"com.apple.Shell");;
#"com.apple.ScreenSaver.Computer-Name");;
#"com.apple.WordOfTheDay");;
"com.apple.ScreenSaver.Random");;
#"com.apple.ScreenSaver.FloatingMessage");;
*) getUserDefaultsExport "$user" "$bundle_id" | plutil -p - | indent;;
esac
}
GetScreensaverCatalina() {
screensaver=$(sudo -u "$user" /usr/bin/defaults -currentHost export "com.apple.screensaver" -)
module_dict=$(printf "%s" "$screensaver" | plutil -extract moduleDict xml1 -o - -)
if [[ $osVerMajor -ge 12 ]]; then
# The 'raw' format was introduced in Monterey
module_name=$(printf "%s" "$screensaver" | plutil -extract moduleDict.moduleName raw -o - -)
path=$(printf "%s" "$screensaver" | plutil -extract moduleDict.path raw -o - -)
else
module_name=$(printf "%s" "$module_dict" | xmllint --xpath 'string(//key[text()="moduleName"]/following-sibling::*[1])' -)
path=$(printf "%s" "$module_dict" | xmllint --xpath 'string(//key[text()="path"]/following-sibling::*[1])' -)
fi
bundle_id=$(getBundleID "$path")
printf "Module: %s\n" "$module_name"
printf "Settings:\n%s\n" "$(GetScreensaverSettings "$bundle_id")"
}
Help()
{
echo "Add description of the script functions here."
echo
echo "Syntax: screensaver [-h|v] [-g|-s screensaver] [-u user]"
echo "options:"
echo "h Print this Help."
echo "v Verbose mode."
echo "u For user (must be root)"
echo "g Get screensaver"
echo "s Set screensaver"
echo "w Get wallpaper"
echo "d Set wallpaper"
echo
}
log() {
if [ "$verbose" = true ]; then
printf "$@"
echo ""
fi
}
GetScreensaver() {
printf "Idle Time: %s\n" "$(getIdleTime "$user")"
#printf "Display Off: %s, " ""
#printf "Lock Time: %s, " ""
if [[ $osVerMajor -ge 14 ]]; then
GetScreensaverSonoma "AllSpacesAndDisplays" "Idle"
#GgetScreensaverSonoma "SystemDefault" # usually just a copy of AllSpacesAndDisplays
else
GetScreensaverCatalina
fi
}
GetWallpaperSonoma() {
GetScreensaverSonoma "AllSpacesAndDisplays" "Desktop"
}
GetWallpaperCatalina() {
sudo -u "$user" /usr/bin/osascript -e 'tell app "finder" to get posix path of (get desktop picture as alias)'
}
GetWallpaper() {
if [[ $osVerMajor -ge 14 ]]; then
GetWallpaperSonoma "AllSpacesAndDisplays"
#GgetScreensaverSonoma "SystemDefault" # usually just a copy of AllSpacesAndDisplays
else
GetWallpaperCatalina
fi
}
SetWallpaper() {
sudo -u "$user" /usr/bin/osascript -e 'tell application "Finder" to set desktop picture to POSIX file "'"$1"'"'
ret=$?
if [ $ret == "0" ]; then
log "Wallpaper set successfully"
else
log "Wallpaper set failed"
fi
killall cfprefsd
}
createSettings() {
wallpaperPath=$(urlencode "$1")
screensaverPath=$(urlencode "$2")
wallpaperBase64="$(plutil -create binary1 - |
plutil -insert 'backgroundColor' -dictionary -o - - |
plutil -insert 'backgroundColor.colorSpace' -data "$(plutil -convert binary1 -o - - <<< "kCGColorSpaceGenericRGB" | base64)" -o - - |
plutil -insert 'backgroundColor.components' -array -o - - |
plutil -insert 'backgroundColor.components' -float '0.0' -append -o - - |
plutil -insert 'backgroundColor.components' -float '0.0' -append -o - - |
plutil -insert 'backgroundColor.components' -float '0.0' -append -o - - |
plutil -insert 'backgroundColor.components' -float 1 -append -o - - |
plutil -insert 'placement' -integer 1 -o - - |
base64)"
screensaverBase64="$(plutil -create binary1 - |
plutil -insert 'module' -dictionary -o - - |
plutil -insert 'module.relative' -string "file://${screensaverPath}" -o - - |
base64)"
currentRFC3339UTCDate="$(date -u '+%FT%TZ')"
xml="$(plutil -create xml1 - |
plutil -insert 'Desktop' -dictionary -o - - |
plutil -insert 'Desktop.Content' -dictionary -o - - |
plutil -insert 'Desktop.Content.Choices' -array -o - - |
plutil -insert 'Desktop.Content.Choices' -dictionary -append -o - - |
plutil -insert 'Desktop.Content.Choices.0.Configuration' -data "${wallpaperBase64}" -o - - |
plutil -insert 'Desktop.Content.Choices.0.Files' -array -o - - |
plutil -insert 'Desktop.Content.Choices.0.Files' -dictionary -append -o - - |
plutil -insert 'Desktop.Content.Choices.0.Files.0.relative' -string "file://${wallpaperPath}" -o - - |
plutil -insert 'Desktop.Content.Choices.0.Provider' -string 'com.apple.wallpaper.choice.image' -o - - |
plutil -insert 'Desktop.Content.Shuffle' -string '$null' -o - - |
plutil -insert 'Desktop.LastSet' -date "${currentRFC3339UTCDate}" -o - - |
plutil -insert 'Desktop.LastUse' -date "${currentRFC3339UTCDate}" -o - - |
plutil -insert 'Idle' -dictionary -o - - |
plutil -insert 'Idle.Content' -dictionary -o - - |
plutil -insert 'Idle.Content.Choices' -array -o - - |
plutil -insert 'Idle.Content.Choices' -dictionary -append -o - - |
plutil -insert 'Idle.Content.Choices.0.Configuration' -data "${screensaverBase64}" -o - - |
plutil -insert 'Idle.Content.Choices.0.Files' -array -o - - |
plutil -insert 'Idle.Content.Choices.0.Provider' -string 'com.apple.wallpaper.choice.screen-saver' -o - - |
plutil -insert 'Idle.Content.Shuffle' -string '$null' -o - - |
plutil -insert 'Idle.LastSet' -date "${currentRFC3339UTCDate}" -o - - |
plutil -insert 'Idle.LastUse' -date "${currentRFC3339UTCDate}" -o - - |
plutil -insert 'Type' -string 'individual' -o - -)"
echo "$xml"
}
createIndexPlist() {
xml=$1
path=$2
plutil -create binary1 - |
plutil -insert 'AllSpacesAndDisplays' -xml "${xml}" -o - - |
plutil -insert 'Displays' -dictionary -o - - |
plutil -insert 'Spaces' -dictionary -o - - |
plutil -insert 'SystemDefault' -xml "${xml}" -o "${path}" -
}
killWallpaperAgent() {
# Kill the wallpaperAgent to refresh and apply the screen saver/wallpaper settings.
echo "$(date) - Restarting wallpaper agent..."
killall WallpaperAgent
}
SetScreensaverSonoma() {
wallpaperPath=$1
screensaverPath=$2
wallpaperStoreDirectory="/Users/${user}/Library/Application Support/com.apple.wallpaper/Store"
wallpaperStoreFile="Index.plist"
wallpaperStoreFullPath="${wallpaperStoreDirectory}/${wallpaperStoreFile}"
# Create the path to the screen saver/wallpaper Index.plist.
mkdir -p "${wallpaperStoreDirectory}"
createIndexPlist "$(createSettings "$wallpaperPath" "$screensaverPath"))" "$wallpaperStoreFullPath"
killWallpaperAgent
}
SetScreensaverCatalina() {
sudo -u "$user" /usr/bin/defaults -currentHost write com.apple.screensaver moduleDict -dict-add moduleName "$1"
sudo -u "$user" /usr/bin/defaults -currentHost write com.apple.screensaver moduleDict -dict-add path "$2"
if [[ $osVerMajor -lt 10 || ( $osVerMajor -eq 10 && $osVerMinor -le 15 ) ]]; then
# Removes the .plist LaunchAgent from inside the User Launch Agent Folder. (todo: not sure which OS versions this is for)
rm -f "/Users/$user/Library/LaunchAgents/set-screensaver.plist"
fi
}
GetScreensaverModulePath() {
sonoma_prefix="/System/Library/ExtensionKit/Extensions"
catalina_prefix="/System/Library/Screen Savers"
case $1 in
"Ventura")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Ventura.appex"
elif [[ $osVerMajor -eq 13 ]]; then
path="$catalina_prefix/Ventura.saver"
fi
;;
"Monterey")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Monterey.appex"
elif [[ $osVerMajor -ge 12 ]]; then
path="$catalina_prefix/Monterey.saver"
fi
;;
"iLifeSlideshows")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/iLifeSlideshows.appex"
elif [[ $osVerMajor -lt 10 || ( $osVerMajor -eq 10 && $osVerMinor -lt 14 ) || ( $osVerMajor -eq 10 && $osVerMinor -eq 14 && $osVerPatch -lt 2 ) ]]; then
path="/System/Library/Frameworks/ScreenSaver.framework/Resources/iLifeSlideshows.saver"
else
path="/System/Library/Frameworks/ScreenSaver.framework/PlugIns/iLifeSlideshows.appex"
fi
;;
"Album Artwork")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Album Artwork.appex"
else
path="$catalina_prefix/Album Artwork.saver"
fi
;;
"Arabesque")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Arabesque.appex"
else
path="$catalina_prefix/Arabesque.saver"
fi
;;
"Drift")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Drift.appex"
else
path="$catalina_prefix/Drift.saver"
fi
;;
"Flurry")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Flurry.appex"
else
path="$catalina_prefix/Flurry.saver"
fi
;;
"Hello")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Hello.appex"
else
path="$catalina_prefix/Hello.saver"
fi
;;
"Shell")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Shell.appex"
else
path="$catalina_prefix/Shell.saver"
fi
;;
"Computer Name")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Computer Name.appex"
elif [[ $osVerMajor -gt 11 || ($osVerMajor -eq 11 && $osVerMinor -gt 5) || ($osVerMajor -eq 11 && $osVerMinor -eq 5 && $osVerPatch -ge 2) ]]; then
path="/System/Library/Frameworks/ScreenSaver.framework/PlugIns/Computer Name.appex"
fi
;;
"Word of the Day")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/Word of the Day.appex"
else
path="$catalina_prefix/Word of the Day.saver"
fi
;;
"Random")
path="/System/Library/Screen Savers/Random.saver"
;;
"Floating Message")
if [[ $osVerMajor -ge 14 ]]; then
path="$sonoma_prefix/FloatingMessage.saver"
else
path="$catalina_prefix/Floating Message.saver"
fi
;;
*) ;;
esac
printf "%s" "$path"
}
SetScreensaver() {
screensaver=$1
screensaverPath=$(GetScreensaverModulePath "$screensaver")
wallpaperPath=$(GetWallpaperCatalina)
log "Setting screensaver to %s (%s) for %s" "$screensaver" "$screensaverPath" "$user"
if [ -n "$screensaverPath" ]; then
if [[ $osVerMajor -ge 14 ]]; then
SetScreensaverSonoma "$wallpaperPath" "$screensaverPath"
else
SetScreensaverCatalina "$screensaverPath"
fi
fi
}
verbose=false
user=$(/usr/bin/stat -f "%Su" /dev/console)
osVersion=$(/usr/bin/sw_vers -productVersion)
osVerMajor=$(echo "$osVersion" | /usr/bin/awk -F"." '{print $1}')
osVerMinor=$(echo "$osVersion" | /usr/bin/awk -F"." '{print $2}')
osVerPatch=$(echo "$osVersion" | /usr/bin/awk -F"." '{print $3}')
idleassetsd_path="/Library/Application Support/com.apple.idleassetsd"
Interactive() {
while getopts ":hvgs:wd:u:" option; do
case $option in
h) # display Help
Help
exit;;
v) verbose=true;;
g) action="getScreensaver";;
s) action="setScreensaver"; screensaver=${OPTARG};;
w) action="getWallpaper";;
d) action="setWallpaper"; wallpaper=${OPTARG};;
u) user=${OPTARG};;
\?) echo "Error: Invalid option" >&2; exit 1;;
:) echo "$0: Error: option -${OPTARG} requires an argument" >&2; exit 1;;
esac
done
shift $((OPTIND - 1))
case $action in
getScreensaver) GetScreensaver;;
setScreensaver) SetScreensaver "$screensaver";;
getWallpaper) GetWallpaper;;
setWallpaper) SetWallpaper "$wallpaper";;
esac
}
#GetScreensaver
#SetScreensaver
Interactive "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment