您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Real-Debrid.com magnet link converter with streaming support, adds a tab for a converted magnet to RD download and streaming link and then copies to the clipboard when you click on it
// ==UserScript== // @name RD-MagnetDL // @namespace http://tampermonkey.net/ // @version 0.1 // @description Real-Debrid.com magnet link converter with streaming support, adds a tab for a converted magnet to RD download and streaming link and then copies to the clipboard when you click on it // @author goodchoice // @license MIT // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_setClipboard // ==/UserScript== (function() { 'use strict'; const API_KEY = ''; const BASE_URL = 'https://api.real-debrid.com/rest/1.0/'; function convertMagnetToRD(magnetLink, isStreaming = false, button) { console.log(`Converting magnet link: ${magnetLink}, isStreaming: ${isStreaming}`); GM_xmlhttpRequest({ method: 'POST', url: `${BASE_URL}torrents/addMagnet`, data: `magnet=${encodeURIComponent(magnetLink)}`, headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/x-www-form-urlencoded', }, onload: function(response) { console.log('addMagnet response:', response); if (response.status === 201) { const torrentId = JSON.parse(response.responseText).id; console.log('Torrent ID:', torrentId); // Select files regardless of the action (download or stream) selectFiles(torrentId, isStreaming, button); } else { console.error('Error adding magnet:', response.status, response.responseText); alert('Error adding magnet link. Check console for details.'); resetButton(button); } }, onerror: function(error) { console.error('Request failed:', error); alert('Network error. Check console for details.'); resetButton(button); } }); } function selectFiles(torrentId, isStreaming, button) { console.log(`Selecting files for torrent ID: ${torrentId}`); GM_xmlhttpRequest({ method: 'POST', url: `${BASE_URL}torrents/selectFiles/${torrentId}`, data: 'files=all', headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/x-www-form-urlencoded', }, onload: function(response) { console.log('selectFiles response:', response); if (response.status === 204) { if (isStreaming) { getStreamingLink(torrentId, button); } else { getDownloadLink(torrentId, button); } } else { console.error('Error selecting files:', response.status, response.responseText); alert('Error selecting files. Check console for details.'); resetButton(button); } }, onerror: function(error) { console.error('Request failed:', error); alert('Network error. Check console for details.'); resetButton(button); } }); } function getDownloadLink(torrentId, button) { console.log(`Getting download link for torrent ID: ${torrentId}`); GM_xmlhttpRequest({ method: 'GET', url: `${BASE_URL}torrents/info/${torrentId}`, headers: { 'Authorization': `Bearer ${API_KEY}` }, onload: function(response) { console.log('getDownloadLink response:', response); if (response.status === 200) { const downloadLinks = JSON.parse(response.responseText).links; unrestrictLinks(downloadLinks, button); } else { console.error('Error getting download link:', response.status, response.responseText); alert('Error getting download link. Check console for details.'); resetButton(button); } }, onerror: function(error) { console.error('Request failed:', error); alert('Network error. Check console for details.'); resetButton(button); } }); } function unrestrictLinks(links, button) { console.log('Unrestricting links:', links); const unrestrictedLinks = []; function processLink(index) { if (index >= links.length) { console.log('Unrestricted download links:', unrestrictedLinks); GM_setClipboard(unrestrictedLinks.join('\n')); alert('Unrestricted download links copied to clipboard!'); resetButton(button); return; } const link = links[index]; GM_xmlhttpRequest({ method: 'POST', url: `${BASE_URL}unrestrict/link`, data: `link=${encodeURIComponent(link)}`, headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/x-www-form-urlencoded' }, onload: function(response) { console.log(`Unrestricting link ${link}:`, response); if (response.status === 200) { const unrestrictedLink = JSON.parse(response.responseText).download; unrestrictedLinks.push(unrestrictedLink); processLink(index + 1); } else { console.error('Error unrestricting link:', response.status, response.responseText); alert(`Error unrestricting link: ${link}`); resetButton(button); } }, onerror: function(error) { console.error('Request failed:', error); alert('Network error during link unrestriction. Check console for details.'); resetButton(button); } }); } processLink(0); } function getStreamingLink(torrentId, button) { console.log(`Getting streaming link for torrent ID: ${torrentId}`); GM_xmlhttpRequest({ method: 'GET', url: `${BASE_URL}torrents/info/${torrentId}`, headers: { 'Authorization': `Bearer ${API_KEY}` }, onload: function(response) { console.log('getTorrentInfo response:', response); if (response.status === 200) { const torrentInfo = JSON.parse(response.responseText); if (torrentInfo.status === 'downloaded') { const links = torrentInfo.links; if (links && links.length > 0) { // First unrestrict the download link GM_xmlhttpRequest({ method: 'POST', url: `${BASE_URL}unrestrict/link`, data: `link=${encodeURIComponent(links[0])}`, headers: { Authorization: `Bearer ${API_KEY}`, 'Content-Type': 'application/x-www-form-urlencoded' }, onload: function(unrestrictResponse) { console.log('Unrestrict response:', unrestrictResponse); if (unrestrictResponse.status === 200) { const unrestrictedInfo = JSON.parse(unrestrictResponse.responseText); const downloadUrl = unrestrictedInfo.download; const match = downloadUrl.match(/\/d\/([^/]+)/); if (match && match[1]) { const streamingId = match[1]; const streamingUrl = `https://real-debrid.com/streaming-${streamingId}`; console.log('Streaming URL:', streamingUrl); GM_setClipboard(streamingUrl); alert('Streaming link copied to clipboard!'); resetButton(button); } else { console.error('Could not extract streaming ID'); alert('Error generating streaming link'); resetButton(button); } } else { console.error('Error unrestricting link:', unrestrictResponse.status); alert('Error generating streaming link'); resetButton(button); } }, onerror: function(error) { console.error('Request failed:', error); alert('Network error during link unrestriction'); resetButton(button); } }); } else { console.error('No download links available'); alert('No download links available'); resetButton(button); } } else { console.log('Torrent not ready, waiting...'); setTimeout(() => getStreamingLink(torrentId, button), 2000); } } else { console.error('Error checking torrent status:', response.status); alert('Error checking torrent status'); resetButton(button); } }, onerror: function(error) { console.error('Request failed:', error); alert('Network error checking torrent status'); resetButton(button); } }); } function createRDButton(type) { const button = document.createElement('button'); button.textContent = type === 'download' ? 'RD DL' : 'RD Stream'; button.classList.add('rd-button', `rd-${type}`); button.style.cssText = ` margin-left: 5px; padding: 2px 8px; border-radius: 4px; border: 1px solid #ccc; background: #f0f0f0; cursor: pointer; `; return button; } function resetButton(button) { button.disabled = false; button.textContent = button.classList.contains('rd-download') ? 'RD DL' : 'RD Stream'; } function addRDButton(magnetLink) { if (magnetLink.nextSibling?.classList?.contains('rd-button')) return; const buttonContainer = document.createElement('span'); buttonContainer.style.display = 'inline-block'; const dlButton = createRDButton('download'); const streamButton = createRDButton('stream'); dlButton.addEventListener('click', (e) => { e.preventDefault(); dlButton.disabled = true; dlButton.textContent = 'Converting...'; convertMagnetToRD(magnetLink.href, false, dlButton); }); streamButton.addEventListener('click', (e) => { e.preventDefault(); streamButton.disabled = true; streamButton.textContent = 'Converting...'; convertMagnetToRD(magnetLink.href, true, streamButton); }); buttonContainer.appendChild(dlButton); buttonContainer.appendChild(streamButton); magnetLink.parentNode.insertBefore(buttonContainer, magnetLink.nextSibling); } function processMagnetLinks() { const magnetLinks = document.querySelectorAll('a[href^="magnet:"]'); magnetLinks.forEach(addRDButton); } // Initialize processMagnetLinks(); // Watch for new magnet links const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // Element node const magnetLinks = node.querySelectorAll('a[href^="magnet:"]'); magnetLinks.forEach(addRDButton); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })();