Random wallpaper with just bash and systemd

I’m a big fan of Variety1, probably the most popular wallpaper changer among Linux users. It’s been sitting in my GNOME desktop’s system tray for a long time. (Yes, I know GNOME doesn’t actually have a system tray, but I can’t live without it so I installed Ubuntu’s AppIndicator and KStatusNotifierItem Support extension).

Recently, Variety started having some hiccups, for the simple reason that the API key it uses for Unsplash is shared among all Variety’s users, thus incurring rate limiting2. Since I don’t use most of Variety’s features, and I have only Unsplash enabled as image source, I scratched an itch by writing my own little wallpaper changer. Truth be told, it’s nothing fancy, but it does the job.

Here’s the Bash script (be sure to chmod +x it before running):

#!/usr/bin/env bash

TOPIC="bo8jQKTaE0Y" # "Wallpapers"

if ! photo_path="$(mktemp -p "${WALLPAPER_DIR}" "unsplash.com.XXXXXXXXXX.jpg")"
  >&2 echo "Error: failed to create temporary file."
  exit 1

if ! photo_url="$(curl --silent --show-error --header "Authorization: Client-ID ${ACCESS_KEY}" \
  "https://api.unsplash.com/photos/random?orientation=landscape&topic=${TOPIC}" \
  | grep --ignore-case --only-matching --perl-regexp '(?<=download":").*?(?=")')"
  >&2 echo "Error: failed to retrieve download URL."
  exit 1

if ! curl --silent --show-error --location --header "Authorization: Client-ID ${ACCESS_KEY}" \
  --output "${photo_path}" "${photo_url}"
  >&2 echo "Error: failed to download photo."
  exit 1

for setting_name in "background" "screensaver"; do
  if ! gsettings set "org.gnome.desktop.${setting_name}" "picture-uri" "file:///${photo_path}"
    >&2 echo "Error: failed to set photo as ${setting_name}."
    exit 1

As you can see, it does nothing more than downloading a random picture from Unplash’s Wallpapers topic, saving it to the user’s default backgrounds directory, and setting it as GNOME wallpaper. Additionally, it sets the picture as screen saver, so that it is displayed in the lock screen as well. One thing that could be added is purging old image files based on their modification time. This way, the backgrounds directory doesn’t grown boundlessly. For now, I’ll leave it as is.

Of course, the above script assumes that you use GNOME as desktop environment, and that you have obtained an API key from Unsplash3. The default, free “demo” mode is capped at 50 requests per hour, which is more than enough for this use case… Right?

If you prefer other topic(s) to pull photos from, here are their respective IDs:

Actually, you don’t even have to choose a topic. The ways in which the pool of photos can be narrowed down are explained in Unsplash’s API docs4.

Anyway, we’ve done only half of the job, as the script alone doesn’t automate wallpaper switching. The standard way of achieving that is a systemd service/timer combo. Since we’re only interested in running the script as regular, non-root user, unit files can be conveniently installed under ~/.config/systemd/user. Here is the service unit I use:

# ~/.config/systemd/user/wallchanger.service
Description=Change GNOME wallpaper


Of course, replace /path/to/wallchanger.sh with whatever the script’s path is. As mentioned, we also need a timer unit, which is responsible for the actual automation:

# ~/.config/systemd/user/wallchanger.timer
Description=Start wallchanger.service hourly



Notice that for this to work, the two unit files must have the same name (except for the .timer/.service suffix). You can change hourly to your preferred interval; for example, to switch wallpaper once a day, you can put daily. Systemd has its own way of specifying times and dates, so if you need something more complex, I encourage you to check systemd’s documentation5.

Once everything is in place, we need to tell systemd to reload its configuration with:

systemctl --user daemon-reload

Now, it’s time to test the service unit:

systemctl --user start wallchanger.service

If you don’t see any output, don’t despair, that’s the expected outcome! Actually, your desktop’s wallpaper should have already changed by now. If that’s not the case, you can inspect what’s going on with journalctl (add --follow to monitor the unit in realtime):

journalctl --user --unit wallchanger.service

Lastly, we need to enable and start the timer so that it is preseved across reboots:

systemctl enable --now wallchanger.timer

That’s all folks!

  1. https://peterlevi.com/variety/ ↩︎

  2. https://github.com/varietywalls/variety/issues/332 ↩︎

  3. https://unsplash.com/developers ↩︎

  4. https://unsplash.com/documentation#get-a-random-photo ↩︎

  5. https://www.freedesktop.org/software/systemd/man/systemd.time.html ↩︎