From 64c3a55df4387ea6f205b7263b06c505d94b6537 Mon Sep 17 00:00:00 2001 From: andwati Date: Wed, 12 Aug 2026 09:46:54 +0300 Subject: [PATCH] Get correct filenames, skip KGet's dialog, and add a finished notification Switch auto-capture from onCreated to onDeterminingFilename, which fires once Chrome has already resolved the real filename (from Content-Disposition or the URL). That name is now passed through to the native host and used to build a full dir+filename destination for addTransfer, replacing showNewTransferDialog. A non-empty destDir makes KGet skip its interactive dialog and start immediately, which also fixes it showing an opaque URL path segment as the filename for signed/obfuscated URLs (e.g. cloud storage links) instead of the real name. Also enable KGet's existing (but disabled-by-default) "Download Finished" KNotify popup via install.sh, so there's still feedback now that captures no longer show an interactive dialog. --- README.md | 56 ++++++++++++++++++++------------ extension/background.js | 43 ++++++++++++++++-------- install.sh | 11 +++++++ native-host/kget_capture_host.py | 39 +++++++++++++++++----- 4 files changed, 106 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 7e42a9f..41684b9 100644 --- a/README.md +++ b/README.md @@ -5,12 +5,14 @@ A Chrome (and other Chromium-browser) extension that sends downloads to 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. + **"Download with KGet"** to send it straight to KGet — it starts + downloading immediately into your Downloads folder, no dialog. - 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. + starts is cancelled and handed off to KGet the same way, automatically, + with the correct filename (resolved by Chrome itself, so it's right even + for URLs whose path is just an opaque ID). Defaults to ON. +- KGet's own "Download Finished" desktop notification is enabled on install, + so you still get feedback once a capture completes. ## Requirements @@ -18,6 +20,8 @@ addition to) the browser's built-in downloader. - One of: Google Chrome, Chromium, Brave, Vivaldi, Microsoft Edge - `python3` and `dbus-send` on `PATH` (standard on virtually all Linux/KDE systems already) +- `kwriteconfig6` (ships with KDE Plasma) — optional, only used to enable the + download-finished notification; install still works without it ## Install @@ -72,14 +76,25 @@ git push origin v1.0.0 - **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. +- **No editable dialog.** Captures start immediately with no chance to + rename the file or pick a different folder beforehand — rename/move it + afterward in KGet or your file manager if needed. This is intentional: KGet + only skips its interactive "New Download" dialog when given a real + destination path up front, so instant capture and an editable prompt are + mutually exclusive given KGet's D-Bus API. +- **The context-menu capture can't always get the correct filename.** + Auto-capture gets the real filename for free from Chrome's own + `Content-Disposition` resolution. Right-click captures don't have that — + the extension only has the raw URL — so KGet falls back to guessing from + the URL path, which is wrong for opaque/signed URLs (e.g. cloud storage + links). Fixing this would require broad host permissions and an extra HTTP + request per right-click, which isn't worth it for now. +- **Chrome may still show its own "Save As" dialog.** This is controlled by + Chrome's own **Ask where to save each file before downloading** setting + (`chrome://settings/downloads`) — no extension API can read or suppress + it, and if it's on, Chrome shows the picker *before* our extension gets a + chance to see the download at all. Turn that setting off for auto-capture + to work without an extra prompt. - **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). @@ -95,15 +110,14 @@ git push origin v1.0.0 - **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 + org.kde.kget.main.addTransfer string:"https://example.com/file.zip" string:"$HOME/Downloads/file.zip" boolean:true ``` + If this fails with `ServiceUnknown`, KGet isn't running. +- **Download-finished notification not showing?** `install.sh` enables it via + `kwriteconfig6 --file knotifyrc --group "Event/kget/finished" --key Action Popup`. + Check System Settings → Notifications → Applications → "KGet Download + Manager" to confirm it's on, or disable it the same way with + `kwriteconfig6 --file knotifyrc --group "Event/kget/finished" --key Action None`. ## License diff --git a/extension/background.js b/extension/background.js index eff3978..191e79d 100644 --- a/extension/background.js +++ b/extension/background.js @@ -11,16 +11,20 @@ async function refreshBadge() { 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; +function sendToKGet(url, filename) { + chrome.runtime.sendNativeMessage( + NATIVE_HOST, + { action: "addTransfer", url, filename: filename || null }, + (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); + } } - if (!response || !response.ok) { - console.error("[kget-capture] KGet reported failure:", response && response.error); - } - }); + ); } chrome.runtime.onInstalled.addListener(async (details) => { @@ -40,10 +44,21 @@ chrome.contextMenus.onClicked.addListener((info) => { if (info.menuItemId !== MENU_ID) return; const url = info.linkUrl || info.srcUrl; if (!url) return; - sendToKGet(url); + sendToKGet(url, null); }); -chrome.downloads.onCreated.addListener(async (item) => { +// onDeterminingFilename (rather than onCreated) fires once Chrome has +// already resolved the real filename (from Content-Disposition or the URL), +// which is exactly what we need to hand KGet the correct name instead of an +// opaque URL path segment. +chrome.downloads.onDeterminingFilename.addListener((item, suggest) => { + // We're about to cancel this download regardless, so Chrome's own choice + // doesn't matter -- just let it proceed so the event resolves promptly. + suggest(); + captureDownload(item); +}); + +async function captureDownload(item) { const { autoCaptureEnabled } = await chrome.storage.local.get({ autoCaptureEnabled: true }); if (!autoCaptureEnabled) return; @@ -67,8 +82,10 @@ chrome.downloads.onCreated.addListener(async (item) => { } catch (e) { console.error("[kget-capture] failed to erase Chrome download entry:", e); } - sendToKGet(url); -}); + + const filename = item.filename ? item.filename.split(/[\\/]/).pop() : null; + sendToKGet(url, filename); +} chrome.storage.onChanged.addListener((changes, area) => { if (area === "local" && "autoCaptureEnabled" in changes) { diff --git a/install.sh b/install.sh index 48aeca3..e560ccf 100755 --- a/install.sh +++ b/install.sh @@ -90,6 +90,17 @@ else: print("(If KGet is currently running, restart it for this to take effect.)") PYEOF +echo "Checking KGet's download-finished notification..." +KNOTIFYRC="$HOME/.config/knotifyrc" +if [ -f "$KNOTIFYRC" ] && grep -q '^\[Event/kget/finished\]' "$KNOTIFYRC"; then + echo "KGet's download-finished notification is already configured, leaving it as-is" +elif command -v kwriteconfig6 >/dev/null 2>&1; then + kwriteconfig6 --file knotifyrc --group "Event/kget/finished" --key Action Popup + echo "Enabled a desktop popup notification for KGet's \"Download Finished\" event" +else + echo "Skipped: 'kwriteconfig6' not found (not on KDE Plasma?) -- no popup notification set up" +fi + EXT_ID=$(cat "$SCRIPT_DIR/keys/extension-id.txt") cat <