您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a column with torrent and magnet links, extends titles, adds images, full width site with configurable settings
// ==UserScript== // @name 1337x - Combined Enhancements 2025 (v12) - Configurable // @namespace http://tampermonkey.net/ // @version 2025.12 // @description Adds a column with torrent and magnet links, extends titles, adds images, full width site with configurable settings // @author sharmanhall // @contributor darkred, NotNeo, barn852, French Bond // @match *://*.1337x.to/* // @match *://*.1337x.ws/* // @match *://*.1337x.eu/* // @match *://*.1337x.se/* // @match *://*.1337x.is/* // @match *://*.1337x.gd/* // @match *://*.x1337x.cc/* // @match *://*.1337x.st/* // @match *://*.x1337x.ws/* // @match *://*.x1337x.eu/* // @match *://*.x1337x.se/* // @match http://l337xdarkkaqfwzntnfk5bmoaroivtl6xsbatabvlb52umg6v3ch44yd.onion/* // @match https://www.1337x.to/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // @license MIT // @icon https://www.google.com/s2/favicons?sz=64&domain=1337x.to // ==/UserScript== // // Thanks to: // - French Bond: modified original script taken from https://greasyfork.org/en/scripts/479974-1337x-ux-enhancement // - darkred: modified original script taken from https://greasyfork.org/en/scripts/479974-1337x-ux-enhancement // - NotNeo: most of the CSS used is taken from this script: https://greasyfork.org/en/scripts/373230-1337x-magnet-torrent-links-everywhere . // - barn852 for his contribution here: https://greasyfork.org/en/scripts/420754-1337x-torrent-and-magnet-links/discussions/96026 // // Official mirrors list: https://1337x.to/about // // @downloadURL https://update.greasyfork.org/scripts/483602/1337x%20-%20Combined%20Enhancements%202024.user.js // @updateURL https://update.greasyfork.org/scripts/483602/1337x%20-%20Combined%20Enhancements%202024.meta.js // ==/UserScript== (function() { 'use strict'; // Configuration object let config = { showThumbnails: GM_getValue('showThumbnails', true), showExtraColumn: GM_getValue('showExtraColumn', true), //shows column with magnet/torrent links showButtonsInNameColumn: GM_getValue('showButtonsInNameColumn', false), // new option, defaults to false fullWidthSite: GM_getValue('fullWidthSite', true), visibleImages: GM_getValue('visibleImages', 4), queueFetchDelay: GM_getValue('queueFetchDelay', 0), //default value is 0ms between fetch requests maxRetries: GM_getValue('maxRetries', 1) //default is 2 max retries per queue request }; let extraColumnAdded = false; // CSS for the settings menu const settingsCSS = ` .list-button-magnet > i.flaticon-magnet { font-size: 13px; color: #da3a04 } .list-button-dl > i.flaticon-torrent-download { font-size: 13px; color: #89ad19; } table.table-list td.dl-buttons { border-left: 1px solid #f6f6f6; border-right: 1px solid #c0c0c0; padding-left: 2.5px; padding-right: 2.5px; text-align: center !important; position: relative; display: table-cell !important; width: 6%; } td.dl-buttons > a, td.dl-buttons > a:hover, td.dl-buttons > a:visited, td.dl-buttons > a:link, td.dl-buttons > a:active { color: inherit; text-decoration: none; cursor: pointer; display: inline-block !important; margin: 0 2px; } table.table-list td.coll-1b { border-right: 1px solid silver; } .table-list > thead > tr > th:nth-child(2), .table-list > thead > tr > td:nth-child(2) { text-align: center; } #x1337-settings-wrapper { font-family: 'Open Sans', sans-serif; background-color: #1d1d1d; color: #fff; border-radius: 5px; box-shadow: 0 0 10px rgba(241, 78, 19, 0.5); position: fixed; top: 20px; right: -300px; /* Start off-screen */ width: 300px; transition: right 0.3s ease; z-index: 9999; } #x1337-settings-toggle { position: absolute; left: -30px; top: 0; width: 30px; height: 30px; background-color: #F14E13; border-top-left-radius: 5px; border-bottom-left-radius: 5px; box-shadow: -2px 0 5px rgba(0,0,0,0.2); cursor: pointer; text-align: center; line-height: 30px; } #x1337-settings-content { padding: 15px; } #x1337-settings-content h3 { color: #F14E13; border-bottom: 1px solid #F14E13; padding-bottom: 10px; margin-bottom: 15px; } .x1337-option { margin-bottom: 15px; color: #fff; } .x1337-option label { display: flex; align-items: center; cursor: pointer; color: #fff; } .x1337-option input[type="checkbox"] { margin-right: 10px; } .x1337-option input[type="number"], .x1337-option input[type="text"] { background-color: #2d2d2d; border: 1px solid #F14E13; color: #fff; padding: 5px; border-radius: 3px; } #x1337-save-settings { background-color: #F14E13; color: #fff; border: none; padding: 10px 20px; border-radius: 3px; cursor: pointer; transition: background-color 0.3s; box-shadow: 0 0 10px rgba(241, 78, 19, 0.5); } #x1337-save-settings:hover { background-color: #ff6a3c; } /* Custom radio buttons */ .x1337-option input[type="radio"] { display: none; } .x1337-option input[type="radio"] + label:before { content: ''; display: inline-block; width: 16px; height: 16px; margin-right: 10px; border: 2px solid #F14E13; border-radius: 50%; background-color: #2d2d2d; } .x1337-option input[type="radio"]:checked + label:before { background-color: #F14E13; box-shadow: inset 0 0 0 3px #2d2d2d; } /* Ensure text is always white for better readability */ #x1337-settings-wrapper, #x1337-settings-wrapper * { color: #fff; } #x1337-popup { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); background-color: #F14E13; color: #fff; padding: 10px 20px; border-radius: 5px; z-index: 10000; opacity: 0; transition: opacity 0.3s ease-in-out; } `; const settingsHTML = ` <script> </script> <div id="x1337-settings-wrapper"> <div id="x1337-settings-toggle">⚙️</div> <div id="x1337-settings-content"> <h3>1337x Enhancements Settings</h3> <div class="x1337-option"> <label> <input type="checkbox" id="x1337-show-thumbnails" ${config.showThumbnails ? 'checked' : ''}> Show Thumbnails </label> <div class="x1337-sub-option" ${config.showThumbnails ? '' : 'style="display:none;"'}> <label> Visible Images: <input type="number" id="x1337-visible-images" value="${config.visibleImages}" min="1" max="10"> </label> <label> Queue Fetch Delay (ms): <input type="number" id="x1337-queue-fetch-delay" value="${config.queueFetchDelay}" min="50" max="5000"> </label> <label> Max Fetch Retries: <input type="number" id="x1337-max-retries" value="${config.maxRetries}" min="0" max="10"> </label> </div> </div> <div class="x1337-option"> <label> <input type="checkbox" id="x1337-show-magnet-column" ${config.showExtraColumn ? 'checked' : ''}> Show Magnet URL Column </label> </div> <div class="x1337-option"> <label> <input type="checkbox" id="x1337-show-buttons-in-name" ${config.showButtonsInNameColumn ? 'checked' : ''}> Show Buttons in Name Column </label> </div> <div class="x1337-option"> <label> <input type="checkbox" id="x1337-full-width-site" ${config.fullWidthSite ? 'checked' : ''}> Full Width Site </label> </div> <button id="x1337-save-settings">Save Settings</button><br> <small>v2025.12 | by sharmanhall</small> </div> </div> `; function appendColumn() { if (!config.showExtraColumn || extraColumnAdded) return; const allTables = document.querySelectorAll('.table-list-wrap'); const isSeries = window.location.href.includes('/series/'); const title = 'ml dl'; allTables.forEach((table) => { const headersCellsInitial = table.querySelectorAll(`.table-list > thead > tr:not(.blank) > th:nth-child(1), .table-list > tbody > tr:not(.blank) > td:nth-child(1)`); headersCellsInitial.forEach((cell, index) => { if (index === 0 && !isSeries) { cell.insertAdjacentHTML('afterend', `<th class="coll-1b">` + title + `</th>`); } else { // Find the correct link (the second one, which is the title link) let titleLink = cell.querySelectorAll('a')[1]; let href = titleLink ? titleLink.href : ''; cell.insertAdjacentHTML('afterend', ` <td class="coll-1b dl-buttons"> <a class="list-button-magnet" href="javascript:void(0)" data-href="${href}" title="Magnet link"> <i class="flaticon-magnet"></i> </a> <a class="list-button-dl" href="javascript:void(0)" data-href="${href}" title="Torrent download"> <i class="flaticon-torrent-download"></i> </a> </td> `); } }); extraColumnAdded = true; }); addClickListeners(document.querySelectorAll('.list-button-magnet'), 'ml'); addClickListeners(document.querySelectorAll('.list-button-dl'), 'dl'); } function handleDownloadClick(event) { event.preventDefault(); const button = event.currentTarget; console.log('Clicked button:', button); let href = button.getAttribute('data-href'); console.log('Data-href attribute:', href); if (!href) { console.error('No data-href attribute found on the button'); showPopup('Error: No link found'); return; } // Prepend the base URL if it's a relative URL if (href.startsWith('/')) { href = 'https://1337x.to' + href; } const ismagnet = button.classList.contains('list-button-magnet'); console.log('Is magnet link:', ismagnet); //fetchContent(href, (doc) => { queuefetchContent(href, (doc) => { console.log('Fetched content, searching for link'); showPopup('Fetched content, searching for link'); let link = ismagnet ? doc.querySelector("a[href^='magnet:']") : doc.querySelector("a[href*='itorrents.org/torrent/']"); if (link) { console.log('Found link:', link.href); showPopup('found link:', link.href); button.href = link.href; button.removeEventListener('click', handleDownloadClick); console.log('Triggering click on button'); button.click(); } else { console.error('Download link not found in fetched content'); console.log('Fetched HTML:', doc.documentElement.outerHTML); showPopup('Download link not found'); } }, 5000, 2); // Increased retry delay to 5 seconds and max retries to 2 } // Function to add click listeners for magnet and download links function addClickListeners(links, type) { links.forEach((link) => { link.addEventListener('click', function(){ let href = this.getAttribute('href'); if (href === 'javascript:void(0)') { let tLink = this.getAttribute('data-href'); GM_xmlhttpRequest({ method: 'GET', url: tLink, onload: function (response) { let container = document.implementation.createHTMLDocument().documentElement; container.innerHTML = response.responseText; let retrievedLink = (type === 'ml') ? container.querySelector('a[href^="magnet:"]') : container.querySelector('.dropdown-menu > li > a'); if (retrievedLink) { link.setAttribute('href', retrievedLink.href.replace('http:', 'https:')); link.click(); } } }); } }, false); }); } function optimizeImageUrl(imgSrc) { const optimizations = [ { from: 'https://imgtraffic.com/1s/', to: 'https://imgtraffic.com/1/' }, { from: /https?:\/\/.*\/images\/.*\.th\.jpg$/, to: (url) => url.replace(/\.th\.jpg$/, '.jpg') }, { from: 'https://22pixx.xyz/as/', to: 'https://22pixx.xyz/a/' }, { from: 'http://imgblaze.net/data_server_', to: 'https://www.imgopaleno.site/data_server_' }, { from: '/small/small_', to: '/big/' } ]; return optimizations.reduce((url, opt) => { if (typeof opt.from === 'string') { return url.replace(opt.from, opt.to); } else if (opt.from instanceof RegExp) { return opt.from.test(url) ? url.replace(opt.from, opt.to) : url; } return url; }, imgSrc); } function appendImages(link, doc) { if (!config.showThumbnails) return; // Check if thumbnails are already added if (link.parentNode.querySelector('.thumbnail-container')) { return; } let images = doc.querySelectorAll('#description img'); if (images.length > 0) { let flexContainer = document.createElement('div'); flexContainer.classList.add('thumbnail-container'); flexContainer.style.display = 'flex'; flexContainer.style.flexWrap = 'wrap'; flexContainer.style.gap = '10px'; flexContainer.style.marginTop = '10px'; let clonedImages = []; images.forEach((img, index) => { let clonedImg = img.cloneNode(true); let imgSrc = img.getAttribute('data-original') || img.src; // URL restructuring for larger resolutions if (imgSrc.includes('https://imgtraffic.com/1s/')) { imgSrc = imgSrc.replace('https://imgtraffic.com/1s/', 'https://imgtraffic.com/1/'); } if (imgSrc.includes('https://pilot007.org/images/')) { imgSrc = imgSrc.replace(/.th\.jpg$/, '.jpg'); } if (imgSrc.includes('https://13xpics.space/images/')) { imgSrc = imgSrc.replace(/.th\.jpg$/, '.jpg'); } if (imgSrc.includes('https://37xpics.space/images/')) { imgSrc = imgSrc.replace(/.th\.jpg$/, '.jpg'); } if (/https?:\/\/.*\/images\/.*\.th\.jpg$/.test(imgSrc)) { imgSrc = imgSrc.replace(/\.th\.jpg$/, '.jpg'); } if (imgSrc.includes('https://22pixx.xyz/as/')) { imgSrc = imgSrc.replace('https://22pixx.xyz/as/', 'https://22pixx.xyz/a/'); } if (imgSrc.includes('http://imgblaze.net/data_server_')) { imgSrc = imgSrc.replace('http://imgblaze.net/data_server_', 'https://www.imgopaleno.site/data_server_') .replace('/small/small_', '/big/'); } imgSrc = optimizeImageUrl(imgSrc); clonedImg.src = imgSrc; clonedImg.style.maxHeight = '100px'; clonedImg.style.setProperty('margin', '0', 'important'); clonedImg.style.display = index < config.visibleImages ? 'block' : 'none'; flexContainer.appendChild(clonedImg); clonedImages.push(clonedImg); // Add mouseover events to each image clonedImg.addEventListener('mouseover', function(e) { showEnlargedImg(imgSrc, e); }); clonedImg.addEventListener('mousemove', updateEnlargedImgPosition); clonedImg.addEventListener('mouseout', removeEnlargedImg); }); if (images.length > config.visibleImages) { let showMoreButton = document.createElement('button'); showMoreButton.textContent = 'Show More'; showMoreButton.onclick = function () { let isShowingMore = showMoreButton.textContent === 'Show Less'; clonedImages.forEach((img, index) => { if (index >= config.visibleImages) { img.style.display = isShowingMore ? 'none' : 'block'; } }); showMoreButton.textContent = isShowingMore ? 'Show More' : 'Show Less'; }; flexContainer.appendChild(showMoreButton); } link.parentNode.insertBefore(flexContainer, link.nextSibling); } } /* clonedImg.src = imgSrc; clonedImg.style.maxHeight = '100px'; clonedImg.style.setProperty('margin', '0', 'important'); clonedImg.style.display = index < config.visibleImages ? 'block' : 'none'; flexContainer.appendChild(clonedImg); clonedImages.push(clonedImg); // Add mouseover events to each image clonedImg.addEventListener('mouseover', function(e) { showEnlargedImg(imgSrc, e); }); clonedImg.addEventListener('mousemove', updateEnlargedImgPosition); clonedImg.addEventListener('mouseout', removeEnlargedImg); }); if (images.length > config.visibleImages) { let showMoreButton = document.createElement('button'); showMoreButton.textContent = 'Show More'; showMoreButton.onclick = function () { let isShowingMore = showMoreButton.textContent === 'Show Less'; clonedImages.forEach((img, index) => { if (index >= config.visibleImages) { img.style.display = isShowingMore ? 'none' : 'block'; } }); showMoreButton.textContent = isShowingMore ? 'Show More' : 'Show Less'; }; flexContainer.appendChild(showMoreButton); } link.parentNode.insertBefore(flexContainer, link.nextSibling); } }*/ // Function to show an enlarged image /*function showEnlargedImg(imgSrc, event) { removeEnlargedImg(); // Remove any existing enlarged image const enlargedImg = document.createElement('img'); enlargedImg.src = imgSrc; enlargedImg.id = 'x1337-enlarged-img'; enlargedImg.style.position = 'fixed'; enlargedImg.style.maxWidth = '500px'; enlargedImg.style.maxHeight = '500px'; enlargedImg.style.zIndex = '10000'; enlargedImg.style.border = '2px solid #F14E13'; enlargedImg.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)'; document.body.appendChild(enlargedImg); updateEnlargedImgPosition(event); }*/ // Function to show an enlarged image function showEnlargedImg(imgSrc, event) { removeEnlargedImg(); // Remove any existing enlarged image const enlargedImg = document.createElement('img'); enlargedImg.src = imgSrc; enlargedImg.id = 'x1337-enlarged-img'; enlargedImg.style.position = 'fixed'; enlargedImg.style.zIndex = '10000'; enlargedImg.style.border = '2px solid #F14E13'; enlargedImg.style.boxShadow = '0 0 10px rgba(0,0,0,0.5)'; // Set max dimensions while maintaining aspect ratio enlargedImg.style.maxWidth = '500px'; // Set max width enlargedImg.style.maxHeight = '500px'; // Set max height enlargedImg.style.width = 'auto'; // Set width to auto to maintain aspect ratio enlargedImg.style.height = 'auto'; // Set height to auto to maintain aspect ratio // Append the enlarged image to the document document.body.appendChild(enlargedImg); updateEnlargedImgPosition(event); } // Function to update the position of the enlarged image function updateEnlargedImgPosition(e) { const enlargedImg = document.getElementById('x1337-enlarged-img'); if (enlargedImg) { const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; const imgWidth = enlargedImg.offsetWidth; const imgHeight = enlargedImg.offsetHeight; let left = e.clientX + 20; // 20px offset from cursor let top = e.clientY + 20; // Adjust position if it goes off-screen if (left + imgWidth > viewportWidth) { left = e.clientX - imgWidth - 20; } if (top + imgHeight > viewportHeight) { top = e.clientY - imgHeight - 20; } enlargedImg.style.left = `${left}px`; enlargedImg.style.top = `${top}px`; } } // Function to remove enlarged image function removeEnlargedImg() { const enlargedImg = document.getElementById('x1337-enlarged-img'); if (enlargedImg) { document.body.removeChild(enlargedImg); } } // Function to optimize image URL function optimizeImageUrl(imgSrc) { const optimizations = [ { from: 'https://imgtraffic.com/1s/', to: 'https://imgtraffic.com/1/' }, { from: /https?:\/\/.*\/images\/.*\.th\.jpg$/, to: (url) => url.replace(/\.th\.jpg$/, '.jpg') }, { from: 'https://22pixx.xyz/as/', to: 'https://22pixx.xyz/a/' }, { from: 'http://imgblaze.net/data_server_', to: 'https://www.imgopaleno.site/data_server_' }, { from: '/small/small_', to: '/big/' } ]; return optimizations.reduce((url, opt) => { if (typeof opt.from === 'string') { return url.replace(opt.from, opt.to); } else if (opt.from instanceof RegExp) { return opt.from.test(url) ? url.replace(opt.from, opt.to) : url; } return url; }, imgSrc); } // Function to inject custom CSS function injectCustomCSS() { let customCSS = ` .list-button-magnet > i.flaticon-magnet { font-size: 13px; color: #da3a04 } .list-button-dl > i.flaticon-torrent-download { font-size: 13px; color: #89ad19; } table.table-list td.dl-buttons { border-left: 1px solid #f6f6f6; border-right: 1px solid #c0c0c0; padding-left: 2.5px; padding-right: 2.5px; text-align: center !important; position: relative; display: table-cell !important; width: 6%; } td.dl-buttons > a, td.dl-buttons > a:hover, td.dl-buttons > a:visited, td.dl-buttons > a:link, td.dl-buttons > a:active { color: inherit; text-decoration: none; cursor: pointer; display: inline-block !important; margin: 0 2px; } table.table-list td.coll-1b { border-right: 1px solid silver; } .table-list > thead > tr > th:nth-child(2), .table-list > thead > tr > td:nth-child(2) { text-align: center; } `; if (config.fullWidthSite) { customCSS += ` .container { max-width: none !important; } main.container, div.container { max-width: 1450px; } `; } GM_addStyle(customCSS); } // Function to clean the page title function cleanTitle(title) { if (title.startsWith('Download ')) { title = title.substring('Download '.length); } let pipeIndex = title.indexOf(' Torrent |'); if (pipeIndex !== -1) { title = title.substring(0, pipeIndex); } return title; } // Function to modify H1 content on torrent pages function modifyH1ContentOnTorrentPages() { if (window.location.pathname.startsWith('/torrent/')) { let h1Element = document.querySelector('.box-info-heading h1'); if (h1Element) { h1Element.textContent = cleanTitle(document.title); } } } // Queue for managing fetch requests const fetchQueue = []; let isProcessingQueue = false; // Function to add a fetch request to the queue /*function queueFetchRequest(link, onSuccess, retryDelay = 5000, maxRetries = 2) { fetchQueue.push({ link, onSuccess, retryDelay, maxRetries, retries: 0 }); if (!isProcessingQueue) { processQueue(); } }*/ function queueFetchRequest(link, onSuccess) { fetchQueue.push({ link, onSuccess, retries: 0 }); if (!isProcessingQueue) { processQueue(); } } // Function to process the queue /*function processQueue() { if (fetchQueue.length === 0) { isProcessingQueue = false; return; } isProcessingQueue = true; const { link, onSuccess, retryDelay, maxRetries, retries } = fetchQueue.shift(); fetchContent(link, onSuccess, retryDelay, maxRetries, retries); }*/ function processQueue() { if (fetchQueue.length === 0) { isProcessingQueue = false; return; } isProcessingQueue = true; const { link, onSuccess, retries } = fetchQueue.shift(); fetchContent(link, onSuccess, retries); } // Modified fetchContent function with adjustable delay /*function fetchContent(link, onSuccess, retries = 0) { console.log(`Attempting to fetch ${link} (Attempt ${retries + 1} of ${config.maxRetries + 1})`); GM_xmlhttpRequest({ method: 'GET', url: link, onload: function(response) { console.log(`Received response for ${link} with status ${response.status}`); if (response.status === 200) { console.log(`Successfully fetched ${link}`); let parser = new DOMParser(); let doc = parser.parseFromString(response.responseText, 'text/html'); console.log(`Parsed HTML content for ${link}`); onSuccess(doc); setTimeout(processQueue, config.queueFetchDelay); } else if (response.status === 429 && retries < config.maxRetries) { console.warn(`Rate limited for ${link}. Retrying in ${config.queueFetchDelay * 10}ms (Retry ${retries + 1} of ${config.maxRetries})`); fetchQueue.push({ link, onSuccess, retries: retries + 1 }); setTimeout(processQueue, config.queueFetchDelay * 10); } else { console.error(`Failed to fetch ${link} after ${retries} retries. Status: ${response.status}`); console.error(`Response text: ${response.responseText}`); showPopup(`Failed to fetch ${link} after ${retries} retries`); setTimeout(processQueue, config.queueFetchDelay); } }, onerror: function(error) { console.error(`Error fetching ${link}:`, error); console.error(`Error details:`, JSON.stringify(error)); setTimeout(processQueue, config.queueFetchDelay); }, ontimeout: function() { console.error(`Request timed out for ${link}`); setTimeout(processQueue, config.queueFetchDelay); } }); }*/ function fetchContent(link, onSuccess, retries = 0) { console.log(`Attempting to fetch ${link} (Attempt ${retries + 1} of ${config.maxRetries + 1})`); GM_xmlhttpRequest({ method: 'GET', url: link, onload: function(response) { console.log(`Received response for ${link} with status ${response.status}`); if (response.status === 200) { console.log(`Successfully fetched ${link}`); let parser = new DOMParser(); let doc = parser.parseFromString(response.responseText, 'text/html'); console.log(`Parsed HTML content for ${link}`); onSuccess(doc); setTimeout(processQueue, config.queueFetchDelay); } else if (response.status === 429 && retries < config.maxRetries) { console.warn(`Rate limited for ${link}. Retrying in ${config.queueFetchDelay * 10}ms (Retry ${retries + 1} of ${config.maxRetries})`); fetchQueue.push({ link, onSuccess, retries: retries + 1 }); setTimeout(processQueue, config.queueFetchDelay * 10); } else { console.error(`Failed to fetch ${link} after ${retries} retries. Status: ${response.status}`); console.error(`Response text: ${response.responseText}`); showPopup(`Failed to fetch ${link} after ${retries} retries`); setTimeout(processQueue, config.queueFetchDelay); } }, onerror: function(error) { console.error(`Error fetching ${link}:`, error); console.error(`Error details:`, JSON.stringify(error)); setTimeout(processQueue, config.queueFetchDelay); }, ontimeout: function() { console.error(`Request timed out for ${link}`); setTimeout(processQueue, config.queueFetchDelay); } }); } // Function to process a link function processLink(link) { // Find the parent row of the link const row = link.closest('tr'); // Check if the row has already been processed if (row.dataset.processed === 'true') { return; } queueFetchRequest(link.href, (doc) => { let torrentLink = doc.querySelector("a[href*='itorrents.org/torrent/']"); let magnetLink = doc.querySelector("a[href^='magnet:?']"); updateLinkTitle(link, doc); if (config.showThumbnails) { appendImages(link, doc); } if (config.showButtonsInNameColumn) { addDownloadButtons(link, torrentLink, magnetLink); } // Mark the row as processed row.dataset.processed = 'true'; }); } // Function to update the link title function updateLinkTitle(link, doc) { let title = cleanTitle(doc.querySelector('title').innerText); link.innerText = title; } // Function to add download buttons next to the link function addDownloadButtons(link, torrentLink, magnetLink) { // Check if buttons are already added let existingTorrentButton = link.parentNode.querySelector('#DLT'); let existingMagnetButton = link.parentNode.querySelector('#DLM'); // Create a container for buttons if not already present let buttonsContainer = link.parentNode.querySelector('.buttons-container'); if (!buttonsContainer) { buttonsContainer = document.createElement('div'); buttonsContainer.classList.add('buttons-container'); buttonsContainer.style.display = 'flex'; buttonsContainer.style.alignItems = 'center'; buttonsContainer.style.gap = '5px'; buttonsContainer.style.marginTop = '10px'; link.after(buttonsContainer); } // Add torrent button if it doesn't already exist if (torrentLink && !existingTorrentButton) { let torrentButton = document.createElement('a'); torrentButton.href = torrentLink.href.replace('http:', 'https:'); torrentButton.title = 'Download torrent file'; torrentButton.id = 'DLT'; // Set the ID torrentButton.innerHTML = '<i class="flaticon-torrent-download" style="color: #89ad19; font-size: 16px"></i>'; buttonsContainer.appendChild(torrentButton); } // Add magnet button if it doesn't already exist if (magnetLink && !existingMagnetButton) { let magnetButton = document.createElement('a'); magnetButton.href = magnetLink.href; magnetButton.title = 'Download via magnet'; magnetButton.id = 'DLM'; // Set the ID magnetButton.innerHTML = '<i class="flaticon-magnet" style="color: #da3a04; font-size: 16px"></i>'; buttonsContainer.appendChild(magnetButton); } } // Function to update download buttons function updateDownloadButtons() { document.querySelectorAll('.table-list-wrap .table-list tbody tr').forEach(row => { let torrentPageLink = row.querySelector('.coll-1.name a').getAttribute('href'); let fullTorrentPageLink = `https://1337x.to${torrentPageLink}`; //fetchContent(fullTorrentPageLink, (doc) => { fetchContent(fullTorrentPageLink, (doc) => { let torrentLink = doc.querySelector("a[href*='itorrents.org/torrent/']"); let magnetLink = doc.querySelector("a[href^='magnet:?']"); let dlButtonsCell = row.querySelector('.coll-1b.dl-buttons'); if (dlButtonsCell) { updateOrCreateButtons(dlButtonsCell, torrentLink, magnetLink); } }); }); } // Function to update or create buttons function updateOrCreateButtons(dlButtonsCell, torrentLink, magnetLink) { let existingButtons = dlButtonsCell.querySelectorAll('a'); if (existingButtons.length === 2) { if (torrentLink) existingButtons[0].href = torrentLink.href.replace('http:', 'https:'); if (magnetLink) existingButtons[1].href = magnetLink.href; } else { dlButtonsCell.innerHTML = createButtonHTML(torrentLink, magnetLink); } } // Function to create HTML for download and magnet buttons function createButtonHTML(torrentLink, magnetLink) { let torrentButtonHTML = torrentLink ? `<a href="${torrentLink.href.replace('http:', 'https:')}" title="Download torrent file"><i class="flaticon-torrent-download" style="color: #89ad19; font-size: 16px"></i></a>` : ''; let magnetButtonHTML = magnetLink ? `<a href="${magnetLink.href}" title="Download via magnet"><i class="flaticon-magnet" style="color: #da3a04; font-size: 16px"></i></a>` : ''; return `<div style="display: flex; align-items: center; gap: 5px; margin-top: 10px;">${torrentButtonHTML}${magnetButtonHTML}</div>`; } // Function to replace link text with titles and append images function replaceLinkTextWithTitlesAndAppendImages() { let unprocessedRows = document.querySelectorAll('.table-list tbody tr:not([data-processed])'); unprocessedRows.forEach(row => { let link = row.querySelector('a[href^="/torrent/"]'); if (link) { processLink(link); } }); } /*function showPopup(message, duration = 10000) { const popup = document.createElement('div'); popup.id = 'x1337-popup'; popup.textContent = message; document.body.appendChild(popup); // Fade in setTimeout(() => { popup.style.opacity = '1'; }, 10); // Fade out and remove setTimeout(() => { popup.style.opacity = '0'; setTimeout(() => { document.body.removeChild(popup); }, 300); }, duration); }*/ let popupQueue = []; let isShowingPopup = false; function showPopup(message, duration = 10000) { popupQueue.push({ message, duration }); if (!isShowingPopup) { displayNextPopup(); } } function displayNextPopup() { if (popupQueue.length === 0) { isShowingPopup = false; return; } isShowingPopup = true; const { message, duration } = popupQueue.shift(); const popup = document.createElement('div'); popup.id = 'x1337-popup'; popup.textContent = message; document.body.appendChild(popup); // Fade in setTimeout(() => { popup.style.opacity = '1'; }, 10); // Fade out and remove setTimeout(() => { popup.style.opacity = '0'; setTimeout(() => { document.body.removeChild(popup); displayNextPopup(); // Show next popup in queue }, 300); }, duration); } // Save settings function addSettingsMenu() { GM_addStyle(settingsCSS); document.body.insertAdjacentHTML('beforeend', settingsHTML); // Toggle settings menu document.getElementById('x1337-settings-toggle').addEventListener('click', function() { const wrapper = document.getElementById('x1337-settings-wrapper'); wrapper.style.right = wrapper.style.right === '0px' ? '-300px' : '0px'; }); // Add event listener for showing/hiding the visible images input document.getElementById('x1337-show-thumbnails').addEventListener('change', function() { const visibleImagesOption = document.querySelector('.x1337-sub-option'); visibleImagesOption.style.display = this.checked ? 'block' : 'none'; }) document.getElementById('x1337-save-settings').addEventListener('click', function() { config.showThumbnails = document.getElementById('x1337-show-thumbnails').checked; config.showExtraColumn = document.getElementById('x1337-show-magnet-column').checked; config.showButtonsInNameColumn = document.getElementById('x1337-show-buttons-in-name').checked; config.fullWidthSite = document.getElementById('x1337-full-width-site').checked; config.visibleImages = parseInt(document.getElementById('x1337-visible-images').value); config.queueFetchDelay = parseInt(document.getElementById('x1337-queue-fetch-delay').value); config.maxRetries = parseInt(document.getElementById('x1337-max-retries').value); GM_setValue('showThumbnails', config.showThumbnails); GM_setValue('showExtraColumn', config.showExtraColumn); GM_setValue('showButtonsInNameColumn', config.showButtonsInNameColumn); GM_setValue('fullWidthSite', config.fullWidthSite); GM_setValue('visibleImages', config.visibleImages); GM_setValue('queueFetchDelay', config.queueFetchDelay); GM_setValue('maxRetries', config.maxRetries); // Apply changes immediately applySettings(); // Show the popup showPopup('Settings saved successfully!'); }); } function applySettings() { if (config.showExtraColumn) { appendColumn(); } else { // Remove extra column if it exists, including the header document.querySelectorAll('.table-list-wrap').forEach(table => { const header = table.querySelector('.table-list > thead > tr > th.coll-1b'); if (header) header.remove(); table.querySelectorAll('.table-list > tbody > tr > td.coll-1b.dl-buttons').forEach(cell => { cell.remove(); }); }); extraColumnAdded = false; // Reset the flag } if (!config.showButtonsInNameColumn) { // Remove buttons in name column if the setting is disabled document.querySelectorAll('.buttons-container').forEach(container => { container.remove(); }); } if (config.fullWidthSite) { document.body.classList.add('full-width-site'); } else { document.body.classList.remove('full-width-site'); } // Re-apply thumbnails settings and update titles and download buttons replaceLinkTextWithTitlesAndAppendImages(); // Update CSS for full width if needed injectCustomCSS(); } // Add this near the end of your script, just before the init() call function addMutationObserver() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { mutation.addedNodes.forEach((node) => { if (node.nodeType === Node.ELEMENT_NODE && node.matches('.table-list tbody tr')) { let link = node.querySelector('a[href^="/torrent/"]'); if (link) { processLink(link); } } }); } }); }); observer.observe(document.body, { childList: true, subtree: true }); } let hasInitialized = false; function init() { if (hasInitialized) return; hasInitialized = true; showPopup("1337x Enhancements v12 (by sharmanhall)", 5000); addSettingsMenu(); injectCustomCSS(); applySettings(); modifyH1ContentOnTorrentPages(); replaceLinkTextWithTitlesAndAppendImages(); // Add mutation observer to handle dynamically loaded content addMutationObserver(); } // Run the script init(); })();