Warning: fopen(/www/sites/update.greasyfork.icu/index/store/forever/08d5ac405a1ffb43f6c6129f8190fef7.js): failed to open stream: No space left on device in /www/sites/update.greasyfork.icu/index/scriptControl.php on line 65
// ==UserScript==
// @name Lyra's Exporter Fetch
// @namespace userscript://lyra-conversation-exporter
// @version 2.1
// @description 获取Claude的UUID并跳转到API页面,支持树形模式切换,收纳隐藏,UI更友好!
// @author Yalums
// @match https://claude.ai/*
// @run-at document-start
// @grant none
// @license GNU General Public License v3.0
// @downloadURL none
// ==/UserScript==
(function() {
'use strict';
// 存储请求到的用户ID
let capturedUserId = '';
// 存储工具栏的折叠状态
let isCollapsed = localStorage.getItem('claudeToolCollapsed') === 'true';
// 拦截XMLHttpRequest
const originalXHROpen = XMLHttpRequest.prototype.open;
XMLHttpRequest.prototype.open = function(method, url) {
const organizationsMatch = url.match(/api\/organizations\/([a-zA-Z0-9-]+)/);
if (organizationsMatch && organizationsMatch[1]) {
capturedUserId = organizationsMatch[1];
console.log("✨ 已请求用户ID:", capturedUserId);
}
return originalXHROpen.apply(this, arguments);
};
// 拦截fetch请求
const originalFetch = window.fetch;
window.fetch = function(resource, options) {
if (typeof resource === 'string') {
const organizationsMatch = resource.match(/api\/organizations\/([a-zA-Z0-9-]+)/);
if (organizationsMatch && organizationsMatch[1]) {
capturedUserId = organizationsMatch[1];
console.log("✨ 已请求用户ID:", capturedUserId);
}
}
return originalFetch.apply(this, arguments);
};
const CONTROL_ID = "lyra-tool-container";
const SWITCH_ID = "lyra-tree-mode";
const TOGGLE_ID = "lyra-toggle-button";
function injectCustomStyle() {
const style = document.createElement('style');
style.textContent = `
#${CONTROL_ID} {
position: fixed;
right: 10px;
bottom: 80px;
display: flex;
flex-direction: column;
gap: 8px;
z-index: 999999;
transition: all 0.3s ease;
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
padding: 10px;
border: 1px solid rgba(77, 171, 154, 0.3);
max-width: 200px;
}
#${CONTROL_ID}.collapsed {
transform: translateX(calc(100% - 40px));
}
#${TOGGLE_ID} {
position: absolute;
left: 0;
top: 10px;
width: 28px;
height: 28px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background: rgba(77, 171, 154, 0.2);
color: #4DAB9A;
cursor: pointer;
border: 1px solid rgba(77, 171, 154, 0.3);
transition: all 0.3s;
transform: translateX(-50%);
}
#${TOGGLE_ID}:hover {
background: rgba(77, 171, 154, 0.3);
}
.lyra-main-controls {
display: flex;
flex-direction: column;
gap: 8px;
padding-left: 15px;
}
.lyra-button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: 8px 10px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
background-color: rgba(77, 171, 154, 0.1);
color: #4DAB9A;
border: 1px solid rgba(77, 171, 154, 0.2);
transition: all 0.3s;
text-align: left;
}
.lyra-button:hover {
background-color: rgba(77, 171, 154, 0.2);
}
.lyra-toggle {
display: flex;
align-items: center;
font-size: 13px;
margin-bottom: 5px;
}
.lyra-switch {
position: relative;
display: inline-block;
width: 32px;
height: 16px;
margin: 0 5px;
}
.lyra-switch input {
opacity: 0;
width: 0;
height: 0;
}
.lyra-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 34px;
}
.lyra-slider:before {
position: absolute;
content: "";
height: 12px;
width: 12px;
left: 2px;
bottom: 2px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
input:checked + .lyra-slider {
background-color: #4DAB9A;
}
input:checked + .lyra-slider:before {
transform: translateX(16px);
}
.lyra-toast {
position: fixed;
bottom: 60px;
right: 20px;
background-color: #323232;
color: white;
padding: 8px 12px;
border-radius: 6px;
z-index: 1000000;
opacity: 0;
transition: opacity 0.3s ease-in-out;
font-size: 13px;
}
.lyra-title {
font-size: 12px;
font-weight: 500;
color: #4DAB9A;
margin-bottom: 5px;
text-align: center;
}
`;
document.head.appendChild(style);
}
function showToast(message) {
let toast = document.querySelector(".lyra-toast");
if (!toast) {
toast = document.createElement("div");
toast.className = "lyra-toast";
document.body.appendChild(toast);
}
toast.textContent = message;
toast.style.opacity = "1";
setTimeout(() => {
toast.style.opacity = "0";
}, 2000);
}
function getCurrentChatUUID() {
const url = window.location.href;
const match = url.match(/\/chat\/([a-zA-Z0-9-]+)/);
return match ? match[1] : null;
}
function checkUrlForTreeMode() {
return window.location.href.includes('?tree=True&rendering_mode=messages&render_all_tools=true') ||
window.location.href.includes('&tree=True&rendering_mode=messages&render_all_tools=true');
}
function toggleCollapsed() {
const container = document.getElementById(CONTROL_ID);
if (container) {
isCollapsed = !isCollapsed;
if (isCollapsed) {
container.classList.add('collapsed');
} else {
container.classList.remove('collapsed');
}
localStorage.setItem('claudeToolCollapsed', isCollapsed);
}
}
function createUUIDControls() {
// 如果控件已存在,则不再创建
if (document.getElementById(CONTROL_ID)) return;
// 创建主容器
const container = document.createElement('div');
container.id = CONTROL_ID;
container.className = isCollapsed ? 'collapsed' : '';
// 创建展开/折叠按钮
const toggleButton = document.createElement('div');
toggleButton.id = TOGGLE_ID;
toggleButton.innerHTML = isCollapsed ?
'' :
'';
toggleButton.addEventListener('click', () => {
toggleCollapsed();
toggleButton.innerHTML = isCollapsed ?
'' :
'';
});
container.appendChild(toggleButton);
// 创建主控件区域
const controlsArea = document.createElement('div');
controlsArea.className = 'lyra-main-controls';
// 添加标题
const title = document.createElement('div');
title.className = 'lyra-title';
title.textContent = 'Lyra Fetch Exporter';
controlsArea.appendChild(title);
// 创建模式切换开关
const toggleContainer = document.createElement('div');
toggleContainer.className = 'lyra-toggle';
toggleContainer.innerHTML = `
树形(多分支)模式
`;
controlsArea.appendChild(toggleContainer);
// 创建获取UUID按钮
const uuidButton = document.createElement('button');
uuidButton.className = 'lyra-button';
uuidButton.innerHTML = `
获取对话UUID
`;
// 处理UUID按钮点击事件
uuidButton.addEventListener('click', () => {
const uuid = getCurrentChatUUID();
if (uuid) {
if (!capturedUserId) {
showToast("未能请求用户ID,请刷新页面或进行一些操作");
return;
}
navigator.clipboard.writeText(uuid).then(() => {
console.log("UUID 已复制:", uuid);
showToast("UUID已复制!");
}).catch(err => {
console.error("复制失败:", err);
showToast("复制失败");
});
const treeMode = document.getElementById(SWITCH_ID).checked;
const jumpUrl = `https://claude.ai/api/organizations/${capturedUserId}/chat_conversations/${uuid}${treeMode ? '?tree=True&rendering_mode=messages&render_all_tools=true' : ''}`;
window.open(jumpUrl, "_blank");
} else {
showToast("未找到UUID!");
}
});
controlsArea.appendChild(uuidButton);
// 创建导出JSON按钮
const downloadJsonButton = document.createElement('button');
downloadJsonButton.className = 'lyra-button';
downloadJsonButton.innerHTML = `
导出对话JSON
`;
// 处理导出JSON按钮点击事件
downloadJsonButton.addEventListener('click', async () => {
const uuid = getCurrentChatUUID();
if (uuid) {
if (!capturedUserId) {
showToast("未能请求用户ID,请刷新页面或进行一些操作");
return;
}
try {
const treeMode = document.getElementById(SWITCH_ID).checked;
const apiUrl = `https://claude.ai/api/organizations/${capturedUserId}/chat_conversations/${uuid}${treeMode ? '?tree=True&rendering_mode=messages&render_all_tools=true' : ''}`;
// 获取JSON数据
showToast("正在获取数据...");
const response = await fetch(apiUrl);
if (!response.ok) {
throw new Error(`请求失败: ${response.status}`);
}
const data = await response.json();
// 创建下载
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `claude_${uuid.substring(0, 8)}_${new Date().toISOString().slice(0,10)}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
showToast("JSON导出成功!");
} catch (error) {
console.error("导出失败:", error);
showToast("导出失败: " + error.message);
}
} else {
showToast("未找到对话UUID!");
}
});
controlsArea.appendChild(downloadJsonButton);
container.appendChild(controlsArea);
document.body.appendChild(container);
}
// 初始化脚本
function initScript() {
injectCustomStyle();
// 延迟执行,确保DOM加载完毕
setTimeout(() => {
if (/\/chat\/[a-zA-Z0-9-]+/.test(window.location.href)) {
createUUIDControls();
}
}, 1000);
// 监听 URL 变化(防止 SPA 页面跳转失效)
let lastUrl = window.location.href;
const observer = new MutationObserver(() => {
if (window.location.href !== lastUrl) {
lastUrl = window.location.href;
setTimeout(() => {
if (/\/chat\/[a-zA-Z0-9-]+/.test(lastUrl)) {
createUUIDControls();
}
}, 1000);
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
// 等待DOM加载完成
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initScript);
} else {
initScript();
}
})();