您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Automatically downloads torrents within your size and count limits (perfect for 2x seedbonus). Configure min/max size, download limit, and total size. Click "Download Start" on the search page and keep the tab open.
// ==UserScript== // @name TorrentBD-Torrent Downloader // @namespace Violentmonkey Scripts // @match https://www.torrentbd.net/* // @match https://www.torrentbd.com/* // @match https://www.torrentbd.org/* // @icon data:image/png;base64,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 // @version 2.0 // @run-at document-end // @author TheMyth // @grant GM_registerMenuCommand // @license MIT // @description Automatically downloads torrents within your size and count limits (perfect for 2x seedbonus). Configure min/max size, download limit, and total size. Click "Download Start" on the search page and keep the tab open. // ==/UserScript== // Default configuration const defaultConfig = { max: [200,"mb"], min: [100, "mb"], downloadLimit: 200, sumDownloadSize: null, }; // Function to get current user config function getUserConfig() { const savedConfig = localStorage.getItem("torrentBDConfig"); if (savedConfig) { try { return JSON.parse(savedConfig); } catch (e) { console.error("Failed to parse saved config:", e); return defaultConfig; } } return defaultConfig; } // Function to process config into working format function processConfig(userConfig) { const t_c = {}; function converter(x) { if (["kib", "kb"].includes(String(x[1]).toLowerCase())) { return parseFloat(x[0]); } else if (["mib", "mb"].includes(String(x[1]).toLowerCase())) { return parseFloat(x[0]) * 1024; } else if (["gib", "gb"].includes(String(x[1]).toLowerCase())) { return parseFloat(x[0]) * 1024 * 1024; } else if (["tib", "tb"].includes(String(x[1]).toLowerCase())) { return parseFloat(x[0]) * 1024 * 1024 * 1024; } else { return null; } } if (userConfig.max) { t_c.max = converter(userConfig.max); } else { t_c.max = null; } if (userConfig.min) { t_c.min = converter(userConfig.min); } else { t_c.min = null; } if (userConfig.sumDownloadSize) { t_c.sumDownloadSize = converter(userConfig.sumDownloadSize); } else { t_c.sumDownloadSize = null; } t_c.downloadLimit = userConfig.downloadLimit; return t_c; } // Initialize config let Config = processConfig(getUserConfig()); let sumDownlodSize = 0.0; let DownloadedTorrents = 0; console.log(`User Config:`, Config); console.log("Last History:",getLocal()); function sleep(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); } function setLocal(object) { localStorage.setItem("endof", JSON.stringify(object)); alert(`Download Done!\nTotalDownloads:${object.DownloadedTorrents}\nLatTorrentName:${object.lastTorrentName}\nTotalFileSize:${object.sumDownlodSize}`) } function getLocal() { if (localStorage.getItem("endof")) { return JSON.parse(localStorage.getItem("endof")); } else { return null; } } /** * * @param {HTMLElement} element */ function getTheFileSize(element) { let el_TextContent = element .querySelector('div[title="File Size"') .textContent.split(" "); if (el_TextContent[2].toLowerCase() == "kib") { return parseFloat(el_TextContent[1]); } else if (el_TextContent[2].toLowerCase() == "mib") { return parseFloat(el_TextContent[1]) * 1024; } else if (el_TextContent[2].toLowerCase() == "gib") { return parseFloat(el_TextContent[1]) * 1024 * 1024; } else if (el_TextContent[2].toLowerCase() == "tib") { return parseFloat(el_TextContent[1]) * 1024 * 1024 * 1024; } } async function getTorrentData() { // Get fresh config at the start of download const currentUserConfig = getUserConfig(); Config = processConfig(currentUserConfig); console.log('Using current config:', Config); while (true) { /** * * @param {HTMLElement} element * @param {Float} fileSize */ async function downloadHelper(element, fileSize) { let title = element.querySelector("td:nth-child(2) a"); let dwnLink = element.querySelector("td:nth-child(3) a"); sumDownlodSize += fileSize; DownloadedTorrents += 1; dwnLink.click(); console.log(`${DownloadedTorrents}:${title.textContent}`); } let tableBody = document.querySelector( "#kuddus-results-container > table > tbody" ); let lastTorrentName = ""; for (let index = 0; index < tableBody.children.length; index++) { const element = tableBody.children[index]; let fileSize = getTheFileSize(element); if (Config.max && Config.min) { if (fileSize >= Config.min && fileSize <= Config.max) { downloadHelper(element, fileSize); await sleep(2000); } } else if (Config.max && fileSize <= Config.max) { downloadHelper(element, fileSize); await sleep(2000); } else if (Config.min && fileSize >= Config.min) { downloadHelper(element, fileSize); await sleep(2000); } if (Config.downloadLimit && Config.downloadLimit == DownloadedTorrents) { lastTorrentName = element.querySelector("td:nth-child(2) a").textContent; break; } else if ( Config.sumDownloadSize && sumDownlodSize >= Config.sumDownloadSize ) { lastTorrentName = element.querySelector("td:nth-child(2) a").textContent; break; } else if ( !Config.sumDownloadSize && !Config.downloadLimit && DownloadedTorrents == 100 ) { lastTorrentName = element.querySelector("td:nth-child(2) a").textContent; break; } } console.log(sumDownlodSize); console.log(DownloadedTorrents); let next = document.querySelector('li[title="Next page"]'); if (Config.downloadLimit && Config.downloadLimit == DownloadedTorrents) { setLocal({ sumDownlodSize: sumDownlodSize, DownloadedTorrents: DownloadedTorrents, page: parseInt(next.getAttribute("data-paginate-to")) - 1, lastTorrentName: lastTorrentName, }); return } else if ( Config.sumDownloadSize && sumDownlodSize >= Config.sumDownloadSize ) { setLocal({ sumDownlodSize: sumDownlodSize, DownloadedTorrents: DownloadedTorrents, page: parseInt(next.getAttribute("data-paginate-to")) - 1, lastTorrentName: lastTorrentName, }); return } else if ( !Config.sumDownloadSize && !Config.downloadLimit && DownloadedTorrents == 100 ) { setLocal({ sumDownlodSize: sumDownlodSize, DownloadedTorrents: DownloadedTorrents, page: parseInt(next.getAttribute("data-paginate-to")) - 1, lastTorrentName: lastTorrentName, }); return } if (!next) { return } else { next.click(); await sleep(2000); } } } async function dwnBtnFunc() { let resultContainer = document.querySelector("#kuddus-results-container"); if (resultContainer.childNodes.length == 0) { alert("No Torrent Found on th page"); } else if (resultContainer.childNodes.length > 0) { sumDownlodSize = 0.0; DownloadedTorrents = 0; getTorrentData(); } } // Create configuration UI function createConfigUI(panel) { const configPanel = document.createElement("div"); configPanel.id = "torrentbd-config-panel"; configPanel.style = "position: absolute; background: white; padding: 10px; border-radius: 5px; box-shadow: 0 0 10px rgba(0,0,0,0.2); z-index: 9999; display: none; color: black; font-size: 12px; width: 300px; top: 5%;left:30%;"; // Get current user config for the UI const currentUserConfig = getUserConfig(); configPanel.innerHTML = ` <h3 style="margin: 0 0 5px 0; font-size: 14px;">TorrentBD Settings</h3> <div style="display: grid; grid-template-columns: auto 60px 50px 55px; gap: 5px; align-items: center;"> <label title="Maximum size of a single torrent file">Max Size:</label> <input type="number" id="config-max-value" value="${currentUserConfig.max ? currentUserConfig.max[0] : ''}" style="width: 100%;" /> <select id="config-max-unit" style="width: 100%;"> ${['kb', 'mb', 'gb', 'tb'].map(unit => `<option value="${unit}" ${currentUserConfig.max && currentUserConfig.max[1].toLowerCase() === unit ? 'selected' : ''}>${unit}</option>`).join('')} </select> <div> <input type="checkbox" id="config-max-enabled" ${currentUserConfig.max ? 'checked' : ''} /> <label for="config-max-enabled"></label> </div> <label title="Minimum size of a single torrent file">Min Size:</label> <input type="number" id="config-min-value" value="${currentUserConfig.min ? currentUserConfig.min[0] : ''}" style="width: 100%;" /> <select id="config-min-unit" style="width: 100%;"> ${['kb', 'mb', 'gb', 'tb'].map(unit => `<option value="${unit}" ${currentUserConfig.min && currentUserConfig.min[1].toLowerCase() === unit ? 'selected' : ''}>${unit}</option>`).join('')} </select> <div> <input type="checkbox" id="config-min-enabled" ${currentUserConfig.min ? 'checked' : ''} /> <label for="config-min-enabled"></label> </div> <label title="Number of torrents to download">Download Limit:</label> <input type="number" id="config-limit-value" value="${currentUserConfig.downloadLimit || ''}" style="width: 100%;" /> <span></span> <div> <input type="checkbox" id="config-limit-enabled" ${currentUserConfig.downloadLimit ? 'checked' : ''} /> <label for="config-limit-enabled"></label> </div> <label title="Total size of all downloaded torrents">Sum Size:</label> <input type="number" id="config-sum-value" value="${currentUserConfig.sumDownloadSize ? currentUserConfig.sumDownloadSize[0] : ''}" style="width: 100%;" /> <select id="config-sum-unit" style="width: 100%;"> ${['kb', 'mb', 'gb', 'tb'].map(unit => `<option value="${unit}" ${currentUserConfig.sumDownloadSize && currentUserConfig.sumDownloadSize[1].toLowerCase() === unit ? 'selected' : ''}>${unit}</option>`).join('')} </select> <div> <input type="checkbox" id="config-sum-enabled" ${currentUserConfig.sumDownloadSize ? 'checked' : ''} /> <label for="config-sum-enabled"></label> </div> </div> <div style="display: flex; justify-content: space-between; margin-top: 10px;"> <button id="config-save" style="padding: 3px 8px;">Save</button> <button id="config-cancel" style="padding: 3px 8px;">Cancel</button> </div> <div style="font-size: 10px; margin-top: 5px;"> <strong>Tips:</strong> Hover over labels for descriptions </div> `; panel.appendChild(configPanel); // Add event listeners document.getElementById("config-save").addEventListener("click", saveConfig); document.getElementById("config-cancel").addEventListener("click", hideConfigPanel); // Helper functions function saveConfig() { const config = {}; if (document.getElementById("config-max-enabled").checked) { config.max = [ parseFloat(document.getElementById("config-max-value").value), document.getElementById("config-max-unit").value ]; } else { config.max = null; } if (document.getElementById("config-min-enabled").checked) { config.min = [ parseFloat(document.getElementById("config-min-value").value), document.getElementById("config-min-unit").value ]; } else { config.min = null; } if (document.getElementById("config-limit-enabled").checked) { config.downloadLimit = parseInt(document.getElementById("config-limit-value").value, 10); } else { config.downloadLimit = null; } if (document.getElementById("config-sum-enabled").checked) { config.sumDownloadSize = [ parseFloat(document.getElementById("config-sum-value").value), document.getElementById("config-sum-unit").value ]; } else { config.sumDownloadSize = null; } localStorage.setItem("torrentBDConfig", JSON.stringify(config)); // Update the current Config object immediately Config = processConfig(config); console.log('Config updated:', Config); alert("Settings saved successfully! You can now use DownloadStart with the new configuration."); hideConfigPanel(); } function hideConfigPanel() { const panel = document.getElementById("torrentbd-config-panel"); if (panel) { panel.style.display = "none"; } } } function showConfigPanel() { const panel = document.getElementById("torrentbd-config-panel"); if (panel) { panel.style.display = "block"; } else { console.error("Config panel not found. Make sure createConfigUI was called."); } } // Register menu command for configuration GM_registerMenuCommand('TorrentBD Downloader Settings', showConfigPanel); let panel = document.querySelector("#kuddus-wrapper"); const dwnBtn = document.createElement("button"); dwnBtn.textContent = "DownloadStart"; dwnBtn.setAttribute("align", "center"); dwnBtn.setAttribute("title", "DownloadStart"); dwnBtn.style = "position: fixed; top: -6px; left: 70px; border-radius: 4px; margin: 6px 8px; padding: 6px 14px; border: none; opacity: 0.5;"; dwnBtn.addEventListener("click", dwnBtnFunc); if (panel.children.length > 0) { // Check if panel has children to avoid errors panel.insertBefore(dwnBtn, panel.children[panel.children.length - 1]); } else { panel.appendChild(dwnBtn); // If panel has no children, just append it } let panel2=document.querySelector(".kuddus") // Initialize configuration UI createConfigUI(panel2);