Greasy Fork

来自缓存

Greasy Fork is available in English.

智谱 GLM Coding Plan 订阅 抢购助手 - 2026-04-20有效

用于使前端按扭可点击,能少几次请求,不用刷新页面。实测是可以抢到的。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         智谱 GLM Coding Plan 订阅 抢购助手 - 2026-04-20有效
// @name:en      Zhipu GLM Coding Purchase Assistant
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  用于使前端按扭可点击,能少几次请求,不用刷新页面。实测是可以抢到的。
// @description:en make the button click-able so you don't need to refresh page
// @author       YourName
// @match        *://www.bigmodel.cn/*
// @match        https://www.bigmodel.cn/glm-coding
// @match        https://bigmodel.cn/glm-coding*
// @run-at       document-start
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const SCRIPT_NAME = '[抢购助手1.0]';
    const STOCK_VALUE = 999;

    console.log(`${SCRIPT_NAME} 拦截器已启动...`);

    // ==========================================
    // 工具函数
    // ==========================================

    /**
     * 判断对象是否为商品对象
     * @param {Object} obj - 待检查的对象
     * @returns {boolean} - 是否为商品对象
     */
    function isProductObject(obj) {
        return obj.price !== undefined ||
               obj.productId !== undefined ||
               obj.title !== undefined;
    }

    /**
     * 递归修改对象中的售罄相关属性
     * @param {Object} obj - 待修改的对象
     */
    function deepModify(obj) {
        if (!obj || typeof obj !== 'object') return;

        // 篡改核心售罄标识
        if (obj.isSoldOut === true) {
            obj.isSoldOut = false;
        }
        if (obj.soldOut === true) {
            obj.soldOut = false;
        }

        // 如果遇到 disabled,且该对象看起来是个商品,则强制启用
        if (obj.disabled === true && isProductObject(obj)) {
            obj.disabled = false;
        }

        // 修改库存数量
        if (obj.stock === 0) {
            obj.stock = STOCK_VALUE;
        }

        // 递归处理子属性
        for (const key in obj) {
            if (obj[key] && typeof obj[key] === 'object') {
                deepModify(obj[key]);
            }
        }
    }

    /**
     * 修改响应文本中的售罄状态
     * @param {string} text - 原始响应文本
     * @returns {string} - 修改后的响应文本
     */
    function modifyResponseText(text) {
        return text
            .replace(/"isSoldOut":true/g, '"isSoldOut":false')
            .replace(/"disabled":true/g, '"disabled":false')
            .replace(/"soldOut":true/g, '"soldOut":false')
            .replace(/"stock":0/g, `"stock":${STOCK_VALUE}`);
    }

    /**
     * 检查响应文本是否包含售罄状态
     * @param {string} text - 响应文本
     * @returns {boolean} - 是否包含售罄状态
     */
    function hasSoldOutStatus(text) {
        return text.includes('"isSoldOut":true') ||
               text.includes('"disabled":true') ||
               text.includes('"soldOut":true');
    }

    // ==========================================
    // 战术一:拦截 SSR 页面初始注入数据
    // 通过劫持浏览器的 JSON 解析器,修改带有"售罄"属性的对象
    // ==========================================

    const originalJSONParse = JSON.parse;

    JSON.parse = function(text, reviver) {
        const result = originalJSONParse(text, reviver);

        try {
            deepModify(result);
        } catch (error) {
            // 静默处理错误,避免影响页面正常功能
        }

        return result;
    };

    // ==========================================
    // 战术二:拦截 Fetch 接口请求
    // 针对用户在页面停留时,前端向后端发起的库存/价格检查
    // ==========================================

    const originalFetch = window.fetch;

    window.fetch = async function(...args) {
        const response = await originalFetch.apply(this, args);
        const contentType = response.headers.get('content-type') || '';

        // 只处理 JSON 接口
        if (!contentType.includes('application/json')) {
            return response;
        }

        const clone = response.clone();

        try {
            let text = await clone.text();

            if (hasSoldOutStatus(text)) {
                console.log(`${SCRIPT_NAME} 拦截到 Fetch 售罄数据,正在执行篡改!`, args[0]);
                text = modifyResponseText(text);

                // 构造并返回修改后的响应
                return new Response(text, {
                    status: response.status,
                    statusText: response.statusText,
                    headers: response.headers
                });
            }
        } catch (error) {
            // 静默处理错误
        }

        return response;
    };

    // ==========================================
    // 战术三:拦截 XMLHttpRequest (兜底方案)
    // ==========================================

    const originalXHROpen = XMLHttpRequest.prototype.open;
    const originalXHRSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.open = function(method, url, ...rest) {
        this._requestUrl = url;
        return originalXHROpen.call(this, method, url, ...rest);
    };

    XMLHttpRequest.prototype.send = function(...args) {
        this.addEventListener('readystatechange', function() {
            if (this.readyState !== 4 || this.status !== 200) {
                return;
            }

            const contentType = this.getResponseHeader('content-type') || '';

            if (!contentType.includes('application/json')) {
                return;
            }

            try {
                let text = this.responseText;

                if (hasSoldOutStatus(text)) {
                    console.log(`${SCRIPT_NAME} 拦截到 XHR 售罄数据,正在执行篡改!`, this._requestUrl);
                    text = modifyResponseText(text);

                    // 使用劫持 getter 的方式修改响应数据
                    Object.defineProperty(this, 'responseText', {
                        get: function() { return text; }
                    });
                    Object.defineProperty(this, 'response', {
                        get: function() { return JSON.parse(text); }
                    });
                }
            } catch (error) {
                // 静默处理错误
            }
        });

        originalXHRSend.apply(this, args);
    };

})();