more convenient wallpaper select/fetch

This commit is contained in:
2025-12-01 12:16:03 +03:00
parent 4ff652145b
commit abbea47279
7 changed files with 205 additions and 9 deletions
+7 -1
View File
@@ -1,7 +1,6 @@
{ config, pkgs, lib, ... }:
# TODO:
# - configure comands like hyprpaper, waybar, etc.
# - make hyprexpo work
{
@@ -18,12 +17,19 @@
./hypridle.nix # done
];
home.packages = with pkgs; [
(writeShellScriptBin "next_wallpaper"
(builtins.readFile ./scripts/wallpaper/next_wallpaper.sh))
(writeShellScriptBin "move_wallpaper"
(builtins.readFile ./scripts/wallpaper/move_wallpaper.sh))
(writeShellScriptBin "fetch_wallpaper"
(builtins.readFile ./scripts/wallpaper/fetch_wallpaper.sh))
hyprland
brightnessctl
playerctl
hyprshot
nemo
pywal
jq
];
services.swww.enable = true;
programs.hyprpanel = {
@@ -56,7 +56,15 @@
"${super}, L, exec, loginctl lock-session"
''
${super}, Return, exec, ~/.config/hypr/scripts/launch_first_available.sh "kitty" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm"
${super}+Shift, D, exec, ~/.config/hypr/scripts/wallpaper/fetch_wallpaper.sh
''
''
${super}+Shift, C, exec, ~/.config/hypr/scripts/wallpaper/next_wallpaper.sh -f $(zenity --title "Pick a wallpaper" --file-selection --file-filter \*.png)
''
''
${super}, Return, exec, ~/.config/hypr/scripts/launch_first_available.sh "kitty" "foot" "alacritty" "wezterm" "konsole" "kgx" "uxterm" "xterm"
''
"${super}, T, exec, telegram-desktop"
''
@@ -67,7 +75,7 @@
${super}, C, exec, ~/.config/hypr/scripts/launch_first_available.sh "code" "codium" "cursor" "zed" "zedit" "zeditor" "kate" "gnome-text-editor" "emacs" "command -v nvim && kitty -1 nvim"''
''
Ctrl+Shift, Escape, exec, ~/.config/hypr/scripts/launch_first_available.sh "kitty -1 fish -c btop"''
Ctrl+Shift, Escape, exec, ~/.config/hypr/scripts/launch_first_available.sh "kitty -1 zsh -c btop"''
"${super}+Shift, 1, exec, ~/.config/hypr/scripts/workspace_action.sh movetoworkspacesilent 1"
"${super}+Shift, 2, exec, ~/.config/hypr/scripts/workspace_action.sh movetoworkspacesilent 2"
"${super}+Shift, 3, exec, ~/.config/hypr/scripts/workspace_action.sh movetoworkspacesilent 3"
@@ -0,0 +1,135 @@
#!/usr/bin/env bash
# fetch_wallpaper.sh
# Requires: wl-paste, curl, jq, move-wallpaper, next-wallpaper
set -euo pipefail
URL="$(wl-paste --no-newline || true)"
if [ -z "$URL" ]; then
echo "No URL in clipboard" >&2
exit 1
fi
# extract id (last path segment, strip trailing slash and query)
WALLPAPER_ID="$(printf '%s' "$URL" | sed -E 's#^.*/##; s/[/?].*$//')"
if [ -z "$WALLPAPER_ID" ]; then
echo "Could not extract id from URL: $URL" >&2
exit 1
fi
# Configuration
TEMP_DIR="/tmp/wallhaven_downloads"
API_KEY="$(pass api/wallhaven)" # Can set API key as environment variable
TARGET_RESOLUTION="2560x1600"
# Validate input
if [[ -z "$WALLPAPER_ID" ]]; then
echo "Error: No content in clipboard"
exit 1
fi
if [[ ! "$WALLPAPER_ID" =~ ^[a-zA-Z0-9]{4,8}$ ]]; then
echo "Error: Invalid wallhaven ID format: $WALLPAPER_ID"
exit 1
fi
# Create temp directory
mkdir -p "$TEMP_DIR"
# Build API URL
API_URL="https://wallhaven.cc/api/v1/w/$WALLPAPER_ID"
if [[ -n "$API_KEY" ]]; then
API_URL="$API_URL?apikey=$API_KEY"
fi
echo "Fetching wallpaper info for ID: $WALLPAPER_ID"
# Fetch wallpaper data from API
response=$(curl -s -f "$API_URL")
curl_exit_code=$?
if [[ $curl_exit_code -ne 0 ]]; then
echo "Error: Failed to fetch data from wallhaven API (curl exit: $curl_exit_code)"
exit 1
fi
# Check if jq is available for proper JSON parsing
if ! command -v jq &> /dev/null; then
echo "Error: jq is required for JSON parsing. Please install jq."
echo "Ubuntu/Debian: sudo apt install jq"
echo "Fedora: sudo dnf install jq"
echo "macOS: brew install jq"
exit 1
fi
# Parse JSON response
if echo "$response" | jq -e '.error' > /dev/null; then
error_msg=$(echo "$response" | jq -r '.error.message')
echo "API Error: $error_msg"
exit 1
fi
# Extract wallpaper information
wallpaper_data=$(echo "$response" | jq -r '.data')
if [[ "$wallpaper_data" == "null" || -z "$wallpaper_data" ]]; then
echo "Error: No wallpaper data found in API response"
exit 1
fi
# Get image URL and details
image_url=$(echo "$response" | jq -r '.data.path')
resolution=$(echo "$response" | jq -r '.data.resolution')
file_type=$(echo "$response" | jq -r '.data.file_type')
file_size=$(echo "$response" | jq -r '.data.file_size')
purity=$(echo "$response" | jq -r '.data.purity')
# Validate extracted data
if [[ -z "$image_url" || "$image_url" == "null" ]]; then
echo "Error: Could not extract image URL from API response"
exit 1
fi
echo "Wallpaper details:"
echo " Resolution: $resolution"
echo " File type: $file_type"
echo " File size: $((file_size / 1024)) KB"
echo " Purity: $purity"
echo " URL: $image_url"
# Check if resolution matches target
if [[ "$resolution" != "$TARGET_RESOLUTION" ]]; then
echo "Warning: Wallpaper resolution is $resolution (target: $TARGET_RESOLUTION)"
fi
# Download the image
filename=$(basename "$image_url")
full_path="$TEMP_DIR/$filename"
echo "Downloading wallpaper to: $full_path"
if curl -s -f -o "$full_path" "$image_url"; then
# Verify download
if [[ -f "$full_path" && -s "$full_path" ]]; then
downloaded_size=$(stat -c%s "$full_path" 2>/dev/null || stat -f%z "$full_path" 2>/dev/null)
echo "Download successful: $full_path ($((downloaded_size / 1024)) KB)"
# Execute move_wallpaper command
echo "Executing: move_wallpaper -r \"$full_path\""
if move_wallpaper -r "$full_path" 2>/dev/null; then
echo "Wallpaper processing completed successfully"
else
echo "move_wallpaper command completed (exit status ignored as requested)"
fi
zenity --notification --text "Wallpaper downloaded!"
else
echo "Error: Downloaded file is empty or missing"
exit 1
fi
else
echo "Error: Failed to download the wallpaper from: $image_url"
exit 1
fi
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
set -euo pipefail
dest_dir="$HOME/Pictures/Wallpapers"
rmflag=0
usage() {
echo "Usage: $0 [-r] <src-file> [src-file ...]"
echo " -r remove source file after successful conversion"
exit 2
}
while getopts ":r" opt; do
case "$opt" in
r) rmflag=1 ;;
*) usage ;;
esac
done
shift $((OPTIND-1))
# Require at least one file
if [ "$#" -lt 1 ]; then
echo "Error: no source files provided"
usage
fi
# Check ImageMagick
if ! command -v magick >/dev/null 2>&1; then
echo "Error: ImageMagick 'magick' command not found"
exit 1
fi
mkdir -p "$dest_dir"
timestamp=$(date +%Y%m%d%H%M%S)
counter=0
# Process each file one by one
for src in "$@"; do
if [ ! -e "$src" ]; then
echo "Error: '$src' does not exist, skipping"
continue
fi
counter=$((counter + 1))
dst="$dest_dir/wallpaper${timestamp}_${counter}.png"
if magick -- "$src" "$dst"; then
echo "Created: $dst"
if [ "$rmflag" -eq 1 ]; then
rm -f -- "$src"
fi
else
echo "Error: conversion failed for '$src'"
fi
done
exit 0
@@ -0,0 +1,157 @@
#!/usr/bin/env bash
# /home/krosh/Documents/Github/nixos-config/home-manager/modules/zsh/next_wallpaper.sh
# Pick next or random wallpaper from ~/Pictures/Wallpapers and update symlink ~/Pictures/wallpaper.png
# Then call: swww img "$WALLPAPER"
set -euo pipefail
# Handle -f <file> anywhere in argv: remove it from "$@" so getopts can still parse -r.
FORCE_FILE=""
_remaining=()
while [ $# -gt 0 ]; do
case "$1" in
-f)
if [ -z "${2-}" ]; then
echo "Option -f requires an argument" >&2
exit 2
fi
FORCE_FILE="$2"
shift 2
;;
*)
_remaining+=("$1")
shift
;;
esac
done
# restore remaining args for subsequent getopts
if [ "${#_remaining[@]}" -gt 0 ]; then
set -- "${_remaining[@]}"
else
set --
fi
# If -f was given, validate and immediately update the symlink & wallpaper, then exit.
if [ -n "$FORCE_FILE" ]; then
if [ ! -f "$FORCE_FILE" ]; then
echo "Specified wallpaper not found: $FORCE_FILE" >&2
exit 1
fi
TARGET="$(readlink -f "$FORCE_FILE")"
SYMLINK_PATH="$HOME/Pictures/wallpaper.png"
TMP_LINK="$(mktemp -u "${SYMLINK_PATH}.tmp.XXXX")"
ln -sfn -- "$TARGET" "$TMP_LINK"
mv -f "$TMP_LINK" "$SYMLINK_PATH"
# export and trigger compositor/wallpaper tools
WALLPAPER="$TARGET"
swww img "$WALLPAPER" --transition-type fade
hyprpanel -q ; hyprpanel & disown
wal -c
wal -n -i "$WALLPAPER"
exit 0
fi
RANDOM_MODE=0
while getopts "r" opt; do
case "$opt" in
r) RANDOM_MODE=1 ;;
*) echo "Usage: $0 [-r]" >&2; exit 2 ;;
esac
done
WALLPAPERS_DIR="$HOME/Pictures/Wallpapers"
SYMLINK="$HOME/Pictures/wallpaper.png"
if [ ! -d "$WALLPAPERS_DIR" ]; then
echo "Wallpapers directory not found: $WALLPAPERS_DIR" >&2
exit 1
fi
# Resolve current wallpaper (target of symlink). If not a symlink or missing, CUR will be empty.
CUR="$(readlink -f "$SYMLINK" 2>/dev/null || true)"
# Collect png files; sort by timestamp ascending (oldest first) using ls -tr.
# If there are spaces in names, ls handles them, but filenames with newlines are unsupported.
mapfile -t FILES < <(find "$WALLPAPERS_DIR" -maxdepth 1 -type f -iname '*.png' -print0 | xargs -0 ls -1tr 2>/dev/null || true)
if [ "${#FILES[@]}" -eq 0 ]; then
echo "No png wallpapers found in $WALLPAPERS_DIR" >&2
exit 1
fi
choose_random() {
# pick random file different from CUR if possible
candidates=()
for f in "${FILES[@]}"; do
[ "$(readlink -f "$f")" = "$CUR" ] && continue
candidates+=("$f")
done
if [ "${#candidates[@]}" -eq 0 ]; then
# only current exists
echo "No other wallpaper to choose (only current exists)." >&2
exit 1
fi
idx=$((RANDOM % ${#candidates[@]}))
echo "${candidates[$idx]}"
}
choose_next() {
# find current in sorted list and pick next (wrap). If current not found, choose first.
n=${#FILES[@]}
if [ "$n" -eq 1 ]; then
# only one file
if [ "$(readlink -f "${FILES[0]}")" = "$CUR" ]; then
echo "No other wallpaper to choose (only current exists)." >&2
exit 1
else
echo "${FILES[0]}"
return
fi
fi
# find index of current
idx=-1
for i in "${!FILES[@]}"; do
if [ "$(readlink -f "${FILES[i]}")" = "$CUR" ]; then
idx="$i"
break
fi
done
if [ "$idx" -eq -1 ]; then
# current not in list: choose first
echo "${FILES[0]}"
return
fi
# next index with wrap
next=$(( (idx + 1) % n ))
# if next equals current (possible if only one), error handled above
echo "${FILES[$next]}"
}
if [ "$RANDOM_MODE" -eq 1 ]; then
NEW="$(choose_random)"
else
NEW="$(choose_next)"
fi
# Ensure absolute path
NEW="$(readlink -f "$NEW")"
# Create symlink (atomic-ish): create temporary symlink and move
TMP_SYMLINK="$(mktemp -u "${SYMLINK}.tmp.XXXX")"
ln -sfn -- "$NEW" "$TMP_SYMLINK"
mv -f "$TMP_SYMLINK" "$SYMLINK"
# Export for hyprctl command (and run it)
WALLPAPER="$NEW"
swww img "$WALLPAPER" --transition-type fade
hyprpanel -q ; hyprpanel & disown
wal -c
wal -n -i "$WALLPAPER"
exit 0