您需要先安装一个扩展,例如 篡改猴、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和按钮
- })();