您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Add button to summarize and toggle content of the main post
当前为
// ==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和按钮 })();