【油猴脚本】sub2api 账号周配额计算器

KawaTU 2026-08-20 13:16 1

逻辑:U(用量)/ 使用配额占账号百分比



开发过程:


// ==UserScript==
// @name Sub2API 账号周限额预估
// @namespace https://example.invalid/sub2api-userscripts
// @version 1.2.0
// @description 在账号管理页根据周用户扣费和周配额占用比例显示预估周限额
// @match *://*/admin/accounts*
// @grant none
// @run-at document-idle
// ==/UserScript==

(function () {
'use strict';

// ==================== 在这里添加适配域名 ====================
// 添加方法:
// 1. 每行填写一个域名,并用英文逗号结尾。
// 2. 只填写域名,不要包含 http://、https://、端口或页面路径。
// 3. 需要添加多个域名时,照着下面的格式继续增加新行即可。
// 4. 下方均为示例域名,安装后请替换成自己的 Sub2API 域名。
const TARGET_HOSTS = [
'sub2api.example.com',
// 'sub2api-2.example.net',
// 'sub2api-3.example.org',
];
// ==================== 域名配置结束 ====================

if (!TARGET_HOSTS.includes(location.hostname)) return;

const MARKER_CLASS = 'tm-estimated-weekly-limit';
const USD_FORMATTER = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
minimumFractionDigits: 0,
maximumFractionDigits: 0,
});

function readNumber(text) {
const match = text.replaceAll(',', '').match(/-?\d+(?:\.\d+)?/);
return match ? Number(match[0]) : Number.NaN;
}

function findWeeklyBadge() {
return [...document.querySelectorAll('table tbody td span')]
.filter((span) => span.textContent.trim() === '7d');
}

function updateWeeklyLimit(weeklyBadge) {
const progressRow = weeklyBadge.parentElement;
const weeklyBlock = progressRow?.parentElement;
if (!progressRow || !weeklyBlock) return;

const userCostElement = [...weeklyBlock.querySelectorAll('span')].find((span) =>
span.title === '用户扣费' || /^\s*U\s*\$/.test(span.textContent),
);
const percentElement = [...progressRow.querySelectorAll('span')].find((span) =>
/^\d+(?:\.\d+)?%$/.test(span.textContent.trim()),
);
const existing = progressRow.querySelector(`.${MARKER_CLASS}`);

const userCost = userCostElement ? readNumber(userCostElement.textContent) : Number.NaN;
const percent = percentElement ? readNumber(percentElement.textContent) : Number.NaN;

if (!Number.isFinite(userCost) || !Number.isFinite(percent) || userCost <= 0 || percent <= 0) {
existing?.remove();
return;
}

const estimatedLimit = userCost / (percent / 100);
const formattedLimit = USD_FORMATTER.format(estimatedLimit);
const label = `周限额(预估)${formattedLimit}`;
const title = `按页面显示值估算:U $${userCost.toFixed(2)} ÷ ${percent}% = ${formattedLimit};页面百分比经过取整,结果仅供参考。`;

const limitElement = existing || document.createElement('span');
limitElement.className = `${MARKER_CLASS} shrink-0 text-[10px] font-medium text-gray-500 dark:text-gray-400`;
if (limitElement.textContent !== label) limitElement.textContent = label;
limitElement.title = title;
limitElement.dataset.estimatedWeeklyLimit = String(estimatedLimit);

if (!existing) progressRow.append(limitElement);
}

function updateAll() {
findWeeklyBadge().forEach(updateWeeklyLimit);
}

let updateQueued = false;
function queueUpdate() {
if (updateQueued) return;
updateQueued = true;
requestAnimationFrame(() => {
updateQueued = false;
updateAll();
});
}

const observer = new MutationObserver(queueUpdate);
observer.observe(document.documentElement, {
childList: true,
subtree: true,
characterData: true,
});

updateAll();
})();

最新回复 (4)
  • contrails 08-20 13:23
    1

    可以直接 github 提 pull request 合进去

  • fanfan142 08-20 13:24
    2

    这个不错 每次还得计算器算 UI界面还没小数点 哈哈

  • fanfan142 08-20 13:27
    3

    @fanfan142 #2 发布于2026/8/20 13:24:39

    这个不错 每次还得计算器算 UI界面还没小数点 哈哈


    但我这只显示plus 不显示pro号的 是什么问题呢

  • KawaTU 楼主 08-20 13:28
    4

    @fanfan142 #3

    不知道,你直接让Ai改吧,我也是纯AI写的,全程5分钟内搞完的

* 帖子来源NodeSeek
返回