// ==UserScript== // @name DeepSeek 对话导出器 优化版(Optimized version of dialogue exporter) // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 1. 优化了旧版UI,现在不在阻挡视野 2. 针对ds缓冲机制进行了优化,现在无需 重新登陆/继续对话 也可以导出对话 // @author 口吃者 // @match https://chat.deepseek.com/a/chat/s/* // @icon https://www.google.com/s2/favicons?sz=64&domain=deepseek.com // @require https://update.greasyfork.icu/scripts/498507/1398070/sweetalert2.js // @grant none // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/525805/DeepSeek%20%E5%AF%B9%E8%AF%9D%E5%AF%BC%E5%87%BA%E5%99%A8%20%E4%BC%98%E5%8C%96%E7%89%88%28Optimized%20version%20of%20dialogue%20exporter%29.user.js // @updateURL https://update.greasyfork.icu/scripts/525805/DeepSeek%20%E5%AF%B9%E8%AF%9D%E5%AF%BC%E5%87%BA%E5%99%A8%20%E4%BC%98%E5%8C%96%E7%89%88%28Optimized%20version%20of%20dialogue%20exporter%29.meta.js // ==/UserScript== var comment_params = { "chat_session_id": '' }; var headersAuthorization = ''; class DsExportTool { constructor(sessionId = '', jsonData = '', markdownData = '') { this.sessionId = sessionId; this.jsonData = jsonData; this.markdownData = markdownData; } // 导出JSON文件方法 exportDsJsonData() { if (!this.jsonData) { console.error('No JSON data to export'); return; } let outputData; if (typeof this.jsonData === 'string') { // 如果数据是字符串,尝试解析为对象(确保有效性) try { outputData = JSON.parse(this.jsonData); } catch (e) { console.error('Invalid JSON string:', e); return; } } else { // 如果已经是对象/数组,直接使用 outputData = this.jsonData; } // 生成格式化的JSON(仅需一次序列化) const jsonString = JSON.stringify(outputData, null, 2); // 创建JSON类型Blob(修正MIME类型) const blob = new Blob([jsonString], { type: 'application/json;charset=utf-8' }); // 生成带时间戳和会话ID的文件名(示例:chat_export_12345_20230815.json) const timestamp = new Date().toISOString().slice(0, 10).replace(/-/g, ''); const filename = `chat_export_${this.sessionId || 'unknown'}_${timestamp}.json`; // 创建下载链接 const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = filename; anchor.style.display = 'none'; // 触发下载 document.body.appendChild(anchor); anchor.click(); document.body.removeChild(anchor); URL.revokeObjectURL(url); } // 新增 Markdown 导出方法 exportDsMarkdownData() { // 注意方法名驼峰式命名 if (!this.markdownData) { console.error('No Markdown data to export'); return; } // 创建标准 Markdown Blob(指定 MIME 类型) const blob = new Blob([this.markdownData], { type: 'text/markdown;charset=utf-8' // 或使用 text/plain }); // 生成带时间戳的文件名(示例:chat_history_12345_20230815.md) const timestamp = new Date().toISOString().slice(0, 10).replace(/-/g, ''); const filename = `chat_history_${this.sessionId || 'unknown'}_${timestamp}.md`; // 创建并触发下载链接 const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = filename; anchor.style.display = 'none'; document.body.appendChild(anchor); anchor.click(); // 清理资源 document.body.removeChild(anchor); URL.revokeObjectURL(url); } } const dsExportTool = new DsExportTool(); (function () { 'use strict'; const originalOpen = XMLHttpRequest.prototype.open; const authorizationParamsReady = new Promise((resolve) => { // 保存原始 open 方法 const originalOpen = XMLHttpRequest.prototype.open; // 保存原始 send 方法(关键!) const originalSend = XMLHttpRequest.prototype.send; // 保存原始 setRequestHeader 方法 const originalSetRequestHeader = XMLHttpRequest.prototype.setRequestHeader; // 重写 setRequestHeader 以捕获请求头 XMLHttpRequest.prototype.setRequestHeader = function (name, value) { this._requestHeaders = this._requestHeaders || {}; this._requestHeaders[name.toLowerCase()] = value; originalSetRequestHeader.apply(this, arguments); }; // 重写 open 方法 XMLHttpRequest.prototype.open = function (method, url) { // 先调用原始 open(确保兼容性) originalOpen.apply(this, arguments); // 仅监听目标 URL if (['chat/history_messages'].some(substring => url.includes(substring))) { // 重写 send 方法以在请求发送时捕获 Authorization const _this = this; this.send = function (body) { // 从缓存的请求头中获取 Authorization const authHeader = _this._requestHeaders?.authorization; if (authHeader) { headersAuthorization = authHeader; // 监听请求完成 _this.addEventListener('readystatechange', function () { if (this.readyState === 4 && this.status === 200) { resolve({ authorization: authHeader }); } }); } // 调用原始 send originalSend.call(this, body); }; } }; }); window.addEventListener('load', addPanel); })(); function addPanel() { function genButton(text, foo, id, fooParams = {}) { let b = document.createElement('button'); b.textContent = text; b.style.verticalAlign = 'inherit'; // 使用箭头函数创建闭包来保存 fooParams 并传递给 foo b.addEventListener('click', () => { foo.call(b, ...Object.values(fooParams)); // 使用 call 方法确保 this 指向按钮对象 }); if (id) { b.id = id }; return b; } function changeRangeDynamics() { const value = parseInt(this.value, 10); const roundedValue = Math.ceil(value / 10) * 10; targetAmountGlobal = roundedValue; // 只能通过 DOM 方法改变 document.querySelector('#swal-range > output').textContent = roundedValue; } async function openPanelFunc() { let isLoadEnd = false; const { value: formValues } = await Swal.fire({ title: "选择导出类型", showCancelButton: true, cancelButtonText: '取消', confirmButtonText: '确定', //class="swal2-range" swalalert框架可能会对其有特殊处理,导致其内标签的id声明失效 html: `