rsshub helper

Make copy rsshub link easy.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

You will need to install an extension such as Tampermonkey to install this script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==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;
            }
        });

    });
})();