From 1a650b73bc75a7b617d9e0c24d680eae47218f3d Mon Sep 17 00:00:00 2001 From: 2 * r + 2 * t <61896496+soramanew@users.noreply.github.com> Date: Mon, 5 May 2025 19:06:32 +1000 Subject: thumbnailer: better caching --- modules/background/Wallpaper.qml | 14 ++++--- services/Thumbnailer.qml | 80 +++++++++++++++++++++++++++------------- widgets/CachingImage.qml | 47 ++++++----------------- 3 files changed, 75 insertions(+), 66 deletions(-) diff --git a/modules/background/Wallpaper.qml b/modules/background/Wallpaper.qml index 2ffc922..78624d5 100644 --- a/modules/background/Wallpaper.qml +++ b/modules/background/Wallpaper.qml @@ -28,23 +28,25 @@ Item { id: two } - component Img: Image { + component Img: CachingImage { id: img function update(): void { - if (source === root.source) + const srcPath = `${root.source}`.slice(7); + if (thumbnail.originalPath === srcPath) { root.current = this; - else - source = root.source; + } else + path = srcPath; } anchors.fill: parent + asynchronous: true + cache: false fillMode: Image.PreserveAspectCrop + opacity: 0 scale: Wallpapers.showPreview ? 1 : 0.8 - sourceSize.width: width - sourceSize.height: height onStatusChanged: { if (status === Image.Ready) diff --git a/services/Thumbnailer.qml b/services/Thumbnailer.qml index 7f7a9a4..3bdcaf0 100644 --- a/services/Thumbnailer.qml +++ b/services/Thumbnailer.qml @@ -1,7 +1,9 @@ pragma Singleton +pragma ComponentBehavior: Bound import Quickshell import Quickshell.Io +import QtQuick import Qt.labs.platform Singleton { @@ -9,36 +11,64 @@ Singleton { readonly property string thumbDir: `${StandardPaths.standardLocations(StandardPaths.GenericCacheLocation)[0]}/caelestia/thumbnails`.slice(7) - function go(sha: string, path: string, width: int, height: int): string { - if (!sha || !path || !width || !height) - return ""; + function go(path: string, width: int, height: int): var { + return thumbComp.createObject(root, { + originalPath: path, + width: width, + height: height + }); + } - const thumbPath = `${thumbDir}/${sha}@${width}x${height}-exact.png`; + component Thumbnail: QtObject { + id: obj - thumbProc.path = path; - thumbProc.thumbPath = thumbPath; - thumbProc.width = width; - thumbProc.height = height; - thumbProc.startDetached(); + required property string originalPath + required property int width + required property int height - return thumbPath; - } + property string path - Process { - id: thumbProc + readonly property Process shaProc: Process { + running: true + command: ["sha1sum", obj.originalPath] + stdout: SplitParser { + onRead: data => { + const sha = data.split(" ")[0]; + obj.path = `${root.thumbDir}/${sha}@${obj.width}x${obj.height}-exact.png`; + obj.thumbProc.running = true; + } + } + } - property string path - property string thumbPath - property int width - property int height - - command: ["fish", "-c", ` -if ! test -f ${thumbPath} - set -l size (identify -ping -format '%w\n%h' ${path}) - if test $size[1] -gt ${width} -o $size[2] -gt ${height} - magick ${path} -thumbnail ${width}x${height}^ -background none -gravity center -extent ${width}x${height} -unsharp 0x.5 ${thumbPath} + readonly property Process thumbProc: Process { + command: ["fish", "-c", ` +if test -f ${obj.path} + exit 1 +else + set -l size (identify -ping -format '%w\n%h' ${obj.originalPath}) + if test $size[1] -gt ${obj.width} -o $size[2] -gt ${obj.height} + magick ${obj.originalPath} -${obj.width > 1024 || obj.height > 1024 ? "resize" : "thumbnail"} ${obj.width}x${obj.height}^ -background none -gravity center -extent ${obj.width}x${obj.height} -unsharp 0x.5 ${obj.path} + else + cp ${obj.originalPath} ${obj.path} end -end -`] +end`] + onExited: code => { + if (code === 0) { + const path = obj.path; + obj.path = ""; + obj.path = path; + } + } + } + + function reload(): void { + shaProc.running = true; + } + } + + Component { + id: thumbComp + + Thumbnail {} } } diff --git a/widgets/CachingImage.qml b/widgets/CachingImage.qml index 85593ed..08be473 100644 --- a/widgets/CachingImage.qml +++ b/widgets/CachingImage.qml @@ -5,46 +5,23 @@ import QtQuick Image { id: root - required property string path - property string thumbnail + property string path + readonly property Thumbnailer.Thumbnail thumbnail: Thumbnailer.go(path, width, height) - source: { - if (thumbnail) - return `file://${thumbnail}`; - shaProc.running = true; - return ""; - } + source: thumbnail.path ? `file://${thumbnail.path}` : "" asynchronous: true fillMode: Image.PreserveAspectCrop - onPathChanged: shaProc.running = true - onWidthChanged: shaProc.running = true - onHeightChanged: shaProc.running = true - onStatusChanged: { - if (status === Image.Error) - waitProc.running = true; + onPathChanged: { + thumbnail.originalPath = path; + thumbnail.reload(); } - - Process { - id: shaProc - - command: ["sha1sum", root.path] - stdout: SplitParser { - onRead: data => root.thumbnail = Thumbnailer.go(data.split(" ")[0], root.path, root.width, root.height) - } + onWidthChanged: { + thumbnail.width = width; + thumbnail.reload(); } - - Process { - id: waitProc - - command: ["inotifywait", "-q", "-e", "close_write", "--format", "%w%f", "-m", root.thumbnail.slice(0, root.thumbnail.lastIndexOf("/"))] - stdout: SplitParser { - onRead: file => { - if (file === root.thumbnail) { - root.source = file; - waitProc.running = false; - } - } - } + onHeightChanged: { + thumbnail.height = height; + thumbnail.reload(); } } -- cgit v1.2.3-freya