感谢[[email protected] ~]#
佬引用的帖子集百家之长的claude session管理工具
这个项目我试了下功能上确实是应有尽有并且UI非常美观,我之前没刷到过,大家有需求的都去看看那个项目吧
,我第一次发帖希望大家海涵,帖子好像没法删得联系管理员,所以暂时先保留着了
。
USER: 脚本升级啦!
在 xiaohan17 大佬的
[更新了链接] 切换Claude Sessionkey的油猴脚本(适用fuclaude), 优化版
基础上,我进一步迭代了脚本功能,带来了以下超实用更新!
新增功能
管理界面升级
- 支持在管理界面直接查看并复制“token key”,操作更方便!
存储方式优化
- 将 token 从浏览器存储转为存储到油猴中,
- 已储存的 key 可以随脚本一起导出,备份无忧!
使用方法
- 直接将代码粘贴到油猴脚本编辑器中,即可开用!简单粗暴!
// ==UserScript==// ==UserScript==
// @name ClaudeToken切换(十七优化版,存储到油猴,可查看Token)
// @namespace https://www.violet17.com
// @version 1.7.6
// @description 动态切换claude的token(数据改为GM存储,管理界面可查看完整Token, 修复IP显示问题和改善token展示)
// @author
// @match https://claude.ai/*
// @match https://demo.fuclaude.com/*
// @match https://claude.asia/*
// @grant GM_xmlhttpRequest
// @grant GM.setValue
// @grant GM.getValue
// @connect ipapi.co
// @license GNU GPLv3
// ==/UserScript==
(async function() {
'use strict';
// 配置
const config = {
storageKey: 'claudeTokens',
ipApiUrl: 'https://ipapi.co/json/', // 使用JSON接口获取更多信息
defaultToken: {
name: 'xiaohan17',
key: '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'
}
};
// 样式
const getStyles = (isDarkMode) => `
.claude-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: ${isDarkMode ? 'rgba(0, 0, 0, 0.7)' : 'rgba(0, 0, 0, 0.5)'};
display: flex;
justify-content: center;
align-items: center;
z-index: 10000;
}
.claude-modal-content {
background-color: ${isDarkMode ? '#2c2b28' : '#fff'};
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 10px ${isDarkMode ? 'rgba(0, 0, 0, 0.3)' : 'rgba(0, 0, 0, 0.1)'};
width: 300px;
max-width: 90%;
}
.claude-modal h2 {
margin-top: 0;
margin-bottom: 15px;
color: ${isDarkMode ? '#f5f4ef' : '#333'};
font-size: 18px;
}
.claude-modal input {
width: 100%;
padding: 8px;
margin-bottom: 10px;
border: 1px solid ${isDarkMode ? '#3f3f3c' : '#ddd'};
border-radius: 4px;
font-size: 14px;
background-color: ${isDarkMode ? '#2f2f2c' : '#fff'};
color: ${isDarkMode ? '#f5f4ef' : '#333'};
}
.claude-modal button {
padding: 8px 12px;
margin-right: 10px;
border: none;
border-radius: 4px;
background-color: ${isDarkMode ? '#3f3f3c' : '#4CAF50'};
color: ${isDarkMode ? '#f5f4ef' : 'white'};
cursor: pointer;
transition: background-color 0.3s;
}
.claude-modal button:hover {
background-color: ${isDarkMode ? '#4a4a47' : '#45a049'};
}
.claude-modal button.cancel {
background-color: ${isDarkMode ? '#3a3935' : '#f44336'};
}
.claude-modal button.cancel:hover {
background-color: ${isDarkMode ? '#454540' : '#da190b'};
}
.claude-token-list {
max-height: 300px;
overflow-y: auto;
margin-bottom: 15px;
}
.claude-token-item {
margin-bottom: 10px;
padding: 10px;
border: 1px solid ${isDarkMode ? '#3f3f3c' : '#eee'};
border-radius: 4px;
background-color: ${isDarkMode ? '#3a3935' : '#fafafa'};
}
.claude-token-item-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 5px;
}
.claude-token-name {
font-weight: bold;
font-size: 14px;
color: ${isDarkMode ? '#f5f4ef' : '#333'};
}
.claude-token-key {
font-family: monospace;
font-size: 12px;
color: ${isDarkMode ? '#ddd' : '#555'};
word-break: break-all;
}
.copy-button {
margin-left: 5px;
font-size: 12px;
padding: 2px 6px;
border: none;
border-radius: 3px;
background-color: ${isDarkMode ? '#2f2f2c' : '#e0e0e0'};
color: ${isDarkMode ? '#f5f4ef' : '#333'};
cursor: pointer;
}
`;
// UI 组件
const UI = {
createElem(tag, styles) {
const elem = document.createElement(tag);
Object.assign(elem.style, styles);
return elem;
},
createButton(text, styles) {
const button = this.createElem('button', styles);
button.innerText = text;
return button;
},
createTokenSelect(isDarkMode) {
return this.createElem('select', {
marginRight: '4px',
fontSize: '12px',
width: '150px',
backgroundColor: isDarkMode ? '#2f2f2c' : '#f5f1e9',
color: isDarkMode ? '#f5f4ef' : '#333',
height: '24px',
padding: '0 4px',
lineHeight: '24px',
border: `1px solid ${isDarkMode ? '#3f3f3c' : '#ccc'}`,
borderRadius: '3px',
appearance: 'none',
WebkitAppearance: 'none',
MozAppearance: 'none',
backgroundImage: 'url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%20width%3D%22292.4%22%20height%3D%22292.4%22%3E%3Cpath%20fill%3D%22%23007CB2%22%20d%3D%22M287%2069.4a17.6%2017.6%200%200%200-13-5.4H18.4c-5%200-9.3%201.8-12.9%205.4A17.6%2017.6%200%200%200%200%2082.2c0%205%201.8%209.3%205.4%2012.9l128%20127.9c3.6%203.6%207.8%205.4%2012.8%205.4s9.2-1.8%2012.8-5.4L287%2095c3.5-3.5%205.4-7.8%205.4-12.8%200-5-1.9-9.2-5.5-12.8z%22/%3E%3C/svg%3E")',
backgroundRepeat: 'no-repeat',
backgroundPosition: 'right .5em top 50%',
backgroundSize: '.65em auto',
});
},
createModal(title, content) {
const modal = document.createElement('div');
modal.className = 'claude-modal';
const modalContent = document.createElement('div');
modalContent.className = 'claude-modal-content';
const titleElem = document.createElement('h2');
titleElem.textContent = title;
modalContent.appendChild(titleElem);
modalContent.appendChild(content);
modal.appendChild(modalContent);
document.body.appendChild(modal);
return {
modal,
close: () => document.body.removeChild(modal)
};
}
};
// 主要功能
const App = {
async init() {
this.isDarkMode = document.documentElement.getAttribute('data-mode') === 'dark';
this.injectStyles();
// 从GM存储中获取Tokens(如果没有则使用默认token)
const saved = await GM.getValue(config.storageKey, '[]');
const parsed = JSON.parse(saved);
this.tokens = parsed.length > 0 ? parsed : [config.defaultToken];
this.createUI();
this.setupEventListeners();
this.updateTokenSelect();
this.fetchIPCountryCode();
this.observeThemeChanges();
},
injectStyles() {
this.styleElem = document.createElement('style');
this.styleElem.textContent = getStyles(this.isDarkMode);
document.head.appendChild(this.styleElem);
},
updateStyles() {
this.styleElem.textContent = getStyles(this.isDarkMode);
this.updateUIColors();
},
updateUIColors() {
Object.assign(this.container.style, {
backgroundColor: this.isDarkMode ? '#2c2b28' : '#fcfaf5',
boxShadow: `0 1px 3px ${this.isDarkMode ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.2)'}`,
});
Object.assign(this.tokenSelect.style, {
backgroundColor: this.isDarkMode ? '#2f2f2c' : '#f5f1e9',
color: this.isDarkMode ? '#f5f4ef' : '#333',
border: `1px solid ${this.isDarkMode ? '#3f3f3c' : '#ccc'}`,
});
[this.switchButton, this.addButton, this.manageButton].forEach(button => {
Object.assign(button.style, {
backgroundColor: this.isDarkMode ? '#2f2f2c' : '#f5f1e9',
color: this.isDarkMode ? '#f5f4ef' : '#333',
border: `1px solid ${this.isDarkMode ? '#3f3f3c' : '#ccc'}`,
});
});
this.toggleButton.style.color = this.isDarkMode ? '#f5f4ef' : '#29261b';
},
async saveTokens() {
// 存入Tampermonkey存储
await GM.setValue(config.storageKey, JSON.stringify(this.tokens));
},
createUI() {
this.tokenSelect = UI.createTokenSelect(this.isDarkMode);
this.toggleButton = UI.createButton('...', {
position: 'fixed',
top: '10px',
right: '145px',
zIndex: '9998',
width: '36px',
height: '36px',
backgroundColor: 'transparent',
border: 'none',
borderRadius: '0.375rem',
fontSize: '12px',
cursor: 'pointer',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
transition: 'background-color 0.3s ease, color 0.3s ease',
color: this.isDarkMode ? '#f5f4ef' : '#29261b',
});
this.switchButton = UI.createButton('切换', {
fontSize: '12px',
height: '24px',
padding: '0 8px',
lineHeight: '22px',
border: `1px solid ${this.isDarkMode ? '#3f3f3c' : '#ccc'}`,
borderRadius: '3px',
backgroundColor: this.isDarkMode ? '#2f2f2c' : '#f5f1e9',
color: this.isDarkMode ? '#f5f4ef' : '#333',
cursor: 'pointer',
});
this.addButton = UI.createButton('添加', {
fontSize: '12px',
height: '24px',
padding: '0 8px',
lineHeight: '22px',
border: `1px solid ${this.isDarkMode ? '#3f3f3c' : '#ccc'}`,
borderRadius: '3px',
backgroundColor: this.isDarkMode ? '#2f2f2c' : '#f5f1e9',
color: this.isDarkMode ? '#f5f4ef' : '#333',
cursor: 'pointer',
});
this.manageButton = UI.createButton('管理', {
fontSize: '12px',
height: '24px',
padding: '0 8px',
lineHeight: '22px',
border: `1px solid ${this.isDarkMode ? '#3f3f3c' : '#ccc'}`,
borderRadius: '3px',
backgroundColor: this.isDarkMode ? '#2f2f2c' : '#f5f1e9',
color: this.isDarkMode ? '#f5f4ef' : '#333',
cursor: 'pointer',
});
this.container = UI.createElem('div', {
position: 'fixed',
top: '50px',
right: '77px',
zIndex: '9999',
backgroundColor: this.isDarkMode ? '#2c2b28' : '#fcfaf5',
padding: '8px',
borderRadius: '3px',
boxShadow: `0 1px 3px ${this.isDarkMode ? 'rgba(0,0,0,0.3)' : 'rgba(0,0,0,0.2)'}`,
display: 'none',
fontSize: '12px',
width: 'auto',
});
const buttonContainer = UI.createElem('div', {
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
gap: '4px',
});
buttonContainer.appendChild(this.tokenSelect);
buttonContainer.appendChild(this.switchButton);
buttonContainer.appendChild(this.addButton);
buttonContainer.appendChild(this.manageButton);
this.container.appendChild(buttonContainer);
document.body.appendChild(this.container);
document.body.appendChild(this.toggleButton);
},
setupEventListeners() {
this.toggleButton.addEventListener('click', () => this.toggleContainer());
this.toggleButton.addEventListener('mouseover', () => {
this.toggleButton.style.backgroundColor = this.isDarkMode ? '#1a1915' : '#ded8c4';
this.toggleButton.style.color = this.isDarkMode ? '#f5f4ef' : '#29261b';
});
this.toggleButton.addEventListener('mouseout', () => {
this.toggleButton.style.backgroundColor = 'transparent';
this.toggleButton.style.color = this.isDarkMode ? '#f5f4ef' : '#29261b';
});
this.switchButton.addEventListener('click', () => this.switchToken());
this.addButton.addEventListener('click', () => this.showAddTokenModal());
this.manageButton.addEventListener('click', () => this.showManageTokensModal());
},
observeThemeChanges() {
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' && mutation.attributeName === 'data-mode') {
this.isDarkMode = document.documentElement.getAttribute('data-mode') === 'dark';
this.updateStyles();
}
});
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-mode']
});
},
toggleContainer() {
this.container.style.display = this.container.style.display === 'none' ? 'block' : 'none';
},
updateTokenSelect() {
this.tokenSelect.innerHTML = '';
this.tokens.forEach((token, index) => {
const option = document.createElement('option');
option.value = index;
option.text = token.name;
this.tokenSelect.appendChild(option);
});
},
// 修正处:切换时将所选 token 移动到数组首位,这样显示的名称即为当前激活的 token
switchToken() {
const index = parseInt(this.tokenSelect.value, 10);
const selectedToken = this.tokens[index];
if (index !== 0) {
this.tokens.splice(index, 1);
this.tokens.unshift(selectedToken);
this.saveTokens();
this.updateTokenSelect();
}
this.applyToken(selectedToken.key);
},
applyToken(token) {
const currentURL = window.location.href;
if (currentURL.startsWith('https://claude.ai/')) {
// 修改cookie后刷新
document.cookie = `sessionKey=${token}; path=/; domain=.claude.ai`;
window.location.reload();
} else {
let loginUrl;
if (currentURL.startsWith('https://demo.fuclaude.com/')) {
loginUrl = `https://demo.fuclaude.com/login_token?session_key=${token}`;
} else if (currentURL.startsWith('https://claude.asia/')) {
loginUrl = `https://claude.asia/login_token?session_key=${token}`;
}
if (loginUrl) {
window.location.href = loginUrl;
}
}
},
showAddTokenModal() {
const content = document.createElement('div');
const nameInput = document.createElement('input');
nameInput.placeholder = 'Token名称';
const keyInput = document.createElement('input');
keyInput.placeholder = 'Token密钥';
const addButton = document.createElement('button');
addButton.textContent = '添加';
const cancelButton = document.createElement('button');
cancelButton.textContent = '取消';
cancelButton.className = 'cancel';
content.appendChild(nameInput);
content.appendChild(keyInput);
content.appendChild(addButton);
content.appendChild(cancelButton);
const { close } = UI.createModal('添加新Token', content);
addButton.addEventListener('click', async () => {
if (nameInput.value && keyInput.value) {
this.tokens.push({ name: nameInput.value, key: keyInput.value });
await this.saveTokens();
this.updateTokenSelect();
close();
}
});
cancelButton.addEventListener('click', close);
},
showManageTokensModal() {
const content = document.createElement('div');
const tokenList = document.createElement('div');
tokenList.className = 'claude-token-list';
this.tokens.forEach((token, index) => {
const tokenItem = document.createElement('div');
tokenItem.className = 'claude-token-item';
const headerDiv = document.createElement('div');
headerDiv.className = 'claude-token-item-header';
const nameDiv = document.createElement('div');
nameDiv.className = 'claude-token-name';
nameDiv.textContent = token.name;
const deleteButton = document.createElement('button');
deleteButton.textContent = '删除';
deleteButton.className = 'cancel';
deleteButton.addEventListener('click', async () => {
this.tokens.splice(index, 1);
await this.saveTokens();
this.updateTokenSelect();
tokenItem.remove();
});
headerDiv.appendChild(nameDiv);
headerDiv.appendChild(deleteButton);
const keyDiv = document.createElement('div');
keyDiv.className = 'claude-token-key';
keyDiv.textContent = token.key;
const copyButton = document.createElement('button');
copyButton.textContent = '复制';
copyButton.className = 'copy-button';
copyButton.addEventListener('click', () => {
navigator.clipboard.writeText(token.key);
copyButton.textContent = '已复制';
setTimeout(() => {
copyButton.textContent = '复制';
}, 2000);
});
const keyContainer = document.createElement('div');
keyContainer.style.display = 'flex';
keyContainer.style.alignItems = 'center';
keyContainer.appendChild(keyDiv);
keyContainer.appendChild(copyButton);
tokenItem.appendChild(headerDiv);
tokenItem.appendChild(keyContainer);
tokenList.appendChild(tokenItem);
});
content.appendChild(tokenList);
const closeButton = document.createElement('button');
closeButton.textContent = '关闭';
content.appendChild(closeButton);
const { close } = UI.createModal('管理Tokens', content);
closeButton.addEventListener('click', close);
},
fetchIPCountryCode() {
GM_xmlhttpRequest({
method: "GET",
url: config.ipApiUrl,
onload: (response) => {
if (response.status === 200) {
try {
const data = JSON.parse(response.responseText);
this.toggleButton.innerText = data.country_code || 'NA';
} catch (e) {
this.toggleButton.innerText = 'ERR';
}
} else {
this.toggleButton.innerText = 'ERR';
}
},
onerror: () => {
this.toggleButton.innerText = 'ERR';
}
});
}
};
// 初始化应用
await App.init();
})();
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 2025-03-13
// @description try to take over the world!
// @author You
// @match http://*/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
})();
// ==UserScript==
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 2025-03-13
// @description try to take over the world!
// @author You
// @match https://duckduckgo.com/?q=DuckDuckGo+AI+Chat&ia=chat&duckai=1
// @icon https://www.google.com/s2/favicons?sz=64&domain=duckduckgo.com
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
})();
// @name New Userscript
// @namespace http://tampermonkey.net/
// @version 2025-03-16
// @description try to take over the world!
// @author You
// @match http://*/*
// @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant none
// ==/UserScript==
(function() {
'use strict';
// Your code here...
})();
管理界面效果图(有点丑 ):
致谢
感谢以下大佬们的努力,为 Claude 多账户管理带来了便利: