// ==UserScript==
// @name ChatGPT AccessToken 自动更新
// @namespace http://tampermonkey.net/
// @version 3.0
// @description 根据token过期时间自动获取accessToken并发送POST请求后自动跳转到new.oaifree.com
// @author AMT
// @match *://new.oaifree.com/*
// @grant GM_xmlhttpRequest
// @grant GM_addStyle
// @grant GM_setValue
// @grant GM_getValue
// @connect chatgpt.com
// @connect new.oaifree.com
// @license MIT
// ==/UserScript==
(function() {
'use strict';
// 定义ChatGPT登录页面的URL
const chatgptLoginUrl = "https://chatgpt.com";
// 定义获取accessToken的URL
const tokenUrl = "https://chatgpt.com/api/auth/session";
// 定义POST请求的目标URL
const postUrl = "https://new.oaifree.com/auth/login_token";
// 定义跳转的目标URL
const redirectUrl = "https://new.oaifree.com";
// 定义GM存储的key
const expiresKey = 'tokenExpires'; // 保存token过期时间的key
// 获取当前时间的时间戳(毫秒)
let currentTime = new Date().getTime();
// 将延迟时间存储到GM存储中
let delay = GM_getValue('delay', 60000);
// 从GM存储获取token过期时间
let expires = GM_getValue(expiresKey, 0);
// 计算距离token过期的时间
function calculateTimeUntilExpiry() {
currentTime = new Date().getTime();
const timeUntilExpiry = expires - currentTime;
// 计算剩余时间的各个部分
const daysUntilExpiry = Math.floor(timeUntilExpiry / (24 * 60 * 60 * 1000));
const hoursUntilExpiry = Math.floor((timeUntilExpiry % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
const minutesUntilExpiry = Math.floor((timeUntilExpiry % (60 * 60 * 1000)) / (60 * 1000));
const secondsUntilExpiry = Math.floor((timeUntilExpiry % (60 * 1000)) / 1000);
// 返回各个部分的时间和秒数
return { daysUntilExpiry, hoursUntilExpiry, minutesUntilExpiry, secondsUntilExpiry };
}
// Base64URL 解码
function base64UrlDecode(str) {
return decodeURIComponent(atob(str.replace(/-/g, '+').replace(/_/g, '/')).split('').map(function(c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
}
// 解析 JWT
function parseJWT(token) {
const parts = token.split('.');
if (parts.length !== 3) {
console.error('Invalid JWT token');
return null;
}
const payload = JSON.parse(base64UrlDecode(parts[1])); // 仅解析payload部分
return payload;
}
//刷新时间
// 创建可视化窗口
const panel = document.createElement('div');
panel.id = 'script-panel';
const { daysUntilExpiry, hoursUntilExpiry, minutesUntilExpiry } = calculateTimeUntilExpiry();
panel.innerHTML = `
<div id="panel-content">
<p>距离AccessToken过期还有:<br>
<span id="time-until-expiry"></span></p>
<button id="run-script-button">立即获取AccessToken</button>
<br>
<button id="jump-to-chatgpt-button">跳转到ChatGPT</button>
</div>
`;
document.body.appendChild(panel);
updateDisplay()
// 添加样式
GM_addStyle(`
#script-panel {
position: fixed;
top: 10%;
right: 0;
width: 300px;
background-color: rgba(0, 0, 0, 0.7);
color: white;
padding: 15px;
border-radius: 10px 0 0 10px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
z-index: 10000;
transform: translateX(98%);
transition: transform 0.5s ease-in-out;
cursor: move;
}
#panel-content {
display: block;
text-align: center;
}
#script-panel:hover {
transform: translateX(0);
}
#run-script-button,#jump-to-chatgpt-button {
background-color: #4CAF50;
color: white;
border: none;
padding: 10px 15px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 10px 0;
cursor: pointer;
border-radius: 5px;
transition: background-color 0.3s, box-shadow 0.1s;
}
#run-script-button:hover,#jump-to-chatgpt-button:hover {
background-color: #45a049;
}
#run-script-button:active,#jump-to-chatgpt-button:active {
box-shadow: inset 0px 3px 5px rgba(0, 0, 0, 0.2);
background-color: #39843b;
}
`);
// 添加拖动功能
let isDragging = false;
let startY = 0;
let startTop = 0;
panel.addEventListener('mousedown', function(e) {
isDragging = true;
startY = e.clientY;
startTop = panel.offsetTop;
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
});
function onMouseMove(e) {
if (isDragging) {
const deltaY = e.clientY - startY;
panel.style.top = `${startTop + deltaY}px`;
}
}
function onMouseUp() {
isDragging = false;
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
}
function updateDisplay() {
const { daysUntilExpiry, hoursUntilExpiry, minutesUntilExpiry, secondsUntilExpiry } = calculateTimeUntilExpiry();
let displayText = "";
if (daysUntilExpiry > 0) {
displayText += `${daysUntilExpiry}天`;
}
if (hoursUntilExpiry > 0 ) {
displayText += `${hoursUntilExpiry}小时`;
}
if (minutesUntilExpiry > 0 ) {
displayText += `${minutesUntilExpiry}分钟`;
}
if (daysUntilExpiry === 0 && hoursUntilExpiry === 0 && minutesUntilExpiry === 0) {
displayText = `${secondsUntilExpiry}秒`;
if (delay !=1000) {
delay = 1000; // 设置为每秒刷新一次
GM_setValue('delay', delay);
}
}
document.getElementById('time-until-expiry').textContent = displayText;
}
// 添加时间自动更新功能
setInterval(() => {
updateDisplay();
if (shouldFetchToken()) {
fetchAndPostToken();
}
}, delay);
// 添加按钮点击事件
document.getElementById('run-script-button').addEventListener('click', function() {
fetchAndPostToken();
});
document.getElementById('jump-to-chatgpt-button').addEventListener('click', function() {
window.open(chatgptLoginUrl, '_blank'); // 在新标签页中打开 chatgpt.com
});
//showAlert();
// 检查是否需要获取token
if (shouldFetchToken()) {
fetchAndPostToken();
} else {
console.log("Script not run: Token is still valid.");
}
// 判断是否需要获取token
function shouldFetchToken() {
currentTime = new Date().getTime();
return currentTime > expires;
}
// 获取token并发送POST请求的函数
function fetchAndPostToken() {
GM_xmlhttpRequest({
method: "GET",
url: tokenUrl,
onload: function(response) {
if (response.status === 200) {
// 解析返回的JSON
const responseData = JSON.parse(response.responseText);
// 提取accessToken
const accessToken = responseData.accessToken;
// 解析JWT获取过期时间
const parsedToken = parseJWT(accessToken);
if (parsedToken && parsedToken.exp) {
const tokenExpires = parsedToken.exp * 1000; // 将exp转换为毫秒
// 更新过期时间
GM_setValue(expiresKey, tokenExpires);
currentTime = new Date().getTime();
GM_setValue('delay', 60000);
if (currentTime > tokenExpires){
showAlert();
}
else{
// 发送POST请求
sendPostRequest(accessToken, tokenExpires);
}
} else {
console.error("Failed to parse JWT token or exp not found.");
}
} else {
console.error("Failed to fetch accessToken. Status:", response.status);
}
}
});
}
// 弹出过期提示并在1秒后自动跳转
function showAlert() {
// 创建一个div作为自定义弹窗
let alertBox = document.createElement("div");
alertBox.innerHTML = `
<div style="
position: fixed;
top: 0;
left: 50%;
transform: translateX(-50%);
background-color: white;
color: black;
border: 2px solid #007BFF; /* 蓝色边框 */
padding: 20px;
z-index: 10000;
border-radius: 10px;
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
font-family: Arial, sans-serif;
font-size: 14px;
text-align: center;
animation: fadeIn 0.3s ease;
">
<p>Access Token已过期,系统将自动跳转以重新登录chatgpt.com</p>
</div>`;
// 添加淡入效果的动画
const style = document.createElement("style");
style.innerHTML = `
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
`;
document.head.appendChild(style);
// 将自定义弹窗添加到页面中
document.body.appendChild(alertBox);
// 1.2秒后自动跳转并移除自定义弹窗
setTimeout(function() {
document.body.removeChild(alertBox); // 移除弹窗
window.open(chatgptLoginUrl, '_blank'); // 在新标签页中打开 chatgpt.com
}, 1200); // 延迟1.2秒后跳转
}
// 发送POST请求的函数
function sendPostRequest(accessToken, tokenExpires) {
const data = {
action: "token",
access_token: accessToken
};
GM_xmlhttpRequest({
method: "POST",
url: postUrl,
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
data: Object.keys(data).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join('&'),
onload: function(response) {
console.log("Status Code:", response.status);
console.log("Response:", response.responseText);
// 成功发送POST请求后自动跳转
if (response.status === 200) {
window.location.href = redirectUrl;
}
},
onerror: function(error) {
console.error("Error in POST request:", error);
}
});
}
})();