RSS 订阅链接查找器(扩展版)

打开网页时,查询常用的 RSS 后缀并验证是否可用,在网页右下角显示,可一键复制。已适配世界 TOP500 网站及绝大部分网站,此外除常见网站、博客, 添加一些自写规则 BiliBili、GitHub、Twitter(七天内更新)

// ==UserScript==
// @name         RSS 订阅链接查找器(扩展版)
// @namespace    https://gf.qytechs.cn/users/1171320
// @version      1.14
// @description  打开网页时,查询常用的 RSS 后缀并验证是否可用,在网页右下角显示,可一键复制。已适配世界 TOP500 网站及绝大部分网站,此外除常见网站、博客, 添加一些自写规则 BiliBili、GitHub、Twitter(七天内更新)
// @author         yzcjd
// @author2       ChatGPT4 辅助
// @match        *://*/*
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// @grant        GM_setClipboard
// @license MIT
// ==/UserScript==

(function () {
    'use strict';
    if (window.self !== window.top) return;

    const rssLinks = new Map();
    const possibleRssPaths = [
        '/rss', '/feed', '/atom.xml', '/rss.xml', '/feed.xml', '/index.xml',
        '/feed.atom', '/rss.json', '/atom', '/index.atom', '/index.rss',
        '/?feed=rss', '/?feed=rss2', '/blog/feed', '/blog/rss', '/latest/rss',
        '/news/atom', '/feed/index.xml', '/articles/feed', '/rss2',
        '/home/rss', '/media/rss', '/feed.rss', '/rss/latest', '/?feed=rss3',
        '/rss/1', '/feed1', '/posts.rss', '/news/rss', '/feed?format=rss',
        '/latest/rss.xml', '/rss/articles', '/rss/latestposts',
        '/rss.json', '/atom.json', '/feed.json', '/news/atom.json', '/rss.xml',
        '/api/v1/feed', '/v1/feed', '/user/feed', '/posts/feed',
        '/author/feed', '/tag/feed', '/category/feed', '/comments/feed',
        '/rss2.0', '/rss2.json', '/atom2.xml', '/topics/feed', '/channel/feed',
        '/user/feed', '/subscribe.rss', '/activity/rss', '/site/rss',
        '/stream/rss', '/events/rss', '/post/rss', '/recent/rss', '/site-rss',
        '/subscribe/feed', '/latest/feed', '/content/rss', '/new-content/rss',
        '/trending/feed', '/updates/feed', '/new/rss', '/articles/rss',
        '/news/feed', '/breaking/rss', '/info/rss', '/comments.rss',
        '/media/rss.xml', '/video/feed', '/video/rss', '/updates/rss', '/global/rss'
    ];

    function addStyle() {
        GM_addStyle(`
            #rss-finder-toggle {
                position: fixed;
                bottom: 40px;
                right: 20px;
                width: 22.5px;
                height: 22.5px;
                border-radius: 50%;
                background: #0078d7;
                color: #fff;
                font-size: 12px;
                display: flex;
                align-items: center;
                justify-content: center;
                cursor: pointer;
                z-index: 9999;
                padding: 2px;
                user-select: none;
            }
            #rss-finder-container {
                position: fixed;
                bottom: 80px;
                right: 20px;
                background: #fdfdfd;
                border: 1px solid #ccc;
                padding: 10px;
                display: none;
                z-index: 9998;
                font-family: Arial, sans-serif;
                font-size: 14px;
            }
            #rss-finder-container h4 {
                margin: 0 0 5px 0;
                font-size: 1em;
            }
            #rss-finder-list {
                list-style: none;
                padding: 0;
                margin: 0;
            }
            #rss-finder-list li {
                margin-bottom: 5px;
                display: flex;
                justify-content: space-between;
                align-items: center;
                font-size: 0.9em;
                flex-wrap: wrap;
            }
            #rss-finder-list li a {
                color: blue;
                text-decoration: none;
                word-break: break-word;
                flex-grow: 1;
                max-width: 400px;
                margin-right: 10px;
                word-wrap: break-word;
            }
            #rss-finder-list li button {
                font-size: 0.6em;
                padding: 2px 4px;
                cursor: pointer;
                border: 1px solid #ccc;
                background-color: #f0f0f0;
                border-radius: 0;
                user-select: none;
                color: black; /* 设置字体颜色为黑色 */
                width: auto;
                min-width: 40px;
                text-align: center;
            }
            #rss-finder-list li button.success {
                background-color: #28a745 !important;
                color: white !important;
                border-color: #28a745;
            }
            #rss-finder-list li button.success {
                font-weight: bold;
                background-color: #4CAF50;
                color: white;
                border: 1px solid #4CAF50;
            }
        `);
    }

    function updateRssList() {
        let container = document.getElementById('rss-finder-container');
        let toggle = document.getElementById('rss-finder-toggle');

        if (!toggle) {
            toggle = document.createElement('div');
            toggle.id = 'rss-finder-toggle';
            document.body.appendChild(toggle);
            toggle.addEventListener('click', (e) => {
                e.stopPropagation();
                const visible = container.style.display === 'block';
                container.style.display = visible ? 'none' : 'block';
            });
            document.addEventListener('click', (e) => {
                if (!container.contains(e.target) && !toggle.contains(e.target)) {
                    container.style.display = 'none';
                }
            });
        }

        if (!container) {
            container = document.createElement('div');
            container.id = 'rss-finder-container';
            container.innerHTML = '<h4>可用 RSS 订阅:</h4><ul id="rss-finder-list"></ul>';
            document.body.appendChild(container);
        }

        toggle.textContent = rssLinks.size;

        const list = container.querySelector('#rss-finder-list');
        list.innerHTML = '';

        rssLinks.forEach((label, url) => {
            const li = document.createElement('li');
            const a = document.createElement('a');
            a.href = url;
            a.target = '_blank';
            a.rel = 'noopener noreferrer';
            a.textContent = label ? `[${label}] ${url}` : url;

            const copyButton = document.createElement('button');
            copyButton.textContent = 'copy';
            copyButton.onclick = function () {
                GM_setClipboard(url);
                copyButton.textContent = 'success';
                copyButton.classList.add('success');
                setTimeout(() => {
                    copyButton.textContent = 'copy';
                    copyButton.classList.remove('success');
                }, 1500);
            };

            li.appendChild(a);
            li.appendChild(copyButton);
            list.appendChild(li);
        });
    }

    function findRssLinks() {
        const links = document.querySelectorAll('link[type*="rss"], link[type*="atom"], link[type="application/feed+json"]');
        links.forEach(link => {
            const href = link.href || link.getAttribute('href');
            if (href) {
                rssLinks.set(href, link.title || '');
            }
        });

        possibleRssPaths.forEach(path => {
            const base = location.origin || (location.protocol + '//' + location.host);
            const url = new URL(path, base).href;
            tryRssUrl(url);
        });

        setTimeout(updateRssList, 800);
    }

    function tryRssUrl(url) {
        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            headers: { 'Accept': 'application/rss+xml, application/xml, text/xml, */*' },
            onload: function (response) {
                if (response.status === 200 && /<rss|<feed|<rdf|<channel/i.test(response.responseText)) {
                    rssLinks.set(url, '');
                    updateRssList();
                }
            }
        });
    }

    // 寻找未明确标示的RSS源
    function findUnknownFeeds() {
        const links = document.links || document.getElementsByTagName("a");
        for (const link of links) {
            const href = link.href;
            if (
                href.match(/^(https|http|ftp|feed).*([.\/]rss([.\/]xml|\.aspx|\.jsp|\/)?$|\/node\/feed$|\/feed(\.xml|\/$|$)|\/rss\/[a-z0-9]+$|[?&;](rss|xml)=|[?&;]feed=rss[0-9.]*$|[?&;]action=rss_rc$|feeds\.feedburner\.com\/[\w\W]+$)/i)
                || href.match(/^(https|http|ftp|feed).*\/atom(\.xml|\.aspx|\.jsp|\/)?$|[?&;]feed=atom[0-9.]*$/i)
                || href.match(/^(https|http|ftp|feed).*(\/feeds?\/[^.\/]*\.xml$|.*\/index\.xml$|feed\/msgs\.xml(\?num=\d+)?$)/i)
                || href.match(/^(https|http|ftp|feed).*\.rdf$/i)
                || href.match(/^(rss|feed):\/\//i)
                || href.match(/^(https|http):\/\/feed\./i)
            ) {
                addFeed(link.title || link.textContent || link.innerText || document.title, href);
            }
        }
    }

    function addFeed(label, href) {
        if (href) {
            rssLinks.set(href, label || '');
            updateRssList();
        }
    }

    addStyle();
    findRssLinks();
    findUnknownFeeds();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址