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和按钮
})();