Greasy Fork

Greasy Fork is available in English.

自动转换 ed2k 和磁力链接并一键复制

自动检测网页中的所有 ed2k 和磁力链接并将其转换为可点击的超链接,同时提供一键复制所有链接的功能,并支持排除指定网址。

当前为 2025-02-07 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         自动转换 ed2k 和磁力链接并一键复制
// @namespace    http://tampermonkey.net/
// @version      1.7
// @description  自动检测网页中的所有 ed2k 和磁力链接并将其转换为可点击的超链接,同时提供一键复制所有链接的功能,并支持排除指定网址。
// @author       98-liu**
// @match        *://*/*
// @grant        GM_setClipboard
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function() {
    'use strict';

    const EXCLUDE_KEY = 'excludedUrls';

    // 检查当前页面是否在排除列表中
    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.top = '10px';
        button.style.right = '10px';
        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.addEventListener('click', () => {
            const links = getAllLinks();
            if (links) {
                GM_setClipboard(links);
                alert('已复制所有链接到剪贴板!');
            } else {
                alert('未找到链接!');
            }
        });

        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.top = '40px';
        button.style.right = '10px';
        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.addEventListener('click', openConfigPanel);

        document.body.appendChild(button);
    }

    // 在页面加载完成后执行
    window.addEventListener('load', () => {
        if (!isExcluded(window.location.href)) {
            convertLinks();
            createCopyButton();
            createConfigButton();
        } else {
            // 如果页面在排除列表中,移除可能存在的按钮
            const copyButton = document.getElementById('copyAllLinksButton');
            if (copyButton) {
                document.body.removeChild(copyButton);
            }
            const configButton = document.getElementById('configExcludeButton');
            if (configButton) {
                document.body.removeChild(configButton);
            }
        }
    });

    // 监听动态内容加载(例如 AJAX)
    const observer = new MutationObserver(() => {
        if (!isExcluded(window.location.href)) {
            convertLinks();
        }
    });
    observer.observe(document.body, { childList: true, subtree: true });
})();