您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds magnet links to BT4G and Limetorrents
当前为
// ==UserScript== // @name Magnet Links for BT4G and Limetorrents // @description Adds magnet links to BT4G and Limetorrents // @version 20240913 // @author mykarean // @match *://bt4gprx.com/* // @match *://*.limetorrents.*/search/all/* // @run-at document-idle // @grant GM_xmlhttpRequest // @grant GM_addStyle // @compatible chrome // @license GPL3 // @noframes // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAAMFBMVEUAAAD/////PwA/v/8KIDUifaxN2//Cw8L5ywC8hwBuQwA+HQDSLAcPBAJvb2////9VWbprAAAAEHRSTlP///////////////////8A4CNdGQAAAAlwSFlzAAALEwAACxMBAJqcGAAABr5pVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDYuMC1jMDA1IDc5LjE2NDU5MCwgMjAyMC8xMi8wOS0xMTo1Nzo0NCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iIHhtbG5zOnBob3Rvc2hvcD0iaHR0cDovL25zLmFkb2JlLmNvbS9waG90b3Nob3AvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0RXZ0PSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VFdmVudCMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIDIyLjEgKFdpbmRvd3MpIiB4bXA6Q3JlYXRlRGF0ZT0iMjAyNC0wNi0yMVQwODoyMTo0NCswMjowMCIgeG1wOk1vZGlmeURhdGU9IjIwMjQtMDYtMjFUMTI6MDA6MzQrMDI6MDAiIHhtcDpNZXRhZGF0YURhdGU9IjIwMjQtMDYtMjFUMTI6MDA6MzQrMDI6MDAiIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIiBwaG90b3Nob3A6Q29sb3JNb2RlPSIyIiBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODZhZDM2M2ItOWY4Ny0xNzQ3LWE2MDQtOTBmODg4MzA3MmU5IiB4bXBNTTpEb2N1bWVudElEPSJhZG9iZTpkb2NpZDpwaG90b3Nob3A6ODVkNmE1ODktZmZhZC1kYTRmLWE1NTktOTc5ODAxNmRkMDJjIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6YjAwNjgyYTQtMGQ2NS01YjRlLTg3MTMtMGVmYzNlN2U4ODI0Ij4gPHhtcE1NOkhpc3Rvcnk+IDxyZGY6U2VxPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0iY3JlYXRlZCIgc3RFdnQ6aW5zdGFuY2VJRD0ieG1wLmlpZDpiMDA2ODJhNC0wZDY1LTViNGUtODcxMy0wZWZjM2U3ZTg4MjQiIHN0RXZ0OndoZW49IjIwMjQtMDYtMjFUMDg6MjE6NDQrMDI6MDAiIHN0RXZ0OnNvZnR3YXJlQWdlbnQ9IkFkb2JlIFBob3Rvc2hvcCAyMi4xIChXaW5kb3dzKSIvPiA8cmRmOmxpIHN0RXZ0OmFjdGlvbj0ic2F2ZWQiIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6OTNhYTg2MjktN2RhNy0wOTQ4LWI0Y2UtODQ1YjM2ODA4ZmQzIiBzdEV2dDp3aGVuPSIyMDI0LTA2LTIxVDA4OjUzOjAzKzAyOjAwIiBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgMjIuMSAoV2luZG93cykiIHN0RXZ0OmNoYW5nZWQ9Ii8iLz4gPHJkZjpsaSBzdEV2dDphY3Rpb249InNhdmVkIiBzdEV2dDppbnN0YW5jZUlEPSJ4bXAuaWlkOjg2YWQzNjNiLTlmODctMTc0Ny1hNjA0LTkwZjg4ODMwNzJlOSIgc3RFdnQ6d2hlbj0iMjAyNC0wNi0yMVQxMjowMDozNCswMjowMCIgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWRvYmUgUGhvdG9zaG9wIDIyLjEgKFdpbmRvd3MpIiBzdEV2dDpjaGFuZ2VkPSIvIi8+IDwvcmRmOlNlcT4gPC94bXBNTTpIaXN0b3J5PiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PocnnoQAAAGsSURBVFjD7ZdJcsQgDEV/wNACQXz/22YRNzOSU92VRSpaUv4PDWAknFtDY8JXuliG4K58h4CmziwzoO0eg+wFNOdDlAOBoo+kpAJK7igo2YSsjxQB5JrSiYBJz23aiZhDyHNJZkDdNNbPIhFRiYJzjFMUmPznUOMmIiKKBRd4ysMMQN3y24FSh0CEHaCv/FV7Jgqx+sOhr2kL6DLP4AsQMxDo6XZkLI41lhXk3AS0WBwBEGx9kioBip6JIRJGwGe19jI2y1kE5I9ij+tYAQAedf2YABABLAGgAy6HJQBEAGQA3g5AMk9L7bLzxRQPtgD7tBGA1wD4B/wD/grg5cv0FwDn5o9k8g3AKQGaJ+mw1TABOkKsgJQXDninPG1sFoQmABWQTUvgDOBo9NYfC8C5SYIxJiVnbau3q+e9I7DpzTfywYFNhzK4YDu93bQ45y4LI+DYNFn7IDpAV4J9n9iehQ4wlXDd6g6nSdEvmu0+igLwa/2u3S+3MhX5sR4YtgMHXwjrvffWHTcGjhGROaWUnHNuL9eHrqxNj7g7dN4c+1TCb4y+7xi+fzL+fwG9j0ZciTgBKAAAAABJRU5ErkJggg== // @namespace https://greasyfork.org/users/1367334 // ==/UserScript== "use strict"; GM_addStyle(` .magnet-link-img { cursor: pointer; margin: 0px 5px 2px; border-radius: 50%; vertical-align: bottom; height: 20px; transition: filter 0.2s ease; } `); const hostname = location.hostname; let magnetImage = GM_info.script.icon; /** * @param {String} tag Elements HTML Tag * @param {String|RegExp} regex Regular expression or string for text search * @param {Number} index Item Index * @returns {Object|null} Node or null if not found */ function getElementByText(tag, regex, item = 0) { if (typeof regex === "string") { regex = new RegExp(regex); } const elements = document.getElementsByTagName(tag); let count = 0; for (let i = 0; i < elements.length; i++) { if (regex.test(elements[i].textContent)) { if (count === item) { return elements[i]; } count++; } } return null; } // --------------------------------------------------------- // search results handling // --------------------------------------------------------- function observeSearchResults() { const observer = new MutationObserver(() => { observer.disconnect(); setTimeout(() => { processLinksInSearchResults().then(() => { observeSearchResults(); }); }, 500); }); observer.observe(document, { childList: true, subtree: true, attributes: true, attributeFilter: ["style"], }); } async function processLinksInSearchResults() { const links = Array.from(getSearchResultLinks()); const promises = links.map(async (link) => { if (hostname === "bt4gprx.com") { await processLinksInSearchResultsBt4g(link); } else if (hostname === "www.limetorrents.lol") { await processLinksInSearchResultsLimeTorrents(link); } }); await Promise.all(promises); // Add amount of visible magnet links into text const amountVisibleMagnets = links.length; const magnetLinkAllSpan = document.querySelector(".magnet-link-all-span"); if (amountVisibleMagnets > 0 && magnetLinkAllSpan) { magnetLinkAllSpan.innerHTML = `Open all <b>${amountVisibleMagnets}</b> loaded magnet links`; } // Remove spam elements setTimeout(() => { links.forEach((link) => { const title = link.title; if (title.includes("Downloader.exe") || title.includes("Downloader.dmg")) { link.parentElement.parentElement.style.display = "none"; } }); }, 100); } function getSearchResultLinks() { if (hostname === "bt4gprx.com") { const elements = document.querySelectorAll('a[href*="/magnet/"]:not([href^="magnet:"])'); // Filter and return only the visible elements (those without 'display: none' in their parent chain) return Array.from(elements).filter((element) => { let current = element; while (current) { if (window.getComputedStyle(current).display === "none") { return false; } current = current.parentElement; } return true; }); } else if (hostname === "www.limetorrents.lol") { return document.querySelectorAll('a[href*="//itorrents.org/torrent/"]'); } } async function processLinksInSearchResultsBt4g(link) { try { const details = { method: "GET", url: link.href, timeout: 5000, }; const response = await requestGM_XHR(details); const html = response.responseText; // Find magnet links const parser = new DOMParser(); const doc = parser.parseFromString(html, "text/html"); // Skip if magnet link exists const magnetLink = link.getAttribute("data-magnet-added"); if (magnetLink === "true") { return; } const downloadLink = doc.querySelector('a[href^="//downloadtorrentfile.com/hash/"]'); if (downloadLink) { const hash = extractHashFromUrl(downloadLink.href.split("/").pop().split("?")[0]); if (hash) { insertMagnetLink(link, hash); link.setAttribute("data-magnet-added", "true"); } } } catch (error) { console.error("Error getting magnet link:", error); } } function requestGM_XHR(details) { return new Promise((resolve, reject) => { details.onload = function (response) { resolve(response); }; details.onerror = function (response) { reject(response); }; details.ontimeout = function () { reject(new Error("Request timed out")); }; GM_xmlhttpRequest(details); }); } function processLinksInSearchResultsLimeTorrents(link) { // Skip if magnet link exists const magnetLink = link.getAttribute("data-magnet-added"); if (magnetLink === "true") { return; } const hash = extractHashFromUrl(link.href.split("/").pop().split("?")[0]); if (hash) { insertMagnetLink(link, hash); link.setAttribute("data-magnet-added", "true"); // Hide unnecessary element link.style.display = "none"; } } // --------------------------------------------------------- function insertMagnetLink(link, hash) { const magnetLink = `magnet:?xt=urn:btih:${hash}`; const newLink = document.createElement("a"); newLink.classList.add("magnet-link"); newLink.href = magnetLink; newLink.addEventListener("click", function () { imgElement.style.filter = "grayscale(100%) opacity(0.7)"; }); const imgElement = document.createElement("img"); imgElement.src = magnetImage; imgElement.classList.add("magnet-link-img"); newLink.appendChild(imgElement); link.parentNode.insertBefore(newLink, link); } function extractHashFromUrl(href) { const hashRegex = /(^|\/|&|-|\.|\?|=|:)([a-fA-F0-9]{40})/; const matches = href.match(hashRegex); return matches ? matches[2] : null; } // --------------------------------------------------------- function addClickAllMagnetLinks() { // only needed if document-start // const openAllMagnetLinks = document.querySelector(".magnet-link-all-span"); // if (openAllMagnetLinks) { // return; // } let itemsFoundElement; if (hostname === "bt4gprx.com") { itemsFoundElement = getElementByText("span", /Found\ [0-9].*\ items\ for\ .*/i); } else if (hostname === "www.limetorrents.lol") { itemsFoundElement = getElementByText("h2", "Search Results"); } const targetElement = itemsFoundElement?.parentElement?.children[1]; if (targetElement) { const openAllMagnetLinksSpan = document.createElement("span"); openAllMagnetLinksSpan.innerHTML = "Open all <b>0</b> loaded magnet links"; openAllMagnetLinksSpan.classList.add("magnet-link-all-span"); openAllMagnetLinksSpan.style.marginLeft = "10px"; const openAllMagnetLinksImg = document.createElement("img"); openAllMagnetLinksImg.src = magnetImage; openAllMagnetLinksImg.classList.add("magnet-link-img"); openAllMagnetLinksImg.style.cssText = "cursor:pointer;vertical-align:sub;"; targetElement.parentNode.insertBefore(openAllMagnetLinksSpan, targetElement.nextSibling); openAllMagnetLinksSpan.parentNode.insertBefore(openAllMagnetLinksImg, openAllMagnetLinksSpan.nextSibling); openAllMagnetLinksImg.addEventListener("click", () => { const addedMagnetLinks = document.querySelectorAll("a.magnet-link"); if (addedMagnetLinks.length > 0) { openAllMagnetLinksImg.style.filter = "grayscale(100%) opacity(0.7)"; addedMagnetLinks.forEach((link, index) => { // ignore hidden elements if (getComputedStyle(link.parentElement.parentElement).display !== "none") { setTimeout(() => { link.click(); }, index * 100); } }); } else { openAllMagnetLinksSpan.textContent = "No magnet links found"; } }); // for a fixed position and more space, remove superfluous information if (hostname === "bt4gprx.com") { itemsFoundElement.innerHTML = itemsFoundElement.innerHTML.replace(/(\ items)\ for\ .*/, "$1"); } else if (hostname === "www.limetorrents.lol") { itemsFoundElement.textContent = ""; } } } function main() { switch (true) { // search results page case /\/search/.test(window.location.href): addClickAllMagnetLinks(); observeSearchResults(); processLinksInSearchResults(); break; // BT4G only: torrent detail page case /\/magnet/.test(window.location.href): const link = document.querySelector('a[href*="/hash/"]:not([href^="magnet:"])'); const hash = extractHashFromUrl(link ? link.href : ""); if (hash) { insertMagnetLink(link, hash); } break; } } main();