#!/bin/sh # Sets your Mac's desktop picture to the image published next to this script. # # All the code is inside main() so that a partial download runs nothing. die() { echo "bgmac: $1" >&2 exit 1 } main() { set -eu base_url="${BG_BASE_URL:-https://bgmac.pages.dev}" image="standard_pride-flagg.png" dry_run="${BG_DRY_RUN:-0}" [ "$(uname -s)" = "Darwin" ] || die "this only works on macOS for now." [ "$(id -u)" -ne 0 ] || die "run this without sudo, it changes your own desktop." dest_dir="$HOME/Library/Application Support/bgmac" tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT echo "Downloading image..." curl -fsSL "$base_url/$image" -o "$tmp/wallpaper.png" \ || die "could not download the image." sips -g pixelWidth "$tmp/wallpaper.png" 2>/dev/null | grep -q "pixelWidth: [0-9]" \ || die "the downloaded file is not a valid image." # The picture has to stay on disk for macOS to keep showing it. The hash in # the name makes macOS notice when a new image is published. hash="$(shasum -a 256 "$tmp/wallpaper.png" | cut -c1-12)" dest="$dest_dir/wallpaper-$hash.png" mkdir -p "$dest_dir" mv -f "$tmp/wallpaper.png" "$dest" # NSWorkspace needs no Automation permission, unlike System Events or Finder. screens="$(osascript -l JavaScript - "$dest" "$dry_run" <<'JS' ObjC.import('AppKit'); function run(argv) { var url = $.NSURL.fileURLWithPath(argv[0]); var dryRun = argv[1] === '1'; var workspace = $.NSWorkspace.sharedWorkspace; var screens = $.NSScreen.screens; var count = screens.count; if (count === 0) throw new Error('no displays found'); if (typeof workspace.setDesktopImageURLForScreenOptionsError !== 'function') { throw new Error('this macOS version does not offer the wallpaper API'); } if (!dryRun) { for (var i = 0; i < count; i++) { var error = Ref(); var ok = workspace.setDesktopImageURLForScreenOptionsError( url, screens.objectAtIndex(i), $.NSDictionary.alloc.init, error); if (!ok) throw new Error(ObjC.unwrap(error[0].localizedDescription)); } } return count; } JS )" || die "macOS refused to change the desktop picture." if [ "$dry_run" = "1" ]; then echo "Dry run: found $screens display(s), nothing changed." return fi # Only our own older copies. The current one is still in use. find "$dest_dir" -maxdepth 1 -name 'wallpaper-*.png' ! -name "wallpaper-$hash.png" -delete echo "Done! New desktop picture on $screens display(s)." } main "$@"