Download ChatGPT record

以html文件的形式保存当前页面下ChatGPT的对话记录:Save the chat record of ChatGPT on the current page in the form of html file

  1. // ==UserScript==
  2. // @name Download ChatGPT record
  3. // @namespace http://tampermonkey.net/
  4. // @version 0.5.3
  5. // @description 以html文件的形式保存当前页面下ChatGPT的对话记录:Save the chat record of ChatGPT on the current page in the form of html file
  6. // @author YYForReal
  7. // @match https://chat.openai.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=openai.com
  9. // @grant none
  10. // @license MIT
  11.  
  12. // ==/UserScript==
  13.  
  14. (function() {
  15. 'use strict';
  16. (function(){
  17. // 原本官网的域名,用于连接资源
  18. // const ResourceDomain = "https://chat.openai.com/"
  19. // 使用Gitee仓库内托管的资源
  20. const ResourceDomain = "https://gitee.com/friendArt/download-ChatGPT-record/raw/master/resource/"
  21. function downloadInit(){
  22. // DOM 深拷贝,防止影响页面
  23. const head = document.head.cloneNode(true)
  24. const body = document.body.cloneNode(true)
  25.  
  26. // 替换所有的href链接
  27. let links = head.querySelectorAll("link");
  28. for (let link of links) {
  29. if (link.getAttribute("href").indexOf("http") !== 0) {
  30. link.setAttribute("href", ResourceDomain + link.getAttribute("href"));
  31. }
  32. }
  33.  
  34. // 移除head内部的script代码
  35. let scripts = head.querySelectorAll("script");
  36. for (let scriptDom of scripts) {
  37. scriptDom.parentElement.removeChild(scriptDom);
  38. // 如果需要继续使用的话可以拼接保留
  39. // if (link.getAttribute("href").indexOf("http") !== 0) {
  40. // link.setAttribute("href", ResourceDomain + link.getAttribute("href"));
  41. // }
  42. }
  43.  
  44. // 单独移除最新的CSS样式
  45. links = head.querySelectorAll('link[rel="stylesheet"]');
  46. for (var i = 0; i < links.length; i++) {
  47. var link = links[i];
  48. link.parentNode.removeChild(link);
  49. }
  50.  
  51. // 单独引入CSS样式
  52. var link = document.createElement('link');
  53. link.rel = 'stylesheet';
  54. link.type = 'text/css';
  55. link.href = 'https://gitee.com/friendArt/download-ChatGPT-record/raw/master/resource/_next/static/css/c770e01054031fe0.css';
  56. head.appendChild(link);
  57.  
  58.  
  59. // 移除body底部栏
  60. let bottom = body.querySelector('.absolute.bottom-0')
  61. bottom.parentNode.removeChild(bottom)
  62.  
  63. // 修改样式,使之可以滚动
  64. let overflowDoms = body.querySelectorAll('.overflow-hidden')
  65. for (let dom of overflowDoms){
  66. dom.classList.remove("overflow-hidden")
  67. }
  68.  
  69. // 拿到修改之后的字符串文本
  70. let mainStr = body.getElementsByTagName('main')[0].cloneNode(true).outerHTML;
  71. let headStr = head.outerHTML;
  72.  
  73. // 去除所有的<script>
  74. // 获取script标签内的内容
  75. let reg = /<script[^>]*>([^<]|<(?!\/script))*<\/script>/gmi
  76. let res = mainStr.match(reg)
  77. // 如果具有script标签
  78. if (res != null) {
  79. res.forEach((ele) => {
  80. mainStr = mainStr.replace(ele,'')
  81. })
  82. }
  83. res = headStr.match(reg)
  84. if (res != null) {
  85. res.forEach((ele) => {
  86. headStr = headStr.replace(ele,'')
  87. })
  88. }
  89.  
  90. // 去除头部的跨域标签
  91. headStr = headStr.replace(/crossorigin/igm,"")
  92. // 获取风格模式(light mode / dark mode)
  93. let htmlDom = document.querySelector('html')
  94. let mode = htmlDom.getAttribute('style')
  95. let htmlClass = htmlDom.className;
  96.  
  97. // 增加copy code功能
  98. let copyCodeScript = `<script>
  99. let buttons = document.querySelectorAll('button.flex.ml-auto.gap-2')
  100. let timer = null;
  101. buttons.forEach(button => {
  102. button.addEventListener('click',(e)=>{
  103. // 不使用event对象找DOM会出现闭包、e.target是事件源、currentTarget是监听的对象
  104. let button = e.currentTarget
  105. let codeBlock = button.parentNode.nextSibling.children[0];
  106. const textArea = document.createElement("textarea");
  107. textArea.value = codeBlock.textContent;
  108. document.body.appendChild(textArea);
  109. textArea.select();
  110. document.execCommand("copy");
  111. textArea.remove();
  112. button.innerHTML = button.innerHTML.replace(/Copy code/igm,'Copied!');
  113. if(timer == null){
  114. timer = setTimeout(()=>{
  115. button.innerHTML = button.innerHTML.replace(/Copied!/igm,'Copy code');
  116. clearTimeout(timer);
  117. timer = null
  118. },1000)
  119. }
  120. })
  121. });
  122. </script>`
  123.  
  124. return `<html class="${htmlClass}" style="${mode}" >${headStr} <body> ${mainStr} ${copyCodeScript}</body> </html>`
  125. }
  126.  
  127. // 定义按钮
  128. var downloadButton = document.createElement("button");
  129. downloadButton.className = "download-button"
  130. downloadButton.innerHTML = "Download Record";
  131.  
  132. // 设置按钮元素的样式
  133. downloadButton.style.position = "fixed";
  134. downloadButton.style.padding = "5px";
  135. downloadButton.style.bottom = "100px";
  136. downloadButton.style.right = "20px";
  137. downloadButton.style.backgroundColor = "skyblue"
  138. downloadButton.style.border = "1px solid black";
  139. downloadButton.style.borderRadius = "10px";
  140. downloadButton.style.zIndex = 99;
  141.  
  142. // 为按钮添加点击事件
  143. downloadButton.addEventListener("click", function () {
  144. // 定义html代码字符串
  145. // var htmlCode = "<html><body><h1>Example HTML code</h1></body></html>";
  146. var htmlCode = downloadInit();
  147. // 创建Blob对象
  148. var blob = new Blob([htmlCode], {
  149. type: "text/html"
  150. });
  151.  
  152. // 获取时间,用于文件命名
  153. var today = new Date();
  154. var month = (today.getMonth() + 1).toString().padStart(2, '0');
  155. var day = today.getDate().toString().padStart(2, '0');
  156.  
  157.  
  158. // 创建下载链接
  159. var downloadLink = document.createElement("a");
  160. downloadLink.download = `Chat-${document.title}(${month}${day}).html`
  161. downloadLink.href = URL.createObjectURL(blob);
  162.  
  163. // 点击链接,实现下载
  164. downloadLink.click();
  165.  
  166. // 由于修改了DOM,所以需要重新刷新页面
  167. // window.location.reload();
  168. });
  169.  
  170. // 将按钮添加到页面中
  171. document.body.appendChild(downloadButton);
  172. })()
  173.  
  174.  
  175.  
  176. })();

QingJ © 2025

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