Files
NixOsConfig/user/kirill/modules/hyprland.nix
T

287 lines
7.8 KiB
Nix

{ pkgs, lib, config, inputs, host, osConfig, ... }:
let
secretPath =
if osConfig ? sops.secrets.wallhaven
then osConfig.sops.secrets.wallhaven.path
else "";
wallpaper_changer = pkgs.writers.writePython3Bin "wallpaper_changer" {
libraries = [ pkgs.python3Packages.requests ];
flakeIgnore = [ "E111" "E121" "E241" "E501" "E701" "E731" ];
} /*py*/ ''
import requests as requests
from random import choice
from os import environ, getuid, listdir, makedirs, remove, replace, system
from os.path import exists, getmtime, isfile
from subprocess import run
notify_id = None
def notify(text, progress=None, expire_time=5000):
global notify_id
command = [
"${pkgs.libnotify}/bin/notify-send",
"--app-name", "wallpaper_changer",
"--print-id",
"--expire-time", str(expire_time),
]
if notify_id:
command.extend(["--replace-id", str(notify_id)])
if progress is not None:
command.extend(["--hint", f"int:value:{progress}"])
command.extend(["Wallpaper", text])
result = run(command, capture_output=True, text=True, check=False)
output = result.stdout.strip()
if output.isdigit():
notify_id = output
def download_with_progress(link, destination):
temporary = f"{destination}.part"
downloaded = 0
last_progress = -1
response = None
try:
response = requests.get(link, stream=True, timeout=30)
response.raise_for_status()
total = int(response.headers.get("content-length", 0))
with open(temporary, "wb") as file:
for chunk in response.iter_content(chunk_size=256 * 1024):
if not chunk:
continue
file.write(chunk)
downloaded += len(chunk)
if total <= 0:
continue
progress = min(100, downloaded * 100 // total)
if progress == 100 or progress >= last_progress + 2:
notify(f"Downloading... {progress}%", progress, 0)
last_progress = progress
replace(temporary, destination)
except Exception:
if exists(temporary):
remove(temporary)
raise
finally:
if response is not None:
response.close()
def prune(folder, keep=20):
files = [
(name, getmtime(f"{folder}/{name}"))
for name in listdir(folder)
if isfile(f"{folder}/{name}") and not name.endswith(".part")
]
if len(files) <= keep:
return
for name, _ in sorted(files, key=lambda item: item[1])[:len(files) - keep]:
remove(f"{folder}/{name}")
def read_history(path):
try:
with open(path) as file:
return [line.strip() for line in file if line.strip()]
except OSError:
return []
def write_history(path, ids):
try:
with open(path, "w") as file:
file.write("\n".join(dict.fromkeys(ids)) + "\n")
except OSError:
pass
folder = "${config.home.homeDirectory}/wallpapers"
url = "https://wallhaven.cc/api/v1/collections/BlackRaven21/2284568"
runtime = environ.get("XDG_RUNTIME_DIR") or f"/run/user/{getuid()}"
history = f"{runtime}/wallpaper_changer_history"
token = None
try:
with open("${secretPath}") as file:
token = file.read().strip() or None
except OSError:
pass
filename = None
notify("Updating wallpaper...", 0)
try:
params = {}
if token:
params["apikey"] = token
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
page_json = response.json()
walls = list(page_json['data'])
for page in range(2, page_json['meta']['last_page'] + 1):
params['page'] = page
response = requests.get(url, params=params, timeout=10)
response.raise_for_status()
walls.extend(response.json()['data'])
seen = read_history(history)
candidates = [wall for wall in walls if wall['id'] not in seen]
if not candidates:
seen = []
candidates = walls
wallpaper = choice(candidates)
link = wallpaper['path']
format = wallpaper['file_type']
id = wallpaper['id']
if format == "image/jpeg": ext = "jpg"
else: ext = "png"
filename = f"{id}.{ext}"
destination = f"{folder}/{filename}"
if not exists(destination):
makedirs(folder, exist_ok=True)
notify("Downloading... 0%", 0, 0)
download_with_progress(link, destination)
notify("Downloaded", 100)
prune(folder)
else:
notify("Using cached wallpaper", 100)
write_history(history, seen + [id])
except requests.exceptions.RequestException:
notify("Offline mode")
try:
filename = choice(listdir(folder))
except (FileNotFoundError, IndexError):
notify("Offline mode and wallpaper cache is empty")
finally:
if filename is not None:
notify("Applying wallpaper", 100)
system(f"${lib.getExe pkgs.awww} img {folder}/{filename} --transition-type center")
'';
in {
imports = [(
import ../../../modules/user/hyprland.nix {
inherit lib;
inherit pkgs;
inherit config;
inherit inputs;
inherit host;
}
)];
home.packages = [ wallpaper_changer ];
wayland.windowManager.hyprland = let
colors = config.lib.stylix.colors;
hyprLua = import ../../../modules/user/hyprland/lua.nix { inherit lib; };
in {
settings = {
config = {
general = {
gaps_in = 5;
gaps_out = 5;
border_size = 2;
"col.active_border" = lib.mkForce {
colors = [
"rgba(${colors.base0C}ee)"
"rgba(${colors.base0B}ee)"
];
angle = 45;
};
"col.inactive_border" = lib.mkForce "rgba(${colors.base05}aa)";
layout = "dwindle";
};
decoration = {
border_part_of_window = false;
rounding = 10;
blur = {
enabled = true;
size = 16;
passes = 2;
new_optimizations = true;
};
shadow = {
enabled = true;
range = 4;
render_power = 3;
};
};
animations.enabled = true;
dwindle.smart_split = true;
master.new_status = "master";
misc = {
focus_on_activate = true;
animate_manual_resizes = true;
animate_mouse_windowdragging = true;
enable_swallow = true;
};
};
animation = [
{ leaf = "windows"; enabled = true; speed = 7; bezier = "myBezier"; }
{ leaf = "windowsOut"; enabled = true; speed = 7; bezier = "default"; style = "popin 80%"; }
{ leaf = "border"; enabled = true; speed = 10; bezier = "default"; }
{ leaf = "borderangle"; enabled = true; speed = 8; bezier = "default"; }
{ leaf = "fade"; enabled = true; speed = 7; bezier = "default"; }
{ leaf = "workspaces"; enabled = true; speed = 6; bezier = "default"; }
];
curve = {
_args = [
"myBezier"
{
type = "bezier";
points = [
[ 0.05 0.9 ]
[ 0.1 1.05 ]
];
}
];
};
workspace_rule = [
{
workspace = "2";
layout = "scrolling";
}
];
on = [
(hyprLua.onStart [ "${lib.getExe wallpaper_changer}" ])
];
bind = [
(hyprLua.bind "SUPER + W" (hyprLua.exec "${lib.getExe wallpaper_changer}"))
(hyprLua.bind "SUPER + SHIFT + S" (hyprLua.exec "${lib.getExe pkgs.grimblast} --notify --freeze copy area"))
(hyprLua.bind "F11" (hyprLua.exec "ghostty -e sh -c hyprlock"))
];
};
};
}