Greasy Fork is available in English.
查找并验证网页中的 RSS 链接,在页面右下角显示,支持一键复制。添加了 GitHub 和 Twitter 的自定义规则。
当前为
// ==UserScript==
// @name RSS 订阅链接查找器(扩展版)
// @namespace http://greasyfork.icu/users/1171320
// @version 1.03
// @description 查找并验证网页中的 RSS 链接,在页面右下角显示,支持一键复制。添加了 GitHub 和 Twitter 的自定义规则。
// @author Lama AI 辅助
// @match *://*/*
// @exclude *://challenges.cloudflare.com/*
// @exclude *://dash.cloudflare.com/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_setClipboard
// @license MIT
// ==/UserScript==
(function() {
'use strict';
if (window.self !== window.top) return; // 排除 iframe
const rssLinks = new Set();
const possibleRssPaths = [
'/rss', '/feed', '/atom.xml', '/rss.xml', '/feed.xml', '/index.xml',
'/feed.atom', '/rss.json', '/atom', '/index.atom', '/index.rss'
];
const xmlRegex = /<\?xml.*?<rss|<feed/; // 用于检测返回内容是否为 XML/RSS/Atom
function addStyle() {
GM_addStyle(`
#rss-finder-container {
position: fixed;
bottom: 20px;
right: 20px;
background: #fdfdfd;
border: 1px solid #ccc;
padding: 10px;
max-height: 300px;
overflow-y: auto;
z-index: 9999;
}
#rss-finder-container h4 {
margin: 0 0 5px;
}
#rss-finder-list {
list-style: none;
padding: 0;
}
#rss-finder-list li {
margin-bottom: 5px;
display: flex;
align-items: center;
font-size: 0.8em;
}
#rss-finder-list li a {
color: blue;
text-decoration: none;
margin-right: 5px;
}
#rss-finder-list li button {
font-size: 0.6em;
padding: 2px 5px;
margin-left: auto;
cursor: pointer;
}
`);
}
function addRssLink(url) {
if (rssLinks.has(url)) return;
GM_xmlhttpRequest({
method: 'GET',
url: url,
onload: function(response) {
if (response.status === 200 && xmlRegex.test(response.responseText)) {
rssLinks.add(url);
updateRssList();
}
},
onerror: function(error) {
console.log(`加载失败: ${url}`, error);
}
});
}
function updateRssList() {
let container = document.getElementById('rss-finder-container');
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);
setTimeout(() => {
if (container) container.style.display = 'none';
}, 15000);
}
const list = container.querySelector('#rss-finder-list');
list.innerHTML = '';
rssLinks.forEach(url => {
const li = document.createElement('li');
const a = document.createElement('a');
a.href = url;
a.target = '_blank';
a.rel = 'noopener noreferrer';
a.textContent = url;
const copyButton = document.createElement('button');
copyButton.textContent = '复制';
copyButton.onclick = function() {
navigator.clipboard.writeText(url).then(() => {
alert('已复制');
}).catch(err => {
console.error('复制失败', err);
});
};
li.appendChild(a);
li.appendChild(copyButton);
list.appendChild(li);
});
}
function findRssLinks() {
const rssTags = document.querySelectorAll('link[type="application/rss+xml"], link[type="application/atom+xml"], meta[type="application/rss+xml"], meta[type="application/atom+xml"]');
rssTags.forEach(tag => {
const url = tag.getAttribute('href') || tag.getAttribute('content');
if (url) {
addRssLink(url);
}
});
possibleRssPaths.forEach(path => {
const guessedUrl = window.location.origin + path;
addRssLink(guessedUrl);
});
if (window.location.hostname === 'github.com') {
const pathParts = window.location.pathname.split('/').filter(Boolean);
if (pathParts.length >= 2) {
const [user, repo] = pathParts;
addRssLink(`https://github.com/${user}.atom`);
addRssLink(`https://github.com/${user}/${repo}/commits.atom`);
addRssLink(`https://github.com/${user}/${repo}/releases.atom`);
}
}
if (window.location.hostname === "twitter.com" && window.location.pathname.startsWith('/')) {
const userName = window.location.pathname.slice(1);
if (userName) {
addRssLink(`https://news.google.com/rss/search?q=site:twitter.com/${userName}+when:7d`);
}
}
const rssSubscribeLinks = document.querySelectorAll('a.rss-subscribe');
rssSubscribeLinks.forEach(link => {
if (link.href) {
addRssLink(link.href);
}
});
}
addStyle();
window.onload = findRssLinks;
})();