Greasy Fork is available in English.

🚀🚀GPT4直连账号切换🚀🚀

为GPT4直连账号切换提供便利

// ==UserScript==
// @name         🚀🚀GPT4直连账号切换🚀🚀
// @namespace    gpt4-account-switch
// @version      0.0.6
// @description  为GPT4直连账号切换提供便利
// @author       LLinkedList771
// @run-at       document-end
// @match        https://gpt4.xn--fiqq6k90ovivepbxtg0bz10m.xyz/*
// @match        https://chat.freegpts.org/*
// @homepageURL  https://github.com/linkedlist771/GPT4-Account-Switch
// @supportURL   https://github.com/linkedlist771/GPT4-Account-Switch/issues

// @license      MIT
// ==/UserScript==

(function () {
  "use strict";
  let accountData = null;
  console.log("GPT4-Account-Switch 脚本正在运行");

  function setAccountData(data) {
    accountData = data;
  }

  function clearPreviousAccountData() {
    // 清除内存中的账号数据
    accountData = null;

    localStorage.removeItem("gpt4_account_json");

    const switchDiv = document.querySelector(".tools-logger-panel .switch");
    if (switchDiv) {
      while (switchDiv.firstChild) {
        switchDiv.removeChild(switchDiv.firstChild);
      }
    }
  }
  function isValidEmail(email) {
    // 使用正则表达式验证电子邮件地址
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }

  // ----------------- Styles -----------------
  function addStyles() {
    const styles = `
            .tools-logger-panel {
                position: fixed;
               top: 10%;
            right: 2%;
                background-color: white;
                padding: 10px;
                border: 1px solid #ccc;
                border-radius: 5px;
                box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
                z-index: 9999;
                width: 250px;
                
            }
            .tools-logger-panel.minimized {
                width: auto;
                padding: 5px;
            }
 

            .switch.minimized {
                display: none;
            }

            .head {
                font-weight: bold;
                margin-bottom: 10px;
            }
            .switch
                display: inline-block;
                vertical-align: middle;
            }
            .close {
                cursor: pointer;
            }
            .loadAccountJsonBtn {
                border: 1px solid #ccc;
                border-radius: 5px;
                text-decoration: underline;

            }
           .account-container {
                display: flex;
                flex-direction: column; 
                align-items: center; 
                margin-bottom: 10px; 
            }

            .account-btn {
                padding: 5px 10px;
                margin: 2px 0; 
                background-color: #f0f0f0;
                font-weight: bold;
            }
           
            .email-display {
                font-size: 0.8em; 
                color: #666; 
                margin-top: 2px; 
            }


            .latex-toggle {
                cursor: pointer;
                float:right;
                margin-right:5px;
            }
            .latex-toggle.minimized::before {
                content: "[+]";
            }
            .latex-toggle.maximized::before {
                content: "[-]";
            }

        `;
    const styleSheet = document.createElement("style");
    styleSheet.type = "text/css";
    styleSheet.innerText = styles;
    document.head.appendChild(styleSheet);
  }

  // ----------------- UI Creation -----------------
  function createUI() {
    const controlDiv = document.createElement("div");
    controlDiv.className = "tools-logger-panel";

    controlDiv.innerHTML = `
            <div class="head">
                <span class="title">GPT4账号切换助手</span>
                <span class="latex-toggle maximized"></span>
                </div>
            <div class="main">
                <button id="loadAccountJsonBtn">导入账号信息</button>
            </div>
            <div class="switch">

            </div>
        `;

    document.body.appendChild(controlDiv);

    // controlDiv.querySelector(".close").onclick = function() {
    //     controlDiv.remove();
    // };

    const toggleIcon = controlDiv.querySelector(".latex-toggle");
    const title = controlDiv.querySelector(".title");
    const switchDiv = controlDiv.querySelector(".switch");
    toggleIcon.onclick = function () {
      if (toggleIcon.classList.contains("maximized")) {
        controlDiv.querySelector(".main").style.display = "none";
        title.style.display = "none";
        toggleIcon.classList.remove("maximized");
        toggleIcon.classList.add("minimized");
        controlDiv.classList.add("minimized");
        switchDiv.classList.add("minimized");
      } else {
        controlDiv.querySelector(".main").style.display = "block";
        title.style.display = "inline-block";
        toggleIcon.classList.remove("minimized");
        toggleIcon.classList.add("maximized");
        controlDiv.classList.remove("minimized");
        switchDiv.classList.remove("minimized");
      }
      saveSettings(controlDiv); // Save settings when panel state is changed
    };

    // 添加文件输入元素
    const fileInput = document.createElement("input");
    fileInput.type = "file";
    fileInput.accept = ".json";
    fileInput.style.display = "none";
    controlDiv.appendChild(fileInput);

    // 为导入账号信息按钮添加点击事件监听器
    document
      .getElementById("loadAccountJsonBtn")
      .addEventListener("click", function () {
        fileInput.click();
      });

    // 监听文件选择事件
    fileInput.addEventListener("change", function (event) {
      const file = event.target.files[0];

      // 创建FileReader对象
      const reader = new FileReader();

      // 监听文件读取完成事件
      reader.onload = function (event) {
        try {
          const jsonData = JSON.parse(event.target.result);
          // 在这里处理获取到的JSON数据
          console.log(jsonData);
          processAccountJsonData(jsonData);
          // 可以在这里执行其他操作,如在页面上显示数据等
        } catch (error) {
          console.error("Error parsing JSON:", error);
        }
      };
      // 读取文件内容为文本
      reader.readAsText(file);
    });
    loadSettings(controlDiv); // Load settings when panel is created
  }

  // 获取当前的url的(去掉路由)
  function getCurrentUrl() {
    const targetURLBase =
      window.location.protocol + "//" + window.location.host;
    return targetURLBase;
  }

  function redirectToBaseUrl() {
    // https://gpt4.xn--fiqq6k90ovivepbxtg0bz10m.xyz/auth/login
    console.log("Log in");
    const targetURLBase = getCurrentUrl();
    window.location.href = targetURLBase;
  }

  function logOutCurrentAccount(accessToken) {
    const targetURLBase = getCurrentUrl();
    const logoutURL = targetURLBase + "/auth/logout";

    window.location.href = logoutURL;
  }

  function logInNewAccount(userName, passWork) {
    // var loginBtn = document.querySelector('#submit');
    // if(loginBtn) {
    //     loginBtn.click();
    // }
    // 第一个输入id="username" 填入userName
    var userNameArea = document.getElementById("username");
    if (userNameArea) {
      userNameArea.value = userName; // 将 '你的用户名' 替换为你想要输入的内容
    }

    // 第二个输入id="password" 填入passWork
    var passWordArea = document.getElementById("password");
    if (passWordArea) {
      passWordArea.value = passWork; // 将 '你的密码' 替换为你想要输入的内容
    }

    // 找到登录按钮
    var loginBtn = document.querySelector('button[type="submit"]');
    if (loginBtn) {
      loginBtn.click();
    }
    // // 找到button里面的值(innerHtml)为OK的按钮
    // var okBtn = Array.from(document.querySelectorAll('button')).find(function(btn) {
    //     return btn.innerText.trim() === 'OK';
    // });

    // if(okBtn) {
    //     okBtn.click();
    // }
  }

  function processAccountJsonData(jsonData) {
    // 检查所有键是否都是有效的电子邮件
    const allKeysAreValid = Object.keys(jsonData).every(isValidEmail);

    if (allKeysAreValid) {
      clearPreviousAccountData(); // 调用清理函数
      localStorage.setItem("gpt4_account_json", JSON.stringify(jsonData));
      setAccountData(jsonData);
      creatSwitchBtnUI(); // 确保此时已经有有效的accountData来创建按钮
    } else {
      alert("Some entries are invalid. Please check the data.");
    }
  }
  function alertLoadAccountData() {
    alert("请先导入账号信息");
  }

  function retriveAccountData() {
    // 1.首先判断当前的accountData是否为空
    if (accountData !== null) {
      return true;
    }
    // 2.从localStorage中读取数据
    const jsonData = localStorage.getItem("gpt4_account_json");
    if (jsonData !== null) {
      accountData = JSON.parse(jsonData);
      return true;
    }

    // 如果当前的accountData为空, 但是localStoraage也为空, 则提示当前需要加载账号信息
    alertLoadAccountData();
    return false;
  }

  // ----------------- Save and Load Settings -----------------
  function saveSettings(controlDiv) {
    const panelState = controlDiv.classList.contains("minimized")
      ? "minimized"
      : "maximized";
    localStorage.setItem("gpt4PanelState", panelState);
  }

  function loadSettings(controlDiv) {
    const panelState = localStorage.getItem("gpt4PanelState");

    const toggleIcon = controlDiv.querySelector(".latex-toggle");
    const title = controlDiv.querySelector(".title");
    const switchDiv = controlDiv.querySelector(".switch");

    if (panelState === "minimized") {
      controlDiv.querySelector(".main").style.display = "none";
      title.style.display = "none";
      toggleIcon.classList.remove("maximized");
      toggleIcon.classList.add("minimized");
      controlDiv.classList.add("minimized");
      switchDiv.classList.add("minimized");
    } else {
      controlDiv.querySelector(".main").style.display = "block";
      title.style.display = "inline-block";
      toggleIcon.classList.remove("minimized");
      toggleIcon.classList.add("maximized");
      controlDiv.classList.remove("minimized");
      switchDiv.classList.remove("minimized");
    }
  }

  function creatSwitchBtnUI() {
    const controlDiv = document.querySelector(".tools-logger-panel .switch");
    if (!controlDiv) return;
    let button = document.createElement("button");
    button.className = "account-btn";

    button.textContent = `登出账号`;
    button.onclick = () => {
      // Logic to switch accounts
      // setAccountData(accountData[key]);
      logOutCurrentAccount();
      console.log("Switched to account:", accountData[key]);
    };
    controlDiv.appendChild(button);
    //                 redirectToBaseUrl();

    button = document.createElement("button");
    button.className = "account-btn";

    button.textContent = `登录账号`;
    button.onclick = () => {
      // Logic to switch accounts
      // setAccountData(accountData[key]);
      redirectToBaseUrl();
      console.log("Switched to account:", accountData[key]);
    };
    controlDiv.appendChild(button);
    Object.keys(accountData).forEach((email, index) => {
      // 创建包含按钮和电子邮件地址的容器
      const container = document.createElement("div");
      container.className = "account-container";

      // 创建登录按钮
      const button = document.createElement("button");
      button.className = "account-btn";
      button.textContent = `登录账号${index + 1}`;
      button.onclick = () => {
        logInNewAccount(email, accountData[email]);
        console.log("Switched to account:", email);
      };

      // 创建显示电子邮件地址的元素
      const emailDisplay = document.createElement("span");
      emailDisplay.className = "email-display";
      emailDisplay.textContent = email;

      // 将按钮和电子邮件地址添加到容器
      container.appendChild(button);
      container.appendChild(emailDisplay);

      // 将容器添加到主DIV
      controlDiv.appendChild(container);
    });
  }

  function loadAndCreateAccountSwitchBtnUI() {
    // 首先判断localStorage中是否有数据
    if (!retriveAccountData()) {
      return;
    }
    creatSwitchBtnUI(); // Create switch buttons based on account data

    // 现在开始加载UI
  }

  function init() {
    // try to find 'account-btn';
    // if found, then return;
    console.log("try to init");
    const accountBtn = document.querySelector(".account-btn");
    if (accountBtn) {
      console.log("account-btn found");
      return;
    }
    console.log("account-btn not found");
    addStyles();
    createUI();
    loadAndCreateAccountSwitchBtnUI(); // Ensure the switch buttons are created after UI is loaded and data is retrieved
  }

  // set time interval to check if the element is loaded
  setInterval(function () {
    if (document.querySelector(".tools-logger-panel")) {
    } else {
      init();
    }
  }, 1000);
})();