Tokens Usage Number Formatter

将 DeepSeek 使用量统计图表中的 tokens 数字修改为下划线分隔格式 (如 '342054 tokens' -> '342_054 tokens')

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Tokens Usage Number Formatter
// @author       ExcuseLme
// @namespace    https://github.com/ExcuseLme
// @version      1.1
// @description  将 DeepSeek 使用量统计图表中的 tokens 数字修改为下划线分隔格式 (如 '342054 tokens' -> '342_054 tokens')
// @match        https://platform.deepseek.com/usage
// @grant        none
// @icon         https://fe-static.deepseek.com/platform/favicon.svg
// @run-at       document-idle
// @license      MIT
// ==/UserScript==

(function () {
  'use strict'

  /**
   * 格式化数字函数
   * 将 342054 转换为 342_054
   */
  const formatNumber = (text) => {
    const regex = /^(\d+)(\s+tokens)$/
    const match = text.match(regex)

    if (match) {
      const num = match[1]
      const unit = match[2]
      // 使用正则每隔三位插入下划线
      const formattedNum = num.replace(/\B(?=(\d{3})+(?!\d))/g, '_')
      return `${formattedNum}${unit}`
    }
    return null
  }

  /**
   * 处理节点函数
   */
  const processNode = (node) => {
    const processTextNode = (textNode) => {
      const originalText = textNode.textContent.trim()
      const newText = formatNumber(originalText)
      if (newText && originalText !== newText) {
        textNode.textContent = newText
      }
    }

    if (node.nodeType === Node.ELEMENT_NODE) {
      // 深度优先检查包含文本的 div
      // 创建自定义过滤器,只处理包含数字的文本节点以提高性能
      const numberFilter = {
        acceptNode: function (textNode) {
          // 只接受包含数字的文本节点
          if (/\d/.test(textNode.textContent)) {
            return NodeFilter.FILTER_ACCEPT
          }
          return NodeFilter.FILTER_SKIP
        }
      }

      const walker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, numberFilter)
      let textNode
      while ((textNode = walker.nextNode()) !== null) {
        processTextNode(textNode)
      }
    } else if (node.nodeType === Node.TEXT_NODE) {
      // 直接处理文本节点
      processTextNode(node)
    }
  }

  // 实例化观察器
  const observer = new MutationObserver((mutations) => {
    for (const mutation of mutations) {
      // 监听新增节点(浮窗出现时)
      mutation.addedNodes.forEach(node => {
        processNode(node)
      })
      // 监听文本变化(浮窗内容更新时)
      if (mutation.type === 'characterData' || mutation.type === 'childList') {
        processNode(mutation.target)
      }
    }
  })

  // 配置观察选项:子节点、后代节点、文本内容
  const config = {
    childList    : true,
    subtree      : true,
    characterData: true
  }

  // 开始观察 body 元素
  observer.observe(document.body, config)

  console.log('DeepSeek Tokens Formatter 脚本已启动')
})()