Grok-4 Rate Limits 状态栏 油猴脚本(使用Grok4魔改)(2025-7-30更新)

基于佬的脚本,使用Grok-4和claude 4修改的。

如果没效果可以尝试到主页刷新看下

// ==UserScript==
// @name         Grok速率限制监视器
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  现代、带动画的速率限制监视器,支持暗/亮模式 - 更新以适应新 Grok 接口,显示token和努力等级
// @author       Grok-4 (修改)
// @match        https://grok.com/*
// @grant        none
// ==/UserScript==

(function () {
  "use strict";

  // 配置
  const UPDATE_INTERVAL = 60000 * 5; // 每 5 分钟更新一次
  const DISPLAY_MODES = [
    {
      name: "TOTAL_TOKENS",
      displayName: "总token",
      iconColor: "#4CAF50",
      darkColor: "#88E388",
      lightColor: "#2D882D",
    },
    {
      name: "LOW_EFFORT",
      displayName: "低努力 (1点)",
      iconColor: "#2196F3",
      darkColor: "#90CAF9",
      lightColor: "#0D47A1",
    },
    {
      name: "HIGH_EFFORT",
      displayName: "高努力 (4点)",
      iconColor: "#FF9800",
      darkColor: "#FFCC80",
      lightColor: "#E65100",
    },
    {
      name: "WINDOW_TIME",
      displayName: "重置时间",
      iconColor: "#9C27B0",
      darkColor: "#CE93D8",
      lightColor: "#6A1B9A",
    },
  ];

  let updateTimer = null; // 存储更新定时器
  let lastFetchTime = 0; // 跟踪最后获取时间
  let currentData = null; // 存储当前数据
  let limitsPopup = null; // 存储弹出窗口元素
  let isDarkMode = true; // 默认暗模式,将被检测
  let isPinned = false; // 跟踪弹出窗口是否固定
  let buttonElement = null; // 存储按钮元素引用
  let hideTimeout = null; // 用于延迟隐藏的定时器

  // 辅助函数:检测颜色模式
  function detectColorMode() {
    // 检查 body 或 html 是否有暗背景
    const bodyBg = window.getComputedStyle(document.body).backgroundColor;
    const htmlBg = window.getComputedStyle(
      document.documentElement
    ).backgroundColor;

    // 将 RGB 转换为亮度
    function getBrightness(color) {
      // 提取 RGB 值
      const rgb = color.match(/\d+/g);
      if (!rgb) return 255; // 如果无法确定,默认亮模式

      // 计算亮度(简单近似)
      return (
        (parseInt(rgb[0]) * 299 +
          parseInt(rgb[1]) * 587 +
          parseInt(rgb[2]) * 114) /
        1000
      );
    }

    const bodyBrightness = getBrightness(bodyBg);
    const htmlBrightness = getBrightness(htmlBg);

    // 如果 body 或 html 有暗背景,则视为暗模式
    const brightness = Math.min(bodyBrightness, htmlBrightness);
    return brightness < 128; // 低于 128 视为暗模式
  }

  // 设置外部点击监听器
  function setupOutsideClickListener() {
    document.addEventListener("click", (event) => {
      if (!isPinned) return;

      // 检查点击是否在弹出窗口外部
      if (limitsPopup && !limitsPopup.contains(event.target)) {
        // 检查是否点击了按钮
        if (buttonElement && !buttonElement.contains(event.target)) {
          isPinned = false;
          hideLimitsPopup();
        }
      }
    });
  }

  // 查找侧边栏的合适容器
  function findSidebarContainer() {
    // 尝试多个选择器以找到侧边栏菜单容器
    const selectors = [
      // 查找侧边栏内容区域
      '[data-sidebar="content"]',
      // 查找侧边栏菜单组
      '[data-sidebar="group"]',
      // 查找具有侧边栏菜单的 ul 元素
      '[data-sidebar="menu"]',
      // 回退选项
      '.flex.min-h-0.flex-col.overflow-auto'
    ];

    for (const selector of selectors) {
      const container = document.querySelector(selector);
      if (container) {
        console.log(`找到侧边栏容器,选择器:${selector}`);
        return container;
      }
    }

    return null;
  }

  // 创建侧边栏菜单项
  function createSidebarButton() {
    let attempts = 0;
    const maxAttempts = 20;

    const interval = setInterval(() => {
      attempts++;

      if (attempts >= maxAttempts) {
        clearInterval(interval);
        console.error('无法找到速率限制按钮的合适侧边栏容器');
        return;
      }

      const sidebarContent = findSidebarContainer();

      if (sidebarContent) {
        clearInterval(interval);

        // 更新暗模式检测
        isDarkMode = detectColorMode();

        // 创建菜单组容器
        const menuGroup = document.createElement("div");
        menuGroup.setAttribute("data-sidebar", "group");
        menuGroup.className = "relative flex w-full min-w-0 flex-col px-1.5 py-[2px] shrink-0 transition-[width,transform,opacity] duration-200";

        // 创建菜单列表
        const menuList = document.createElement("ul");
        menuList.setAttribute("data-sidebar", "menu");
        menuList.className = "flex w-full min-w-0 flex-col cursor-default";

        // 创建菜单项
        const menuItem = document.createElement("li");
        menuItem.setAttribute("data-sidebar", "menu-item");
        menuItem.className = "group/menu-item whitespace-nowrap font-semibold mx-1 relative";

        // 创建按钮元素 (模仿其他菜单项的结构)
        buttonElement = document.createElement("div");
        buttonElement.id = "rate-limits-button";
        buttonElement.setAttribute("role", "button");
        buttonElement.setAttribute("tabindex", "0");
        buttonElement.setAttribute("aria-label", "速率限制");
        buttonElement.className = "peer/menu-button flex items-center gap-2 overflow-hidden rounded-xl text-left outline-none ring-sidebar-ring transition-[width,height,padding] focus-visible:ring-1 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 [&>span:last-child]:truncate [&>svg]:shrink-0 text-sm h-[36px] border-transparent data-[state=open]:hover:bg-button-ghost-hover data-[active=true]:bg-button-ghost-active aria-expanded:bg-button-ghost-hover hover:bg-transparent active:bg-transparent cursor-default hover:text-fg-secondary w-full flex flex-row justify-start gap-1 bg-background text-secondary text-sm rounded-xl p-[0.375rem] border-transparent cursor-pointer hover:text-primary hover:!bg-button-ghost-hover";
        buttonElement.setAttribute("data-sidebar", "menu-button");
        buttonElement.setAttribute("data-active", "false");
        buttonElement.setAttribute("data-state", "closed");

        // 创建图标容器
        const iconContainer = document.createElement("div");
        iconContainer.setAttribute("data-sidebar", "icon");
        iconContainer.className = "size-6 flex items-center justify-center shrink-0";

        // 创建 SVG 图标
        iconContainer.innerHTML = `
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" class="stroke-[2]">
            <path d="M12 6V12L16 14" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
            <path d="M5.63604 5.63603C7.5 3.77207 10.125 2.5 13 2.5C18.6944 2.5 23.25 7.05558 23.25 12.75C23.25 18.4444 18.6944 23 13 23C7.30558 23 2.75 18.4444 2.75 12.75C2.75 11 3.125 9.36907 3.75 8" stroke="currentColor" stroke-linecap="round"/>
          </svg>
        `;

        // 创建文本标签和token状态指示器
        const textContainer = document.createElement("div");
        textContainer.className = "flex items-center gap-2 flex-1";

        const textLabel = document.createElement("span");
        textLabel.style.opacity = "1";
        textLabel.textContent = "速率限制";

        const tokenBadge = document.createElement("span");
        tokenBadge.id = "token-badge";
        tokenBadge.className = "px-1.5 py-0.5 text-xs rounded-full font-medium";
        tokenBadge.style.cssText = `
          background-color: ${isDarkMode ? "rgba(76, 175, 80, 0.2)" : "rgba(76, 175, 80, 0.1)"};
          color: ${isDarkMode ? "#88E388" : "#2D882D"};
          min-width: 28px;
          text-align: center;
        `;
        tokenBadge.textContent = "—";

        textContainer.appendChild(textLabel);
        textContainer.appendChild(tokenBadge);

        // 组装按钮
        buttonElement.appendChild(iconContainer);
        buttonElement.appendChild(textContainer);

        // 组装菜单结构
        menuItem.appendChild(buttonElement);
        menuList.appendChild(menuItem);
        menuGroup.appendChild(menuList);

        // 将菜单组添加到侧边栏内容的合适位置
        // 查找最后一个菜单组,在其后插入
        const existingGroups = sidebarContent.querySelectorAll('[data-sidebar="group"]');
        if (existingGroups.length > 0) {
          const lastGroup = existingGroups[existingGroups.length - 1];
          lastGroup.insertAdjacentElement('afterend', menuGroup);
        } else {
          sidebarContent.appendChild(menuGroup);
        }

        // 添加点击事件处理程序
        buttonElement.addEventListener("click", (e) => {
          e.stopPropagation();

          if (
            !limitsPopup ||
            getComputedStyle(limitsPopup).display === "none"
          ) {
            showLimitsPopup(e);
            isPinned = true;
          } else if (isPinned) {
            isPinned = false;
            hideLimitsPopup();
          } else {
            isPinned = true;
          }
        });

        // 添加悬停事件
        buttonElement.addEventListener("mouseenter", (e) => {
          if (!isPinned) {
            clearTimeout(hideTimeout);
            showLimitsPopup(e);
          }
        });
        buttonElement.addEventListener("mouseleave", (e) => {
          if (!isPinned) {
            hideTimeout = setTimeout(() => {
              hideLimitsPopup();
            }, 200); // 延迟 200ms 隐藏,以允许鼠标移动到弹出窗口
          }
        });

        // 设置主题变化观察器
        const observer = new MutationObserver((mutations) => {
          const newDarkMode = detectColorMode();
          if (newDarkMode !== isDarkMode) {
            isDarkMode = newDarkMode;
            if (limitsPopup) {
              updatePopupTheme();
            }
            updateTokenBadge();
          }
        });

        observer.observe(document.body, {
          attributes: true,
          childList: false,
          subtree: false,
        });

        // 设置外部点击监听器
        setupOutsideClickListener();

        console.log('速率限制按钮已成功添加到侧边栏');

        // 初始获取数据
        fetchRateLimit();

        return buttonElement;
      }
    }, 500);
  }

  // 更新token徽章
  function updateTokenBadge() {
    const tokenBadge = document.getElementById("token-badge");
    if (!tokenBadge || !currentData) return;

    const remaining = currentData.remainingTokens || 0;
    const total = currentData.totalTokens || 140;

    tokenBadge.textContent = remaining.toString();

    // 根据剩余比例更新颜色
    const percentage = total > 0 ? remaining / total : 0;

    let bgColor, textColor;
    if (percentage <= 0.2) {
      // 低 - 红色
      bgColor = isDarkMode ? "rgba(255, 50, 50, 0.2)" : "rgba(255, 50, 50, 0.1)";
      textColor = isDarkMode ? "#FF8A80" : "#C62828";
    } else if (percentage <= 0.5) {
      // 中等 - 橙色
      bgColor = isDarkMode ? "rgba(255, 150, 0, 0.2)" : "rgba(255, 150, 0, 0.1)";
      textColor = isDarkMode ? "#FFCC80" : "#E65100";
    } else {
      // 良好 - 绿色
      bgColor = isDarkMode ? "rgba(76, 175, 80, 0.2)" : "rgba(76, 175, 80, 0.1)";
      textColor = isDarkMode ? "#88E388" : "#2D882D";
    }

    tokenBadge.style.backgroundColor = bgColor;
    tokenBadge.style.color = textColor;
  }

  // 根据暗/亮模式更新弹出窗口主题
  function updatePopupTheme() {
    if (!limitsPopup) return;

    if (isDarkMode) {
      limitsPopup.style.backgroundColor = "rgba(28, 30, 33, 0.95)";
      limitsPopup.style.color = "#e0e0e0";
      limitsPopup.style.border = "1px solid rgba(255, 255, 255, 0.1)";
      limitsPopup.style.boxShadow = "0 3px 20px rgba(0, 0, 0, 0.5)";
    } else {
      limitsPopup.style.backgroundColor = "rgba(250, 250, 250, 0.95)";
      limitsPopup.style.color = "#333333";
      limitsPopup.style.border = "1px solid rgba(0, 0, 0, 0.1)";
      limitsPopup.style.boxShadow = "0 3px 20px rgba(0, 0, 0, 0.15)";
    }

    // 更新显示项
    DISPLAY_MODES.forEach((mode) => {
      const indicator = document.getElementById(
        `${mode.name.toLowerCase()}-indicator`
      );
      const label = document.getElementById(`${mode.name.toLowerCase()}-label`);
      const value = document.getElementById(`${mode.name.toLowerCase()}-value`);

      if (indicator && label && value) {
        indicator.style.backgroundColor = mode.iconColor;
        label.style.color = isDarkMode ? "#ffffff" : "#333333";
        value.style.color = isDarkMode ? mode.darkColor : mode.lightColor;
      }
    });

    // 更新分隔线
    const divider = document.querySelector("#limit-monitor .divider");
    if (divider) {
      divider.style.borderBottomColor = isDarkMode
        ? "rgba(255, 255, 255, 0.15)"
        : "rgba(0, 0, 0, 0.1)";
    }

    // 更新刷新按钮
    const refreshBtn = document.querySelector("#limit-monitor .refresh-btn");
    if (refreshBtn) {
      refreshBtn.style.color = isDarkMode ? "#ffffff" : "#333333";
      refreshBtn.style.backgroundColor = isDarkMode
        ? "rgba(255, 255, 255, 0.1)"
        : "rgba(0, 0, 0, 0.05)";
    }
  }

  // 创建并显示限制弹出窗口,带动画
  function showLimitsPopup(event) {
    if (limitsPopup) {
      // 根据按钮动态更新位置
      const buttonRect = buttonElement.getBoundingClientRect();
      limitsPopup.style.left = `${buttonRect.right + 8}px`; // 按钮右侧 8px
      limitsPopup.style.top = `${buttonRect.top}px`;
      limitsPopup.style.right = 'auto';

      limitsPopup.style.opacity = "1";
      limitsPopup.style.transform = "translateX(0) scale(1)";
      limitsPopup.style.display = "block";
      return;
    }

    // 更新暗模式检测
    isDarkMode = detectColorMode();

    limitsPopup = document.createElement("div");
    limitsPopup.id = "limit-monitor";
    limitsPopup.style.cssText = `
      position: fixed;
      background-color: ${
        isDarkMode
          ? "rgba(28, 30, 33, 0.95)"
          : "rgba(250, 250, 250, 0.95)"
      };
      border-radius: 12px;
      padding: 16px;
      color: ${isDarkMode ? "#e0e0e0" : "#333333"};
      font-family: 'Segoe UI', -apple-system, BlinkMacSystemFont, Arial, sans-serif;
      font-size: 14px;
      z-index: 10000;
      box-shadow: ${
        isDarkMode
          ? "0 3px 20px rgba(0, 0, 0, 0.5)"
          : "0 3px 20px rgba(0, 0, 0, 0.15)"
      };
      min-width: 280px;
      user-select: none;
      border: 1px solid ${
        isDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.1)"
      };
      transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.16, 1, 0.3, 1);
      transform: translateX(-10px) scale(0.98);
      opacity: 0;
      backdrop-filter: blur(8px);
    `;

    // 根据按钮设置初始位置 (侧边栏按钮的右侧)
    const buttonRect = buttonElement.getBoundingClientRect();
    limitsPopup.style.left = `${buttonRect.right + 8}px`;
    limitsPopup.style.top = `${buttonRect.top}px`;
    limitsPopup.style.right = 'auto';

    // 创建带有标题和刷新按钮的头部
    const header = document.createElement("div");
    header.style.cssText = `
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin-bottom: 12px;
    `;

    const title = document.createElement("div");
    title.style.cssText = `
      font-weight: 600;
      font-size: 15px;
      letter-spacing: 0.3px;
      display: flex;
      align-items: center;
      gap: 8px;
    `;

    // 为标题添加图标
    title.innerHTML = `
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M12 6V12L16 14" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M5.63604 5.63603C7.5 3.77207 10.125 2.5 13 2.5C18.6944 2.5 23.25 7.05558 23.25 12.75C23.25 18.4444 18.6944 23 13 23C7.30558 23 2.75 18.4444 2.75 12.75C2.75 11 3.125 9.36907 3.75 8" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
      </svg>
      Token使用情况
    `;

    header.appendChild(title);

    // 添加刷新按钮
    const refreshBtn = document.createElement("button");
    refreshBtn.className = "refresh-btn";
    refreshBtn.title = "刷新限制";
    refreshBtn.style.cssText = `
      background: ${
        isDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)"
      };
      border: none;
      border-radius: 6px;
      color: ${isDarkMode ? "#ffffff" : "#333333"};
      cursor: pointer;
      font-size: 16px;
      width: 28px;
      height: 28px;
      display: flex;
      align-items: center;
      justify-content: center;
      transition: all 0.2s ease;
      padding: 0;
    `;
    refreshBtn.innerHTML = `
      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
        <path d="M4 12C4 7.58172 7.58172 4 12 4C15.0796 4 17.7429 5.73685 19 8.27323L19 4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
        <path d="M20 12C20 16.4183 16.4183 20 12 20C8.92038 20 6.25708 18.2632 5 15.7268L5 20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
      </svg>
    `;

    refreshBtn.onmouseover = () => {
      refreshBtn.style.background = isDarkMode
        ? "rgba(255, 255, 255, 0.2)"
        : "rgba(0, 0, 0, 0.1)";
      refreshBtn.style.transform = "rotate(30deg)";
    };
    refreshBtn.onmouseout = () => {
      refreshBtn.style.background = isDarkMode
        ? "rgba(255, 255, 255, 0.1)"
        : "rgba(0, 0, 0, 0.05)";
      refreshBtn.style.transform = "rotate(0deg)";
    };
    refreshBtn.onclick = (e) => {
      e.stopPropagation();
      // 点击时添加旋转动画
      refreshBtn.style.transition =
        "transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)";
      refreshBtn.style.transform = "rotate(360deg)";

      // 动画结束后重置
      setTimeout(() => {
        refreshBtn.style.transition = "all 0.2s ease";
        refreshBtn.style.transform = "rotate(0deg)";
      }, 500);

      fetchRateLimit();
    };
    header.appendChild(refreshBtn);
    limitsPopup.appendChild(header);

    // 添加分隔线
    const divider = document.createElement("div");
    divider.className = "divider";
    divider.style.cssText = `
      border-bottom: 1px solid ${
        isDarkMode ? "rgba(255, 255, 255, 0.15)" : "rgba(0, 0, 0, 0.1)"
      };
      margin-bottom: 12px;
    `;
    limitsPopup.appendChild(divider);

    // 创建显示项的容器
    const itemsContainer = document.createElement("div");
    itemsContainer.style.cssText = `
      display: flex;
      flex-direction: column;
      gap: 12px;
    `;

    // 为每个显示项创建元素,带现代样式
    DISPLAY_MODES.forEach((mode) => {
      const itemDiv = document.createElement("div");
      itemDiv.style.cssText = `
        display: flex;
        align-items: center;
        gap: 12px;
      `;

      // 添加颜色指示器
      const indicator = document.createElement("div");
      indicator.id = `${mode.name.toLowerCase()}-indicator`;
      indicator.style.cssText = `
        width: 8px;
        height: 8px;
        border-radius: 50%;
        background-color: ${mode.iconColor};
        flex-shrink: 0;
      `;
      itemDiv.appendChild(indicator);

      // 添加标签
      const itemLabel = document.createElement("span");
      itemLabel.id = `${mode.name.toLowerCase()}-label`;
      itemLabel.textContent = mode.displayName;
      itemLabel.style.cssText = `
        font-weight: 500;
        color: ${isDarkMode ? "#ffffff" : "#333333"};
        flex-grow: 1;
      `;
      itemDiv.appendChild(itemLabel);

      // 添加值,带药丸样式
      const itemValue = document.createElement("div");
      itemValue.style.cssText = `
        padding: 4px 10px;
        border-radius: 12px;
        background-color: ${
          isDarkMode
            ? "rgba(255, 255, 255, 0.1)"
            : "rgba(0, 0, 0, 0.05)"
        };
        font-weight: 600;
        font-size: 13px;
        min-width: 70px;
        text-align: center;
        transition: all 0.3s ease;
      `;

      const valueText = document.createElement("span");
      valueText.id = `${mode.name.toLowerCase()}-value`;
      valueText.textContent = "—";
      valueText.style.cssText = `
        color: ${isDarkMode ? mode.darkColor : mode.lightColor};
        transition: color 0.3s ease;
      `;

      itemValue.appendChild(valueText);
      itemDiv.appendChild(itemValue);
      itemsContainer.appendChild(itemDiv);
    });

    limitsPopup.appendChild(itemsContainer);
    document.body.appendChild(limitsPopup);

    // 添加鼠标事件
    limitsPopup.addEventListener("mouseenter", () => {
      if (!isPinned) {
        clearTimeout(hideTimeout);
        clearTimeout(limitsPopup.hideTimeout);
      }
    });

    limitsPopup.addEventListener("mouseleave", (e) => {
      if (!isPinned) {
        hideTimeout = setTimeout(() => {
          hideLimitsPopup();
        }, 200); // 延迟 200ms 隐藏
      }
    });

    // 附加后触发动画
    setTimeout(() => {
      limitsPopup.style.opacity = "1";
      limitsPopup.style.transform = "translateX(0) scale(1)";
    }, 10);

    // 获取初始数据
    fetchRateLimit();
  }

  // 隐藏限制弹出窗口,带动画
  function hideLimitsPopup() {
    if (limitsPopup) {
      limitsPopup.style.opacity = "0";
      limitsPopup.style.transform = "translateX(-10px) scale(0.98)";

      limitsPopup.hideTimeout = setTimeout(() => {
        limitsPopup.style.display = "none";
      }, 250);
    }
  }

  // 将秒格式化为可读时间字符串
  function formatTime(seconds) {
    if (seconds < 60) {
      return `${seconds}s`;
    } else if (seconds < 3600) {
      return `${Math.floor(seconds / 60)}m`;
    } else {
      const hours = Math.floor(seconds / 3600);
      const minutes = Math.floor((seconds % 3600) / 60);
      return minutes > 0 ? `${hours}h ${minutes}m` : `${hours}h`;
    }
  }

  // 获取速率限制数据
  async function fetchRateLimit() {
    try {
      // 为显示项添加加载效果
      DISPLAY_MODES.forEach((mode) => {
        const element = document.getElementById(`${mode.name.toLowerCase()}-value`);
        if (element) {
          element.textContent = "···";
          // 脉冲动画
          const parent = element.parentElement;
          if (parent) {
            parent.style.animation = "pulse 1.5s infinite";
            parent.style.animationTimingFunction = "ease-in-out";
          }
        }
      });

      const response = await fetch("https://grok.com/rest/rate-limits", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify({
          requestKind: "DEFAULT",
          modelName: "grok-3", // 默认使用grok-3,但新接口应该返回统一数据
        }),
      });

      if (!response.ok) {
        throw new Error(`HTTP 错误!状态: ${response.status}`);
      }

      const data = await response.json();
      lastFetchTime = Date.now();
      currentData = data;

      updateAllDisplays(data);
      updateTokenBadge();

      return data;
    } catch (error) {
      console.error(`获取速率限制出错:`, error);

      // 显示错误状态
      DISPLAY_MODES.forEach((mode) => {
        const element = document.getElementById(`${mode.name.toLowerCase()}-value`);
        if (element) {
          element.textContent = "错误";
          const parent = element.parentElement;
          if (parent) {
            parent.style.animation = "none";
            parent.style.backgroundColor = isDarkMode
              ? "rgba(255, 50, 50, 0.2)"
              : "rgba(255, 50, 50, 0.1)";
            setTimeout(() => {
              parent.style.backgroundColor = isDarkMode
                ? "rgba(255, 255, 255, 0.1)"
                : "rgba(0, 0, 0, 0.05)";
            }, 1000);
          }
        }
      });
    }
  }

  // 更新所有显示项
  function updateAllDisplays(data) {
    if (!data) return;

    // 更新总token
    const totalElement = document.getElementById("total_tokens-value");
    if (totalElement) {
      const remaining = data.remainingTokens || 0;
      const total = data.totalTokens || 140;
      totalElement.textContent = `${remaining}/${total}`;

      // 根据剩余比例设置背景色
      const percentage = total > 0 ? remaining / total : 0;
      const parent = totalElement.parentElement;
      if (parent) {
        parent.style.animation = "none";
        if (percentage <= 0.2) {
          parent.style.backgroundColor = isDarkMode ? "rgba(255, 50, 50, 0.2)" : "rgba(255, 50, 50, 0.1)";
        } else if (percentage <= 0.5) {
          parent.style.backgroundColor = isDarkMode ? "rgba(255, 150, 0, 0.2)" : "rgba(255, 150, 0, 0.1)";
        } else {
          parent.style.backgroundColor = isDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)";
        }
      }
    }

    // 更新低努力
    const lowEffortElement = document.getElementById("low_effort-value");
    if (lowEffortElement && data.lowEffortRateLimits) {
      const remaining = data.lowEffortRateLimits.remainingQueries || 0;
      lowEffortElement.textContent = `${remaining}次`;

      const parent = lowEffortElement.parentElement;
      if (parent) {
        parent.style.animation = "none";
        parent.style.backgroundColor = isDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)";
      }
    }

    // 更新高努力
    const highEffortElement = document.getElementById("high_effort-value");
    if (highEffortElement && data.highEffortRateLimits) {
      const remaining = data.highEffortRateLimits.remainingQueries || 0;
      highEffortElement.textContent = `${remaining}次`;

      const parent = highEffortElement.parentElement;
      if (parent) {
        parent.style.animation = "none";
        parent.style.backgroundColor = isDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)";
      }
    }

    // 更新窗口时间
    const windowElement = document.getElementById("window_time-value");
    if (windowElement) {
      const windowSize = data.windowSizeSeconds || 7200; // 默认2小时
      windowElement.textContent = formatTime(windowSize);

      const parent = windowElement.parentElement;
      if (parent) {
        parent.style.animation = "none";
        parent.style.backgroundColor = isDarkMode ? "rgba(255, 255, 255, 0.1)" : "rgba(0, 0, 0, 0.05)";
      }
    }

    // 添加视觉反馈
    DISPLAY_MODES.forEach((mode) => {
      const element = document.getElementById(`${mode.name.toLowerCase()}-value`);
      if (element) {
        const pulseColor = isDarkMode ? "#FFFFFF" : "#000000";
        element.style.color = pulseColor;
        setTimeout(() => {
          element.style.color = isDarkMode ? mode.darkColor : mode.lightColor;
        }, 300);
      }
    });
  }

  // 调度定期更新
  function scheduleUpdates() {
    // 清除任何现有定时器
    if (updateTimer) {
      clearInterval(updateTimer);
    }

    // 设置新定时器
    updateTimer = setInterval(() => {
      // 如果固定或弹出窗口可见,则获取数据
      if (
        isPinned ||
        (limitsPopup && getComputedStyle(limitsPopup).display !== "none")
      ) {
        fetchRateLimit();
      }
    }, UPDATE_INTERVAL);
  }

  // 拦截 fetch 以监视网站中的速率限制请求
  function interceptFetch() {
    const originalFetch = window.fetch;

    window.fetch = async function (input, init) {
      const response = await originalFetch(input, init);

      // 克隆响应以避免消耗它
      const responseClone = response.clone();

      try {
        // 检查这是否是速率限制请求
        if (input && input.toString().includes("rate-limits")) {
          responseClone
            .json()
            .then((data) => {
              console.log("速率限制响应:", data);

              currentData = data;
              lastFetchTime = Date.now();

              // 如果弹出窗口存在,则更新显示
              if (limitsPopup) {
                updateAllDisplays(data);
              }

              // 更新token徽章
              updateTokenBadge();

              // 重置定时器
              if (updateTimer) {
                clearInterval(updateTimer);
                updateTimer = setInterval(() => {
                  if (
                    isPinned ||
                    (limitsPopup &&
                      getComputedStyle(limitsPopup).display !== "none")
                  ) {
                    fetchRateLimit();
                  }
                }, UPDATE_INTERVAL);
              }
            })
            .catch((e) => {
              console.error("解析响应出错:", e);
            });
        }
      } catch (e) {
        console.error("fetch 拦截器出错:", e);
      }

      return response;
    };
  }

  // 将 CSS 动画添加到文档
  function addStyles() {
    const styleElement = document.createElement("style");
    styleElement.textContent = `
      @keyframes pulse {
        0% { opacity: 0.7; }
        50% { opacity: 1; }
        100% { opacity: 0.7; }
      }
    `;
    document.head.appendChild(styleElement);
  }

  // 初始化
  function init() {
    // 添加所需样式
    addStyles();

    // 创建侧边栏按钮
    createSidebarButton();

    // 调度更新
    scheduleUpdates();

    // 拦截 fetch 请求
    interceptFetch();
  }

  // 当页面完全加载时启动脚本
  if (document.readyState === 'loading') {
    window.addEventListener('DOMContentLoaded', init);
  } else {
    init();
  }
})();
20 个赞

忘记贴代码了 :bili_057:

感谢大佬!

感谢大佬

是我的问题吗 为什么我开启后没变化呀 :sob:

找找这个按钮,或者看看是不是没开启脚本: :bili_110:

bro,代码最后多了三个反引号```


脚本贴到油猴里会跑不起来,前面佬友说没效果也是这个原因,再调一下格式吧

1 个赞

哦噢 还真是 谢谢佬友了 :face_blowing_a_kiss:

1 个赞

现在好了 原来是最后多了三个` :face_with_peeking_eye:

这额度是一天的还是每几小时的?

我的哈哈哈,第一次贴代码,没经验 :bili_057:
已经改正了

2小时20次好像

我也来一个,改的大佬的脚本,发了个issue等大佬加一下

// ==UserScript==
// @name         Grok Helper
// @namespace    https://github.com/BlueSkyXN/GPT-Models-Plus
// @version      0.1.1
// @author       BlueSkyXN
// @description  Monitor Grok API rate limits (标3, 思考, 搜索, 深搜, 标4), show summary + detail on hover
// @match        https://grok.com/*
// @grant        GM_addStyle
// @supportURL   https://github.com/BlueSkyXN/GPT-Models-Plus
// @homepageURL  https://github.com/BlueSkyXN/GPT-Models-Plus
// @downloadURL https://github.com/BlueSkyXN/GPT-Models-Plus/blob/main/GrokHelper.js
// @updateURL https://github.com/BlueSkyXN/GPT-Models-Plus/blob/main/GrokHelper.js
// ==/UserScript==

(function() {
    'use strict';

    // 四种模式 -> 简短显示标签对应表
    const MODE_LABELS = {
        DEFAULT: '标3',
        REASONING: '思考',
        DEEPSEARCH: '搜索',
        DEEPERSEARCH: '深搜'
    };

    // 我们需要查询的四种模式(Grok-3)
    const REQUEST_KINDS = Object.keys(MODE_LABELS);

    // 添加自定义样式
    GM_addStyle(`
        .grok-monitor {
            position: fixed;
            left: 16px;
            top: 72px; /* 位于 logo 下方 */
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            font-size: 14px;
            z-index: 100;
            display: flex;
            flex-direction: column;
            align-items: flex-start;
            padding: 8px 12px;
            gap: 8px;
            border: 1px solid #ccc;          /* 灰色圆角线始终显示 */
            border-radius: 8px;
            background-color: #fff;          /* 背景白色,可按需改 */
            color: #1a1a1a;
            box-shadow: 0 2px 4px rgba(0,0,0,0.08); /* 轻微投影,可选 */
            transition: all 0.2s ease;
            opacity: 0.9;
        }

        /* 悬浮时增加不透明度 */
        .grok-monitor:hover {
            opacity: 1;
        }

        /* 小版本:只显示总结行 */
        .grok-monitor-summary {
            display: flex;
            align-items: center;
            gap: 6px;
            white-space: nowrap;
            font-weight: 500;
            font-size: 14px;
        }

        /* 指示灯 */
        .grok-monitor-indicator {
            width: 12px;
            height: 12px;
            border-radius: 50%;
            flex-shrink: 0;
            transition: background-color 0.2s ease;
        }

        /* 大版本:详细行,默认隐藏,悬浮时显示 */
        .grok-monitor-details {
            display: none;        /* 默认隐藏 */
            flex-direction: column;
            gap: 4px;
            font-size: 13px;
        }

        /* 悬浮时让 details 显示 */
        .grok-monitor:hover .grok-monitor-details {
            display: flex;
        }

        .grok-monitor-kind-row {
            display: flex;
            align-items: center;
            gap: 6px;
            white-space: nowrap;
        }

        .grok-monitor-kind-name {
            font-weight: 600;
        }

        /* 更新动画(请求中时可以使用) */
        .grok-monitor.updating .grok-monitor-indicator {
            animation: pulse 1s ease-in-out infinite;
        }

        @keyframes pulse {
            0%, 100% {
                transform: scale(1);
                opacity: 1;
            }
            50% {
                transform: scale(1.2);
                opacity: 0.7;
            }
        }

        /* 深色模式下可自行调整 */
        @media (prefers-color-scheme: dark) {
            .grok-monitor {
                background-color: #2b2b2b;
                color: #fff;
                border-color: #666;
            }
        }
    `);

    // 工具函数:格式化等待时间
    function formatWaitTime(seconds) {
        if (seconds <= 0) return '0m';
        const hours = Math.floor(seconds / 3600);
        const minutes = Math.floor((seconds % 3600) / 60);
        if (hours > 0 && minutes > 0) {
            return `${hours}h${minutes}m`;
        } else if (hours > 0) {
            return `${hours}h`;
        } else {
            return `${minutes}m`;
        }
    }

    // 创建监控器UI
    function createMonitor() {
        const monitor = document.createElement('div');
        monitor.className = 'grok-monitor';

        // ---- 小版本(默认显示) ----
        const summaryRow = document.createElement('div');
        summaryRow.className = 'grok-monitor-summary';

        // 剩余次数总和文本
        const sumSpan = document.createElement('span');
        sumSpan.textContent = '剩余总数: ...';

        // 指示灯
        const indicator = document.createElement('div');
        indicator.className = 'grok-monitor-indicator';

        summaryRow.appendChild(sumSpan);
        summaryRow.appendChild(indicator);

        // ---- 大版本(悬浮后展开) ----
        const details = document.createElement('div');
        details.className = 'grok-monitor-details';

        // 为每种模式添加一行
        REQUEST_KINDS.forEach(kind => {
            const row = document.createElement('div');
            row.className = 'grok-monitor-kind-row';

            // 简短名称
            const nameSpan = document.createElement('span');
            nameSpan.className = 'grok-monitor-kind-name';
            nameSpan.textContent = MODE_LABELS[kind];

            // 剩余/等待 文本
            const infoSpan = document.createElement('span');
            infoSpan.textContent = '...';

            row.appendChild(nameSpan);
            row.appendChild(infoSpan);
            details.appendChild(row);
        });

        // 添加 Grok-4 标准模式
        const grok4Row = document.createElement('div');
        grok4Row.className = 'grok-monitor-kind-row';

        const grok4NameSpan = document.createElement('span');
        grok4NameSpan.className = 'grok-monitor-kind-name';
        grok4NameSpan.textContent = '标4';

        const grok4InfoSpan = document.createElement('span');
        grok4InfoSpan.textContent = '...';

        grok4Row.appendChild(grok4NameSpan);
        grok4Row.appendChild(grok4InfoSpan);
        details.appendChild(grok4Row);

        // 组装
        monitor.appendChild(summaryRow);
        monitor.appendChild(details);

        document.body.appendChild(monitor);
        return monitor;
    }

    // 获取当前域名的基础URL
    function getBaseUrl() {
        return window.location.origin;
    }

    // 获取每种模式的限额
    async function fetchRateLimit(kind, modelName = "grok-3") {
        try {
            // 使用动态的基础URL
            const baseUrl = getBaseUrl();
            const response = await fetch(`${baseUrl}/rest/rate-limits`, {
                method: 'POST',
                headers: {
                    'accept': '*/*',
                    'content-type': 'application/json'
                },
                body: JSON.stringify({
                    requestKind: kind,
                    modelName: modelName
                }),
                credentials: 'include'
            });

            if (response.ok) {
                return await response.json();
            } else {
                throw new Error(`Failed to fetch ${kind} rate limit`);
            }
        } catch (error) {
            console.error('Rate limit check failed:', error);
            return null;
        }
    }

    // 一次获取所有模式数据
    async function getAllRateLimits() {
        const results = {};

        // 获取 Grok-3 的所有模式
        for (const kind of REQUEST_KINDS) {
            results[`grok-3-${kind}`] = await fetchRateLimit(kind, "grok-3");
        }

        // 获取 Grok-4 的标准模式
        results['grok-4-DEFAULT'] = await fetchRateLimit('DEFAULT', "grok-4");

        return results;
    }

    // 更新UI
    function updateUI(results) {
        const monitor = document.querySelector('.grok-monitor');
        const sumSpan = monitor.querySelector('.grok-monitor-summary span');
        const indicator = monitor.querySelector('.grok-monitor-indicator');

        // 给指示灯加 "updating" 动画效果
        monitor.classList.add('updating');

        // 计算合计剩余次数(包括所有模型和模式)
        let sum = 0;
        Object.values(results).forEach(data => {
            if (data && data.remainingQueries > 0) {
                sum += data.remainingQueries;
            }
        });

        // 小版本文本:合计剩余
        sumSpan.textContent = `剩余总数: ${sum}`;

        // 指示灯颜色
        if (sum === 0) {
            indicator.style.backgroundColor = '#EF4444'; // 红色
        } else if (sum > 0 && sum < 5) {
            indicator.style.backgroundColor = '#F59E0B'; // 黄色
        } else {
            indicator.style.backgroundColor = '#10B981'; // 绿色
        }

        // 更新大版本详细数据
        const detailRows = monitor.querySelectorAll('.grok-monitor-kind-row');
        detailRows.forEach(row => {
            const label = row.querySelector('.grok-monitor-kind-name').textContent;
            const infoSpan = row.querySelector('span:nth-child(2)');

            let data = null;

            // 根据标签确定对应的数据
            if (label === '标4') {
                data = results['grok-4-DEFAULT'];
            } else {
                // 查找对应的模式
                const kind = Object.keys(MODE_LABELS).find(k => MODE_LABELS[k] === label);
                if (kind) {
                    data = results[`grok-3-${kind}`];
                }
            }

            if (!data) {
                infoSpan.textContent = '获取失败';
                return;
            }

            const { remainingQueries, waitTimeSeconds } = data;
            if (remainingQueries > 0) {
                infoSpan.textContent = `剩余: ${remainingQueries}`;
            } else {
                infoSpan.textContent = `等待: ${formatWaitTime(waitTimeSeconds)}`;
            }
        });

        // 1s 后移除更新动画
        setTimeout(() => monitor.classList.remove('updating'), 1000);
    }

    // 定时检查
    async function checkRateLimits() {
        const results = await getAllRateLimits();
        updateUI(results);
    }

    // 初始化
    function init() {
        createMonitor();
        checkRateLimits(); // 立即检查一次
        setInterval(checkRateLimits, 30000); // 每 30s 检查
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }
})();
1 个赞


变多了,4也是30次了

这个grok4的30次额度是2小时的还是24小时的 :tieba_028:

应该2h吧

1 个赞

const MODES = [
  {
    name: "GROK3_DEFAULT",
    displayName: "Grok 3",
    requestKind: "DEFAULT",
    modelName: "grok-3",
    iconColor: "#4CAF50",
    darkColor: "#88E388",
    lightColor: "#2D882D",
  },
  {
    name: "GROK3_REASONING",
    displayName: "Grok 3 Think",
    requestKind: "REASONING",
    modelName: "grok-3",
    iconColor: "#FF9800",
    darkColor: "#FFCC80",
    lightColor: "#E65100",
  },
  {
    name: "GROK3_DEEPSEARCH",
    displayName: "Grok 3 DeepSearch",
    requestKind: "DEEPSEARCH",
    modelName: "grok-3",
    iconColor: "#2196F3",
    darkColor: "#90CAF9",
    lightColor: "#0D47A1",
  },
  {
    name: "GROK3_DEEPERSEARCH",
    displayName: "Grok 3 DeeperSearch",
    requestKind: "DEEPERSEARCH",
    modelName: "grok-3",
    iconColor: "#009688",
    darkColor: "#80CBC4",
    lightColor: "#00695C",
  },
  {
    name: "GROK4_DEFAULT",
    displayName: "Grok 4",
    requestKind: "DEFAULT",
    modelName: "grok-4",
    iconColor: "#673AB7",
    darkColor: "#D1C4E9",
    lightColor: "#4527A0",
  },
  {
    name: "GROK4HEAVY_DEFAULT",
    displayName: "Grok 4 Heavy",
    requestKind: "DEFAULT",
    modelName: "grok-4-heavy",
    iconColor: "#E91E63",
    darkColor: "#F8BBD9",
    lightColor: "#AD1457",
  },
];

原来要订阅SuperGrok啊,我太天真了,还以为能白嫖 :tieba_087:

第一次用油猴,已下载插件,已配置好脚本,已启用脚本,已购买GROK4,但是grok页面没显示标签,敢问各位大佬,还需要什么操作?


添加新脚本,复制我的代码粘贴进去再启用试试,你现在用的可能是之前的佬的旧代码