Mirrors the solver's Windows-only voyage-import.ahk on KDE Wayland: - poe-clip-bridge.py: clipboard watcher that keeps only PoE item text, serves it on loopback and can trigger a sweep from the browser - voyage-sweep.py: hovers every cell of the in-game chart grid, Ctrl+C's it and hands over the whole batch in one go - userscript: feeds the batch into the solver page without focusing it Includes notes on the four Wayland pointer pitfalls this ran into. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
1.9 KiB
JavaScript
68 lines
1.9 KiB
JavaScript
// ==UserScript==
|
|
// @name Allflame Voyage Solver - clipboard auto-paste
|
|
// @namespace templis
|
|
// @version 1.0
|
|
// @description Polls the local clipboard bridge and feeds copied PoE items into the solver without focusing the browser.
|
|
// @match https://one-more-map.github.io/allflame-voyage-solver/*
|
|
// @grant GM_xmlhttpRequest
|
|
// @connect 127.0.0.1
|
|
// @run-at document-idle
|
|
// ==/UserScript==
|
|
|
|
(function () {
|
|
"use strict";
|
|
|
|
const ENDPOINT = "http://127.0.0.1:8477/clip";
|
|
const INTERVAL = 400;
|
|
let lastSeq = -1;
|
|
|
|
const toast = document.createElement("div");
|
|
toast.style.cssText =
|
|
"position:fixed;bottom:12px;right:12px;z-index:99999;padding:6px 10px;" +
|
|
"border-radius:6px;font:12px/1.4 monospace;background:#222;color:#8f8;" +
|
|
"opacity:0;transition:opacity .2s;pointer-events:none";
|
|
document.body.appendChild(toast);
|
|
|
|
function flash(msg, color) {
|
|
toast.textContent = msg;
|
|
toast.style.color = color;
|
|
toast.style.opacity = "1";
|
|
setTimeout(() => (toast.style.opacity = "0"), 1500);
|
|
}
|
|
|
|
function feed(text) {
|
|
const dt = new DataTransfer();
|
|
dt.setData("text/plain", text);
|
|
document.dispatchEvent(
|
|
new ClipboardEvent("paste", {
|
|
clipboardData: dt,
|
|
bubbles: true,
|
|
cancelable: true,
|
|
})
|
|
);
|
|
flash("item pasted", "#8f8");
|
|
}
|
|
|
|
function poll() {
|
|
GM_xmlhttpRequest({
|
|
method: "GET",
|
|
url: ENDPOINT,
|
|
onload: (r) => {
|
|
try {
|
|
const data = JSON.parse(r.responseText);
|
|
if (data.seq !== lastSeq) {
|
|
lastSeq = data.seq;
|
|
if (data.text) feed(data.text); // also feeds the last item on page load
|
|
}
|
|
} catch (e) {
|
|
/* ignore malformed response */
|
|
}
|
|
},
|
|
onerror: () => flash("bridge offline", "#f88"),
|
|
});
|
|
}
|
|
|
|
setInterval(poll, INTERVAL);
|
|
poll();
|
|
})();
|