Save to Telegraph

点击按钮即可将文章 原文 + Telegraph 自动保存到 Telegram 机器人。配置方法看教程。

// ==UserScript==
// @name         Save to Telegraph
// @version      1.001
// @description  点击按钮即可将文章 原文 + Telegraph 自动保存到 Telegram 机器人。配置方法看教程。
// @match        *://*/*
// @author       yzcjd
// @author2       ChatGPT4辅助
// @namespace    https://greasyfork.org/users/1171320
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @run-at       document-end
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

    let BOT_TOKEN       = GM_getValue("BOT_TOKEN", "");
    let CHAT_ID         = GM_getValue("CHAT_ID", "");
    let TELEGRAPH_TOKEN = GM_getValue("TELEGRAPH_TOKEN", "");
    let menuHidden = GM_getValue("MENU_HIDDEN", false);
    const menuHandles = {};

    function registerAllMenus() {
        for (let key in menuHandles) GM_unregisterMenuCommand(menuHandles[key]);
        if (!menuHidden) {
            menuHandles.BOT = GM_registerMenuCommand("设置 Bot Token", () => {
                const v = prompt("请输入 Bot Token:", BOT_TOKEN);
                if (v !== null) { BOT_TOKEN = v.trim(); GM_setValue("BOT_TOKEN", BOT_TOKEN); alert("✅ Bot Token 已保存"); }
            });
            menuHandles.CHAT = GM_registerMenuCommand("设置 Chat ID", () => {
                const v = prompt("请输入 Chat ID:", CHAT_ID);
                if (v !== null) { CHAT_ID = v.trim(); GM_setValue("CHAT_ID", CHAT_ID); alert("✅ Chat ID 已保存"); }
            });
            menuHandles.TELE = GM_registerMenuCommand("设置 Telegraph Token", () => {
                const v = prompt("请输入 Telegraph Token:", TELEGRAPH_TOKEN);
                if (v !== null) { TELEGRAPH_TOKEN = v.trim(); GM_setValue("TELEGRAPH_TOKEN", TELEGRAPH_TOKEN); alert("✅ Telegraph Token 已保存"); }
            });
            menuHandles.TUTOR = GM_registerMenuCommand("使用教程", () => {
                window.open("https://telegra.ph/%E5%A6%82%E4%BD%95%E4%BD%BF%E7%94%A8%E8%BF%99%E4%B8%AA%E8%84%9A%E6%9C%AC-09-14", "_blank");
            });
            menuHandles.HIDE = GM_registerMenuCommand("隐藏菜单", () => {
                menuHidden = true;
                GM_setValue("MENU_HIDDEN", menuHidden);
                registerAllMenus();
            });
        } else {
            menuHandles.SHOW = GM_registerMenuCommand("显示菜单", () => {
                menuHidden = false;
                GM_setValue("MENU_HIDDEN", menuHidden);
                registerAllMenus();
            });
        }
    }
    registerAllMenus();

    const style = document.createElement('style');
    style.textContent = `
      #save-button {
        position: fixed;
        top: 90px;
        right: 5px;
        z-index: 99999;
        background: #f5f5f5;
        color: #000;
        padding: 4px 8px;
        border-radius: 6px;
        border: 1px solid #ccc;
        cursor: pointer;
        font-size: 12px;
        transform: scale(0.75);
        transition: all 0.2s;
      }
      .btn-click-animate {
        animation: clickAnim 0.2s ease;
      }
      @keyframes clickAnim {
        0% { transform: scale(0.75); }
        50% { transform: scale(0.9); }
        100% { transform: scale(0.8); }
      }
    `;
    document.head.appendChild(style);

    const btn = document.createElement('button');
    btn.id = "save-button";
    btn.innerText = "save";
    document.body.appendChild(btn);
    document.documentElement.setAttribute('translate', 'no');

    function httpPost(url, data, cb) {
        GM_xmlhttpRequest({
            method: "POST",
            url: url,
            headers: { "Content-Type": "application/json" },
            data: JSON.stringify(data),
            onload: res => cb(null, res),
            onerror: err => cb(err)
        });
    }

    function extractContent() {
        const selectors = ['article','.content','#content','.post','.entry-content','.main-content','.article-body','.chapter'];
        for (let sel of selectors) {
            const el = document.querySelector(sel);
            if (el && el.innerText.trim().length>50) return el.innerText.trim();
        }
        return document.body.innerText.trim();
    }

    function extractRealTitle() {
        const h1 = document.querySelector('h1');
        if(h1 && h1.innerText.trim()) return h1.innerText.trim();
        const articleH1 = document.querySelector('article h1');
        if(articleH1 && articleH1.innerText.trim()) return articleH1.innerText.trim();
        const ogTitle = document.querySelector('meta[property="og:title"]');
        if(ogTitle && ogTitle.content.trim()) return ogTitle.content.trim();
        return document.title.trim() || "未命名";
    }

    const MAX_CHARS = 60000;
    function splitContent(text) {
        const segments = [];
        let start = 0;
        while(start < text.length){
            segments.push(text.slice(start, start + MAX_CHARS));
            start += MAX_CHARS;
        }
        return segments;
    }

    async function createTelegraphPages(segments, titleBase, TELEGRAPH_TOKEN) {
        const urls = [];
        for(let i=0;i<segments.length;i++){
            const segmentTitle = segments.length>1 ? `${titleBase}(第${i+1}部分)` : titleBase;
            const contentJson = [{ tag: "p", children: [segments[i]] }];
            const res = await new Promise(resolve=>{
                httpPost("https://api.telegra.ph/createPage",{
                    access_token: TELEGRAPH_TOKEN,
                    title: segmentTitle,
                    content: contentJson,
                    author_name: "AutoSave"
                }, (_, r)=>resolve(JSON.parse(r.responseText)));
            });
            if(res.ok) urls.push(res.result.url);
            else console.error("❌ Telegraph 创建失败:", res);
        }
        return urls;
    }

    function formatTelegramMessage(title, originalUrl, telegraphUrls){
        const titleLink = `[${title}](${originalUrl})`; // 标题超链接到原文
        let archiveLinks = '';
        if(telegraphUrls.length===1){
            archiveLinks = ` || [存档](${telegraphUrls[0]})`;
        }else if(telegraphUrls.length>=4){
            archiveLinks = ' ' + telegraphUrls.map((u,i)=>`|| [存档${i+1}](${u})`).join(' ');
        }else{
            archiveLinks = ' ' + telegraphUrls.map(u=>`|| [存档](${u})`).join(' ');
        }
        return `${titleLink}${archiveLinks}`;
    }

    btn.addEventListener('click', async ()=>{
        if(!BOT_TOKEN || !CHAT_ID || !TELEGRAPH_TOKEN){
            alert("⚠️ 请先通过脚本菜单设置 Bot Token、Chat ID、Telegraph Token!");
            return;
        }

        btn.classList.add("btn-click-animate");
        setTimeout(()=> btn.classList.remove("btn-click-animate"), 200);
        btn.style.background="#4caf50"; btn.style.color="#fff";

        const title = extractRealTitle();
        const content = extractContent();
        const segments = splitContent(content);

        const telegraphUrls = await createTelegraphPages(segments, title, TELEGRAPH_TOKEN);

        const messageText = formatTelegramMessage(title, location.href, telegraphUrls);

        httpPost(`https://api.telegram.org/bot${BOT_TOKEN}/sendMessage`,{
            chat_id: CHAT_ID,
            text: messageText,
            parse_mode: "Markdown",
            disable_web_page_preview: true
        }, (err,res)=>{
            if(!err && res.status===200){
                btn.style.background="#4caf50"; btn.style.color="#fff";
            }else{
                console.error("❌ 发送 Telegram 失败", res?.responseText||err);
                btn.style.background="#f44336"; btn.style.color="#fff";
            }
            setTimeout(()=>{ btn.style.background="#f5f5f5"; btn.style.color="#000"; },1500);
        });
    });

})();