[bin] Add macOS script for setting bing wallpaper

This commit is contained in:
2025-06-09 10:50:03 -04:00
parent 939adbee42
commit bbcc16b8f1

352
bin/.bin/bing-wallpaper.sh Executable file
View File

@ -0,0 +1,352 @@
#!/bin/sh
PATH=/usr/local/bin:/usr/local/sbin:~/bin:/usr/bin:/bin:/usr/sbin:/sbin
readonly SCRIPT=$(basename "$0")
readonly VERSION='1.1.1'
RESOLUTIONS=(1920x1200 1920x1080 1024x768 1280x720 1366x768 UHD)
MONITOR="0" # 0 means all monitors
PLIST_FILE="$HOME/Library/LaunchAgents/com.bing-wallpaper-daily-mac-multimonitor"
AUTO_UPDATE_NAME="default"
ARGS=$@
usage() {
cat <<EOF
Usage:
$SCRIPT [options]
$SCRIPT -h | --help
$SCRIPT --version
Options:
enable-auto-update Enable automatic update of wallpapers every day
the picture if the filename already exists.
disable-auto-update Disable automatic update of wallpapers every day
the picture if the filename already exists.
info Show description of current wallpaper.
--auto-update-name <name> Name of your auto update when enabling/disabling
Using custom name enables setting multiple automatic update configurations.
Eg. Set on monitor 1 todays wallpaper and on monitor 2 wallpaper from yesterday
-f --force Force download of picture. This will overwrite
the picture if the filename already exists.
-s --ssl Communicate with bing.com over SSL.
-q --quiet Do not display log messages.
-c --country <coutry-tag> Specify market country/region eg. en-US, cs-CZ
Pictures may be different for markets on some days.
See full list of countries on https://learn.microsoft.com/en-us/previous-versions/bing/search/dd251064(v=msdn.10)
-d --day <number> Day for which you want to get the picture.
0 is current day, 1 is yesterday etc.
Default is 0.
-n --filename <file name> The name of the downloaded picture. Defaults to
the upstream name.
-p --picturedir <picture dir> The full path to the picture download dir.
Will be created if it does not exist.
[default: $HOME/Pictures/bing-wallpapers/]
-r --resolution <resolution> The resolution of the image to retrieve.
Supported resolutions: ${RESOLUTIONS[*]}
--resolutions <resolutions> The resolutions of the image try to retrieve.
eg.: --resolutions "1920x1200 1920x1080 UHD"
-m --monitor <num> Set wallpaper only on certain monitor (1,2,3...)
--all-desktops-experimental Set wallpaper on all desktops
Fixing osascript bug when wallpaper is not set for Desktop 2.
Known issue: Minimized apps are removed from Dock.
If something goes wrong delete Library/Application Support/Dock/desktoppicture.db
and restart your Mac.
-h --help Show this screen.
--version Show version.
EOF
}
create_plist_in_users_agents_folder() {
local SCRIPT_PATH=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )/$(basename "${BASH_SOURCE:-$0}")
local REST_ARGS=$(echo "$ARGS" | sed -e "s/enable-auto-update//")
if [ $RUN_USING_NPX ]; then
local COMMANDS="<string>source ~/.bashrc && npx --yes bing-wallpaper-daily-mac-multimonitor@latest $REST_ARGS</string>"
else
local COMMANDS="<string>$SCRIPT_PATH $REST_ARGS</string>"
fi
cat > $PLIST_FILE <<- EOM
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.bing-wallpaper-daily-mac-multimonitor.plist</string>
<key>OnDemand</key>
<true/>
<key>ProgramArguments</key>
<array>
<string>/bin/sh</string>
<string>-c</string>
$COMMANDS
</array>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/local/sbin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
<key>StandardErrorPath</key>
<string>/tmp/bing-wallpaper-daily-mac-multimonitor-plist.err</string>
<key>StandardOutPath</key>
<string>/tmp/bing-wallpaper-daily-mac-multimonitor-plist.out</string>
<key>StartInterval</key>
<integer>1800</integer>
<key>RunAtLoad</key>
<true/>
</dict>
</plist>
EOM
launchctl unload -w $PLIST_FILE 2>/dev/null
launchctl load -w $PLIST_FILE
}
remove_plist_in_users_agents_folder() {
launchctl unload -w "$PLIST_FILE" 2>/dev/null
rm "$PLIST_FILE"
}
show_info_text() {
# Parse HPImageArchive API and acquire picture BASE URL
COPYRIGHT=$(cat "$PICTURE_DIR/info.xml" | \
grep -Eo "<copyright>.*<\/copyright>")
COPYRIGHT=$(echo "$COPYRIGHT" | sed -e "s/<copyright>//")
COPYRIGHT=$(echo "$COPYRIGHT" | sed -e "s/<\/copyright>//")
echo $COPYRIGHT
}
print_message() {
if [ ! "$QUIET" ]; then
printf "%s\n" "$(date): ${1}"
fi
}
download_image_curl () {
local RES=$1
FILEURLWITHRES="${FILEURL}_${RES}.jpg"
echo $FILEURLWITHRES
FILENAME=${FILEURLWITHRES/\/th\?id=/}
FILENAME_LOCAL="${AUTO_UPDATE_NAME}-${FILENAME}"
FILEWHOLEURL="$PROTO://bing.com/$FILEURLWITHRES"
if [ $FORCE ] || [ ! -f "$PICTURE_DIR/$FILENAME_LOCAL" ]; then
find $PICTURE_DIR -type f -iname $AUTO_UPDATE_NAME-\*.jpg -delete
print_message "Downloading: $FILENAME..."
curl --fail -Lo "$PICTURE_DIR/$FILENAME_LOCAL" "$FILEWHOLEURL"
curl --fail -Lo "$PICTURE_DIR/info.xml" "$BING_HP_IMAGE_ARCHIVE_URL"
if [ "$?" == "0" ]; then
FILEPATH="$PICTURE_DIR/$FILENAME_LOCAL"
return
fi
FILEPATH=""
return
else
print_message "Skipping download: $FILENAME_LOCAL..."
FILEPATH="$PICTURE_DIR/$FILENAME_LOCAL"
DOWNLOAD_SKIPPED=true
return
fi
}
set_wallpaper () {
local FILEPATH=$1
local MONITOR=$2
if [ "$MONITOR" -ge 1 ] 2>/dev/null; then
print_message "Setting wallpaper for monitor: $MONITOR"
osascript - << EOF
set tlst to {}
tell application "System Events"
set tlst to a reference to every desktop
set picture of item $MONITOR of tlst to "$FILEPATH"
end tell
EOF
else
osascript -e 'tell application "System Events" to tell every desktop to set picture to "'$FILEPATH'"'
fi
}
set_wallpaper_experimental () {
local db_file="Library/Application Support/Dock/desktoppicture.db"
local db_path="$HOME/$db_file"
# Put the image path in the database
local sql="insert into data values(\"$FILEPATH\"); "
sqlite3 "$db_path" "$sql"
# Get the index of the new entry
local sql="select max(rowid) from data;"
local new_entry=$(sqlite3 "$db_path" "$sql")
local new_entry=$(echo $new_entry|tr -d '\n')
# Get all picture ids (monitor/space pairs)
local sql="select rowid from pictures;"
local pictures_string=$(sqlite3 "$db_path" "$sql")
local IFS=$'\n'
local pictures=($pictures_string)
# Clear all existing preferences
local sql="select max(rowid) from data; delete from preferences; "
for pic in "${pictures[@]}"
do
if [ "$pic" ]; then
local sql+="insert into preferences (key, data_id, picture_id) "
local sql+="values(1, $new_entry, $pic); "
fi
done
sqlite3 "$db_path" "$sql"
killall "Dock"
}
# Defaults
PICTURE_DIR="$HOME/Pictures/bing-wallpapers/"
# Option parsing
while [[ $# -gt 0 ]]; do
key="$1"
case $key in
enable-auto-update)
ENABLE_AUTOMATIC_UPDATE=true
;;
disable-auto-update)
DISABLE_AUTOMATIC_UPDATE=true
;;
info)
INFO=true
;;
--auto-update-name)
AUTO_UPDATE_NAME="$2"
shift
;;
-r|--resolution)
RESOLUTION="$2"
shift
;;
-p|--picturedir)
PICTURE_DIR="$2"
shift
;;
-c|--country)
COUNTRY="$2"
shift
;;
-d|--day)
DAY="$2"
shift
;;
-n|--filename)
FILENAME="$2"
shift
;;
-m|--monitor)
MONITOR="$2"
shift
;;
-f|--force)
FORCE=true
;;
-s|--ssl)
SSL=true
;;
-q|--quiet)
QUIET=true
;;
-h|--help)
usage
exit 0
;;
--resolutions)
RESOLUTIONS="$2"
shift
;;
--all-desktops-experimental)
EXPERIMENTAL=true
;;
--version)
printf "%s\n" $VERSION
exit 0
;;
*)
(>&2 printf "Unknown parameter: %s\n" "$1")
usage
exit 1
;;
esac
shift
done
# Set options
[ $QUIET ] && CURL_QUIET='-s'
[ $SSL ] && PROTO='https' || PROTO='http'
[ $DAY ] && IDX=$DAY || IDX='0'
BING_HP_IMAGE_ARCHIVE_URL="https://www.bing.com/HPImageArchive.aspx?format=xml&idx=${IDX}&n=1"
[ $COUNTRY ] && BING_HP_IMAGE_ARCHIVE_URL="${BING_HP_IMAGE_ARCHIVE_URL}&mkt=${COUNTRY}"
PLIST_FILE="${PLIST_FILE}-${AUTO_UPDATE_NAME}.plist"
PARENT_COMMAND=$(ps -o comm= $PPID)
if [[ "$PARENT_COMMAND" == *"npm exec"* ]]; then
RUN_USING_NPX=true
fi
if [ "$ENABLE_AUTOMATIC_UPDATE" ]; then
# enable update
create_plist_in_users_agents_folder
echo "Automatic wallpaper update enabled"
exit 1
fi
if [ "$DISABLE_AUTOMATIC_UPDATE" ]; then
# disable update
remove_plist_in_users_agents_folder
echo "Automatic wallpaper update disabled"
exit 1
fi
if [ "$INFO" ]; then
show_info_text
exit 1
fi
# Create picture directory if it doesn't already exist
mkdir -p "${PICTURE_DIR}"
# Parse HPImageArchive API and acquire picture BASE URL
FILEURL=( $(curl -sL $BING_HP_IMAGE_ARCHIVE_URL | \
grep -Eo "<urlBase>.*?</urlBase>") )
FILEURL=$(echo "$FILEURL" | sed -e "s/<urlBase>//")
FILEURL=$(echo "$FILEURL" | sed -e "s/<\/urlBase>//")
if [ $RESOLUTION ]; then
download_image_curl $RESOLUTION
if [ "$FILEPATH" ]; then
if [ "$EXPERIMENTAL" ]; then
if [ ! "$DOWNLOAD_SKIPPED" ]; then
set_wallpaper_experimental $FILEPATH
fi
else
set_wallpaper $FILEPATH $MONITOR
fi
fi
exit 1
fi
for RESOLUTION in "${RESOLUTIONS[@]}"
do
download_image_curl $RESOLUTION
if [ "$FILEPATH" ]; then
if [ "$EXPERIMENTAL" ]; then
if [ ! "$DOWNLOAD_SKIPPED" ]; then
set_wallpaper_experimental $
fi
else
set_wallpaper $FILEPATH $MONITOR
fi
exit 1
fi
done