thumbnailer: better caching

This commit is contained in:
2 * r + 2 * t 2025-05-05 19:06:32 +10:00
parent 57f815bdc8
commit 1a650b73bc
3 changed files with 75 additions and 66 deletions

View file

@ -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)

View file

@ -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 "";
const thumbPath = `${thumbDir}/${sha}@${width}x${height}-exact.png`;
thumbProc.path = path;
thumbProc.thumbPath = thumbPath;
thumbProc.width = width;
thumbProc.height = height;
thumbProc.startDetached();
return thumbPath;
function go(path: string, width: int, height: int): var {
return thumbComp.createObject(root, {
originalPath: path,
width: width,
height: height
});
}
Process {
id: thumbProc
component Thumbnail: QtObject {
id: obj
required property string originalPath
required property int width
required property int height
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 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;
}
}
}
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 {}
}
}

View file

@ -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();
}
}