From ef70a2009346335cc0e5037b066a16c7f2521c5d Mon Sep 17 00:00:00 2001 From: andwati Date: Wed, 12 Aug 2026 09:02:09 +0300 Subject: [PATCH] initial commit --- .gitignore | 2 + LICENSE | 21 ++++++ README.md | 97 +++++++++++++++++++++++++ extension/background.js | 79 ++++++++++++++++++++ extension/icons/icon128.png | Bin 0 -> 3168 bytes extension/icons/icon16.png | Bin 0 -> 651 bytes extension/icons/icon32.png | Bin 0 -> 1018 bytes extension/icons/icon48.png | Bin 0 -> 1287 bytes extension/manifest.json | 25 +++++++ extension/popup.css | 29 ++++++++ extension/popup.html | 18 +++++ extension/popup.js | 16 ++++ install.sh | 69 ++++++++++++++++++ keys/README.md | 32 ++++++++ keys/extension-id.txt | 1 + keys/kget-capture-public.b64 | 1 + keys/kget-capture-public.der | Bin 0 -> 294 bytes native-host/com.kget_capture.host.json | 7 ++ native-host/kget_capture_host.py | 65 +++++++++++++++++ uninstall.sh | 33 +++++++++ 20 files changed, 495 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 extension/background.js create mode 100644 extension/icons/icon128.png create mode 100644 extension/icons/icon16.png create mode 100644 extension/icons/icon32.png create mode 100644 extension/icons/icon48.png create mode 100644 extension/manifest.json create mode 100644 extension/popup.css create mode 100644 extension/popup.html create mode 100644 extension/popup.js create mode 100755 install.sh create mode 100644 keys/README.md create mode 100644 keys/extension-id.txt create mode 100644 keys/kget-capture-public.b64 create mode 100644 keys/kget-capture-public.der create mode 100644 native-host/com.kget_capture.host.json create mode 100755 native-host/kget_capture_host.py create mode 100755 uninstall.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..19a240c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +keys/*.pem +__pycache__/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..b95ca61 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Ian + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..9abbd0f --- /dev/null +++ b/README.md @@ -0,0 +1,97 @@ +# KGet Capture + +A Chrome (and other Chromium-browser) extension that sends downloads to +[KGet](https://apps.kde.org/kget/), KDE's download manager, instead of (or in +addition to) the browser's built-in downloader. + +- Right-click any link, image, video, or audio element and choose + **"Download with KGet"** to open KGet's "New Download" dialog, prefilled + with the URL — edit the filename or destination folder if you want, then + confirm to start the transfer. +- A toolbar toggle enables **auto-capture**: while on, every download Chrome + starts is cancelled and redirected to the same KGet dialog automatically. + Defaults to ON. + +## Requirements + +- Linux with KGet installed (and running, or set to autostart) +- One of: Google Chrome, Chromium, Brave, Vivaldi, Microsoft Edge +- `python3` and `dbus-send` on `PATH` (standard on virtually all Linux/KDE + systems already) + +## Install + +```bash +git clone kget-capture +cd kget-capture +./install.sh +``` + +`install.sh` registers a native messaging host for every supported browser it +finds installed, then prints the extension's fixed ID and next steps: + +1. Open `chrome://extensions` (or your browser's equivalent). +2. Enable **Developer mode** (top-right toggle). +3. Click **Load unpacked** and select this repo's `extension/` directory. +4. Confirm the loaded extension's ID matches the one `install.sh` printed. + +## Usage + +- **On-demand:** right-click a link/image/video/audio → "Download with KGet". +- **Automatic:** click the toolbar icon and flip "Auto-capture all downloads" + on or off. The badge shows "ON" (green) or "OFF" (grey). + +## Uninstall + +```bash +./uninstall.sh +``` + +This removes the native messaging host registrations and the installed host +script. You'll still need to remove the unpacked extension yourself via +`chrome://extensions` — that step can't be scripted. + +## Known limitations + +- **`blob:`/`data:` URLs can't be captured.** There's no real network URL to + hand to KGet, so these downloads proceed normally through Chrome (a console + warning is logged in the extension's service worker). +- **Auto-capture has a brief head start.** Manifest V3 removed blocking + `webRequest`, so Chrome begins the download before the extension can cancel + it. A small/partial temp file may transiently appear before it's erased. +- **A KGet dialog opens for every capture.** The extension uses KGet's + `showNewTransferDialog` D-Bus method, which opens the interactive "New + Download" dialog rather than starting the transfer immediately. This is + intentional — it lets you rename the file or change the destination folder + before it starts. If you'd rather it start immediately without a prompt, + see [Troubleshooting](#troubleshooting) for the alternate `addTransfer` + call — note that route only returns once the dialog is dismissed, so it's + not what the extension uses by default. +- **KGet must already be running.** If it's not, captures fail silently from + the user's perspective — check the service worker console for the actual + error (see Troubleshooting). + +## Troubleshooting + +- **Check native host registration:** confirm + `~/.config//NativeMessagingHosts/com.kget_capture.host.json` exists + and its `path` points at an executable file + (`~/.local/share/kget-capture/kget_capture_host.py`). +- **Inspect the extension's logs:** on `chrome://extensions`, find "KGet + Capture", click "service worker" under "Inspect views" to open its console. +- **Test D-Bus directly:** + ```bash + dbus-send --print-reply --dest=org.kde.kget /KGet \ + org.kde.kget.main.showNewTransferDialog array:string:"https://example.com/file.zip" + ``` + If this fails with `ServiceUnknown`, KGet isn't running. To skip the dialog + and start a transfer straight away instead, use `addTransfer` with a real + destination folder: + ```bash + dbus-send --print-reply --dest=org.kde.kget /KGet \ + org.kde.kget.main.addTransfer string:"https://example.com/file.zip" string:"$HOME/Downloads" boolean:true + ``` + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/extension/background.js b/extension/background.js new file mode 100644 index 0000000..eff3978 --- /dev/null +++ b/extension/background.js @@ -0,0 +1,79 @@ +const NATIVE_HOST = "com.kget_capture.host"; +const MENU_ID = "kget-capture-download"; + +function updateBadge(enabled) { + chrome.action.setBadgeText({ text: enabled ? "ON" : "OFF" }); + chrome.action.setBadgeBackgroundColor({ color: enabled ? "#2e7d32" : "#9e9e9e" }); +} + +async function refreshBadge() { + const { autoCaptureEnabled } = await chrome.storage.local.get({ autoCaptureEnabled: true }); + updateBadge(autoCaptureEnabled); +} + +function sendToKGet(url) { + chrome.runtime.sendNativeMessage(NATIVE_HOST, { action: "addTransfer", url }, (response) => { + if (chrome.runtime.lastError) { + console.error("[kget-capture] native host error:", chrome.runtime.lastError.message); + return; + } + if (!response || !response.ok) { + console.error("[kget-capture] KGet reported failure:", response && response.error); + } + }); +} + +chrome.runtime.onInstalled.addListener(async (details) => { + chrome.contextMenus.create({ + id: MENU_ID, + title: "Download with KGet", + contexts: ["link", "image", "video", "audio"], + }); + + if (details.reason === "install") { + await chrome.storage.local.set({ autoCaptureEnabled: true }); + } + refreshBadge(); +}); + +chrome.contextMenus.onClicked.addListener((info) => { + if (info.menuItemId !== MENU_ID) return; + const url = info.linkUrl || info.srcUrl; + if (!url) return; + sendToKGet(url); +}); + +chrome.downloads.onCreated.addListener(async (item) => { + const { autoCaptureEnabled } = await chrome.storage.local.get({ autoCaptureEnabled: true }); + if (!autoCaptureEnabled) return; + + const url = item.finalUrl || item.url; + if (url.startsWith("blob:") || url.startsWith("data:")) { + console.warn("[kget-capture] cannot redirect blob:/data: URL, letting Chrome handle it:", url); + return; + } + + try { + await chrome.downloads.cancel(item.id); + // erase() only clears the history entry -- it does NOT delete the + // partial file Chrome already wrote to disk. removeFile() does that. + await chrome.downloads.removeFile(item.id); + } catch (e) { + // Expected if Chrome finished the download before cancel() landed, or + // hadn't written any bytes yet -- not worth surfacing to the user. + } + try { + await chrome.downloads.erase({ id: item.id }); + } catch (e) { + console.error("[kget-capture] failed to erase Chrome download entry:", e); + } + sendToKGet(url); +}); + +chrome.storage.onChanged.addListener((changes, area) => { + if (area === "local" && "autoCaptureEnabled" in changes) { + updateBadge(changes.autoCaptureEnabled.newValue); + } +}); + +refreshBadge(); diff --git a/extension/icons/icon128.png b/extension/icons/icon128.png new file mode 100644 index 0000000000000000000000000000000000000000..dad2f28cfb774e5ab6e96f1edc8753f01a8cd647 GIT binary patch literal 3168 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 literal 0 HcmV?d00001 diff --git a/extension/icons/icon16.png b/extension/icons/icon16.png new file mode 100644 index 0000000000000000000000000000000000000000..e6dd142d6689a4cecf0070c8658d63cc9426e7e8 GIT binary patch literal 651 zcmeAS@N?(olHy`uVBq!ia0vp^0w65F1|$Lb6AYF9SoB8UsT^3j@P1pisjL z28L1t28LG&3=CE?7#PG0=Ijcz0ZOnXdAqy(2LsNC?{|PA>?NMQuI#Tkcv$&W_WX@G z0Tfa#ag8WRNi0dVN-jzTQVd20MrOJO7P^K;AqJ*ahNf1=X4(b@Rt5$OWTR%HXvob^ z$xN%nt>L1>BUPXV4Y&;@nYpROC5gEOxb?J!9tQe}G27F{F~s9|a!LbJ;KeIfnAxvv zcc`$HSJ>ij!W?>VS`A06(C=Sg-`wQmGxwETC^o;%yJYsY;A|u$NhhL&Coz*PHg>&CuYkI{xdsfx`>H~ z=kn>v*E40(6HdIDBVBTMQscwm2irH;+lW{^c+zg&ZvV>2V13BRYvclSC}@Kw9M03$aiCt zh?BCG{1+E@%>(nKw>@!|4NzhzWnkpJ!lt^>=R%fX*5+f9GfrnDE9xvU-F9eIGQ;MU WIcj2U>#hK!iow&>&t;ucLK6Tf!t?b2 literal 0 HcmV?d00001 diff --git a/extension/icons/icon32.png b/extension/icons/icon32.png new file mode 100644 index 0000000000000000000000000000000000000000..2ac1517e1fa1d62016886b561a588462b22d4e64 GIT binary patch literal 1018 zcmeAS@N?(olHy`uVBq!ia0vp^3Lq@N1|*eVE!z&_Bzpw;GB8xBF)%c=FfjZA3N^f7 zU???UV0e|lz+g3lfkC`r&aOZkpaffzx4X-KFyM^%eg`PRUgGKN%KnOjhm~Jt&)=96 zKq1u<*NBpo#FA92f z_wcB*>*Q{QEyoPo9C`CvoL}q|6sTJG;`Q~->DCr|wz-C%?6~{*;xU1HlZ=_)ioR-+ zko0iSsqGSE2 zj`RjLhfiEp(Ym49GtRF&a^S)up?|TdMos?l6Jl6+8G5IF*=Ci!GrB!Tk=gl{;q#-H zvIS~>G4&?}bOh4^v4L*i1m;N~AE#KCv^Ht`A@!Z3c zRa+Y$`lM9%T5^BQ=Ivrmh-gUpkEXD(6w3!&JPv1TyIR$%{q=~1M1;$XYsOwm zPnH|Mt^1d9UV)<_{p@@7e|wG}NHEy>=T+zN5DtzwHa@mAwl=@D8R1vUd3cVk>e8<0 zS6UL=9F=`8)X2bQ?^nN<$B#J*FkIp5=;_y+X;d#M@u(-~zvnT9BaiKTx_3w&KTz=T z#NqJywkw`yNnK$&!p8F5b@&5ALiT2 zU6Vg)<=ZGWwv7A_|Lb2#^D=IbXs?_TvEjv?#AVODB_zC@#Gl^@N=QifapptwL;bIJ z-9MKxEEH+vJ9lrN{KuQK8W;Y#b?NT*){N(cyI2`6GA14jI9$-xsQ4wQ{>RdA9-jK{ ze{27o_pL6!xL1{fyJN=o;K=ncX$ck5pIYC47h`Liu{PLxeSwid&B;F-|DKomwX^+M z>VX9I#kGx%Wd|IX#gar1t=iluxl>W@z^rE*Hnn9jHr#tDx#d8Y;xxsU#)WN(s?X=f zEMk7pCfah$_A&GOFAlmAYZ%_0OKa=oVF^CaTacj}z%-ZX^)`tN{tMz$*0qZ@akJl2 zWo8lUGICVs)m3CNRAYXt@{8ey%){*Hn8}L|m-Go3s&fb@9$6|;j pnG9ho&cAKGz%3aNY{kUD&|K(#+kWoMKfs*9;OXk;vd$@?2>?-koP7WQ literal 0 HcmV?d00001 diff --git a/extension/icons/icon48.png b/extension/icons/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..c251bd94ce52c98d807e993f4480d857104cf427 GIT binary patch literal 1287 zcmeAS@N?(olHy`uVBq!ia0vp^1|TfJ1|-=hsU87R3dtTpz6=aiY77hwEes65fI=o%V@7?@fanpzo~X&V?=85k^(jhcy~AvZrI zGp!Q0hKml5RDl{a;5L+G=B5^xB<2?2*3%Yx80aVF=bkQ(Ar-gY&Z+hY4wN}w?>GC) zgpeT5l?I=tdM?@<^MI#YO6aqr39IYn5SGbT-X!uXd7Bt(3CTON9_+dBihrhUp_|uD zZ`IF&o`;&IEDH)$JNwV#yNOZW?91=+Z||L7UuXS%-rUc-_rJG&{^riz;@krsF)`oX z=jX;=@DEzJ^oUkb$5c_F*MYe?wbvTenj=E>Hu9!-=AM?8UAu~ld-f;OkmlZnOe!A& z?LAj{w$z@Q=K6(S>42PVB;PC=s89lnK!?L<$ztyDEzJC9@0=_T$F>t1wO zB()wm&#!sz$R+Nm^Y7&j@R&|kxvFxk?B=e{YlhB~*YXE@2t&b`?_+cN;~!xoK%Hy|n+c@@_qgl31pU z`xoV{&F~q*^T9@B>>G|r=<$gIISUDn}hQ6Ee z<^SIWjrB^JCvJ%>IRC!3Br)H^{JRrS)7|OEQyjm&Ii6oGC$zSnT_8~W%0nUh|8F<5 z)~SVXtb5?o@M85+=etFRpJtUU`@Tk&%_F4UbeI0j>fOiK=55;f_s7!ZwlS`)&WtAW zZneE%&QPPmKKqt1gGu5o_Q|bpo_7CzWLL?`EOT=5`!8ph8j2S*m>%1np7o$z$vv+A za*?QLi)Y1~x7VkwOkp@VdvfaB>kM+M*4@()MiaWfrLm-MfXK*o8BS+!Ko4Uj63j%7o~p_jWCv@0%}f z{XyhQ>4Eb~v8T5PA86bbRT{7Bkm*_c_=Eks$I;#oG+)>@@LF+R-kGp&Ml_h$8|lD07g%z7N((sPaRg!#PdrEAUpRX>xf=(@@6@Up^whFu)9 z!qmBTpV#=$-@o>6&-c$vwYP$p{0(ngHt0wA@NWoXVVoey;@~F0AnC}E0_1F*y}s+l zysKNnVq$}XufE!OUHJ<`iUgy{?+vmK)o1afaRkY#njL+z>P7NH8zr%4e}3%Nn!Zz1 zaGsmdyXndEMfcyBcZSC?_vVdtA0}_J5!}3V-c4D_wTH_( + + + + + + +

KGet Capture

+ +

+

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

+ + + diff --git a/extension/popup.js b/extension/popup.js new file mode 100644 index 0000000..8f2907b --- /dev/null +++ b/extension/popup.js @@ -0,0 +1,16 @@ +const checkbox = document.getElementById("auto-capture-toggle"); +const statusLine = document.getElementById("status-line"); + +function renderStatus(enabled) { + statusLine.textContent = `Auto-capture: ${enabled ? "ON" : "OFF"}`; +} + +chrome.storage.local.get({ autoCaptureEnabled: true }).then(({ autoCaptureEnabled }) => { + checkbox.checked = autoCaptureEnabled; + renderStatus(autoCaptureEnabled); +}); + +checkbox.addEventListener("change", () => { + chrome.storage.local.set({ autoCaptureEnabled: checkbox.checked }); + renderStatus(checkbox.checked); +}); diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..b4c08c5 --- /dev/null +++ b/install.sh @@ -0,0 +1,69 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +INSTALL_DIR="$HOME/.local/share/kget-capture" +HOST_SCRIPT_SRC="$SCRIPT_DIR/native-host/kget_capture_host.py" +HOST_SCRIPT_DEST="$INSTALL_DIR/kget_capture_host.py" +MANIFEST_TEMPLATE="$SCRIPT_DIR/native-host/com.kget_capture.host.json" +GENERATED_MANIFEST="$INSTALL_DIR/com.kget_capture.host.json" + +echo "Checking dependencies..." +for dep in python3 dbus-send; do + if ! command -v "$dep" >/dev/null 2>&1; then + echo "ERROR: '$dep' is required but not found on PATH." >&2 + exit 1 + fi +done + +echo "Installing native host script to $HOST_SCRIPT_DEST" +mkdir -p "$INSTALL_DIR" +cp "$HOST_SCRIPT_SRC" "$HOST_SCRIPT_DEST" +chmod +x "$HOST_SCRIPT_DEST" + +echo "Generating native messaging host manifest..." +sed "s|__HOST_SCRIPT_PATH__|$HOST_SCRIPT_DEST|" "$MANIFEST_TEMPLATE" > "$GENERATED_MANIFEST" + +declare -A BROWSER_DIRS=( + ["Google Chrome"]="$HOME/.config/google-chrome" + ["Chromium"]="$HOME/.config/chromium" + ["Brave"]="$HOME/.config/BraveSoftware/Brave-Browser" + ["Vivaldi"]="$HOME/.config/vivaldi" + ["Microsoft Edge"]="$HOME/.config/microsoft-edge" +) + +registered_any=false +for browser in "${!BROWSER_DIRS[@]}"; do + config_dir="${BROWSER_DIRS[$browser]}" + if [ -d "$config_dir" ]; then + target_dir="$config_dir/NativeMessagingHosts" + mkdir -p "$target_dir" + cp "$GENERATED_MANIFEST" "$target_dir/com.kget_capture.host.json" + echo "Registered native host for $browser" + registered_any=true + fi +done + +if [ "$registered_any" = false ]; then + echo "WARNING: no supported browser config directories were found. Checked:" + for browser in "${!BROWSER_DIRS[@]}"; do + echo " - ${BROWSER_DIRS[$browser]}" + done +fi + +EXT_ID=$(cat "$SCRIPT_DIR/keys/extension-id.txt") + +cat < keys/extension-id.txt +``` + +Rotating the key changes the extension ID, which means `extension/manifest.json`'s +`"key"` and `native-host/com.kget_capture.host.json`'s `allowed_origins` both +need updating to match. diff --git a/keys/extension-id.txt b/keys/extension-id.txt new file mode 100644 index 0000000..1be9663 --- /dev/null +++ b/keys/extension-id.txt @@ -0,0 +1 @@ +lgkhlfhejbffjnpcdlpjclicihnbjijp diff --git a/keys/kget-capture-public.b64 b/keys/kget-capture-public.b64 new file mode 100644 index 0000000..b2b0a45 --- /dev/null +++ b/keys/kget-capture-public.b64 @@ -0,0 +1 @@ +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtM1nFg5pPd3UBzynUJHj6aUy7bjudZaX9AQTWGMqAX3fXylw1lubSzP1/BaS9ivvgOJg/loyEgzEZlcNPzblFVlg8BqEJ3tntdk2OzYvUs0pUdcPzzyjso9TykCkUUTI7ev8JkreW/FYlinfvNwSYN4/c1s3h8/I6XHtxOdmO1G3bS98+BQaXPldbDmxoKwyWR8u1f8gTO2Mg3GY4BHau3RWf1kgtNzh20p9wE3sEFdWkFu7ArgRCIrWLh6m3O6lolnHQSCWPwtOTx893Qkp9Eu6FwUnoWc8rsYx8sqa0eNCTCS6Kjr1Iu3yEJ5y9390jUiDZTQ/c62ueCTQaYv2bwIDAQAB \ No newline at end of file diff --git a/keys/kget-capture-public.der b/keys/kget-capture-public.der new file mode 100644 index 0000000000000000000000000000000000000000..f931ae8365189500ab41a258f3f248ad40ddcff8 GIT binary patch literal 294 zcmV+>0ondAf&n5h4F(A+hDe6@4FLfG1potr0S^E$f&mHwf&l>lw9RK04rx8z)CWAL zP?6*5r84cf?sb-z^aK-FV=4iC-(M+k)?1rPGxhuylJ+a_fZ|~OS~3z0#Aa6wKQ`qR zSzz!QgeQAvwb?d1HZM}mDN)xC&pe~Dk5kG(q)|l3?d$v|O5R)XSe7Z@yxbCC-am6& zH;2#2>2dAE=Vm)mw{0(c_!Jsk`CV)|v7oFnSsyOd{~%25jDvBQ;1SxpbXI>^Ahg`! z+e&@FP3#a?R*+k}0=N+fiq