rt自动转at

2024/10/31 功能基本完善

// ==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
// ==/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);
    }
}