Export ChatGPT conversations to Obsidian.
当前为
// ==UserScript==
// @name Export Chat Dialogues to Obsidian
// @namespace http://tampermonkey.net/
// @version 0.9
// @description Export ChatGPT conversations to Obsidian.
// @author You
// @match https://chatgpt.com/c/*
// @match https://yuanbao.tencent.com/chat/*
// @match https://chat.deepseek.com/a/chat/s/*
// @grant GM_setClipboard
// @grant GM_openInTab
// @grant GM_registerMenuCommand
// @license MIT
// ==/UserScript==
(function () {
'use strict';
var source="others"
var cssArticle = "article"
var cssUser = "div.whitespace-pre-wrap"
var cssCopyButton = "div.touch\\:-me-2 > button:nth-child(1)"
if (window.location.hostname == 'chatgpt.com') {
source="chatgpt";
} else if (window.location.hostname == 'yuanbao.tencent.com') {
source="yuanbao";
cssArticle = "div.agent-chat__list__item"
cssUser = "div.hyc-content-text"
cssCopyButton = "div.agent-chat__toolbar__item.agent-chat__toolbar__copy"
} else if (window.location.hostname == 'chat.deepseek.com') {
source="deepseek"
}
// 添加导出按钮
function addExportButton() {
if (document.getElementById('export-to-obsidian-btn')) return;
const btn = document.createElement('button');
btn.id = 'export-to-obsidian-btn';
btn.innerText = '💾Export';
btn.style.position = 'fixed';
btn.style.top = '50px';
btn.style.right = '20px';
btn.style.zIndex = '9999';
btn.style.padding = '8px 12px';
btn.style.fontSize = '14px';
btn.style.backgroundColor = '#2670dd';
btn.style.color = '#fff';
btn.style.border = 'none';
btn.style.borderRadius = '5px';
btn.style.cursor = 'pointer';
btn.style.boxShadow = '0 2px 6px rgba(0,0,0,0.2)';
btn.addEventListener('click', exportToObsidian);
document.body.appendChild(btn);
}
function findElementsByStyle(property, value) {
const allElements = document.querySelectorAll('[style*="z-index"], div');
const result = [];
allElements.forEach(element => {
// 获取元素的计算样式
const computedStyle = window.getComputedStyle(element);
// 获取目标属性的值(如 'zIndex')
const propValue = computedStyle.getPropertyValue(property);
// 检查属性值是否匹配(转换为字符串比较)
if (propValue === String(value)) {
result.push(element);
}
});
return result;
}
async function getContents() {
const articles = document.querySelectorAll(cssArticle);
const contents = [];
for (var idx=0; idx < articles.length; idx++) {
const article = articles[idx]
if (idx % 2 === 0) {
const user = article.querySelector(cssUser);
if (!user) {
continue;
}
contents.push(user.textContent);
} else {
const copyButton = article.querySelector(cssCopyButton);
if (!copyButton) continue;
copyButton.click();
await new Promise(resolve => setTimeout(resolve, 250));
const text = await navigator.clipboard.readText();
contents.push(text);
}
}
return contents;
}
async function getDeepSeekContents() {
const contents = [];
var copyButtons = document.querySelectorAll("div.ds-flex > div.ds-icon-button:nth-child(1)")
for (const copyButton of copyButtons) {
copyButton.click();
await new Promise(resolve => setTimeout(resolve, 250));
const text = await navigator.clipboard.readText();
contents.push(text);
}
return contents;
}
// 核心导出逻辑
async function exportToObsidian() {
var contents;
if (source == "deepseek"){
contents = await getDeepSeekContents();
} else {
contents = await getContents();
}
if (contents.length === 0) {
alert("没有找到任何对话记录!");
return;
}
// 构建正文内容
let body = '';
contents.forEach((text, idx) => {
if (idx % 2 === 0) {
body += `# ❓ User:\n> ${text.replace(/\n/g, '\n> ')}\n\n`;
} else {
body += `# 🤖 GPT:\n${text}\n\n`;
}
});
var title = document.title.replace(/[/\\?%*:|"<>]/g, '-').trim();
if(source == "yuanbao") {
var titleElement = document.querySelector("span.agent-dialogue__content--common__header__name__title");
if(titleElement){
title = titleElement.textContent;
}
} else if(source == "deepseek") {
var elements = findElementsByStyle('z-index', 12);
if(elements.length) {
title = elements[0].textContent;
}
}
const timestamp = new Date().toLocaleString();
const url=document.URL
// YAML Frontmatter
const yaml = `---\ntitle: "${title}"\ndate: ${timestamp}\nsource: ${source}\nURL: ${url}\n---\n\n`;
const fullContent = yaml + body;
// 写入剪贴板
GM_setClipboard(fullContent);
const obsidianUrl = `obsidian://new?file=Chat/${source}/${encodeURIComponent(title)}&clipboard`;
const link = document.createElement('a');
link.href = obsidianUrl;
link.click(); // 只在用户触发的事件中使用
}
// 注册菜单项
GM_registerMenuCommand("📥 导出到 Obsidian", exportToObsidian);
// 初始化:添加按钮 + 观察变化
setTimeout(addExportButton, 1000);
const observer = new MutationObserver(addExportButton);
observer.observe(document.body, { childList: true, subtree: true });
})();