Make copy rsshub link easy.
// ==UserScript==
// @name rsshub helper
// @namespace http://tampermonkey.net/
// @description Make copy rsshub link easy.
// @author xiaxuchen
// @match https://rsshub.netlify.app/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant GM_xmlhttpRequest
// @grant GM_download
// @license MIT
// @version 2024-10-01-v2
// @connect https://rsshub.rssforever.com/
// @connect https://rsshub.feeded.xyz/
// @connect https://hub.slarker.me/
// @connect https://rsshub.liumingye.cn/
// @connect https://rsshub-instance.zeabur.app/
// @connect https://rss.fatpandac.com/
// @connect https://rsshub.pseudoyu.com/
// @connect https://rsshub.friesport.ac.cn/
// @connect https://rsshub.friesport.ac.cn/us
// @connect https://rsshub.atgw.io/
// @connect https://rsshub.rss.tips/
// @connect https://rsshub.mubibai.com/
// @connect https://rsshub.ktachibana.party/
// @connect https://rsshub.woodland.cafe/
// @connect https://rsshub.aierliz.xyz/
// @connect *
// ==/UserScript==
(function() {
'use strict';
const ORIGIN_HOST = 'https://rsshub.app/';
const INSTANCE_PAGE = 'https://rsshub.netlify.app/zh/instances';
const KEY_RETURN_URL = 'returnUrl';
const KEY_INSTANCES = 'instanceList';
// 尝试从localStorage中获取已经填充的列表
let list = JSON.parse(localStorage.getItem(KEY_INSTANCES)) || [];
function checkList() {
if (location.href.startsWith(INSTANCE_PAGE)) {
console.log("In instance page, skip check list and prepare to refresh list");
return;
}
// 检查列表是否为空
if (list.length === 0) {
console.log("Instance list is empty and go to instance page to acquire.")
// 保存当前页面的URL
const currentUrl = window.location.href;
// 将当前页面的URL存储在localStorage中
localStorage.setItem(KEY_RETURN_URL, currentUrl);
// 跳转到获取实例信息的页面
window.location.href = INSTANCE_PAGE;
} else {
// 如果列表不为空,直接使用列表
console.log('List is already filled:', list);
}
}
function saveInstances() {
if (!location.href.startsWith(INSTANCE_PAGE)) {
console.log("Not instance page, skip instance save");
return;
}
list = [];
// 获取ID为'public'的元素
const publicElement = document.getElementById('public');
if (publicElement) {
// 获取ID为'public'的元素下的所有表格
const table = publicElement.nextElementSibling;
// 获取表格中的所有行
const rows = table.getElementsByTagName('tr');
// 遍历每行
for (let row of rows) {
// 获取行中的第一个单元格
const firstCell = row.getElementsByTagName('td')[0];
if (firstCell) {
const cellA = firstCell.getElementsByTagName('a')[0];
list.push(cellA.href);
}
}
console.log(`${list.length} instances found: ${list.join(",")}`);
localStorage.setItem(KEY_INSTANCES, JSON.stringify(list));
const returnUrl = localStorage.getItem(KEY_RETURN_URL);
if (returnUrl) {
console.log(`ReturnUrl found and prepare to return`);
localStorage.removeItem(KEY_RETURN_URL);
location.href = returnUrl;
}
} else {
console.error("Element with ID 'public' not found.");
}
}
function getInstanceUrl(url, host) {
return url.replace(ORIGIN_HOST, host);
}
function checkReq(url) {
let p = new Promise((resolve, reject) => {
GM_xmlhttpRequest({
method: 'GET',
url,
onload: function(response) {
// 解析响应数据
if (response.status === 200) {
console.log(`Request success: ${url}`);
resolve(url);
} else {
console.error(`Request failed: ${url}`);
reject(`Request failed: ${url}`);
}
},
onerror: function(error) {
reject(error);
}
});
});
return p;
}
async function getUpUrl(url) {
console.log("Get up url.");
return Promise.any(list.map(host => getInstanceUrl(url, host)).map(item => checkReq(item)));
}
async function writeToClipboard(text) {
try {
await navigator.clipboard.writeText(text);
console.log('Text successfully copied to clipboard:', text);
} catch (err) {
console.error('Failed to write to clipboard:', err);
}
}
function init() {
// 尝试从localStorage中获取已经填充的列表
list = JSON.parse(localStorage.getItem(KEY_INSTANCES)) || [];
checkList();
saveInstances();
}
// 等待页面加载完成
window.addEventListener('load', async () => {
init();
// 添加复制事件监听器
document.addEventListener('copy', async function(event) {
init();
if (list.length == 0) {
return;
}
// 获取选中的文本
const selection = window.getSelection().toString().trim();
if (!selection.startsWith(ORIGIN_HOST)) {
return;
}
const path = prompt("拦截复制,请确认需要获取镜像的path(可修改):", selection.slice(ORIGIN_HOST.length));
if (path == null) {
return;
}
// 阻止默认的复制行为
event.preventDefault();
try {
const upUrl = await getUpUrl(ORIGIN_HOST + path);
// 将修改后的文本设置到剪贴板
if (event.clipboardData) {
await writeToClipboard(upUrl);
console.log(`Original text: ${selection}`);
console.log(`Modified text: ${upUrl}`);
alert(`链接已写入剪切板,${upUrl}`);
}
} catch (e) {
alert("所有镜像都无法访问该地址.");
return;
}
});
});
})();