feat: impl wallpaper

This commit is contained in:
2 * r + 2 * t
2025-06-12 21:35:05 +10:00
parent a53a2568ec
commit c043a14ca2
5 changed files with 154 additions and 12 deletions
+5 -2
View File
@@ -22,11 +22,14 @@ scheme_path = c_state_dir / "scheme.json"
scheme_data_dir = cli_data_dir / "schemes"
scheme_cache_dir = c_cache_dir / "schemes"
last_wallpaper_path = c_state_dir / "wallpaper/last.txt"
wallpapers_dir = Path.home() / "Pictures/Wallpapers"
wallpaper_path_path = c_state_dir / "wallpaper/path.txt"
wallpaper_link_path = c_state_dir / "wallpaper/current"
wallpaper_thumbnail_path = c_state_dir / "wallpaper/thumbnail.jpg"
thumbnail_cache_dir = c_cache_dir / "thumbnails"
def compute_hash(path: str) -> str:
def compute_hash(path: Path | str) -> str:
sha = hashlib.sha256()
with open(path, "rb") as f:
+6 -6
View File
@@ -59,8 +59,7 @@ class Scheme:
self._flavour = flavour
self._check_mode()
self._update_colours()
self.save()
self.update_colours()
@property
def mode(self) -> str:
@@ -75,8 +74,7 @@ class Scheme:
raise ValueError(f'Invalid scheme mode: "{mode}". Valid modes: {get_scheme_modes()}')
self._mode = mode
self._update_colours()
self.save()
self.update_colours()
@property
def variant(self) -> str:
@@ -88,8 +86,7 @@ class Scheme:
return
self._variant = variant
self._update_colours()
self.save()
self.update_colours()
@property
def colours(self) -> dict[str, str]:
@@ -115,6 +112,9 @@ class Scheme:
self._name = random.choice(get_scheme_names())
self._flavour = random.choice(get_scheme_flavours())
self._mode = random.choice(get_scheme_modes())
self.update_colours()
def update_colours(self) -> None:
self._update_colours()
self.save()
+123
View File
@@ -0,0 +1,123 @@
import random
from argparse import Namespace
from pathlib import Path
from materialyoucolor.hct import Hct
from materialyoucolor.utils.color_utils import argb_from_rgb
from PIL import Image
from caelestia.utils.hypr import message
from caelestia.utils.material import get_colours_for_image
from caelestia.utils.paths import (
compute_hash,
thumbnail_cache_dir,
wallpaper_link_path,
wallpaper_path_path,
wallpaper_thumbnail_path,
)
from caelestia.utils.scheme import Scheme, get_scheme
from caelestia.utils.theme import apply_colours
def is_valid_image(path: Path | str) -> bool:
path = Path(path)
return path.is_file() and path.suffix in [".jpg", ".jpeg", ".png", ".webp", ".tif", ".tiff"]
def check_wall(wall: Path, filter_size: tuple[int, int], threshold: float) -> bool:
with Image.open(wall) as img:
width, height = img.size
return width >= filter_size[0] * threshold and height >= filter_size[1] * threshold
def get_wallpaper() -> str:
return wallpaper_path_path.read_text()
def get_wallpapers(args: Namespace) -> list[Path]:
dir = Path(args.random)
if not dir.is_dir():
return []
walls = [f for f in dir.rglob("*") if is_valid_image(f)]
if args.no_filter:
return walls
monitors = message("monitors")
filter_size = monitors[0]["width"], monitors[0]["height"]
for monitor in monitors[1:]:
if filter_size[0] > monitor["width"]:
filter_size[0] = monitor["width"]
if filter_size[1] > monitor["height"]:
filter_size[1] = monitor["height"]
return [f for f in walls if check_wall(f, filter_size, args.threshold)]
def get_thumb(wall: Path) -> Path:
thumb = (thumbnail_cache_dir / compute_hash(wall)).with_suffix(".jpg")
if not thumb.exists():
with Image.open(wall) as img:
img = img.convert("RGB")
img.thumbnail((128, 128), Image.NEAREST)
thumb.parent.mkdir(parents=True, exist_ok=True)
img.save(thumb, "JPEG")
return thumb
def get_smart_mode(wall: Path) -> str:
with Image.open(get_thumb(wall)) as img:
img.thumbnail((1, 1), Image.LANCZOS)
tone = Hct.from_int(argb_from_rgb(*img.getpixel((0, 0)))).tone
return "light" if tone > 60 else "dark"
def get_colours_for_wall(wall: Path | str, no_smart: bool) -> None:
scheme = get_scheme()
if not no_smart:
scheme = Scheme(
{
"name": scheme.name,
"flavour": scheme.flavour,
"mode": get_smart_mode(wall),
"variant": scheme.variant,
"colours": scheme.colours,
}
)
return get_colours_for_image(get_thumb(wall), scheme)
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')
# Update files
wallpaper_path_path.parent.mkdir(parents=True, exist_ok=True)
wallpaper_path_path.write_text(str(wall))
wallpaper_link_path.parent.mkdir(parents=True, exist_ok=True)
wallpaper_link_path.unlink(missing_ok=True)
wallpaper_link_path.symlink_to(wall)
# Generate thumbnail or get from cache
thumb = get_thumb(wall)
wallpaper_thumbnail_path.parent.mkdir(parents=True, exist_ok=True)
wallpaper_thumbnail_path.unlink(missing_ok=True)
wallpaper_thumbnail_path.symlink_to(thumb)
scheme = get_scheme()
# Change mode based on wallpaper colour
scheme.mode = get_smart_mode(wall)
# Update colours
scheme.update_colours()
apply_colours(scheme.colours, scheme.mode)
def set_random(args: Namespace) -> None:
set_wallpaper(random.choice(get_wallpapers(args)), args.no_smart)