DeepSeek Chat to Telegraph

DeepSeek 官网一键分享当前对话, 发布到 telegra.ph

// ==UserScript==
// @name         DeepSeek Chat to Telegraph
// @namespace    https://gf.qytechs.cn/users/428487-cxumol
// @version      0.0.7
// @description  Add "Share" button to DeepSeek Chat to post your chat on Telegraph. 
// @description:zh-CN  DeepSeek 官网一键分享当前对话, 发布到 telegra.ph
// @author       cxumol
// @match        https://*.deepseek.com/a/chat/s/*
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABkAAAAUCAMAAABPqWaPAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAEXRFWHRTb2Z0d2FyZQBTbmlwYXN0ZV0Xzt0AAAF3UExURU1r/k5r/k5s/k9s/k9t/lBt/lBu/lFu/lVx/lVy/lZy/ld0/lhz/lh0/lp2/lt3/lx3/l14/l55/l96/mB6/mB7/mJ9/mN9/miB/miC/mmB/mqD/muD/m6G/nGJ/nKK/nWM/nuR/n+U/oSZ/oWZ/ome/oqe/oue/o2g/o2h/o+h/o+i/pCi/pKk/pOl/pao/pip/pmq/pmr/p6v/qKx/qW0/qa1/qi2/qq4/qu5/qy5/q27/q+9/7G9/rG+/rTA/rXC/rbC/rnF/rrF/rvG/7zH/rzI/r3I/sXO/srS/svU/szU/szV/s3V/tDX/tHZ/tLZ/tPa/tPb/tTa/tXc/9jf/9ng/tzi/uLn/+Pn/uPn/+Po/+To/uTp/uTp/+Xp/ufr/+js/urt/uvu/uvu/+zv/u3w/+7w/u7w/+/y/vHz/vP1//T2//b3/vb4//f4/vf5//j5/vn6//r7//v7/vv8//z8//z9//39/v39//7+/v7+/////1hnCtYAAAEJSURBVBgZdcHVQgJRAEXRrYKJhZ3Y3d3dCnZ3d4sKnI937mC9sBaKBP362B+qTUyr9J4GZCAjeLL4GGzhW2lQFmT4wJHYut3vBFceZB5IQrbLYXB2aTWDcW0Uk3whIdt9ARA9pbOqcum2BPeTkPHRhG1btisXM0KGj7DMT9mWSAghowJSJ4uADtnuYRdZbuMg/W4pCaJGZatmAVlmsTQe1gOOQRlrzCBLNw431Hgx3HPXAb0wjxQK1lGoMv6klcABevDEQPzWezP/eQKoASP23N/OP5viCCjNh2lphB8xvRIruevSchZtkgYIyxiThGz+7CHpOYeUib7OniMZKGznRnrbO37VLxTJF42Gi4sQ++AKAAAAAElFTkSuQmCC
// @grant        GM_info
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_xmlhttpRequest
// @connect      api.telegra.ph
// @require      https://update.gf.qytechs.cn/scripts/506699/1534808/marked.js
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';
    console.log(`UserScript "DeepSeek Chat to Telegraph" loaded, version: ${GM_info.script.version}`);
    const _selectors={"titleBar":".f8d1e4c0"}; // Need update if chat.deepseek.com update; no gentle way to locate the title bar, pls lemme know if u got better idea.

    // Function to create the overlay for displaying the Telegraph URL
    function showShareOverlay(url) {
        var overlay = document.createElement("div");
        var $=q=>overlay.querySelector(q);
        overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.5);
            display: flex;
            justify-content: center;
            align-items: center;
            z-index: 10000;
        `;
        overlay.innerHTML = `
            <div style="background-color: white; padding: 20px; border-radius: 5px; text-align: center;">
                <p>Share this link:</p>
                <p><a href="${url}" target="_blank">${url}</a></p>
                <button class="copy-button" style="margin-right:10px;">Copy URL</button>
                <button class="close-button">Close</button>
                <button class="delete-button" style="margin-left:10px;color:maroon;">Delete</button>
            </div>
        `;
        document.body.appendChild(overlay);
        $(".copy-button").onclick=()=>navigator.clipboard.writeText(url).then(()=>alert("URL copied!"));
        $(".close-button").onclick=()=>overlay.remove();
        $(".delete-button").onclick=()=>deleteTelegraph(url).then(()=>alert(`${url} is deleted!\nClick "Share" to share it again.`));
    }

    // Convert DeepSeek chat messages to Telegraph content format.
    function convertToTelegraphContent(messages) {
        let tgphData = [];
        messages.forEach(message => {
            const {role,content} = message; // role: system | assistant | user
            let text = `\`${role}\`: ${content}`;
            if(role.toLowerCase()==="assistant"&&message.thinking_enabled&&message.thinking_content)text=`\`${role}\`: \n\n${message.thinking_content.split("\n\n").map(e=>"> "+e).join("\n\n")}\n\n${content}`;
            tgphData = tgphData.concat(md2TgphNode(text));
        }); //console.log(tgphData);
        return JSON.stringify(tgphData);
    }
    var SUPPORTED_TGPH_TAGS = ["a","aside","b","blockquote","br","code","em","figcaption","figure","h3","h4","hr","i","iframe","img","li","ol","p","pre","s","strong","u","ul","video"];
    function md2TgphNode(c) {
        c=c.trim();
        var d=new DOMParser().parseFromString(marked.parse(c),"text/html");
        if(!d)throw new Error("Failed to parse HTML to DOM");
        var n=domToNode(d.body);
        if(!n)throw new Error(`Empty node content: ${d.body.textContent}`);
        if(typeof n==="string")return n;
        if(!n.children)throw new Error(`Empty content: ${c}`);
        return n.children;
    }
    function domToNode(el) {
        if(el.nodeType==Node.TEXT_NODE){var t=el.textContent;return el.parentElement?.tagName==="P"&&t?t.replace("\n"," "):t||null;}
        if(!(el instanceof Element))return null;
        var tg=el.tagName.toLowerCase();
        if(!SUPPORTED_TGPH_TAGS.includes(tg)&&tg!=="body") console.log("domToTelegraphNode: unsupported tag: ",el.tagName,el.innerHTML);
        var n={tag:tg};
        if(tg==="code"&&el.parentElement?.tagName==="PRE")n.tag="pre";
        var h=el.getAttribute("href");if(h!=null)n.attrs={href:h};
        var s=el.getAttribute("src");if(s!=null){n.attrs=n.attrs||{};n.attrs.src=s;}
        if(el.childNodes.length){
            n.children=[];
            for(var i=0;i<el.childNodes.length;i++){
                var cN=domToNode(el.childNodes[i]); if(cN&&cN!=="\n"&&(typeof cN==="string"||cN.tag))n.children.push(cN);
            }
        }
        return n;
    }

    // Upload chat to Telegraph.
    async function getTgphToken(){
        let token = GM_getValue('tgphToken');if(token){console.log("telegra.ph token from storage:", token);return token;}
        const data = await fetch('https://api.telegra.ph/createAccount?short_name=ds2ph&author_name=DeepSeekToTelegraph').then(r=>r.json());if(!data.ok)throw new Error(`Telegraph API error: ${data.error}`);
        token = data.result.access_token;
        GM_setValue('tgphToken', token); console.log("create new telegra.ph token:", token);
        return token;
    }
    async function uploadToTelegraph(title,content){
        var telegraphAccessToken=await getTgphToken();
        try{const r=await GM.xmlHttpRequest({method:'POST',url:'https://api.telegra.ph/createPage',headers:{'Content-Type':'application/json'},
                                             data:JSON.stringify({access_token:telegraphAccessToken,title:title,content:content,return_content:true,author_name:"DeepSeek Chat"}),responseType:'json',
                                             onerror:(e)=>{throw new Error(`Telegraph API request failed: ${e.status}`)}});
            if(r.status>299||r.status<200)throw new Error(`Telegraph API error: ${r.status}`)
            const data=r.response; if(!data.ok)throw new Error(`Telegraph API error: ${data.error}`);
            return `https://telegra.ph/${data.result.path}`;
        }catch(e){console.error("Error uploading to Telegraph:",e);throw e}
    }
    function deleteTelegraph(postUrl){
        var telegraphAccessToken=GM_getValue('tgphToken'); if(!telegraphAccessToken)throw new Error("telegraphAccessToken NOT FOUND, cannot delete the post!");
        return fetch(`https://api.telegra.ph/editPage/${postUrl.split('/').pop()}?access_token=${telegraphAccessToken}&title=Removed&author_name=&content=[{"tag":"p","children":["removed by author"]}]`
                    ).then(r=>r.json()).then(j=>{if(!j.ok)throw new Error(j.error);return j;}).catch(e=>{console.error("Error deleting Telegraph:",e);throw e;});
    }

    // Fetch chat history from DeepSeek API
    async function fetchChatHistory() {
        const token = localStorage.getItem("userToken");
        if (!token) throw new Error("User token not found. Please make sure you are logged in.");
        const parsedToken = JSON.parse(token);

        // 1. Get current chat session ID.
        const sessionId = window.location.pathname.split('/').pop();
        if(sessionId.length<30)throw new Error(`Session ID not found from address bar, got: ${sessionId}`);
        // 2. Fetch messages using the session ID.
        const messagesResponse = await fetch(`https://chat.deepseek.com/api/v0/chat/history_messages?chat_session_id=${sessionId}`,
                                             {credentials: "include",headers:{"Authorization":`Bearer ${parsedToken.value}`}});
        if (!messagesResponse.ok) throw new Error(`Failed to fetch chat messages: ${messagesResponse.status}`);
        const messagesData = await messagesResponse.json();
        return { title: messagesData.data.biz_data.chat_session.title,
            messages: messagesData.data.biz_data.chat_messages};
    }

    // Main function to add the share button.
    function addShareButton() {
        const titleContainer = document.querySelector(_selectors.titleBar); //  The container of title.
        if (titleContainer && !document.getElementById('share-chat-button')) {
            const shareButton = document.createElement('button');
            shareButton.id = 'share-chat-button';
            shareButton.textContent = 'Share';
            shareButton.style.cssText = `
                margin-left: 10px;
                padding: 5px 10px;
                border-radius: 4px;
            `;
            titleContainer.appendChild(shareButton);

            shareButton.addEventListener('click', async () => {
                try {
                    shareButton.disabled = true;
                    shareButton.textContent = "Sharing...";
                    const chatHistory = await fetchChatHistory();
                    const telegraphContent = convertToTelegraphContent(chatHistory.messages);
                    const telegraphUrl = await uploadToTelegraph(chatHistory.title, telegraphContent);
                    showShareOverlay(telegraphUrl);
                } catch (error) {
                    alert(`Error sharing chat: ${error.message}`);
                    console.error(error);
                } finally {
                    shareButton.disabled = false;
                    shareButton.textContent = 'Share';
                }
            });
        }
    }
    // Observe changes in the DOM to add the button when the title bar appears.
    const observer = new MutationObserver(()=>addShareButton());
    observer.observe(document.body, { childList: true, subtree: true });
    // also call addShareButton for first time run
    addShareButton();
})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址