From 08744915c48f18083941de1cddef4169bd422097 Mon Sep 17 00:00:00 2001 From: andwati Date: Wed, 12 Aug 2026 15:07:55 +0300 Subject: [PATCH] Add a curl/wget one-line installer and popup setup detection Add install-remote.sh, which fetches the latest release and runs its install.sh so setup no longer needs a git clone. The popup now probes the native host with a "ping" action on open and, if it's not registered yet, shows the one-liner (with copy-to-clipboard) instead of the auto-capture toggle -- so a Web Store install can be completed end-to-end by clicking the extension icon and pasting one command. --- README.md | 29 +++++++++------ extension/popup.css | 37 +++++++++++++++++++- extension/popup.html | 37 ++++++++++++++------ extension/popup.js | 53 ++++++++++++++++++++++++++-- install-remote.sh | 60 ++++++++++++++++++++++++++++++++ native-host/kget_capture_host.py | 12 ++++++- 6 files changed, 202 insertions(+), 26 deletions(-) create mode 100755 install-remote.sh diff --git a/README.md b/README.md index 88e650b..431b62e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,8 @@ browser's built-in downloader. - Linux with KGet installed and running (or set to autostart) - A Chromium-based browser: Chrome, Chromium, Brave, Vivaldi, or Edge - `python3`, `dbus-send` +- `curl` or `wget`, for the one-line remote installer below (skip if you'd + rather download and run `install.sh` yourself) - `notify-send`, optional, for the completion notification - `kwriteconfig6` (KDE Frameworks), optional, silences KGet's own duplicate notification @@ -49,22 +51,26 @@ without them.) 1. Install the extension from the Chrome Web Store: **``** *(placeholder, fill in once the listing is live)*. -2. Install the native messaging host that lets the extension talk to KGet. - Download and extract `kget-capture-vX.Y.Z.zip` (the source archive, not - `kget-capture-extension-vX.Y.Z.zip`) from the - [Releases page](https://github.com/andwati/kget-capture/releases), then - from inside that folder: +2. Click the extension's toolbar icon. The popup detects that the native + messaging host isn't set up yet and shows a one-line command; run it in a + terminal, then click "I ran it, check again" in the popup: ```bash - ./install.sh + curl -fsSL https://raw.githubusercontent.com/andwati/kget-capture/main/install-remote.sh | bash ``` + (or with `wget`: `wget -qO- https://raw.githubusercontent.com/andwati/kget-capture/main/install-remote.sh | bash`) + + This downloads the latest release and runs its `install.sh`, which + registers the native host for every supported browser it finds installed + and prints any remaining setup warnings. No git clone required. If you'd + rather run it yourself: download and extract `kget-capture-vX.Y.Z.zip` + (the source archive, not `kget-capture-extension-vX.Y.Z.zip`) from the + [Releases page](https://github.com/andwati/kget-capture/releases), then + from inside that folder run `./install.sh` directly. 3. Open your browser's download settings (`chrome://settings/downloads`, `brave://settings/downloads`, etc.) and turn **off** "Ask where to save each file before downloading". Chrome shows this dialog itself, before the extension gets a chance to intercept the download, so this one-time change - is required. - -`install.sh` registers the native host for every supported browser it finds -installed and prints any remaining setup warnings. + is required (no extension API can do it for you). ### Building from source @@ -131,6 +137,9 @@ Prebuilt releases are published on the ## Troubleshooting +- **`install-remote.sh` fails to look up the latest release?** It queries + GitHub's API, which rate-limits unauthenticated requests (60/hour per IP); + wait a bit, or fall back to the manual `install.sh` steps in Install above. - **Check native host registration:** confirm `~/.config//NativeMessagingHosts/com.kget_capture.host.json` exists and its `path` points at an executable file diff --git a/extension/popup.css b/extension/popup.css index 8bf071b..2c0ab60 100644 --- a/extension/popup.css +++ b/extension/popup.css @@ -1,5 +1,5 @@ body { - width: 240px; + width: 320px; padding: 12px; font-family: system-ui, sans-serif; font-size: 13px; @@ -36,3 +36,38 @@ h1 { font-family: inherit; cursor: pointer; } + +.cmd-row { + display: flex; + align-items: center; + gap: 6px; + margin-top: 8px; +} + +.cmd-row code { + flex: 1; + min-width: 0; + overflow-x: auto; + white-space: nowrap; + background: #f0f0f0; + padding: 4px 6px; + border-radius: 3px; + font-size: 11px; +} + +.cmd-row button { + flex: none; + padding: 4px 8px; + font-size: 12px; + font-family: inherit; + cursor: pointer; +} + +#recheck-setup { + display: block; + margin-top: 10px; + padding: 4px 8px; + font-size: 12px; + font-family: inherit; + cursor: pointer; +} diff --git a/extension/popup.html b/extension/popup.html index 2b90be2..db719ef 100644 --- a/extension/popup.html +++ b/extension/popup.html @@ -6,17 +6,32 @@

KGet Capture

- -

-

Right-click any link, image, video, or audio and choose - "Download with KGet" to send it to KGet on demand.

-

Downloads still prompting for a location? Chrome shows that - dialog itself, before this extension can intercept anything. - -

+ + + + + diff --git a/extension/popup.js b/extension/popup.js index fef10a8..de25f21 100644 --- a/extension/popup.js +++ b/extension/popup.js @@ -1,13 +1,60 @@ +const NATIVE_HOST = "com.kget_capture.host"; +const INSTALL_COMMAND = + "curl -fsSL https://raw.githubusercontent.com/andwati/kget-capture/main/install-remote.sh | bash"; + +const setupPanel = document.getElementById("setup-needed"); +const readyPanel = document.getElementById("ready"); const checkbox = document.getElementById("auto-capture-toggle"); const statusLine = document.getElementById("status-line"); +const copyFeedback = document.getElementById("copy-feedback"); function renderStatus(enabled) { statusLine.textContent = `Auto-capture: ${enabled ? "ON" : "OFF"}`; } -chrome.storage.local.get({ autoCaptureEnabled: true }).then(({ autoCaptureEnabled }) => { - checkbox.checked = autoCaptureEnabled; - renderStatus(autoCaptureEnabled); +function showReady() { + setupPanel.hidden = true; + readyPanel.hidden = false; + chrome.storage.local.get({ autoCaptureEnabled: true }).then(({ autoCaptureEnabled }) => { + checkbox.checked = autoCaptureEnabled; + renderStatus(autoCaptureEnabled); + }); +} + +function showSetupNeeded() { + document.getElementById("setup-command").textContent = INSTALL_COMMAND; + readyPanel.hidden = true; + setupPanel.hidden = false; +} + +// The native host is only reachable once install.sh (or install-remote.sh) +// has registered it -- sendNativeMessage fails with a lastError like +// "Specified native messaging host not found" until then, which is exactly +// the signal we want to gate the rest of the popup on. +function checkNativeHost() { + chrome.runtime.sendNativeMessage(NATIVE_HOST, { action: "ping" }, () => { + if (chrome.runtime.lastError) { + showSetupNeeded(); + } else { + showReady(); + } + }); +} + +checkNativeHost(); + +document.getElementById("recheck-setup").addEventListener("click", checkNativeHost); + +document.getElementById("copy-command").addEventListener("click", async () => { + try { + await navigator.clipboard.writeText(INSTALL_COMMAND); + copyFeedback.textContent = "Copied to clipboard."; + } catch (e) { + copyFeedback.textContent = "Couldn't copy -- select and copy the command manually."; + } + setTimeout(() => { + copyFeedback.textContent = ""; + }, 2000); }); checkbox.addEventListener("change", () => { diff --git a/install-remote.sh b/install-remote.sh new file mode 100755 index 0000000..e254245 --- /dev/null +++ b/install-remote.sh @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# Fetches the latest release source archive and runs install.sh from it, so +# setup doesn't require a git clone: +# +# curl -fsSL https://raw.githubusercontent.com/andwati/kget-capture/main/install-remote.sh | bash +# wget -qO- https://raw.githubusercontent.com/andwati/kget-capture/main/install-remote.sh | bash +set -euo pipefail + +REPO="andwati/kget-capture" + +fetch_stdout() { + if command -v curl >/dev/null 2>&1; then + curl -fsSL "$1" + elif command -v wget >/dev/null 2>&1; then + wget -qO- "$1" + else + echo "ERROR: this installer needs 'curl' or 'wget' on PATH." >&2 + exit 1 + fi +} + +fetch_to_file() { + if command -v curl >/dev/null 2>&1; then + curl -fsSL "$1" -o "$2" + else + wget -qO "$2" "$1" + fi +} + +echo "Looking up the latest release..." +tag="$(fetch_stdout "https://api.github.com/repos/$REPO/releases/latest" \ + | grep -m1 '"tag_name"' | sed -E 's/.*"tag_name": *"([^"]+)".*/\1/')" +if [ -z "$tag" ]; then + echo "ERROR: couldn't determine the latest release tag from GitHub." >&2 + exit 1 +fi +echo "Latest release: $tag" + +if ! command -v python3 >/dev/null 2>&1; then + echo "ERROR: 'python3' is required but not found on PATH." >&2 + exit 1 +fi + +tmp_dir="$(mktemp -d)" +trap 'rm -rf "$tmp_dir"' EXIT + +zip_path="$tmp_dir/kget-capture.zip" +zip_url="https://github.com/$REPO/releases/download/$tag/kget-capture-$tag.zip" +echo "Downloading $zip_url..." +fetch_to_file "$zip_url" "$zip_path" + +echo "Extracting..." +src_dir="$tmp_dir/src" +python3 -c " +import sys, zipfile +zipfile.ZipFile(sys.argv[1]).extractall(sys.argv[2]) +" "$zip_path" "$src_dir" + +echo "Running install.sh..." +bash "$src_dir/install.sh" diff --git a/native-host/kget_capture_host.py b/native-host/kget_capture_host.py index e4242fd..f62d4eb 100755 --- a/native-host/kget_capture_host.py +++ b/native-host/kget_capture_host.py @@ -154,7 +154,17 @@ def spawn_notifier(transfer_path, dest): def main(): message = read_message() - if not message or message.get("action") != "addTransfer" or "url" not in message: + if not message: + write_message({"ok": False, "error": "invalid request"}) + return + + # The extension popup uses this to detect whether the native host is + # installed/registered at all, distinct from whether a transfer succeeds. + if message.get("action") == "ping": + write_message({"ok": True}) + return + + if message.get("action") != "addTransfer" or "url" not in message: write_message({"ok": False, "error": "invalid request"}) return