您需要先安装一个扩展,例如 篡改猴、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);
- });
- })();