mqtt setup panel: clipboard fallback for http lan, fill webhook url
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m53s
All checks were successful
Build and Push Docker Image / build (push) Successful in 1m53s
two issues surfaced on unraid over plain http:
copy buttons: navigator.clipboard is undefined in non-secure contexts.
fall back to a hidden textarea + document.execCommand('copy'), and
surface a 'select & ⌘C' hint if even that fails.
webhook url: the field is only used by http destinations but the plugin
form requires a value regardless. put the broker url there (mqtt://host:
port) so validation passes and it's still obvious what it points at.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "netfelix-audio-fix",
|
||||
"version": "2026.04.14.3",
|
||||
"version": "2026.04.14.4",
|
||||
"scripts": {
|
||||
"dev:server": "NODE_ENV=development bun --hot server/index.tsx",
|
||||
"dev:client": "vite",
|
||||
|
||||
@@ -45,12 +45,41 @@ function parseBroker(raw: string): { host: string; port: string; useTls: boolean
|
||||
}
|
||||
}
|
||||
|
||||
async function copyText(text: string): Promise<boolean> {
|
||||
// Secure-context fast path
|
||||
if (navigator.clipboard?.writeText) {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return true;
|
||||
} catch {
|
||||
/* fall through to legacy */
|
||||
}
|
||||
}
|
||||
// HTTP LAN fallback: temporary textarea + execCommand.
|
||||
try {
|
||||
const el = document.createElement("textarea");
|
||||
el.value = text;
|
||||
el.setAttribute("readonly", "");
|
||||
el.style.position = "fixed";
|
||||
el.style.top = "0";
|
||||
el.style.left = "0";
|
||||
el.style.opacity = "0";
|
||||
document.body.appendChild(el);
|
||||
el.select();
|
||||
const ok = document.execCommand("copy");
|
||||
document.body.removeChild(el);
|
||||
return ok;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function CopyableValue({ label, value, mono = true }: { label: string; value: string; mono?: boolean }) {
|
||||
const [copied, setCopied] = useState(false);
|
||||
const [copied, setCopied] = useState<"ok" | "fail" | null>(null);
|
||||
const copy = async () => {
|
||||
await navigator.clipboard.writeText(value);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 1500);
|
||||
const ok = await copyText(value);
|
||||
setCopied(ok ? "ok" : "fail");
|
||||
setTimeout(() => setCopied(null), 1500);
|
||||
};
|
||||
return (
|
||||
<div className="flex items-start gap-2 mb-2">
|
||||
@@ -63,7 +92,7 @@ function CopyableValue({ label, value, mono = true }: { label: string; value: st
|
||||
onClick={copy}
|
||||
className="text-xs px-2 py-1 rounded border border-gray-300 text-gray-600 hover:bg-gray-100 flex-shrink-0"
|
||||
>
|
||||
{copied ? "Copied" : "Copy"}
|
||||
{copied === "ok" ? "Copied" : copied === "fail" ? "Select & ⌘C" : "Copy"}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
@@ -257,7 +286,10 @@ export function MqttSection({ cfg, locked }: { cfg: Record<string, string>; lock
|
||||
return (
|
||||
<div className="mt-2">
|
||||
<CopyableValue label="Webhook Name" value="Audio Fix" mono={false} />
|
||||
<CopyableValue label="Webhook Url" value="n/a" mono={false} />
|
||||
<CopyableValue
|
||||
label="Webhook Url"
|
||||
value={`${broker.useTls ? "mqtts" : "mqtt"}://${broker.host || "broker.lan"}:${broker.port}`}
|
||||
/>
|
||||
<CopyableValue label="Status" value="Enabled" mono={false} />
|
||||
<CopyableValue label="Notification Type" value="Item Added" mono={false} />
|
||||
<CopyableValue label="Item Type" value="Movies, Episodes" mono={false} />
|
||||
@@ -278,8 +310,9 @@ export function MqttSection({ cfg, locked }: { cfg: Record<string, string>; lock
|
||||
);
|
||||
})()}
|
||||
<p className="text-[11px] text-gray-400 mt-2">
|
||||
Jellyfin's plugin doesn't expose an "Item Updated" event. When we rewrite a file, Jellyfin treats it as a new add
|
||||
and fires <span className="font-mono">Item Added</span> — that's the event we listen for.
|
||||
Notes: the plugin's "Webhook Url" field is for HTTP destinations; MQTT ignores it, but the form won't save empty,
|
||||
so we put the broker URL there as a placeholder. Jellyfin doesn't expose an "Item Updated" event — any file
|
||||
change fires <span className="font-mono">Item Added</span>, which is what we listen for.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user