您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Show all RSS/Atom/JSON feeds with UI, smart guessing, copy features, feed counter, and draggable floating icon.
// ==UserScript== // @name RSS+ Enhancer // @namespace Eliminater74 // @version 2.6 // @description Show all RSS/Atom/JSON feeds with UI, smart guessing, copy features, feed counter, and draggable floating icon. // @author Eliminater74 // @license MIT // @match *://*/* // @grant GM_setClipboard // ==/UserScript== (function () { 'use strict'; const foundFeeds = []; function isValidFeed(link) { const types = [ "application/rss+xml", "application/atom+xml", "application/json", "application/feed+json" ]; return types.includes(link.type); } function getFeeds() { const links = [...document.querySelectorAll('link')]; const guesses = [ '/feed', '/rss', '/rss.xml', '/atom.xml', '/feeds/posts/default', '/?feed=rss2' ]; links.forEach(link => { if (isValidFeed(link)) { foundFeeds.push({ title: link.title || link.href, href: link.href }); } }); guesses.forEach(path => { try { const testURL = new URL(path, location.href).href; fetch(testURL, { method: 'GET' }).then(resp => { if (resp.ok) { resp.text().then(txt => { if (txt.includes("<rss") || txt.includes("<feed") || txt.includes("application/json")) { if (!foundFeeds.find(f => f.href === testURL)) { foundFeeds.push({ title: testURL, href: testURL }); updatePanel(); } } }); } }).catch(() => {}); } catch {} }); } function createUI() { const icon = document.createElement('div'); icon.id = 'rssPlusIcon'; icon.textContent = '📡'; icon.style.cssText = ` position: fixed; bottom: 20px; right: 20px; font-size: 24px; background: #222; color: #fff; padding: 10px 14px; border-radius: 50%; z-index: 999999; cursor: grab; box-shadow: 0 0 10px #000; user-select: none; `; const badge = document.createElement('span'); badge.id = 'rssCount'; badge.style.cssText = ` position: absolute; top: -6px; right: -6px; background: red; color: white; font-size: 12px; border-radius: 50%; padding: 2px 5px; display: none; `; icon.appendChild(badge); // Drag handling let isDragging = false; let offsetX, offsetY; icon.addEventListener('mousedown', (e) => { isDragging = true; offsetX = e.clientX - icon.getBoundingClientRect().left; offsetY = e.clientY - icon.getBoundingClientRect().top; icon.style.cursor = 'grabbing'; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; icon.style.left = 'unset'; icon.style.top = e.clientY - offsetY + 'px'; icon.style.right = 'unset'; icon.style.left = e.clientX - offsetX + 'px'; icon.style.bottom = 'unset'; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; icon.style.cursor = 'grab'; } }); icon.onclick = () => { const panel = document.getElementById('rssPanel'); panel.style.display = (panel.style.display === 'none') ? 'block' : 'none'; }; document.body.appendChild(icon); const panel = document.createElement('div'); panel.id = 'rssPanel'; panel.style.cssText = ` position: fixed; top: 60px; right: 20px; background: #2c2c2c; color: white; font-family: sans-serif; padding: 10px; border-radius: 6px; box-shadow: 0 0 15px #000; z-index: 999998; max-width: 400px; min-width: 250px; display: none; `; panel.innerHTML = `<div style="font-weight:bold; margin-bottom: 6px;">RSS Feeds Found:</div><div id="rssFeedList"></div> <div style="margin-top: 10px;"> <button id="rssCopyAll">Copy All</button> <button id="rssToggleTheme">Toggle Theme</button> <button id="rssHide">Hide</button> </div>`; document.body.appendChild(panel); document.getElementById('rssCopyAll').onclick = () => { const text = foundFeeds.map(f => f.href).join('\n'); GM_setClipboard(text); alert("All RSS feed URLs copied to clipboard!"); }; document.getElementById('rssToggleTheme').onclick = () => { const dark = panel.style.background === 'white'; panel.style.background = dark ? '#2c2c2c' : 'white'; panel.style.color = dark ? 'white' : 'black'; }; document.getElementById('rssHide').onclick = () => { panel.style.display = 'none'; }; } function updatePanel() { const list = document.getElementById('rssFeedList'); const badge = document.getElementById('rssCount'); if (!list || !badge) return; list.innerHTML = ''; foundFeeds.forEach(f => { const row = document.createElement('div'); row.style.marginBottom = '6px'; const link = document.createElement('a'); link.href = f.href; link.target = '_blank'; link.textContent = f.title.length > 60 ? f.title.slice(0, 60) + '…' : f.title; link.style.cssText = `color: #4FC3F7; word-break: break-all;`; const copyBtn = document.createElement('button'); copyBtn.textContent = '📋'; copyBtn.style.cssText = `margin-left: 5px;`; copyBtn.onclick = () => GM_setClipboard(f.href); row.appendChild(link); row.appendChild(copyBtn); list.appendChild(row); }); badge.style.display = foundFeeds.length ? 'block' : 'none'; badge.textContent = foundFeeds.length; } window.addEventListener('load', () => { createUI(); getFeeds(); setTimeout(updatePanel, 2500); }); })();