ChatGPT AccessToken 自动更新

根据token过期时间自动获取accessToken并发送POST请求后自动跳转到new.oaifree.com

  1. // ==UserScript==
  2. // @name ChatGPT AccessToken 自动更新
  3. // @namespace http://tampermonkey.net/
  4. // @version 3.0
  5. // @description 根据token过期时间自动获取accessToken并发送POST请求后自动跳转到new.oaifree.com
  6. // @author AMT
  7. // @match *://new.oaifree.com/*
  8. // @grant GM_xmlhttpRequest
  9. // @grant GM_addStyle
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @connect chatgpt.com
  13. // @connect new.oaifree.com
  14. // @license MIT
  15. // ==/UserScript==
  16.  
  17.  
  18. (function() {
  19. 'use strict';
  20.  
  21. // 定义ChatGPT登录页面的URL
  22. const chatgptLoginUrl = "https://chatgpt.com";
  23. // 定义获取accessToken的URL
  24. const tokenUrl = "https://chatgpt.com/api/auth/session";
  25. // 定义POST请求的目标URL
  26. const postUrl = "https://new.oaifree.com/auth/login_token";
  27. // 定义跳转的目标URL
  28. const redirectUrl = "https://new.oaifree.com";
  29. // 定义GM存储的key
  30. const expiresKey = 'tokenExpires'; // 保存token过期时间的key
  31. // 获取当前时间的时间戳(毫秒)
  32. let currentTime = new Date().getTime();
  33. // 将延迟时间存储到GM存储中
  34. let delay = GM_getValue('delay', 60000);
  35. // 从GM存储获取token过期时间
  36. let expires = GM_getValue(expiresKey, 0);
  37.  
  38. // 计算距离token过期的时间
  39. function calculateTimeUntilExpiry() {
  40. currentTime = new Date().getTime();
  41. const timeUntilExpiry = expires - currentTime;
  42.  
  43. // 计算剩余时间的各个部分
  44. const daysUntilExpiry = Math.floor(timeUntilExpiry / (24 * 60 * 60 * 1000));
  45. const hoursUntilExpiry = Math.floor((timeUntilExpiry % (24 * 60 * 60 * 1000)) / (60 * 60 * 1000));
  46. const minutesUntilExpiry = Math.floor((timeUntilExpiry % (60 * 60 * 1000)) / (60 * 1000));
  47. const secondsUntilExpiry = Math.floor((timeUntilExpiry % (60 * 1000)) / 1000);
  48.  
  49. // 返回各个部分的时间和秒数
  50. return { daysUntilExpiry, hoursUntilExpiry, minutesUntilExpiry, secondsUntilExpiry };
  51. }
  52. // Base64URL 解码
  53. function base64UrlDecode(str) {
  54. return decodeURIComponent(atob(str.replace(/-/g, '+').replace(/_/g, '/')).split('').map(function(c) {
  55. return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
  56. }).join(''));
  57. }
  58.  
  59. // 解析 JWT
  60. function parseJWT(token) {
  61. const parts = token.split('.');
  62. if (parts.length !== 3) {
  63. console.error('Invalid JWT token');
  64. return null;
  65. }
  66.  
  67. const payload = JSON.parse(base64UrlDecode(parts[1])); // 仅解析payload部分
  68. return payload;
  69. }
  70. //刷新时间
  71. // 创建可视化窗口
  72. const panel = document.createElement('div');
  73. panel.id = 'script-panel';
  74. const { daysUntilExpiry, hoursUntilExpiry, minutesUntilExpiry } = calculateTimeUntilExpiry();
  75. panel.innerHTML = `
  76. <div id="panel-content">
  77. <p>距离AccessToken过期还有:<br>
  78. <span id="time-until-expiry"></span></p>
  79. <button id="run-script-button">立即获取AccessToken</button>
  80. <br>
  81. <button id="jump-to-chatgpt-button">跳转到ChatGPT</button>
  82. </div>
  83. `;
  84. document.body.appendChild(panel);
  85. updateDisplay()
  86. // 添加样式
  87. GM_addStyle(`
  88. #script-panel {
  89. position: fixed;
  90. top: 10%;
  91. right: 0;
  92. width: 300px;
  93. background-color: rgba(0, 0, 0, 0.7);
  94. color: white;
  95. padding: 15px;
  96. border-radius: 10px 0 0 10px;
  97. box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.5);
  98. z-index: 10000;
  99. transform: translateX(98%);
  100. transition: transform 0.5s ease-in-out;
  101. cursor: move;
  102. }
  103. #panel-content {
  104. display: block;
  105. text-align: center;
  106. }
  107. #script-panel:hover {
  108. transform: translateX(0);
  109. }
  110. #run-script-button,#jump-to-chatgpt-button {
  111. background-color: #4CAF50;
  112. color: white;
  113. border: none;
  114. padding: 10px 15px;
  115. text-align: center;
  116. text-decoration: none;
  117. display: inline-block;
  118. font-size: 14px;
  119. margin: 10px 0;
  120. cursor: pointer;
  121. border-radius: 5px;
  122. transition: background-color 0.3s, box-shadow 0.1s;
  123. }
  124. #run-script-button:hover,#jump-to-chatgpt-button:hover {
  125. background-color: #45a049;
  126. }
  127. #run-script-button:active,#jump-to-chatgpt-button:active {
  128. box-shadow: inset 0px 3px 5px rgba(0, 0, 0, 0.2);
  129. background-color: #39843b;
  130. }
  131. `);
  132.  
  133. // 添加拖动功能
  134. let isDragging = false;
  135. let startY = 0;
  136. let startTop = 0;
  137.  
  138. panel.addEventListener('mousedown', function(e) {
  139. isDragging = true;
  140. startY = e.clientY;
  141. startTop = panel.offsetTop;
  142. document.addEventListener('mousemove', onMouseMove);
  143. document.addEventListener('mouseup', onMouseUp);
  144. });
  145.  
  146. function onMouseMove(e) {
  147. if (isDragging) {
  148. const deltaY = e.clientY - startY;
  149. panel.style.top = `${startTop + deltaY}px`;
  150. }
  151. }
  152.  
  153. function onMouseUp() {
  154. isDragging = false;
  155. document.removeEventListener('mousemove', onMouseMove);
  156. document.removeEventListener('mouseup', onMouseUp);
  157. }
  158. function updateDisplay() {
  159. const { daysUntilExpiry, hoursUntilExpiry, minutesUntilExpiry, secondsUntilExpiry } = calculateTimeUntilExpiry();
  160.  
  161. let displayText = "";
  162. if (daysUntilExpiry > 0) {
  163. displayText += `${daysUntilExpiry}天`;
  164. }
  165. if (hoursUntilExpiry > 0 ) {
  166. displayText += `${hoursUntilExpiry}小时`;
  167. }
  168. if (minutesUntilExpiry > 0 ) {
  169. displayText += `${minutesUntilExpiry}分钟`;
  170. }
  171. if (daysUntilExpiry === 0 && hoursUntilExpiry === 0 && minutesUntilExpiry === 0) {
  172. displayText = `${secondsUntilExpiry}秒`;
  173. if (delay !=1000) {
  174. delay = 1000; // 设置为每秒刷新一次
  175. GM_setValue('delay', delay);
  176. }
  177. }
  178.  
  179. document.getElementById('time-until-expiry').textContent = displayText;
  180. }
  181. // 添加时间自动更新功能
  182. setInterval(() => {
  183. updateDisplay();
  184. if (shouldFetchToken()) {
  185. fetchAndPostToken();
  186. }
  187. }, delay);
  188.  
  189. // 添加按钮点击事件
  190. document.getElementById('run-script-button').addEventListener('click', function() {
  191. fetchAndPostToken();
  192. });
  193. document.getElementById('jump-to-chatgpt-button').addEventListener('click', function() {
  194. window.open(chatgptLoginUrl, '_blank'); // 在新标签页中打开 chatgpt.com
  195. });
  196. //showAlert();
  197. // 检查是否需要获取token
  198. if (shouldFetchToken()) {
  199. fetchAndPostToken();
  200. } else {
  201. console.log("Script not run: Token is still valid.");
  202. }
  203. // 判断是否需要获取token
  204. function shouldFetchToken() {
  205. currentTime = new Date().getTime();
  206. return currentTime > expires;
  207. }
  208.  
  209. // 获取token并发送POST请求的函数
  210. function fetchAndPostToken() {
  211. GM_xmlhttpRequest({
  212. method: "GET",
  213. url: tokenUrl,
  214. onload: function(response) {
  215. if (response.status === 200) {
  216. // 解析返回的JSON
  217. const responseData = JSON.parse(response.responseText);
  218. // 提取accessToken
  219. const accessToken = responseData.accessToken;
  220.  
  221. // 解析JWT获取过期时间
  222. const parsedToken = parseJWT(accessToken);
  223. if (parsedToken && parsedToken.exp) {
  224. const tokenExpires = parsedToken.exp * 1000; // 将exp转换为毫秒
  225. // 更新过期时间
  226. GM_setValue(expiresKey, tokenExpires);
  227. currentTime = new Date().getTime();
  228. GM_setValue('delay', 60000);
  229. if (currentTime > tokenExpires){
  230. showAlert();
  231. }
  232. else{
  233. // 发送POST请求
  234. sendPostRequest(accessToken, tokenExpires);
  235. }
  236. } else {
  237. console.error("Failed to parse JWT token or exp not found.");
  238. }
  239. } else {
  240. console.error("Failed to fetch accessToken. Status:", response.status);
  241. }
  242. }
  243. });
  244. }
  245.  
  246. // 弹出过期提示并在1秒后自动跳转
  247. function showAlert() {
  248. // 创建一个div作为自定义弹窗
  249. let alertBox = document.createElement("div");
  250. alertBox.innerHTML = `
  251. <div style="
  252. position: fixed;
  253. top: 0;
  254. left: 50%;
  255. transform: translateX(-50%);
  256. background-color: white;
  257. color: black;
  258. border: 2px solid #007BFF; /* 蓝色边框 */
  259. padding: 20px;
  260. z-index: 10000;
  261. border-radius: 10px;
  262. box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
  263. font-family: Arial, sans-serif;
  264. font-size: 14px;
  265. text-align: center;
  266. animation: fadeIn 0.3s ease;
  267. ">
  268. <p>Access Token已过期,系统将自动跳转以重新登录chatgpt.com</p>
  269. </div>`;
  270. // 添加淡入效果的动画
  271. const style = document.createElement("style");
  272. style.innerHTML = `
  273. @keyframes fadeIn {
  274. from { opacity: 0; }
  275. to { opacity: 1; }
  276. }
  277. `;
  278. document.head.appendChild(style);
  279. // 将自定义弹窗添加到页面中
  280. document.body.appendChild(alertBox);
  281.  
  282. // 1.2秒后自动跳转并移除自定义弹窗
  283. setTimeout(function() {
  284. document.body.removeChild(alertBox); // 移除弹窗
  285. window.open(chatgptLoginUrl, '_blank'); // 在新标签页中打开 chatgpt.com
  286. }, 1200); // 延迟1.2秒后跳转
  287. }
  288.  
  289.  
  290. // 发送POST请求的函数
  291. function sendPostRequest(accessToken, tokenExpires) {
  292. const data = {
  293. action: "token",
  294. access_token: accessToken
  295. };
  296.  
  297. GM_xmlhttpRequest({
  298. method: "POST",
  299. url: postUrl,
  300. headers: {
  301. "Content-Type": "application/x-www-form-urlencoded"
  302. },
  303. data: Object.keys(data).map(key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`).join('&'),
  304. onload: function(response) {
  305. console.log("Status Code:", response.status);
  306. console.log("Response:", response.responseText);
  307.  
  308. // 成功发送POST请求后自动跳转
  309. if (response.status === 200) {
  310. window.location.href = redirectUrl;
  311. }
  312. },
  313. onerror: function(error) {
  314. console.error("Error in POST request:", error);
  315. }
  316. });
  317. }
  318. })();