您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在PT站点添加加载更多功能和删除行功能,适用于多个相似结构的PT站点
// ==UserScript== // @name PT站点加载更多种子 // @namespace http://tampermonkey.net/ // @version 0.7 // @description 在PT站点添加加载更多功能和删除行功能,适用于多个相似结构的PT站点 // @author Andiedie // @match https://pt.agsvpt.cn/torrents.php* // @match https://piggo.me/special.php* // @match https://piggo.me/search.php* // @match https://piggo.me/torrents.php* // @match https://ourbits.club/torrents.php* // @match https://www.qingwapt.com/torrents.php* // @match https://www.agsvpt.com/torrents.php* // @match https://audiences.me/torrents.php* // @match https://www.ptzone.xyz/torrents.php* // @match https://rousi.zip/torrents.php* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; // 记录已加载的页面和最大已加载页码 let loadedPages = new Set(); let maxLoadedPageDisplay = 1; // 从1开始计数的显示页码 // 主函数 function init() { // 寻找分页元素(使用新函数) const paginationElements = findPaginationElements(); if (paginationElements.length === 0) { console.log('未找到分页元素'); return; } // 从URL获取当前页码 const urlParams = new URLSearchParams(window.location.search); const currentPage = parseInt(urlParams.get('page') || 0); // 将当前页面标记为已加载 loadedPages.add(currentPage); maxLoadedPageDisplay = currentPage + 1; // 当前页码(从0开始) + 1 = 显示页码(从1开始) // 找到最后一页的页码 const lastPageNumber = findLastPageNumber(paginationElements[0]); // 检查是否在第一页 if (currentPage === 0) { // 添加输入框和按钮到分页元素 addLoadMoreInterface(paginationElements, lastPageNumber); } // 添加统计信息到分页元素 updateStatistics(paginationElements); // 为现有的种子行添加删除按钮 addDeleteButtonsToExistingRows(); } // 函数:查找分页元素 function findPaginationElements() { let elements = []; // 策略1: 使用原有的类名选择器(保持向后兼容) const nexusPagination = document.querySelectorAll('.nexus-pagination'); if (nexusPagination.length > 0) { return Array.from(nexusPagination); } // 策略2: 查找包含"上一页"和"下一页"文本的p元素 const allParagraphs = document.querySelectorAll('p'); for (const p of allParagraphs) { const text = p.textContent.toLowerCase(); if ((text.includes('上一页') || text.includes('previous')) && (text.includes('下一页') || text.includes('next'))) { elements.push(p); continue; } // 策略3: 查找包含页码范围格式的p元素 if (p.textContent.match(/\d+\s*-\s*\d+/)) { // 确认这个元素包含多个页面链接 const links = p.querySelectorAll('a'); if (links.length >= 3 && links[0].href.includes('page=')) { elements.push(p); continue; } } // 策略4: 查找带有align="center"属性且包含页面链接的p元素 if (p.getAttribute('align') === 'center') { const links = p.querySelectorAll('a'); if (links.length >= 3) { let isPageLinks = false; for (const link of links) { if (link.href.includes('page=')) { isPageLinks = true; break; } } if (isPageLinks) { elements.push(p); continue; } } } } return elements; } // 函数:为已存在的种子行添加删除按钮 function addDeleteButtonsToExistingRows() { const torrentTable = document.querySelector('.torrents>tbody'); if (!torrentTable) return; // 获取所有种子行(跳过表头) const torrentRows = Array.from(torrentTable.querySelectorAll(':scope>tr')).slice(1); // 为每一行添加删除按钮 torrentRows.forEach(row => { addDeleteButtonToRow(row); }); } // 函数:为单个种子行添加删除按钮 function addDeleteButtonToRow(row) { // 创建一个新的表格单元格 const deleteCell = document.createElement('td'); deleteCell.className = 'row-delete-cell'; deleteCell.style.textAlign = 'center'; // 创建删除按钮 const deleteButton = document.createElement('button'); deleteButton.textContent = 'x'; deleteButton.style.padding = '8px'; deleteButton.style.cursor = 'pointer'; deleteButton.style.backgroundColor = '#d0d0d0'; deleteButton.style.color = 'black'; deleteButton.style.border = 'none'; deleteButton.style.borderRadius = '3px'; // 添加删除功能 deleteButton.addEventListener('click', function() { // 删除行 row.remove(); // 更新统计信息 updateStatistics(findPaginationElements()); }); deleteCell.appendChild(deleteButton); row.appendChild(deleteCell); } // 函数:寻找最后一页的页码 function findLastPageNumber(paginationElement) { // 寻找分页中的所有链接 const links = paginationElement.querySelectorAll('a'); let lastPageNumber = 0; // 遍历链接找到最高页码 links.forEach(link => { const href = link.getAttribute('href'); if (href) { const pageMatch = href.match(/[?&]page=(\d+)/); if (pageMatch && pageMatch[1]) { const pageNum = parseInt(pageMatch[1]); if (pageNum > lastPageNumber) { lastPageNumber = pageNum; } } } }); return lastPageNumber; } // 函数:添加加载更多的界面 function addLoadMoreInterface(paginationElements, lastPageNumber) { paginationElements.forEach(pagination => { const container = document.createElement('div'); container.className = 'load-more-container'; container.style.margin = '10px 0'; container.style.textAlign = 'center'; const label = document.createElement('span'); label.textContent = '加载到第 '; const input = document.createElement('input'); input.type = 'number'; input.min = 1; input.max = lastPageNumber + 1; // +1 因为页面显示从1开始 input.value = lastPageNumber + 1; // 默认显示到最后一页 input.style.width = '60px'; input.style.marginRight = '5px'; input.style.marginLeft = '5px'; const postLabel = document.createElement('span'); postLabel.textContent = ' 页 '; const button = document.createElement('button'); button.textContent = '加载更多'; button.addEventListener('click', () => { // 将用户输入的页码(从1开始)转换为系统页码(从0开始) const targetPageDisplay = parseInt(input.value); if (targetPageDisplay > 0 && targetPageDisplay <= lastPageNumber + 1) { const targetPage = targetPageDisplay - 1; // 转换为从0开始的索引 // 获取当前页码 const currentUrl = new URL(window.location.href); const urlParams = new URLSearchParams(currentUrl.search); const currentPage = parseInt(urlParams.get('page') || 0); // 设置最大已加载页码 maxLoadedPageDisplay = Math.max(maxLoadedPageDisplay, targetPageDisplay); // 开始递归加载页面 button.disabled = true; button.textContent = '加载中...'; // 从当前页+1开始加载,直到目标页 loadMultiplePages(currentPage + 1, targetPage); } else { alert('请输入有效的页码 (1-' + (lastPageNumber + 1) + ')'); } }); container.appendChild(label); container.appendChild(input); container.appendChild(postLabel); container.appendChild(button); pagination.appendChild(container); }); } // 函数:递归加载多个页面 function loadMultiplePages(currentPage, targetPage) { // 如果当前页已超过目标页,则停止加载 if (currentPage > targetPage) { document.querySelectorAll('.load-more-container button').forEach(btn => { btn.disabled = false; btn.textContent = '加载更多'; }); // 更新统计信息 updateStatistics(findPaginationElements()); return; } // 如果当前页已经加载过,跳到下一页 if (loadedPages.has(currentPage)) { loadMultiplePages(currentPage + 1, targetPage); return; } // 加载当前页 const loadingText = `加载中 ${currentPage + 1}/${targetPage + 1}...`; document.querySelectorAll('.load-more-container button').forEach(btn => { btn.textContent = loadingText; }); loadOnePage(currentPage, () => { // 加载完成后,记录并继续加载下一页 loadedPages.add(currentPage); loadMultiplePages(currentPage + 1, targetPage); }); } // 函数:加载单个页面的种子 function loadOnePage(pageNumber, callback) { // 创建目标页面的URL const currentUrl = new URL(window.location.href); const urlParams = new URLSearchParams(currentUrl.search); urlParams.set('page', pageNumber); currentUrl.search = urlParams.toString(); // 获取目标页面 fetch(currentUrl.toString()) .then(response => response.text()) .then(html => { const parser = new DOMParser(); const doc = parser.parseFromString(html, 'text/html'); // 在获取的页面中找到种子表格 const fetchedTorrentTable = doc.querySelector('.torrents>tbody'); if (!fetchedTorrentTable) { console.error('在获取的页面中未找到种子表格'); callback(); return; } // 获取种子行(跳过表头)- 使用直接子选择器 const torrentRows = Array.from(fetchedTorrentTable.querySelectorAll(':scope>tr')).slice(1); // 在当前页面找到种子表格 const currentTorrentTable = document.querySelector('.torrents>tbody'); if (!currentTorrentTable) { console.error('在当前页面未找到种子表格'); callback(); return; } // 将种子行添加到当前表格,并为每一行添加删除按钮 torrentRows.forEach(row => { const newRow = row.cloneNode(true); addDeleteButtonToRow(newRow); currentTorrentTable.appendChild(newRow); }); // 更新统计信息(只针对计数和总大小,不更新页码显示) updateStatistics(findPaginationElements(), false); console.log(`已添加 ${torrentRows.length} 个种子,来自第 ${pageNumber + 1} 页`); // 执行回调 callback(); }) .catch(error => { console.error(`获取第 ${pageNumber + 1} 页种子时出错:`, error); // 即使出错也执行回调以继续后续操作 callback(); }); } // 函数:从单元格解析大小 function parseSize(sizeCell) { // 获取单元格的文本内容 const sizeText = sizeCell.textContent.replace(/\s+/g, ' ').trim(); // 使用更灵活的正则表达式提取数字和单位 const match = sizeText.match(/([\d.]+)\s*([KMGT]?B)/i); if (!match) return 0; const value = parseFloat(match[1]); const unit = match[2].toUpperCase(); // 转换为字节 switch (unit) { case 'KB': return value * 1024; case 'MB': return value * 1024 * 1024; case 'GB': return value * 1024 * 1024 * 1024; case 'TB': return value * 1024 * 1024 * 1024 * 1024; default: return value; // 假设为字节(B)或未知单位 } } // 函数:将字节格式化为适当的单位 function formatSize(bytes) { if (bytes === 0) return '0 B'; const units = ['B', 'KB', 'MB', 'GB', 'TB']; let index = 0; let size = bytes; while (size >= 1024 && index < units.length - 1) { size /= 1024; index++; } return size.toFixed(2) + ' ' + units[index]; } // 函数:更新统计信息 function updateStatistics(paginationElements, updatePageNumber = true) { // 找到所有种子行(使用直接子选择器) const torrentTable = document.querySelector('.torrents>tbody'); if (!torrentTable) return; const torrentRows = torrentTable.querySelectorAll(':scope>tr'); // 跳过表头行 const torrentCount = torrentRows.length - 1; // 计算总大小 let totalBytes = 0; Array.from(torrentRows).slice(1).forEach(row => { if (row.cells.length >= 5) { const sizeCell = row.cells[4]; // 第5列(从0开始索引) if (sizeCell) { totalBytes += parseSize(sizeCell); } } }); // 格式化总大小 const formattedSize = formatSize(totalBytes); // 创建或更新统计元素 paginationElements.forEach(pagination => { let statsElement = pagination.querySelector('.torrent-stats'); if (!statsElement) { statsElement = document.createElement('div'); statsElement.className = 'torrent-stats'; statsElement.style.margin = '10px 0'; statsElement.style.fontWeight = 'bold'; pagination.appendChild(statsElement); } statsElement.textContent = `当前显示: ${torrentCount} 个种子,总体积: ${formattedSize},已加载到第 ${maxLoadedPageDisplay} 页`; }); } // 初始化脚本 init(); })();