Greasy Fork

来自缓存

Greasy Fork is available in English.

rt自动转at

2024/10/31 功能基本完善

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

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