// ==UserScript==
// @name GLM Coding Plan抢购助手
// @namespace http://tampermonkey.net/
// @version 6.1
// @description 智能监控,支持配置多级备选抢购;自动穿透限流弹窗;默认使用拼团折扣码更优惠,介意误用
// @author mumumi
// @include https://*bigmodel.cn/glm-coding*
// @include https://*bigmodel.cn/html/rate-limit.html*
// @icon https://www.google.com/s2/favicons?sz=64&domain=bigmodel.cn
// @grant GM_setValue
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @run-at document-start
// @license GNU GPLv3
// @downloadURL none
// ==/UserScript==
(function () {
'use strict';
// ======================== 数据字典 ========================
const TABS_MAP = { 1: '连续包月', 2: '连续包季', 3: '连续包年' };
const PKGS_MAP = { 1: 'Lite', 2: 'Pro', 3: 'Max' };
const STORAGE_KEY = 'glm_coding_config_v5';
// ======================== 配置 ========================
const DEFAULT_CONFIG = {
TABS_PRIORITY: '1',
PACKAGES_PRIORITY: '2,3,1',
CHECK_INTERVAL: 100,
SMART_REFRESH: true,
};
function loadConfig() {
try {
const s = GM_getValue(STORAGE_KEY, null);
return s ? { ...DEFAULT_CONFIG, ...JSON.parse(s) } : { ...DEFAULT_CONFIG };
} catch { return { ...DEFAULT_CONFIG }; }
}
function saveConfig(cfg) { GM_setValue(STORAGE_KEY, JSON.stringify(cfg)); }
const CONFIG = loadConfig();
// ======================== 限流页跳回 ========================
if (location.href.includes('rate-limit.html')) {
location.replace(RETURN_URL);
return;
}
// ======================== 扫描队列构建 ========================
// 按用户配置:先遍历每个 tab,在 tab 内按套餐优先级扫描
const tabs = String(CONFIG.TABS_PRIORITY).split(',').map(Number).filter(Boolean);
const pkgs = String(CONFIG.PACKAGES_PRIORITY).split(',').map(Number).filter(Boolean);
const scanQueue = tabs.flatMap(t => pkgs.map(p => ({ tab: t, pkg: p })));
// ======================== 状态机变量 ========================
// 主状态: SCANNING | TASK_UNIT | SLEEPING | DONE
let state = 'SCANNING';
// SCANNING
let qIdx = 0;
let sweepRestocks = []; // 本轮扫到的补货时间
let lastTabSwitch = 0; // 上次切 tab 的时间戳,用于等 Vue 重绘
// TASK_UNIT
let taskTarget = null; // { tab, pkg }
let taskPhase = 'IDLE'; // IDLE | WAITING
let taskClickTime = 0;
let taskRLCount = 0; // 本任务单元内连续限流次数
const MAX_RL = 3; // 连续限流几次后刷新页面
const MODAL_TIMEOUT = 5000; // 点击后等待弹窗的超时时间(ms)
// SLEEPING
let sleepUntil = 0;
// ======================== 工具函数 ========================
function parseRestock(text) {
const m = (text || '').match(/0?(\d{1,2})月0?(\d{1,2})日\s*(\d{1,2}):0?(\d{1,2})/);
if (!m) return null;
const now = new Date();
const t = new Date(now.getFullYear(), +m[1] - 1, +m[2], +m[3], +m[4]);
const dateStr = `${+m[1]}月${+m[2]}日`;
return { dateStr, msUntil: t - now };
}
function todayStr() {
const d = new Date();
return `${d.getMonth() + 1}月${d.getDate()}日`;
}
function fmt(ms) {
if (ms <= 0) return '0秒';
const s = Math.floor(ms / 1000), m = Math.floor(s / 60), h = Math.floor(m / 60);
if (h > 0) return `${h}h${m % 60}m`;
if (m > 0) return `${m}分${s % 60}秒`;
return `${s}秒`;
}
/**
* 梯度休眠时长计算(距补货时间 → 本次页面刷新间隔)
*
* > 60min → 4min (防浏览器休眠选 4min 而非更长)
* > 30min → 3min
* > 15min → 2min
* > 5min → 1min
* > 2min → 30s
* > 1min → 10s
* > 10s → 3s (极短刷新,精确卡点)
* ≤ 10s → 0 (不刷新,原地高频轮询)
*/
function calcSleepMs(msUntil) {
if (msUntil > 3600000) return 240000;
if (msUntil > 1800000) return 180000;
if (msUntil > 900000) return 120000;
if (msUntil > 300000) return 60000;
if (msUntil > 120000) return 30000;
if (msUntil > 60000) return 10000;
if (msUntil > 10000) return 3000;
return 0;
}
// ======================== DOM 访问 ========================
const tabEl = (n) =>
document.querySelector(`#switchTabBox > div > .switch-tab-item:nth-child(${n + 1})`);
const btnEl = (n) =>
document.querySelector(`.glm-coding-package-list > div:nth-child(${n}) > div > .package-card-btn-box > button`);
// 按钮是否可以立即购买
const canBuy = (b) =>
b && !b.disabled && !b.classList.contains('is-disabled') && (b.innerText || '').includes('特惠订阅');
// 按钮是否明确显示售罄/补货
const isSoldOut = (b) =>
/售罄|补货|暂时/.test((b?.innerText) || '');
// ======================== 弹窗检测 ========================
function findRLModal() {
for (const w of document.querySelectorAll('.el-dialog__wrapper')) {
if (getComputedStyle(w).display !== 'none' &&
(w.innerText || '').includes('当前购买人数较多')) {
return w;
}
}
return null;
}
function isSuccessDialog() {
const d = document.querySelector('.pay-success-dialog-box');
if (!d) return false;
const w = d.closest('.el-dialog__wrapper');
return w ? getComputedStyle(w).display !== 'none' : false;
}
function closeModal(w) { w?.querySelector('.el-dialog__close')?.click(); }
// ======================== 底部状态栏 ========================
let _bar = null;
function setBar(html, bg = '#1677ff') {
if (!_bar) {
_bar = document.createElement('div');
_bar.id = 'glm-status-bar';
_bar.style.cssText = `
position:fixed;bottom:0;left:0;right:0;z-index:2147483647;
padding:7px 16px;font:13px/1.5 system-ui,sans-serif;color:#fff;
display:flex;align-items:center;justify-content:space-between;
box-shadow:0 -2px 8px rgba(0,0,0,.25);transition:background .4s;`;
const close = document.createElement('button');
close.textContent = '×';
close.style.cssText = `background:rgba(255,255,255,.2);border:none;color:#fff;
width:22px;height:22px;border-radius:4px;cursor:pointer;font-size:16px;
line-height:1;flex-shrink:0;`;
close.onclick = () => { _bar.remove(); _bar = null; };
const msg = document.createElement('span');
_bar.appendChild(msg);
_bar.appendChild(close);
document.body.appendChild(_bar);
}
_bar.style.background = bg;
_bar.firstElementChild.innerHTML = `🤖 抢购助手 | ${html}`;
}
// ======================== 推广弹窗(多平台版) ========================
function triggerPromo() {
if (Date.now() > new Date('2026-04-30T23:59:59').getTime()) {
setBar('所有套餐今日售罄,脚本停止。', '#434343');
return;
}
const PROVIDERS = [
{ name: 'MiniMax', desc: '¥29起,赠视频/语音/音乐额度', color: '#4CAF50', url: 'https://platform.minimaxi.com/subscribe/token-plan?code=FoGlERWIF3&source=link' },
{ name: '字节·方舟', desc: '首月低至¥8.9,多模型切换', color: '#FF6B35', url: 'https://volcengine.com/L/YIeVPueJ2O4/' },
{ name: '讯飞星辰', desc: '¥19起,首月¥3.9最低门槛', color: '#00BFFF', url: 'https://maas.xfyun.cn/packageSubscription?inviteCode=MAAS-C6BE3A3B' },
{ name: '无问芯穹', desc: '多模型聚合,首月¥19.9', color: '#7B68EE', url: 'https://cloud.infini-ai.com/login?redirect=/genstudio/invitation&invite_code=IyveoKRS' },
];
const rows = PROVIDERS.map(p => `