diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 20ef66a..87f02bc 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -44,6 +44,7 @@ jobs: uses: "marvinpinto/action-automatic-releases@latest" with: repo_token: "${{ secrets.GITHUB_TOKEN }}" + automatic_release_tag: "${{ github.ref_name }}" prerelease: false files: | dist/aria2e-chrome-${{ github.ref_name }}.crx diff --git a/background.js b/background.js index d2b3043..eadd586 100644 --- a/background.js +++ b/background.js @@ -74,9 +74,9 @@ const isDownloadListened = () => downloadCapture.isListening; })() /** - * Invoke a download task - * - * @param {DownloadItem} downloadItem + * Invoke a download task + * + * @param {DownloadItem} downloadItem * @param {RpcItem} rpcItem * @returns {boolean} the result of creating download task */ @@ -109,7 +109,14 @@ async function download(downloadItem, rpcItem) { if (!rpcItem || !rpcItem.url) { rpcItem = getRpcServer(downloadItem.url + downloadItem.filename); } - downloadItem.dir = rpcItem.location; + if (downloadItem.filename) { + let lastSlashIndex = Math.max(downloadItem.filename.lastIndexOf('\\'), downloadItem.filename.lastIndexOf('/')); + if (lastSlashIndex !== -1) { + downloadItem.dir = downloadItem.filename.substring(0, lastSlashIndex); + downloadItem.filename = downloadItem.filename.substring(lastSlashIndex + 1); + } + } + if (!downloadItem.dir) downloadItem.dir = rpcItem.location; if (!downloadItem.filename) downloadItem.filename = ''; if (Configs.askBeforeDownload || downloadItem.multiTask) { try { @@ -158,8 +165,15 @@ async function send2Aria(downloadItem, rpcItem) { } options.header = headers; if (downloadItem.referrer) options.referer = downloadItem.referrer; - if (downloadItem.filename) options.out = downloadItem.filename; - if (downloadItem.dir) options.dir = downloadItem.dir; + if (downloadItem.filename) { + let lastSlashIndex = Math.max(downloadItem.filename.lastIndexOf('\\'), downloadItem.filename.lastIndexOf('/')); + if (lastSlashIndex !== -1) { + options.dir = downloadItem.filename.substring(0, lastSlashIndex); + downloadItem.filename = downloadItem.filename.substring(lastSlashIndex + 1); + } + options.out = downloadItem.filename; + } + if (downloadItem.dir && !options.dir) options.dir = downloadItem.dir; if (downloadItem.hasOwnProperty('options')) { options = Object.assign(options, downloadItem.options); } @@ -200,8 +214,8 @@ async function send2Aria(downloadItem, rpcItem) { } /** - * Get a rpc item whose pattern(s) matches the giving resource url - * + * Get a rpc item whose pattern(s) matches the giving resource url + * * @param {string} url - The resource url to be downloaded * @return {RpcItem} a RpcItem which refers to an Aria2 RPC server */ @@ -279,15 +293,15 @@ function shouldCapture(downloadItem) { } else if (typeof downloadItem.totalBytes === 'number' && downloadItem.totalBytes >= 0) { fileSize = downloadItem.totalBytes; } - + const threshold = Configs.fileSize * 1024 * 1024; - + // If file size is unknown (-1), capture it by default (let aria2 handle it) // This is important for Firefox where size may not be known at onCreated time if (fileSize < 0) { return true; } - + return fileSize >= threshold; } @@ -330,16 +344,16 @@ async function captureDownload(downloadItem) { if (downloadItem.finalUrl && downloadItem.finalUrl != "about:blank") { downloadItem.url = downloadItem.finalUrl; } - + const shouldCaptureResult = shouldCapture(downloadItem); - + if (Configs.integration && shouldCaptureResult) { const downloadId = downloadItem.id; - + // Cancel the browser download try { await chrome.downloads.cancel(downloadId); - + // Firefox: erase the download from history to clean up UI if (BrowserCompat.isFirefox) { setTimeout(async () => { @@ -353,7 +367,7 @@ async function captureDownload(downloadItem) { } catch (err) { // Ignore cancel errors } - + if (downloadItem.referrer == "about:blank") { downloadItem.referrer = ""; } @@ -1199,7 +1213,7 @@ async function notifyTaskStatus(data) { /** * Web page injector which will send all valid urls to background js - * + * * @param {Array} allowedExts - The file extension list which will export * @param {Array} blockedExts - The blocked file extension list which will not export */ diff --git a/js/browserCompat.js b/js/browserCompat.js index dba9321..b4a6345 100644 --- a/js/browserCompat.js +++ b/js/browserCompat.js @@ -5,11 +5,11 @@ class BrowserCompat { // Browser detection // Firefox has browser.runtime.getBrowserInfo, Chrome does not - static isFirefox = typeof browser !== 'undefined' && - browser.runtime?.getBrowserInfo !== undefined; - + static isFirefox = typeof browser !== 'undefined' && + browser.runtime?.getBrowserInfo !== undefined; + static isChrome = !BrowserCompat.isFirefox; - + /** * Check if a specific API path is available * @param {string} apiPath - Dot-separated API path (e.g., 'sidePanel', 'power', 'system.display') @@ -19,7 +19,7 @@ class BrowserCompat { const parts = apiPath.split('.'); let obj = typeof browser !== 'undefined' ? browser : chrome; for (const part of parts) { - if (obj && typeof obj[part] !== 'undefined') { + if (obj && part in obj) { obj = obj[part]; } else { return false; @@ -27,7 +27,7 @@ class BrowserCompat { } return true; } - + /** * Side Panel support detection * Side Panel is Chrome-specific (Chrome 114+) @@ -36,7 +36,7 @@ class BrowserCompat { static get supportsSidePanel() { return BrowserCompat.isChrome && BrowserCompat.hasAPI('sidePanel'); } - + /** * Power API support detection * chrome.power is not available in Firefox @@ -45,7 +45,7 @@ class BrowserCompat { static get supportsPowerAPI() { return BrowserCompat.hasAPI('power'); } - + /** * System Display API support detection * chrome.system.display is not available in Firefox @@ -54,7 +54,7 @@ class BrowserCompat { static get supportsSystemDisplay() { return BrowserCompat.hasAPI('system.display'); } - + /** * downloads.onDeterminingFilename support detection * This event is not available in Firefox @@ -63,7 +63,7 @@ class BrowserCompat { static get supportsOnDeterminingFilename() { return BrowserCompat.hasAPI('downloads.onDeterminingFilename'); } - + /** * Get screen size (cross-browser) * Uses system.display API on Chrome, falls back to window.screen on Firefox @@ -82,7 +82,7 @@ class BrowserCompat { top: 0 }; } - + /** * Request keep awake (cross-browser) * Silently ignored on Firefox where power API is not available @@ -94,7 +94,7 @@ class BrowserCompat { } // Firefox: silently ignore - no power API available } - + /** * Release keep awake (cross-browser) * Silently ignored on Firefox where power API is not available @@ -105,7 +105,7 @@ class BrowserCompat { } // Firefox: silently ignore - no power API available } - + /** * Get platform information (cross-browser) * Uses navigator.userAgentData on modern browsers, falls back to browser.runtime.getPlatformInfo