From 14fe30e906cd93404c637587a22381c6eff5329a Mon Sep 17 00:00:00 2001 From: "Danilo M." Date: Tue, 6 Oct 2026 10:33:34 +0200 Subject: feat(appearance): find a larger version of a low-res wallpaper When the image staged for the targeted screen gets a yellow or red quality note, a button under the mock screens copies it to the clipboard and opens TinEye in the browser, where Ctrl+V runs the reverse search and the matches can be sorted by size. It acts on the staged image, not the hovered one, because the pointer leaves the thumbnail to reach it. The image goes through the clipboard because a search engine takes no local file in a URL, and scripted uploads did not get through: TinEye answered 403 to curl and 405 with a browser user agent, and Google Lens redirected to its consent page, dropping the image. The paste in the browser is the upload, and only on the user's click. The copy is converted to PNG with magick. Copied as itself, a JPEG put only image/jpeg on the clipboard and Firefox pasted nothing into the page; it hands web content image/png. Co-Authored-By: Claude Opus 5.5 --- appearance/AppearancePanel.qml | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'appearance/AppearancePanel.qml') diff --git a/appearance/AppearancePanel.qml b/appearance/AppearancePanel.qml index 0547c6b..9b895f8 100644 --- a/appearance/AppearancePanel.qml +++ b/appearance/AppearancePanel.qml @@ -625,6 +625,44 @@ Scope { color: Wallpapers.qualityColor(subject, Wallpapers.target) } + // A reverse image search for a larger copy of the staged + // image. Staged, not hovered: the pointer leaves the + // thumbnail to reach the button. A search engine cannot be + // handed a local file in a URL and its upload endpoints + // sit behind bot and consent walls, so the image goes on + // the clipboard and the browser opens TinEye, which takes + // a pasted image and sorts its matches by size. The upload + // is the paste, made by the user in the browser. Always + // PNG: Firefox hands a page only image/png from the + // clipboard, so a JPEG copied as itself pasted nothing. + Column { + id: finder + readonly property string staged: + Wallpapers.target === "V" ? Wallpapers.pendingV : Wallpapers.pendingH + property string copied: "" + anchors.horizontalCenter: parent.horizontalCenter + visible: staged !== "" && Wallpapers.qualityNote(staged, Wallpapers.target) !== "" + spacing: 4 + + Tab { + anchors.horizontalCenter: parent.horizontalCenter + text: "Find a larger version" + onClicked: { + Quickshell.execDetached(["sh", "-c", + 'magick "$1" png:- | wl-copy -t image/png && xdg-open https://tineye.com/', + "sh", finder.staged]); + finder.copied = finder.staged; + } + } + Text { + anchors.horizontalCenter: parent.horizontalCenter + visible: finder.copied === finder.staged + text: "image copied: paste it on TinEye with Ctrl+V" + font { family: Theme.fontFamily; pixelSize: Theme.fontSize - 4 } + color: Theme.subtext + } + } + Row { anchors.horizontalCenter: parent.horizontalCenter spacing: 8 -- cgit v1.2.3