Rotate your desktop wallpaper using photos pulled live from your own Immich library — filtered by album or person, changed on whatever interval you like, with a system tray icon for status and quick controls.
Two portrait photos are automatically paired side-by-side into a single composite when your screen resolution can be detected; landscape/square photos are shown singly.
Only ever a handful of images sit on disk at once — the app asks Immich's API for a random photo on each rotation and keeps a small rolling window (your choice how many) rather than syncing your whole library locally.
- Config UI (
config_ui.py) — a local web page (bind to127.0.0.1only) for entering your Immich server URL/API key, picking albums and/or people to pull from, and setting the rotation interval and how many images to keep on disk. - Rotator (
rotate.py) — does the actual work: picks a random photo (or two portraits, paired), downloads it, sets it as the desktop wallpaper, and keeps a bounded back/forward history. - Tray icon (
tray_app.py) — shows live status (active / paused / error), lets you step back/forward through recently-shown photos, open the current photo in Immich's web viewer, save a copy elsewhere, refresh on demand, pause/resume, and jump to settings. - Desktop support: KDE Plasma (via D-Bus scripting — no QtWebEngine
involved) and XFCE (via
xfconf-query/xrandr). Desktop is auto-detected at runtime. - On-image overlays (optional, off by default) — inspired by
Immich Kiosk: a discreet
caption per photo (people names, location, date taken, stacked top to
bottom) and/or today's date in the corner. Baked into the image at each
rotation rather than rendered live, since this is a static wallpaper, not
a web page. Margins automatically clear any taskbar/panel the desktop
reports via the
_NET_WORKAREAX11 property (works through XWayland on Wayland KDE sessions too), on top of a base 0.5" edge margin computed from the display's real DPI. - No syncing, no local mirror of your library — everything is fetched on-demand from Immich's REST API.
sudo apt install ./immich-wallpaper_<version>_all.deb
(or build it yourself — see packaging/debian/build.sh)
This pulls in python3-pystray, python3-pil, python3-gi,
gir1.2-ayatanaappindicator3-0.1, and x11-xserver-utils (for xrandr,
needed on XFCE) automatically, installs the app under
/usr/share/immich-wallpaper/, and registers /etc/xdg/autostart so the
tray icon starts on login for any user.
cd packaging/arch
makepkg -si
All dependencies (python-pystray and xorg-xrandr, needed on XFCE,
included) are in the official extra repo, so plain makepkg -si
resolves everything — no AUR helper needed. Verified building/installing
on Manjaro.
Needs Python 3.8+, Pillow, pystray, PyGObject, an AppIndicator provider,
and (on XFCE) xrandr. On Debian/Ubuntu:
sudo apt install python3-pystray python3-pil python3-gi gir1.2-ayatanaappindicator3-0.1 x11-xserver-utils
python3 tray_app.py
The tray app drives its own periodic rotation internally (no cron/systemd timer needed) — as long as it's running, it self-paces against the interval you set in the config UI.
- Run the tray icon (or
python3 config_ui.pydirectly) and openhttp://127.0.0.1:8877. - Enter your Immich server URL and an API key. Create the key under
Account Settings → API Keys in Immich, and grant only:
asset.read,asset.download,album.read,person.read— no write/delete/admin scopes needed. (If your Immich version doesn't offer granular scopes, an all-permissions key also works.) - Test the connection, then load and pick albums and/or people to filter by (leave both empty to pull from your whole library).
- Set the rotation interval and how many images to keep on disk, save.
- From the tray icon menu: Refresh now to pull the first photo, or just wait for the interval to elapse.
On each rotation, a batch of random candidates (filtered by your
album/person selection) is fetched with EXIF data. If the first pick is
portrait-oriented and the screen resolution can be detected, a second
portrait from the same batch is paired with it into one composite image
sized exactly to your screen (via KDE's screenGeometry() scripting API,
or xrandr on XFCE). Otherwise the photo is shown singly, letting the
desktop's own wallpaper fill mode handle scaling.
libayatana-appindicator is deprecated (please use libayatana-appindicator-glib in newly written code)— you may see this printed when starting the tray icon by hand. It's emitted by the system'slibayatana-appindicatorC library itself, the momentpystrayloads itsAyatanaAppIndicator3GObject-Introspection binding — not by anything in this project.pystraydoesn't yet support the newerlibayatana-appindicator-glib, which also has no widely-packaged Python/GI binding yet, so there's nothing to switch to. Harmless; the tray icon works normally.
MIT — see LICENSE.
The Immich flower logo used in the tray icon is Immich's own trademark, used here only to indicate integration with their project — this is an independent, unofficial companion tool and isn't affiliated with or endorsed by the Immich project.