diff --git a/.config/quickshell/ii/scripts/thumbnails/generate-thumbnails-magick.sh b/.config/quickshell/ii/scripts/thumbnails/generate-thumbnails-magick.sh new file mode 100755 index 000000000..31a346ca1 --- /dev/null +++ b/.config/quickshell/ii/scripts/thumbnails/generate-thumbnails-magick.sh @@ -0,0 +1,122 @@ +#!/usr/bin/env bash + +# Generate thumbnails for files using ImageMagick, following Freedesktop spec +# Usage: +# ./generate-thumbnails-magick.sh --file +# ./generate-thumbnails-magick.sh --directory + +set -e + +# Thumbnail sizes mapping +get_thumbnail_size() { + case "$1" in + normal) echo 128 ;; + large) echo 256 ;; + x-large) echo 512 ;; + xx-large) echo 1024 ;; + *) echo 128 ;; + esac +} + +usage() { + echo "Usage: $0 --file | --directory " + exit 1 +} + +md5() { + # Calculate md5 hash of the file's absolute path + echo -n "$1" | md5sum | awk '{print $1}' +} + +urlencode() { + # Percent-encode a string for use in a URI, but do not encode slashes + local str="$1" + local encoded="" + local c + for ((i=0; i<${#str}; i++)); do + c="${str:$i:1}" + case "$c" in + [a-zA-Z0-9.~_-]|/) encoded+="$c" ;; + *) printf -v hex '%%%02X' "'${c}'"; encoded+="$hex" ;; + esac + done + echo "$encoded" +} + +generate_thumbnail() { + local src="$1" + local abs_path + abs_path="$(realpath "$src")" + local encoded_path + encoded_path="$(urlencode "$abs_path")" + local uri + uri="file://$encoded_path" + local hash + hash="$(md5 "$uri")" + local out="$CACHE_DIR/$hash.png" + mkdir -p "$CACHE_DIR" + if [ -f "$out" ]; then + return + fi + magick "$abs_path" -resize ${THUMBNAIL_SIZE}x${THUMBNAIL_SIZE} "$out" +} + +# Parse arguments +SIZE_NAME="normal" +MODE="" +TARGET="" +while [[ $# -gt 0 ]]; do + case "$1" in + --file|-f) + MODE="file" + TARGET="$2" + shift 2 + ;; + --directory|-d) + MODE="dir" + TARGET="$2" + shift 2 + ;; + --size|-s) + SIZE_NAME="$2" + shift 2 + ;; + *) + usage + ;; + esac + # Only one mode allowed + [[ -n "$MODE" ]] && break +done + +THUMBNAIL_SIZE="$(get_thumbnail_size "$SIZE_NAME")" +CACHE_DIR="$HOME/.cache/thumbnails/$SIZE_NAME" + +if [ -z "$MODE" ] || [ -z "$TARGET" ]; then + usage +fi + +case "$MODE" in + file) + if [ ! -f "$TARGET" ]; then + echo "File not found: $TARGET" + exit 2 + fi + generate_thumbnail "$TARGET" + ;; + dir) + if [ ! -d "$TARGET" ]; then + echo "Directory not found: $TARGET" + exit 2 + fi + for f in "$TARGET"/*; do + [ -f "$f" ] || continue + generate_thumbnail "$f" & + done + wait + ;; + *) + usage + ;; +esac + diff --git a/.config/quickshell/ii/services/Wallpapers.qml b/.config/quickshell/ii/services/Wallpapers.qml index f5c243234..dc8734433 100644 --- a/.config/quickshell/ii/services/Wallpapers.qml +++ b/.config/quickshell/ii/services/Wallpapers.qml @@ -15,6 +15,7 @@ Singleton { id: root property string thumbgenScriptPath: `${FileUtils.trimFileProtocol(Directories.scriptPath)}/thumbnails/thumbgen.py` + property string generateThumbnailsMagicScriptPath: `${FileUtils.trimFileProtocol(Directories.scriptPath)}/thumbnails/generate-thumbnails-magick.sh` property string directory: FileUtils.trimFileProtocol(`${Directories.pictures}/Wallpapers`) property alias folderModel: folderModel // Expose for direct binding when needed property string searchQuery: "" @@ -124,9 +125,8 @@ Singleton { thumbgenProc.directory = root.directory thumbgenProc.running = false thumbgenProc.command = [ - thumbgenScriptPath, - "--size", size, - "-d", `${root.directory}` + "bash", "-c", + `${thumbgenScriptPath} --size ${size} -d ${root.directory} || ${generateThumbnailsMagicScriptPath} --size ${size} -d ${root.directory}`, ] thumbgenProc.running = true }