No description
  • Python 70.5%
  • Shell 29.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-04 18:19:56 -04:00
fonts waifuwall v1.2: ASCII-art wallpaper pipeline + waifufetch config scheme 2026-08-13 16:25:58 -04:00
.gitignore Stop tracking AGENTS.md and CONTEXT.md (local-only project docs, gitignored) 2026-08-13 13:20:03 -04:00
bootstrap.sh waifuwall v1.9.0: ai-upscale pipe, webp/jxl processed cache, --image, fix dead [pipe] config 2026-08-16 15:14:24 -04:00
CHANGELOG.txt waifuwall v1.14.0: -x/--next cycles the terminal's display within its own pipeline 2026-09-04 18:19:56 -04:00
fetch_url.py v1.11: --info/-i provenance sidecars (source, comfyui workflow+seeds, pipeline, URL) 2026-08-17 07:30:36 -04:00
install.sh waifuwall v1.5.3: fix default-wallpaper race — no apply-time fit temp, Plasma FillMode fits 2026-08-14 18:35:46 -04:00
LICENSE waifuwall v1.0: waifu wallpaper setter for KDE Plasma 2026-08-13 12:12:07 -04:00
pipelines.py waifuwall v1.13.1: -p NAME -c clears only that namespace; visible ai-upscale dep warning 2026-08-28 11:38:38 -04:00
README.md waifuwall v1.14.0: -x/--next cycles the terminal's display within its own pipeline 2026-09-04 18:19:56 -04:00
screen.py waifuwall v1.5.0: display-aware -d/--show/--revert + adopt-before-fetch 2026-08-14 14:26:56 -04:00
setter.py waifuwall v1.5.3: fix default-wallpaper race — no apply-time fit temp, Plasma FillMode fits 2026-08-14 18:35:46 -04:00
sources.py v1.11: --info/-i provenance sidecars (source, comfyui workflow+seeds, pipeline, URL) 2026-08-17 07:30:36 -04:00
waifuwall.sh waifuwall v1.14.0: -x/--next cycles the terminal's display within its own pipeline 2026-09-04 18:19:56 -04:00
wall_worker.py waifuwall v1.13: ordered, repeatable pipeline passes 2026-08-28 11:03:11 -04:00

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 separate portrait / landscape name lists per orientation (empty = all). collection (empty = top level) names a subfolder used as an opt-in collection pool — e.g. collection = "succubus" uses workflow_dir/succubus/*.json; waifuwall --collection succubus --raw forces it for one run and --list-collections lists 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_timeout caps one generation (seconds). base_url is the ComfyUI endpoint, api_key optional.
  • Multi-sourcesource may 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.