From 8ce97ea3f5e4b3ca014911de43646970c20bb48a Mon Sep 17 00:00:00 2001 From: Unrectified <83581717+Unrectified@users.noreply.github.com> Date: Fri, 20 Feb 2026 14:17:16 +0100 Subject: [PATCH] feat: add GIF files support as wallpaper (#88) * feat: add GIF files support as wallpaper (not animated tho) * tweak: simplifying variable use * fix: git is good but damn it's annoying * fix --------- Co-authored-by: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> --- src/caelestia/utils/wallpaper.py | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/caelestia/utils/wallpaper.py b/src/caelestia/utils/wallpaper.py index 5564db6..c470b9c 100644 --- a/src/caelestia/utils/wallpaper.py +++ b/src/caelestia/utils/wallpaper.py @@ -24,7 +24,7 @@ from caelestia.utils.theme import apply_colours def is_valid_image(path: Path) -> bool: - return path.is_file() and path.suffix in [".jpg", ".jpeg", ".png", ".webp", ".tif", ".tiff"] + return path.is_file() and path.suffix in [".jpg", ".jpeg", ".png", ".webp", ".tif", ".tiff", ".gif"] def check_wall(wall: Path, filter_size: tuple[int, int], threshold: float) -> bool: @@ -99,6 +99,9 @@ def get_colours_for_wall(wall: Path | str, no_smart: bool) -> None: scheme = get_scheme() cache = wallpapers_cache_dir / compute_hash(wall) + if wall.suffix.lower() == ".gif" + wall = convert_gif(wall) + name = "dynamic" if not no_smart: @@ -121,6 +124,24 @@ def get_colours_for_wall(wall: Path | str, no_smart: bool) -> None: "colours": get_colours_for_image(get_thumb(wall, cache), scheme), } +def convert_gif(wall: Path) -> Path: + cache = wallpapers_cache_dir / compute_hash(wall) + output_path = cache / "first_frame.png" + + if not output_path.exists(): + output_path.parent.mkdir(parents=True, exist_ok=True) + with Image.open(wall) as img: + try: + img.seek(0) + except EOFError: + pass + + img = img.convert("RGB") + img.save(output_path, "PNG") + + return output_path + + def set_wallpaper(wall: Path | str, no_smart: bool) -> None: # Make path absolute @@ -129,6 +150,9 @@ def set_wallpaper(wall: Path | str, no_smart: bool) -> None: if not is_valid_image(wall): raise ValueError(f'"{wall}" is not a valid image') + # Use gif's 1st frame for thumb only + wall_cache = convert_gif(wall) if wall.suffix.lower() == ".gif" else wall + # Update files wallpaper_path_path.parent.mkdir(parents=True, exist_ok=True) wallpaper_path_path.write_text(str(wall)) @@ -136,10 +160,10 @@ def set_wallpaper(wall: Path | str, no_smart: bool) -> None: wallpaper_link_path.unlink(missing_ok=True) wallpaper_link_path.symlink_to(wall) - cache = wallpapers_cache_dir / compute_hash(wall) + cache = wallpapers_cache_dir / compute_hash(wall_cache) # Generate thumbnail or get from cache - thumb = get_thumb(wall, cache) + thumb = get_thumb(wall_cache, cache) wallpaper_thumbnail_path.parent.mkdir(parents=True, exist_ok=True) wallpaper_thumbnail_path.unlink(missing_ok=True) wallpaper_thumbnail_path.symlink_to(thumb) @@ -148,7 +172,7 @@ def set_wallpaper(wall: Path | str, no_smart: bool) -> None: # Change mode and variant based on wallpaper colour if scheme.name == "dynamic" and not no_smart: - smart_opts = get_smart_opts(wall, cache) + smart_opts = get_smart_opts(wall_cache, cache) scheme.mode = smart_opts["mode"] scheme.variant = smart_opts["variant"]