Linux Do Summary

Add button to summarize and toggle content of the main post

目前為 2024-04-04 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Linux Do Summary
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Add button to summarize and toggle content of the main post
// @author       Reno
// @match        https://linux.do/*
// @grant        GM_xmlhttpRequest
// @license      MIT

// ==/UserScript==

(function() {
    'use strict';

    // 定义请求格式
    const BASE_URL = "https://api.openai.com/v1/chat/completions";
    const API_KEY = "Your_API_Key";
    const MODEL = "gpt-4-all";
    const PROMPT = "以下是linu.do论坛的一个主题,帮我用中文梳理总结:";

    let originalContent = ''; // 存储原始内容
    let toggled = false; // 切换状态

    // 提取并格式化主帖内容
    function extractAndFormat() {
        console.log('提取并格式化内容...');
        var postStreamElement = document.querySelector('div.post-stream');
        if (postStreamElement && postStreamElement.querySelector('#post_1')) {
            var articleElement = postStreamElement.querySelector('#post_1');
            if (articleElement) {
                var cookedDiv = articleElement.querySelector('.cooked');
                if (cookedDiv) {
                    var elementsData = [];
                    var index = 0;

                    // 提取并存储所有img、p和li元素,将li转换为p
                    Array.from(cookedDiv.querySelectorAll('img, p, li')).forEach(node => {
                        var tagName = node.tagName.toLowerCase() === 'li' ? 'p' : node.tagName.toLowerCase(); // 将li转换为p
                        var textContent = node.textContent.trim();
                        var src = tagName === 'img' ? node.getAttribute('src')?.trim() : null;

                        if (tagName === 'p' && textContent.includes('\n')) {
                            var contents = textContent.split(/\n+/).map(line => line.trim()).filter(line => line.length > 0);
                            elementsData.push({ index, tagName, textContent: contents[0], src });
                            index++;
                            for (var i = 1; i < contents.length; i++) {
                                elementsData.push({ index, tagName, textContent: contents[i], src });
                                index++;
                            }
                        } else {
                            elementsData.push({ index, tagName, textContent, src });
                            index++;
                        }
                    });

                    // 过滤掉不必要的元素和重复项
                    var cleanedElementsData = elementsData.filter(({ tagName, textContent }) => tagName !== 'p' || textContent.length > 1);
                    var uniqueElementsData = [];
                    var uniqueTextContents = new Set();
                    cleanedElementsData.forEach(({ tagName, textContent, src }) => {
                        var contentKey = `${tagName}_${textContent}_${src}`;
                        if (tagName === 'img' || !uniqueTextContents.has(contentKey)) {
                            uniqueElementsData.push({ tagName, textContent, src });
                            uniqueTextContents.add(contentKey);
                        }
                    });

                    // 转换为HTML
                    var htmlContent = "";
                    uniqueElementsData.forEach(({ tagName, textContent, src }) => {
                        if (tagName === 'p') {
                            htmlContent += `<p>${textContent}</p>`;
                        } else if (tagName === 'img') {
                            htmlContent += `<img src="${src}" alt="${textContent}">`;
                        }
                    });

                    return htmlContent; // 返回最终的HTML字符串
                }
            }
        }
        return '';
    }

    // 发送内容到API
    function sendToAPI(textContent, callback) {
        console.log('向API发送内容...');
        var xhr = new XMLHttpRequest();
        xhr.open("POST", BASE_URL);
        xhr.setRequestHeader("Content-Type", "application/json");
        xhr.setRequestHeader("Authorization", `Bearer ${API_KEY}`);
        xhr.onload = function() {
            if (xhr.status === 200) {
                var jsonResponse = JSON.parse(xhr.responseText);
                if(jsonResponse && jsonResponse.choices && jsonResponse.choices[0] && jsonResponse.choices[0].message) {
                    callback(jsonResponse.choices[0].message.content);
                }
            }
        };
        xhr.onerror = function() {
            console.error('错误:', xhr.statusText);
            callback('');
        };
        xhr.send(JSON.stringify({ model: MODEL, messages: [{ role: "user", content: PROMPT + textContent }] }));
    }

    // 格式化从API接收到的内容
    function formatContent(text) {
        console.log('格式化内容...');
        // 处理换行
        text = text.replace(/\n/g, '<br>');

        // 处理加粗
        text = text.replace(/\*\*\*\*(.*?)\*\*\*\*/g, '<strong>$1</strong>');

        // 处理标题
        text = text.replace(/^(#{1,6})\s(.*?)<br>/gm, function(match, p1, p2) {
            const level = p1.length;
            return `<h${level}>${p2}</h${level}><br>`;
        });

        // 处理列表
        text = text.replace(/- (.*?)<br>/g, '<li>$1</li><br>');
        text = text.replace(/<li>(.*?)<\/li><br><br>/g, '<ul><li>$1</li></ul><br>');

        return text;
    }

    // 检查是否存在post_1元素和按钮
    function checkAndAddButton() {
        console.log('检查帖子元素和按钮...');
        const postElement = document.querySelector('#post_1');
        const buttonExists = document.querySelector('#summaryToggleButton');
        if (postElement && !buttonExists) {
            addButtonAndProcessData();
        }
    }

    // 添加总结按钮并附加事件处理程序
    function addButtonAndProcessData() {
        console.log('添加按钮并处理数据...');
        const controlsContainer = document.querySelector('nav.post-controls');
        if (controlsContainer) {
            const newButton = document.createElement('button');
            newButton.textContent = '总结';
            newButton.id = 'summaryToggleButton'; // 给按钮定义id
            newButton.style.cssText = 'margin-left: 10px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; padding: 5px 10px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; cursor: pointer; transition-duration: 0.4s;'; // 添加样式
            controlsContainer.appendChild(newButton);

            // 初始化状态
            originalContent = '';
            toggled = false;

            newButton.addEventListener('click', function() {
                console.log('按钮点击...');
                const cookedContent = document.querySelector('div.cooked');
                if (cookedContent) {
                    if (!toggled) {
                        originalContent = cookedContent.innerHTML;
                        const textContent = extractAndFormat();
                        sendToAPI(textContent, function(summary) {
                            console.log('从API接收到摘要...');
                            cookedContent.innerHTML = formatContent(summary) || '内容加载中...';
                            window.scrollTo(0, 0);
                        });
                    } else {
                        cookedContent.innerHTML = originalContent;
                    }
                    toggled = !toggled;
                }
            });
        }
    }

    // 持续检查帖子元素和按钮的存在性
    setInterval(checkAndAddButton, 5000); // 每5秒检查一次是否存在post_1和按钮
})();

QingJ © 2025

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