Created
May 15, 2024 05:01
-
-
Save zaxbux/2ede5e3bc73156df63224bf8cd35f075 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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