- Python 70.5%
- Shell 29.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| fonts | ||
| .gitignore | ||
| bootstrap.sh | ||
| CHANGELOG.txt | ||
| fetch_url.py | ||
| install.sh | ||
| LICENSE | ||
| pipelines.py | ||
| README.md | ||
| screen.py | ||
| setter.py | ||
| sources.py | ||
| waifuwall.sh | ||
| wall_worker.py | ||
WaifuWall — Waifu Wallpaper Setter
Fetches waifu wallpapers (landscape or portrait) and sets them as your KDE Plasma desktop wallpaper. Modeled on waifufetch: persistent per-orientation, per-pipeline playlists, a detached flock-guarded background worker, a raw + processed cache, layered processing pipes, and fit-to-display at apply time.
Each distinct pipeline combination — the pipes and their parameter values
(--sharpen 50 vs --sharpen 70) and their order/repetition
(--blur 5 --ascii vs --ascii --blur 5, and a repeated --blur 5 --blur 30
= two blur passes at different radii) — owns its own cache namespace and
playlist, so waifuwall --ascii and waifuwall --pipe ascii in a
cronjob/zshrc stay separate and reusable. Cached images are stored at the
canonical (primary display) size; at apply time the image is handed to Plasma
as-is and Plasma's FillMode (cover/contain/stretch) fits it to each screen.
raw → [pipes] → canonical fit → images/<orient>/ns_<hash>/ww_*.png → Plasma (FillMode fits)
Install
git clone ssh://git@forgejo.fifthdread.com:223/Fifthdread/waifu_wall.git
cd waifuwall && ./install.sh
# or, from the paru repo:
paru -S waifuwall-git
First run seeds 5 landscape wallpapers in the background and sets one immediately.
Usage
waifuwall next cached wallpaper (advances the playlist)
waifuwall -r, --raw fetch one fresh wallpaper now and apply it
waifuwall -s, --search TERM fetch a wallpaper matching TERM (tag/search)
waifuwall -d, --delete delete the wallpaper on the terminal's display
(raw+processed) from every namespace of its
orientation, ban it forever, and show the next
cached wallpaper (on that display only)
waifuwall -x, --next cycle to the next cached wallpaper on the
terminal's display, in the SAME pipeline as the
current one (the on-screen image's namespace
carries its exact parameters); errors when the
display can't be detected or isn't showing a
waifuwall wallpaper
waifuwall --add|-n|--new N [SOURCE]
fetch N more images in the background into the
resolved playlist (never a new playlist; no N = 5;
trailing SOURCE pins the provider, e.g. --add 20 comfyui)
waifuwall --source NAME pin the source for this run: waifuim | nekos |
comfyui (works with --raw/--search/--add; overrides config)
waifuwall -p, --playlist NAME
force a specific playlist (ns_<NAME>) instead of
one derived from the pipeline (e.g. --playlist comfy_ai)
waifuwall --image FILE|DIR set the wallpaper to one image, or a random one
from a directory (runs the pipeline when one is
defined via flags or config; no playlist/cache)
waifuwall --reformat [FMT] re-encode all processed cache files to FMT
(png|webp|jxl; default: the configured format)
waifuwall --reprocess re-render every cached wallpaper in the resolved
playlist(s) through THIS run's pipeline, in place
(same filenames — playlist/.pos stay valid; raws
and provenance untouched; a failed render keeps
the original). Pair with pipeline flags to
re-stamp the cache (e.g. --reprocess --ai-upscale);
--per-display covers both orientations
waifuwall --deny-list print the denylist (banned image hashes)
waifuwall -i, --info provenance of the wallpaper on the terminal's
display: source (waifuim|nekos|comfyui), the comfyui
workflow + collection + seeds, pipeline, URL, when
fetched (--screen N targets another display)
waifuwall --landscape force the landscape orientation cache
waifuwall --portrait force the portrait orientation cache
waifuwall --pipe P[,P...] processing pipes for this run (overrides config)
waifuwall --no-process skip all pipes (canonical fit only)
waifuwall --fit MODE cover | contain | stretch (applied at display time)
waifuwall --ascii ASCII-art wallpaper (same as --pipe ascii)
waifuwall --ascii-style MODE mono|color (overrides [ascii] style)
waifuwall --ascii-background solid|backdrop (overrides [ascii] background)
waifuwall --ascii-size N Spleen px height (overrides [ascii] font_size)
waifuwall --sharpen [N] sharpen pipe; N = unsharp-mask percent
waifuwall --enhance [N] enhance pipe; N = contrast/color multiplier
waifuwall --upscale [N] upscale pipe; N = lanczos scale factor
waifuwall --crop [RATIO] crop pipe; RATIO = aspect (16:9/4:3/auto)
waifuwall --saturate [N] saturate pipe; N = saturation multiplier
waifuwall --pipes list available processing pipes
waifuwall --pipelines list existing pipeline namespaces
waifuwall --per-display one wallpaper per connected display (each matched to
its own orientation and resolution)
waifuwall -S, --shuffle shuffle the current pipeline's playlist
waifuwall -c, --clear-cache wipe all cached images (every pipeline); with
pipeline flags or -p NAME, only that namespace
waifuwall -v, --version
waifuwall -h, --help
Each pipeline flag (and each different value, and each ordering/repetition)
selects a separate playlist/cache. Pipeline flags run as ordered, repeatable
passes, left to right: waifuwall --enhance --blur 5 --ascii color --blur 30 --ascii color enhances, then blurs 5, then renders ASCII in color, then blurs
30, then renders ASCII in color again. waifuwall --ascii cached-run shows the
next cached ASCII wallpaper; run it in a cronjob or your zshrc and it keeps
advancing that pipeline's playlist. Omit values to use the config defaults
(--sharpen = [pipe] sharpen).
With no orientation flag, the primary display (kscreen-doctor priority-1
output) decides landscape vs portrait so the pull matches your screen.
--per-display works in all modes (cached/raw/search); with --raw it
fetches one fresh image per display. Plasma fills each cache image to its
screen via FillMode, so mixed-resolution displays share a pipeline's playlist.
Processing pipelines
Pipes run in the order typed, each flag as its own pass on the output of
the previous one, then a canonical-size (cover) fit normalizes the result for
the cache. The display-specific fit is left to Plasma's FillMode at apply time.
Repeated flags are separate passes with their own values: --blur 5 --blur 30
blurs at radius 5, then at radius 30. When no --pipe is given, the config
pipeline list runs first as a merge-base prefix — the first flag occurrence
of a listed pipe merges its value into that pass (config ["blur"] + --blur 30
is still one blur at 30), while later same-name flags add new passes.
| pipe | effect |
|---|---|
cutout |
rembg isnet-anime background removal (lazy install) |
blurpad |
pad to display aspect with a blurred self-backdrop |
trim |
auto-crop transparent borders |
saturate |
boost color saturation (amount) |
sharpen |
unsharp-mask sharpening (percent) |
enhance |
contrast + color boost (multiplier) |
upscale |
lanczos upscale (factor) |
ai-upscale |
Real-ESRGAN neural upscale (mode anime|photo; needs realesrgan-ncnn-vulkan) |
crop |
center-crop to an aspect ratio |
ascii |
ASCII-art conversion (style mono |
cutout is not part of the default pipeline; enable it per-run with
--pipe cutout or set pipeline = ["cutout"] in config (rembg is
pip-installed on first use).
Cache layout
~/.config/waifuwall/
config.toml
images/
landscape/
ns_<hash>/ .playlist .pos .fetch.lock .playlist.lock spec.json
ww_*.<ext> (processed; format = webp/png/jxl)
raw/ww_*.png (verbatim download)
ns_<hash2>/ ... (each distinct pipeline combination)
portrait/ same shape
ns_<hash> is the sha256 of the canonical effective pipeline spec (pipes +
parameter values, config defaults merged). spec.json holds the readable
spec; --pipelines lists every namespace with its spec. Raw and processed
files share a UUID stem so they pair up (raw is always <stem>.png; processed
is <stem>.<format>). -d removes the shown image from every
namespace of its orientation (raw + processed + playlist entries) and records
its content hash (sha256 of the raw bytes) in ~/.config/waifuwall/denylist.txt
— the image is then never re-downloaded or re-adopted. --deny-list prints
the denylist; remove a line to allow that image again. Legacy pre-namespace
caches are migrated into the default (empty-pipeline) namespace on first run.
Config (~/.config/waifuwall/config.toml)
cap = 50
source = "waifuim"
orientation = "auto" # auto | landscape | portrait
fit = "cover" # cover | contain | stretch (Plasma FillMode at apply)
format = "webp" # processed cache format: webp (default) | png | jxl
pipeline = [] # e.g. ["ascii", "blurpad"]
[pipe]
saturate = 1.3 # saturate: color-saturation multiplier
sharpen = 100 # sharpen: unsharp-mask percent
enhance = 1.2 # enhance: contrast + color boost multiplier
upscale = 2 # upscale: lanczos scale factor
crop = "" # crop: center-crop aspect ("16:9"/"4:3"; ""=display)
ai_upscale = "anime" # ai-upscale: Real-ESRGAN mode (anime|photo)
[ascii]
style = "mono" # mono (single fg) | color (sampled per-char)
background = "backdrop" # solid (hex bg) | backdrop (blurred/dimmed source)
font = "spleen" # spleen (bundled) | mono (DejaVu TTF) | TTF path
font_size = 16 # spleen: nearest px height (12/16/24/32/64)
columns = 200 # grid width for scalable fonts (spleen: derived)
invert = false
gamma = 2.0 # luminance curve; >1 keeps backgrounds dark
contrast = 1.0
bg = "#0f0f0f" # used when background = "solid"
fg = "#b0b0b0" # character color for style = "mono"
[display]
backend = "plasma" # plasma (default) | copy | feh
width = 0 # 0 = auto-detect from primary display
height = 0
[sources.waifuim]
is_nsfw = false
gif = false
included_tags = ""
excluded_tags = ""
order_by = "random"
api_key = ""
[sources.nekos]
category = "waifu"
[sources.comfyui]
base_url = ""
api_key = ""
workflow_dir = ""
portrait = []
landscape = []
collection = ""
random_seed = true
match_orientation = true
gen_timeout = 600
Sources
- waifu.im (default) — orientation-aware (LANDSCAPE/PORTRAIT/ALL), tag filtering, NSFW opt-in, optional API key.
- nekos.best — category-based (waifu, neko, ...); portrait/square-leaning, no orientation param (landscape pulls get cover/blurpad handling).
- comfyui — generate images via a ComfyUI server. Workflows are API-format
JSON exports ("Save (API Format)") in
workflow_dir(default~/.config/waifuwall/workflows/), with separateportrait/landscapename lists per orientation (empty = all).collection(empty = top level) names a subfolder used as an opt-in collection pool — e.g.collection = "succubus"usesworkflow_dir/succubus/*.json;waifuwall --collection succubus --rawforces it for one run and--list-collectionslists the subfolders.random_seed(default on) randomizes seeds so each generation is fresh;match_orientation(default on) swaps the latent to the run's orientation;gen_timeoutcaps one generation (seconds).base_urlis the ComfyUI endpoint,api_keyoptional. - Multi-source —
sourcemay be a weighted table, e.g.source = { waifuim = 3, comfyui = 1 }, to pull from several providers at once; search runs only use sources that support it.
Requirements
- KDE Plasma (Plasma 6 on Wayland tested; wallpapers are applied via the PlasmaShell D-Bus API, so plasmashell must be running)
- python3, curl, pillow + requests + dbus-python (auto-installed into a user venv)
See CONTEXT.md for architecture details and CHANGELOG.txt for history.