- // ==UserScript==
- // @name 自动转换 ed2k 和磁力链接并一键复制
- // @namespace http://tampermonkey.net/
- // @version 2.1
- // @description 自动检测网页中的所有 ed2k 和磁力链接并将其转换为可点击的超链接,同时提供一键复制所有链接的功能,并支持排除指定网址。
- // @author 98-liu**
- // @match *://*/*
- // @grant GM_setClipboard
- // @grant GM_getValue
- // @grant GM_setValue
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- const EXCLUDE_KEY = 'excludedUrls';
- const COPY_BUTTON_POSITION_KEY = 'copyButtonPosition';
- const CONFIG_BUTTON_POSITION_KEY = 'configButtonPosition';
- const TOGGLE_BUTTONS_POSITION_KEY = 'toggleButtonsPosition';
- const COPY_BUTTON_VISIBLE_KEY = 'copyButtonVisible';
- const CONFIG_BUTTON_VISIBLE_KEY = 'configButtonVisible';
-
- // 检查当前页面是否在排除列表中
- function isExcluded(url) {
- const excludedUrls = GM_getValue(EXCLUDE_KEY, []);
- for (const pattern of excludedUrls) {
- if (new RegExp(pattern).test(url)) {
- return true;
- }
- }
- return false;
- }
-
- // 自动检测并转换 ed2k 和磁力链接为超链接
- function convertLinks() {
- if (isExcluded(window.location.href)) return;
-
- // 正则表达式匹配 ed2k 链接
- const ed2kRegex = /ed2k:\/\/\|file\|[^\|]+\|\d+\|[a-fA-F0-9]+\|\//g;
- // 正则表达式匹配磁力链接
- const magnetRegex = /magnet:\?xt=urn:[a-zA-Z0-9:.&=]+/g;
-
- // 遍历网页中的所有文本节点
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
- let node;
-
- while (node = walker.nextNode()) {
- if (node.nodeValue.match(ed2kRegex) || node.nodeValue.match(magnetRegex)) {
- const parent = node.parentNode;
-
- // 避免重复处理(如果已经是超链接则跳过)
- if (parent.tagName !== 'A') {
- let newHTML = node.nodeValue;
- newHTML = newHTML.replace(ed2kRegex, '<a href="$&" target="_blank">$&</a>');
- newHTML = newHTML.replace(magnetRegex, '<a href="$&" target="_blank">$&</a>');
-
- const temp = document.createElement('div');
- temp.innerHTML = newHTML;
-
- // 将新内容插入到 DOM 中
- while (temp.firstChild) {
- parent.insertBefore(temp.firstChild, node);
- }
-
- // 移除原始文本节点
- parent.removeChild(node);
- }
- }
- }
- }
-
- // 获取网页中的所有 ed2k 和磁力链接,包括现有的超链接
- function getAllLinks() {
- const ed2kRegex = /ed2k:\/\/\|file\|[^\|]+\|\d+\|[a-fA-F0-9]+\|\//g;
- const magnetRegex = /magnet:\?xt=urn:[a-zA-Z0-9:.&=]+/g;
-
- const links = [];
-
- // 查找所有现有的 ed2k 和磁力超链接
- document.querySelectorAll('a').forEach(anchor => {
- if (anchor.href.match(ed2kRegex) || anchor.href.match(magnetRegex)) {
- links.push(anchor.href);
- }
- });
-
- // 查找所有文本节点中的 ed2k 和磁力链接
- const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
- let node;
-
- while (node = walker.nextNode()) {
- const matches = node.nodeValue.match(ed2kRegex) || [];
- links.push(...matches);
-
- const magnetMatches = node.nodeValue.match(magnetRegex) || [];
- links.push(...magnetMatches);
- }
-
- return links.join('\n');
- }
-
- // 创建一键复制按钮
- function createCopyButton() {
- const button = document.createElement('button');
- button.id = 'copyAllLinksButton';
- button.textContent = '复制所有链接';
- button.style.position = 'fixed';
- button.style.zIndex = '10000';
- button.style.padding = '10px';
- button.style.backgroundColor = '#007bff';
- button.style.color = '#fff';
- button.style.border = 'none';
- button.style.borderRadius = '5px';
- button.style.cursor = 'pointer';
- button.style.width = '120px'; // 固定宽度
- button.style.height = '40px'; // 固定高度
-
- // 设置初始位置或恢复保存的位置
- const position = GM_getValue(COPY_BUTTON_POSITION_KEY, { top: '10px', left: '10px' });
- button.style.top = position.top;
- button.style.left = position.left;
-
- // 点击按钮时复制所有链接
- button.addEventListener('click', () => {
- const links = getAllLinks();
- if (links) {
- GM_setClipboard(links);
- alert('已复制所有链接到剪贴板!');
- } else {
- alert('未找到链接!');
- }
- });
-
- makeDraggable(button);
-
- document.body.appendChild(button);
- }
-
- // 保存排除网址列表
- function saveExcludedUrls(urls) {
- GM_setValue(EXCLUDE_KEY, urls);
- }
-
- // 打开配置面板
- function openConfigPanel() {
- const panel = document.createElement('div');
- panel.style.position = 'fixed';
- panel.style.top = '10px';
- panel.style.left = '10px';
- panel.style.width = '300px';
- panel.style.height = '200px';
- panel.style.backgroundColor = '#fff';
- panel.style.border = '1px solid #ccc';
- panel.style.padding = '10px';
- panel.style.zIndex = '1001';
- panel.style.boxShadow = '2px 2px 10px rgba(0, 0, 0, 0.1)';
- document.body.appendChild(panel);
-
- const title = document.createElement('h3');
- title.textContent = '排除网址配置';
- panel.appendChild(title);
-
- const list = document.createElement('ul');
- list.style.maxHeight = '100px';
- list.style.overflowY = 'auto';
- panel.appendChild(list);
-
- const input = document.createElement('input');
- input.type = 'text';
- input.placeholder = '输入网址模式(正则表达式)';
- input.style.width = 'calc(100% - 22px)';
- input.style.marginBottom = '5px';
- panel.appendChild(input);
-
- const addButton = document.createElement('button');
- addButton.textContent = '添加';
- addButton.addEventListener('click', () => {
- const value = input.value.trim();
- if (value) {
- const excludedUrls = GM_getValue(EXCLUDE_KEY, []);
- excludedUrls.push(value);
- saveExcludedUrls(excludedUrls);
- updateList();
- input.value = '';
- }
- });
- panel.appendChild(addButton);
-
- const closeButton = document.createElement('button');
- closeButton.textContent = '关闭';
- closeButton.style.float = 'right';
- closeButton.addEventListener('click', () => {
- document.body.removeChild(panel);
- });
- panel.appendChild(closeButton);
-
- updateList();
-
- function updateList() {
- list.innerHTML = '';
- const excludedUrls = GM_getValue(EXCLUDE_KEY, []);
- excludedUrls.forEach((pattern, index) => {
- const li = document.createElement('li');
- li.textContent = pattern;
- const removeButton = document.createElement('button');
- removeButton.textContent = '删除';
- removeButton.style.float = 'right';
- removeButton.addEventListener('click', () => {
- excludedUrls.splice(index, 1);
- saveExcludedUrls(excludedUrls);
- updateList();
- });
- li.appendChild(removeButton);
- list.appendChild(li);
- });
- }
- }
-
- // 创建配置按钮
- function createConfigButton() {
- const button = document.createElement('button');
- button.id = 'configExcludeButton';
- button.textContent = '配置排除网址';
- button.style.position = 'fixed';
- button.style.zIndex = '10000';
- button.style.padding = '10px';
- button.style.backgroundColor = '#ffc107';
- button.style.color = '#fff';
- button.style.border = 'none';
- button.style.borderRadius = '5px';
- button.style.cursor = 'pointer';
- button.style.width = '120px'; // 固定宽度
- button.style.height = '40px'; // 固定高度
-
- // 设置初始位置或恢复保存的位置
- const position = GM_getValue(CONFIG_BUTTON_POSITION_KEY, { top: '60px', left: '10px' });
- button.style.top = position.top;
- button.style.left = position.left;
-
- // 点击按钮时打开配置面板
- button.addEventListener('click', openConfigPanel);
-
- makeDraggable(button);
-
- document.body.appendChild(button);
- }
-
- // 创建两个切换按钮
- function createToggleButtons() {
- const container = document.createElement('div');
- container.style.position = 'fixed';
- container.style.zIndex = '10000';
- container.style.display = 'flex';
- container.style.flexDirection = 'row';
- container.style.alignItems = 'center';
-
- // 设置初始位置或恢复保存的位置
- const position = GM_getValue(TOGGLE_BUTTONS_POSITION_KEY, { top: '110px', left: '10px' });
- container.style.top = position.top;
- container.style.left = position.left;
-
- // 切换复制所有链接按钮
- const toggleCopyButton = document.createElement('button');
- toggleCopyButton.id = 'toggleCopyButton';
- toggleCopyButton.textContent = '隐藏复制按钮';
- toggleCopyButton.style.padding = '10px';
- toggleCopyButton.style.backgroundColor = '#dc3545';
- toggleCopyButton.style.color = '#fff';
- toggleCopyButton.style.border = 'none';
- toggleCopyButton.style.borderRadius = '5px 0 0 5px';
- toggleCopyButton.style.cursor = 'pointer';
- toggleCopyButton.style.width = '80px'; // 固定宽度
- toggleCopyButton.style.height = '50px'; // 固定高度
-
- toggleCopyButton.addEventListener('click', () => {
- toggleCopyButtonVisibility();
- });
-
- // 切换配置排除网址按钮
- const toggleConfigButton = document.createElement('button');
- toggleConfigButton.id = 'toggleConfigButton';
- toggleConfigButton.textContent = '隐藏配置网址按钮';
- toggleConfigButton.style.padding = '10px';
- toggleConfigButton.style.backgroundColor = '#28a745';
- toggleConfigButton.style.color = '#fff';
- toggleConfigButton.style.border = 'none';
- toggleConfigButton.style.borderRadius = '0 5px 5px 0';
- toggleConfigButton.style.cursor = 'pointer';
- toggleConfigButton.style.width = '80px'; // 固定宽度
- toggleConfigButton.style.height = '50px'; // 固定高度
-
- toggleConfigButton.addEventListener('click', () => {
- toggleConfigButtonVisibility();
- });
-
- // 使容器可拖动
- makeDraggable(container);
-
- container.appendChild(toggleCopyButton);
- container.appendChild(toggleConfigButton);
- document.body.appendChild(container);
- }
-
- // 使元素可拖动
- function makeDraggable(element) {
- let offsetX, offsetY;
- let isDragging = false;
-
- element.addEventListener('mousedown', (e) => {
- if (e.target === element || e.target.parentElement === element) {
- offsetX = e.clientX - element.offsetLeft;
- offsetY = e.clientY - element.offsetTop;
- isDragging = true;
- document.addEventListener('mousemove', mouseMoveHandler);
- document.addEventListener('mouseup', mouseUpHandler);
- }
- });
-
- function mouseMoveHandler(e) {
- if (!isDragging) return;
-
- const maxX = window.innerWidth - element.offsetWidth;
- const maxY = window.innerHeight - element.offsetHeight;
- element.style.left = `${Math.min(maxX, Math.max(0, e.clientX - offsetX))}px`;
- element.style.top = `${Math.min(maxY, Math.max(0, e.clientY - offsetY))}px`;
-
- // 更新位置信息
- if (element.id === 'toggleButtonsContainer') {
- GM_setValue(TOGGLE_BUTTONS_POSITION_KEY, { top: element.style.top, left: element.style.left });
- }
- }
-
- function mouseUpHandler() {
- isDragging = false;
- document.removeEventListener('mousemove', mouseMoveHandler);
- document.removeEventListener('mouseup', mouseUpHandler);
- }
- }
-
- // 切换复制所有链接按钮的显示状态
- function toggleCopyButtonVisibility() {
- const copyButton = document.getElementById('copyAllLinksButton');
- const toggleCopyButton = document.getElementById('toggleCopyButton');
-
- const isVisible = !GM_getValue(COPY_BUTTON_VISIBLE_KEY, true);
-
- if (isVisible) {
- copyButton.style.display = 'block';
- toggleCopyButton.textContent = '隐藏复制按钮';
- } else {
- copyButton.style.display = 'none';
- toggleCopyButton.textContent = '显示复制按钮';
- }
-
- GM_setValue(COPY_BUTTON_VISIBLE_KEY, isVisible);
- }
-
- // 切换配置排除网址按钮的显示状态
- function toggleConfigButtonVisibility() {
- const configButton = document.getElementById('configExcludeButton');
- const toggleConfigButton = document.getElementById('toggleConfigButton');
-
- const isVisible = !GM_getValue(CONFIG_BUTTON_VISIBLE_KEY, true);
-
- if (isVisible) {
- configButton.style.display = 'block';
- toggleConfigButton.textContent = '隐藏配置按钮';
- } else {
- configButton.style.display = 'none';
- toggleConfigButton.textContent = '显示配置按钮';
- }
-
- GM_setValue(CONFIG_BUTTON_VISIBLE_KEY, isVisible);
- }
-
- // 在页面加载完成后执行
- window.addEventListener('load', () => {
- if (!isExcluded(window.location.href)) {
- convertLinks();
- createCopyButton();
- createConfigButton();
- createToggleButtons();
-
- // 初始化按钮显示状态
- const copyButtonVisible = GM_getValue(COPY_BUTTON_VISIBLE_KEY, true);
- const configButtonVisible = GM_getValue(CONFIG_BUTTON_VISIBLE_KEY, true);
-
- const copyButton = document.getElementById('copyAllLinksButton');
- const configButton = document.getElementById('configExcludeButton');
- const toggleCopyButton = document.getElementById('toggleCopyButton');
- const toggleConfigButton = document.getElementById('toggleConfigButton');
-
- if (!copyButtonVisible) {
- copyButton.style.display = 'none';
- toggleCopyButton.textContent = '显示复制按钮';
- }
-
- if (!configButtonVisible) {
- configButton.style.display = 'none';
- toggleConfigButton.textContent = '显示配置按钮';
- }
- } else {
- // 如果页面在排除列表中,移除可能存在的按钮
- const copyButton = document.getElementById('copyAllLinksButton');
- if (copyButton) {
- document.body.removeChild(copyButton);
- }
- const configButton = document.getElementById('configExcludeButton');
- if (configButton) {
- document.body.removeChild(configButton);
- }
- const toggleButtonsContainer = document.getElementById('toggleButtonsContainer');
- if (toggleButtonsContainer) {
- document.body.removeChild(toggleButtonsContainer);
- }
- }
- });
-
- // 监听动态内容加载(例如 AJAX)
- const observer = new MutationObserver(() => {
- if (!isExcluded(window.location.href)) {
- convertLinks();
- }
- });
- observer.observe(document.body, { childList: true, subtree: true });
- })();
-
-
-