您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Intercept magnet links and open qBittorrent download dialog in a popup.
// ==UserScript== // @name Magnet Link Handler for qBittorrent WebUI // @namespace http://tampermonkey.net/ // @version 1.4 // @author down_to_earth // @description Intercept magnet links and open qBittorrent download dialog in a popup. // @match *://*/* // @grant GM_getValue // @grant GM_setValue // @grant GM_registerMenuCommand // @license MIT // ==/UserScript== (async function() { 'use strict'; async function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function setValue(node, value) { if (!node || value === undefined) { return; } function triggerChangeEvent(node) { const event = new Event('change', { bubbles: true }); node.dispatchEvent(event); } if (node.type === 'checkbox' || node.type === 'radio') { if (node.checked !== value) { node.checked = value; triggerChangeEvent(node); } } else { if (node.value !== value) { node.value = value; triggerChangeEvent(node); } } } function saveSettings(sourceHostname) { const settings = {}; // Save all <select> elements document.querySelectorAll('select:not([disabled]):not([hidden])').forEach(select => { const key = select.name || select.id; settings[key] = select.value; }); // Save all <input> elements document.querySelectorAll('input:not([disabled]):not([hidden])').forEach(input => { const key = input.name ||input.id; if (input.type === 'checkbox' || input.type === 'radio') { settings[key] = input.checked; } else { settings[key] = input.value; } }); // Save to localStorage localStorage.setItem(`settings_${sourceHostname}`, JSON.stringify(settings)); } async function restoreSettings(sourceHostname) { const settings = JSON.parse(localStorage.getItem(`settings_${sourceHostname}`) || 'null'); if (!settings) { return; } const categoryValue = settings.categorySelect; const categorySelect = document.querySelector('#categorySelect'); if (categoryValue && categorySelect) { // Wait for categories to load while (!Array.from(categorySelect.options).some(option => option.value === categoryValue)) { await sleep(10); } setValue(categorySelect, categoryValue); } // Restore all <select> elements document.querySelectorAll('select:not([disabled]):not([hidden])').forEach(select => { const key = select.name || select.id; if (key === 'categorySelect') { return; } setValue(select, settings[key]); }); // Restore all <input> elements document.querySelectorAll('input:not([disabled]):not([hidden])').forEach(input => { const key = input.name || input.id; setValue(input, settings[key]); }); } // Define the default qBittorrent WebUI URL const defaultQbWebUIHost = 'http://localhost:8080'; // Retrieve the saved qBittorrent WebUI URL or use the default let qbWebUIHost = GM_getValue('qbWebUIHost', defaultQbWebUIHost); // Add a menu command to set the qBittorrent WebUI URL GM_registerMenuCommand('Set qBittorrent WebUI URL', () => { const newUrl = prompt('Enter the qBittorrent WebUI URL:', qbWebUIHost); if (newUrl) { GM_setValue('qbWebUIHost', newUrl); // Save the new URL qbWebUIHost = newUrl; // Update the script's URL alert(`qBittorrent WebUI URL set to: ${newUrl}`); } }); // Check if the current page is the qBittorrent WebUI's const isMainPage = window.location.href.startsWith(qbWebUIHost) && window.location.pathname === '/'; const isDownloadPage = window.location.href.startsWith(qbWebUIHost) && window.location.pathname === '/download.html'; if (isMainPage) { const showDownloadPopup = async () => { const urlParams = new URLSearchParams(window.parent.location.search); const encodedSource = urlParams.get('source'); if (!encodedSource) { // Do nothing if it's a normal WebUI open return; } const downloadIframe = document.createElement('iframe'); const downloadUrl = new URL(window.location.href); downloadUrl.pathname = '/download.html'; downloadIframe.src = downloadUrl.toString(); downloadIframe.style.position = 'fixed'; downloadIframe.style.top = '0'; downloadIframe.style.left = '0'; downloadIframe.style.width = '100%'; downloadIframe.style.height = '100%'; downloadIframe.style.border = 'none'; downloadIframe.style.zIndex = '9999'; downloadIframe.style.backgroundColor = 'white'; // Append the iframe to the document body document.body.appendChild(downloadIframe); }; if (document.readyState == 'complete') { await showDownloadPopup(); } else { window.addEventListener("load", showDownloadPopup); } } else if (isDownloadPage) { // Check if the URL contains the `?source=` parameter const urlParams = new URLSearchParams(window.parent.location.search); const encodedSource = urlParams.get('source'); if (!encodedSource) { return; } // Wait for the preferences to load const savePath = document.querySelector('#savepath'); while (!savePath.value) { await sleep(10); } const sourceHostname = decodeURIComponent(encodedSource); // Register close handler const downloadFrame = document.querySelector('#download_frame'); downloadFrame.addEventListener("load", function() { saveSettings(sourceHostname); window.parent.close(); }); await restoreSettings(sourceHostname); const autoDownload = urlParams.get('autoDownload') === 'true'; if (autoDownload) { document.querySelector('#submitButton')?.click(); } } else { // Function to handle magnet link clicks function handleMagnetLinkClick(event) { if ((event.type === 'click' && event.button !== 0) || (event.type === 'mouseup' && event.button !== 1)) { return; } let target = event.target; while (target && target.tagName !== 'A') { target = target.parentElement; } // Check if the clicked element is a magnet link if (target?.href.startsWith('magnet:')) { event.preventDefault(); // Prevent the default behavior // Encode the magnet link for use in a URL const encodedMagnetLink = encodeURIComponent(target.href); // Get the source website hostname const sourceHostname = window.location.hostname; // Trigger auto download if clicked with Ctrl or Middle mouse click const autoDownload = event.ctrlKey || event.button === 1; // Open the qBittorrent WebUI's magnet handler in a popup const popupUrl = `${qbWebUIHost}/?urls=${encodedMagnetLink}&source=${sourceHostname}&autoDownload=${autoDownload}` // Define the popup dimensions const popupWidth = 500; const popupHeight = window.screen.height; // Calculate the position to center the popup const left = (window.screen.width - popupWidth) / 2; const top = (window.screen.height - popupHeight) / 2; // Open the popup with centered position let popupName = 'qBittorrentAddMagnet'; if (autoDownload) { popupName += crypto.randomUUID() } window.open( popupUrl, popupName, `width=${popupWidth},height=${popupHeight},left=${left},top=${top}` ); } } // Attach the event listeners to the document document.addEventListener('click', handleMagnetLinkClick, true); document.addEventListener('mouseup', handleMagnetLinkClick, true); } })();