// ==UserScript== // @name rt自动转at // @namespace Violentmonkey Scripts // @match https://new.oaifree.com/auth/login_auth0* // @grant none // @version 2.0 // @description 2024/10/31 功能基本完善 // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/500442/rt%E8%87%AA%E5%8A%A8%E8%BD%ACat.user.js // @updateURL https://update.greasyfork.icu/scripts/500442/rt%E8%87%AA%E5%8A%A8%E8%BD%ACat.meta.js // ==/UserScript== // 初始化用户数据 var users = JSON.parse(localStorage.getItem('users')) || []; // 读取上次保存的窗口位置 var savedPosition = JSON.parse(localStorage.getItem('containerPosition')) || { top: 20, left: 20 }; // 创建样式 var style = document.createElement('style'); style.innerHTML = ` .rt-button { display: inline-block; cursor: pointer; background: linear-gradient(135deg, #6A5ACD, #483D8B); border: none; color: #fff; padding: 6px 6px; font-size: 13px; border-radius: 4px; transition: 0.3s; } .rt-button:hover { background: linear-gradient(135deg, #7B68EE, #4B0082); } .rt-container { position: fixed; top: ${savedPosition.top}px; left: ${savedPosition.left}px; border: 1px solid #ddd; border-radius: 10px; background: #f9f9f9; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); padding: 12px; z-index: 99999999; font-family: Arial, sans-serif; } .rt-title { font-size: 16px; font-weight: 600; color: #333; margin-bottom: 10px; cursor: move; } .rt-list { list-style: none; padding: 0; margin: 0; max-height: 180px; overflow-y: auto; } .rt-list-item { display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid #e8e8e8; font-size: 13px; } .rt-list-item:last-child { border-bottom: none; } .rt-input-container { display: flex; margin-bottom: 10px; align-items: center; } .rt-input { flex: 1; padding: 6px; border: 1px solid #ddd; border-radius: 4px; margin-right: 5px; font-size: 13px; background-color: #fff; color: #333; } .username-container { display: inline-block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; color: #333; } .rt-log { position: absolute; top: 5px; right: 5px; background: rgba(0, 0, 0, 0.75); color: #fff; padding: 4px 8px; border-radius: 5px; font-size: 12px; opacity: 0; transition: opacity 0.3s ease; display: none; } `; document.head.appendChild(style); // 创建容器 var container = document.createElement('div'); container.className = 'rt-container'; // 添加标题 var title = document.createElement('div'); title.className = 'rt-title'; title.innerHTML = '账户管理'; // 日志显示容器 var logDiv = document.createElement('div'); logDiv.className = 'rt-log'; container.appendChild(logDiv); // 让容器可拖动 let isDragging = false; let offsetX, offsetY; title.addEventListener('mousedown', (event) => { isDragging = true; offsetX = event.clientX - container.offsetLeft; offsetY = event.clientY - container.offsetTop; document.addEventListener('mousemove', onDrag); document.addEventListener('mouseup', onStopDrag); }); function onDrag(event) { if (isDragging) { container.style.left = `${event.clientX - offsetX}px`; container.style.top = `${event.clientY - offsetY}px`; } } function onStopDrag() { isDragging = false; // 保存位置 localStorage.setItem( 'containerPosition', JSON.stringify({ top: parseInt(container.style.top), left: parseInt(container.style.left) }) ); document.removeEventListener('mousemove', onDrag); document.removeEventListener('mouseup', onStopDrag); } // 显示日志函数 function showLog(message, isError = false) { logDiv.innerText = message; logDiv.style.backgroundColor = isError ? 'rgba(255, 0, 0, 0.8)' : 'rgba(0, 0, 0, 0.75)'; logDiv.style.display = 'block'; logDiv.style.opacity = '1'; // 3秒后隐藏日志 setTimeout(() => { logDiv.style.opacity = '0'; setTimeout(() => { logDiv.style.display = 'none'; }, 300); // 与过渡效果同步 }, 3000); } // 添加输入框和按钮容器 var inputContainer = document.createElement('div'); inputContainer.className = 'rt-input-container'; var refreshTokenInput = document.createElement('input'); refreshTokenInput.className = 'rt-input'; refreshTokenInput.placeholder = 'refresh_token'; var addButton = document.createElement('button'); addButton.className = 'rt-button'; addButton.innerHTML = '添加RT'; addButton.onclick = async function () { var refreshToken = refreshTokenInput.value.trim(); if (refreshToken) { showLog('添加中...'); try { const accessToken = await fetchAccessToken(refreshToken); const email = extractEmail(accessToken); if (email) { users.push({ username: email, refresh_token: refreshToken, access_token: accessToken }); localStorage.setItem('users', JSON.stringify(users)); renderUserList(); showLog('添加成功'); } } catch (error) { showLog('添加失败', true); console.error('添加用户时出错:', error); } refreshTokenInput.value = ''; } }; // 将输入框和按钮添加到容器 inputContainer.appendChild(refreshTokenInput); inputContainer.appendChild(addButton); // 创建用户列表 var ul = document.createElement('ul'); ul.className = 'rt-list'; // 获取最大用户名长度 function getMaxUsernameWidth() { const testDiv = document.createElement('div'); testDiv.className = 'username-container'; testDiv.style.position = 'absolute'; testDiv.style.visibility = 'hidden'; document.body.appendChild(testDiv); let maxWidth = 100; users.forEach(user => { testDiv.innerText = user.username; maxWidth = Math.max(maxWidth, testDiv.scrollWidth); }); document.body.removeChild(testDiv); return maxWidth; } function adjustFontSize(container, text) { let fontSize = 13; container.style.fontSize = fontSize + 'px'; container.innerText = text; while (container.scrollWidth > container.clientWidth && fontSize > 10) { fontSize--; container.style.fontSize = fontSize + 'px'; } } function renderUserList() { ul.innerHTML = ''; const maxUsernameWidth = getMaxUsernameWidth(); const containerWidth = maxUsernameWidth + 200; // 留出按钮的空间 container.style.width = containerWidth + 'px'; users.forEach(function (user, index) { var li = document.createElement('li'); li.className = 'rt-list-item'; var usernameContainer = document.createElement('div'); usernameContainer.className = 'username-container'; usernameContainer.style.width = maxUsernameWidth + 'px'; adjustFontSize(usernameContainer, user.username); var selectButton = document.createElement('button'); selectButton.className = 'rt-button'; selectButton.innerHTML = '选择'; selectButton.onclick = function () { showLog('选择用户中...'); getToken(user.access_token); showLog('选择成功'); }; var refreshButton = document.createElement('button'); refreshButton.className = 'rt-button'; refreshButton.innerHTML = '刷新'; refreshButton.onclick = async function () { showLog('刷新中...'); try { const newAccessToken = await fetchAccessToken(user.refresh_token); user.access_token = newAccessToken; localStorage.setItem('users', JSON.stringify(users)); showLog('刷新成功'); console.log('Access token 已刷新:', newAccessToken); } catch (error) { showLog('刷新失败', true); console.error('刷新 access token 失败:', error); } }; var deleteButton = document.createElement('button'); deleteButton.className = 'rt-button'; deleteButton.innerHTML = '删除'; deleteButton.onclick = function () { users.splice(index, 1); localStorage.setItem('users', JSON.stringify(users)); renderUserList(); showLog('删除成功'); }; li.appendChild(usernameContainer); li.appendChild(selectButton); li.appendChild(refreshButton); li.appendChild(deleteButton); ul.appendChild(li); }); } // 将内容添加到主容器 container.appendChild(title); container.appendChild(inputContainer); container.appendChild(ul); document.body.appendChild(container); // 渲染用户列表 renderUserList(); // 通过refresh_token获取access_token async function fetchAccessToken(refreshToken) { const response = await fetch('https://token.oaifree.com/api/auth/refresh', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' }, body: `refresh_token=${encodeURIComponent(refreshToken)}` }); if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`); const result = await response.json(); return result.access_token; } // 从access_token中提取email function extractEmail(accessToken) { try { const payload = JSON.parse(atob(accessToken.split('.')[1])); return payload["https://api.openai.com/profile"].email || '未知用户'; } catch (error) { console.error('解码access_token时出错:', error); return '未知用户'; } } // 获取token的函数 async function getToken(accessToken) { try { const url = 'https://new.oaifree.com/auth/login_token'; const data = `action=token&access_token=${encodeURIComponent(accessToken)}`; console.log('请求数据:', data); const loginResponse = await fetch(url, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: data }); if (!loginResponse.ok) throw new Error(`HTTP error! status: ${loginResponse.status}`); const loginResult = await loginResponse.json(); console.log('响应数据:', loginResult); window.location.href = 'https://new.oaifree.com/'; } catch (error) { showLog('获取 token 失败', true); console.error('获取token失败:', error); } }