暗暗钩索

为了生活,有什么办法?

// ==UserScript==
// @name         暗暗钩索
// @namespace    frivolous.rope.qiegewala
// @version      2025.9.15.8.9
// @description  为了生活,有什么办法?
// @license      GPL-3.0
// @author       miaoyin-tei
// @match        https://www.bilibili.com/
// @match        https://www.bilibili.com/video/*
// @match        https://www.bilibili.com/list/*
// @connect      https://*.bilibili.com/*
// @icon         https://www.bilibili.com/favicon.ico
// @grant        GM_cookie
// @grant        unsafeWindow
// @run-at       document-start
// ==/UserScript==

(async function () {

    // Debug
    const isDebug = 0;

    // 战利品
    const rope = window.rope_ = {};
    if (isDebug) unsafeWindow.rope_ = rope;
    const pilferLoot = {};


    // 钩索 ( 目标, 名字, 要做什么({ target, thisArg, args}), 异步转同步返回超时时间[5000ms] )
    const hook = (obj, methodName, callback, asyncReturnTimeout = 5000) => {
        if (!obj || typeof obj[methodName] !== 'function') throw new TypeError('搞错目标了');

        const originalFn = obj[methodName];

        function isPromise(obj) {
            return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
        }

        function waitSync(promise, timeout) {
            let done = false, res, err;
            promise.then(r => { done = true; res = r }, e => { done = true; err = e });
            const start = Date.now();
            while (!done) {
                if (Date.now() - start > timeout) {
                    done = true;
                    err = `等待异步返回超时:${timeout} ms`;
                }
            }
            if (err) console.error(err);
            return res;
        }

        function hookedFn(...args) {
            const hookReturn = callback(this, args[0], args);
            if (isPromise(hookReturn)) {
                return waitSync(hookReturn, asyncReturnTimeout);
            } else if (hookReturn !== undefined) {
                return hookReturn;
            }
            return originalFn.apply(this, args);
        }

        Object.setPrototypeOf(hookedFn, Object.getPrototypeOf(originalFn));
        obj[methodName] = hookedFn;

        return {
            restore() {
                obj[methodName] = originalFn;
            }
        }
    };


    // 偷走甜点
    const pilferTreat = (name, index = 0, options = {}) => new Promise(resolve => {
        const query = {
            name,
            domain: options.domain || location.hostname,
            ...options
        };
        const grab = (n) => {
            let i = new RegExp("(^| )" + n + "=([^;]*)(;|$)"),
                t = document.cookie.match(i);
            return t ? decodeURIComponent(t[2]) : null
        };

        GM_cookie.list(query, (treats, error) => {
            const alittle = grab(name);
            if (error && !alittle) {
                resolve();
                return;
            }
            resolve(
                treats.length > 0
                    ? (index < 0 ? treats : treats[index]?.value)
                    : alittle
            );
        });
    });


    // 等待时机
    const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));


    // 行动计划
    const actionGroups = [
        {
            name: '暗中行动',
            urls: [
                '/'
            ],
            actions: [
                {
                    name: '偷暗交物资',
                    task: () => molePilferStash()
                }
            ]
        },
        {
            name: '暗中钩索',
            urls: [
                '/video/',
                '/list/'
            ],
            actions: [
                {
                    name: '偷饭卡',
                    task: () => stealMealCard()
                },
                {
                    name: '偷门卡',
                    task: () => stealVueAccessCard()
                },
            ]
        },
        {
            name: '偷以致用',
            urls: [
                '/video/',
                '/list/'
            ],
            actions: [
                {
                    name: '使用门卡',
                    dependsOn: ['偷门卡'],
                    shouldRun: async (deps) => deps[0].status === TaskStatus.SUCCESS,
                    task: () => useAccessCardInVue()
                },
                {
                    name: '伪装身份',
                    dependsOn: ['偷饭卡'],
                    shouldRun: async (deps) => deps[0].status === TaskStatus.SUCCESS,
                    task: async () => useDisguiseIdentity()
                },
                {
                    name: '暗箱操作',
                    dependsOn: ['伪装身份'],
                    shouldRun: async (deps) => deps[0].status === TaskStatus.SUCCESS,
                    task: async () => doBehindScenesRig().then(snoopIntel())
                }
            ]
        }
    ];


    // 传闻记录
    const heapHearsay = {
        mcpy: "MEDIA_CANPLAY"
    };


    //  月光字
    //  注意:直接阅读这些字可能导致认知混乱
    const moonlitGlyphs = new Set([
        'tcj_ilib',
        'nigoLsi',
        'ytilauQteg',
        'tseTbAbew',
        'nigoLsi.resu',
        'resUrepuSsi',
        'hctiwSlairTsi',
        'ytilauQlairTsi',
        'ytilauQtseuqer',
        'eliforp_reyalp_xpb',
        'hctaWlairTgnirahCsi',
        'noisrev_golaid_nigol',
        'TSAOT_YALP_REYALP_V',
        'tsiLytilauQdetroppuSteg'
    ]);

    // 月光图书馆
    const moonLightLibrary = {
        // 荧光流转
        fluorescenceFlow(lunarScript) {
            const found = [...moonlitGlyphs].find(v => v.startsWith(lunarScript));
            return found ? [...found].reverse().join('') : null;
        }
        // 光痕编织
        // luminousWeaving(mundaneText) {
        //     return [...mundaneText].reverse().join('');
        // }
    };


    // 任务状态结果枚举
    const TaskStatus = { SUCCESS: 1, FAILED: 2, SKIPPED: 3 };

    // 任务对象结构
    class TaskResult {
        constructor(groupName, name, status, data = '这次就算了') {
            Object.assign(this, { groupName, name, status, data, startTime: performance.now() });
        }
        end() { this.duration = performance.now() - this.startTime; return this; }
        get statusText() { return ['✅ 成功', '❌ 失败', '⏸️ 跳过'][this.status - 1]; }
        isSuccess() { return this.status === TaskStatus.SUCCESS; }
    }

    // 任务追踪
    class MissionTracker {
        #missions = Object.create(null);

        // 记录任务结果
        logMission(missionName, status) {
            if (!Object.values(TaskStatus).includes(status)) {
                throw new Error(`无效的任务状态: ${status}`);
            }
            this.#missions[missionName] = status;
        }

        // 验证任务是否达标 (单个或多个任务名, 期望状态, 检查方式[all: 全部达标 / some: 至少一个达标])
        verifyMission(missionNames, targetStatus, mode = 'all') {
            const missions = Array.isArray(missionNames) ? missionNames : [missionNames];
            const statuses = missions.map(name => this.#missions[name] === targetStatus);
            return mode === 'all' ? statuses.every(Boolean) : statuses.some(Boolean);
        }
    }
    const missionTracker = new MissionTracker();


    /**
     * 执行任务
     *
     * @example
     * const globalTaskRegistry = new Map();
     * const actionGroups = [{
     *   name: '示例任务组',
     *   urls: ['/login'], // 匹配域名使用 '/'
     *   actions: [{
     *     name: '任务1',
     *     task: async () => console.log('执行任务')
     *   }, {
     *     name: '任务2',
     *     dependsOn: ['任务1'], // 依赖任务1
     *     shouldRun: async (deps) => deps[0].status === TaskStatus.SUCCESS, // 执行条件控制,deps[n] 依赖任务执行结果数组
     *     task: async () => console.log("依赖任务执行后运行")
     *   }]
     * }];
     *
     * executeActions(actionGroups, globalTaskRegistry);
     *
     * @param {Object} actGroups 任务清单
     * @returns {Promise<void>}
     *
     * @see TaskStatus 任务状态指南
     * @see TaskResult 任务结果指南
     * @see MissionTracker 任务追踪
     * @see generateReport 发布任务报告
    */
    async function executeActions(actGroups) {
        const groups = actGroups.filter(g => g.urls.some(u => location.pathname === u || location.href.includes(u)));
        if (!groups.length) return;

        const withGroupProp = (groups, propName, getter) =>
            groups.map(group => ({
                actions: group.actions.map(action => ({
                    ...action,
                    [propName]: getter(group)
                }))
            }));

        const executeTasks = async (actions) => {
            const taskMap = new Map(actions.map(a => [a.name, a]));
            const results = {};

            const runTask = async (action) => {
                const result = new TaskResult(action.groupName, action.name, TaskStatus.SUCCESS);
                try {
                    const resultDat = await action.task();
                    result.data = resultDat?.data || resultDat;
                    result.status = resultDat?.status || TaskStatus.SUCCESS;
                } catch (e) {
                    result.status = TaskStatus.FAILED;
                    result.data = e;
                }
                return result.end();
            };

            const executeTask = async (action) => {
                if (results[action.name]) return results[action.name];

                const deps = action.dependsOn
                    ? await Promise.all(
                        [].concat(action.dependsOn).map(name => {
                            const depAction = taskMap.get(name);
                            if (!depAction) throw new Error(`依赖任务 ${name} 不存在`);
                            return executeTask(depAction);
                        })
                    )
                    : [];

                const shouldRun = !action.dependsOn || !action.shouldRun || await action.shouldRun(deps);
                results[action.name] = shouldRun
                    ? await runTask(action)
                    : new TaskResult(action.groupName, action.name, TaskStatus.SKIPPED).end();

                missionTracker.logMission(action.name, results[action.name].status);
                return results[action.name];
            };

            await Promise.all(actions.map(executeTask));
            return { taskResults: Object.values(results) };
        };

        const results = await executeTasks(
            withGroupProp(groups, 'groupName', g => g.name)
                .flatMap(g => g.actions)
        );

        isDebug && generateReport([results]);
    }


    // 准备行动
    const ready = document.readyState === 'complete'
        ? Promise.resolve()
        : new Promise(resolve => window.addEventListener('load', resolve));

    ready.then(executeActions(actionGroups)).catch(console.error);


    // ----------------------


    // 发布任务报告
    function generateReport(results) {
        console.group('%c+ 暗暗钩索 +', 'font-size:15px;color:#86f');

        const flatResults = results.flatMap(({ taskResults }) =>
            taskResults.map(task => ({
                任务组: task.groupName,
                任务名称: task.name,
                执行状态: task.statusText,
                耗时: `${task.duration?.toFixed(2) || '0.00'}ms`,
                结果: task.isSuccess() ? task.data : task.data?.message || String(task.data)
            }))
        );

        // 统计结果计数
        const stats = {
            '总任务数': flatResults.length,
            '成功数': flatResults.filter(r => r.执行状态 === '✅ 成功').length,
            '失败数': flatResults.filter(r => r.执行状态 === '❌ 失败').length,
            '跳过数': flatResults.filter(r => r.执行状态 === '⏸️ 跳过').length
        };

        console.table(flatResults);
        console.log('%c统计结果:', 'color:#87f', stats);

        // 失败详情
        flatResults.filter(r => r.执行状态 === '❌ 失败').forEach(failed => {
            console.groupCollapsed(`%c失败任务: ${failed.任务组} > ${failed.任务名称}`, 'color:#e66');
            console.error(failed.结果);
            console.groupEnd();
        });

        console.groupEnd();
    };


    /**
     * 偷设备
     * @param {Set} propSet - 需要偷的设备属性清单
     * @param {boolean} [once=true] - 只偷一次?false:每次见到就偷
     * @param {Function} onStolen({target, name, firstArg, args}) - 偷到时要做的事
     * @param {Function} onUnstolen - 没偷到时要做的事
     */
    function stealFuncCall({
        propSet,
        once = true,
        onStolen = () => { },
        onUnstolen = () => { }
    } = {}) {
        return new Promise(async (resolve, reject) => {
            const allowedProperties = propSet || new Set();
            const hookFnObj = unsafeWindow.Function.prototype;
            const hookFnName = 'call';

            const failed = () => {
                hooked.restore();
                onUnstolen();
                reject(false);
            };

            let timeout = setTimeout(failed, 30000);

            const hooked = hook(hookFnObj, hookFnName, (thisArg, firstArg, args) => {
                if (firstArg && typeof firstArg === 'object') {
                    const matchedProps = Object.keys(firstArg).filter(prop =>
                        allowedProperties.has(prop)
                    );

                    if (matchedProps.length < 1) return;

                    if (timeout) {
                        clearTimeout(timeout);
                        timeout = undefined;
                    }

                    onStolen({
                        target: thisArg,
                        name: thisArg.name,
                        firstArg,
                        args
                    });

                    if (once) {
                        hooked.restore();
                        resolve(true);
                    }
                }
            });
        });
    }


    /**
     * 偷暗交物资
     * @param {Set} contentSet - 需要偷的物资内容清单 [new Set(['findstr1', or 'findstr2']), and new Set...]
     * @param {boolean} [once=true] - 只偷一次?false:每次见到就偷
     * @param {Function} onStolen({target, name, handler, args}) - 偷到时要做的事 - return null 偷走
     * @param {Function} onUnstolen - 没偷到时要做的事
     */
    function stealCovertAwaitGoods({
        contentSet,
        once = true,
        onStolen = () => { },
        onUnstolen = () => { }
    } = {}) {
        return new Promise(async (resolve, reject) => {
            const allowedContents = contentSet || new Set();
            const hookFnObj = unsafeWindow;
            const hookFnName = 'setTimeout';

            const matchGroupedKeywords = (str, groups) =>
                groups.every(group => [...group].some(k => str.includes(k)));

            const hooked = hook(hookFnObj, hookFnName, (thisArg, firstArg, args) => {
                if (firstArg && typeof firstArg === 'function') {

                    const fnStr = firstArg.toString();
                    if (!matchGroupedKeywords(fnStr, allowedContents)) return;

                    const isStral = onStolen({
                        target: thisArg,
                        name: thisArg.name,
                        firstArg,
                        args
                    });

                    if (once) {
                        hooked.restore();
                        resolve(true);
                    }

                    return isStral;
                }
            });
        });
    }


    /**
     * 在Vue组件树中查找包含指定属性的组件
     * @param {VueComponent} component - 起始Vue组件实例
     * @param {string} propPath - 要查找的属性路径(如 'user.name')
     * @param {Object} [options={maxDepth=3, findAll=false}] - 配置选项{ 最大查找深度(-1无限),查找所有匹配组件(false返回第一个)}
     * @returns {VueComponent|VueComponent[]|null} 查找结果(根据findAll决定返回类型)
     */
    function findVueComponentByPropPath(
        component,
        propPath,
        { maxDepth = 3, findAll = false } = {},
        currentDepth = 1
    ) {
        if (!component || (maxDepth !== -1 && currentDepth > maxDepth)) {
            return findAll ? [] : null;
        }

        const propChain = propPath.split('.');
        const results = [];

        // 检查当前组件是否匹配
        const isMatch = propChain.reduce((obj, prop) => {
            return (obj && typeof obj === 'object' && prop in obj)
                ? obj[prop]
                : undefined;
        }, component) !== undefined;

        if (isMatch) {
            if (!findAll) {
                return component; // 立即返回第一个匹配项
            }
            results.push(component); // 收集所有匹配项
        }

        // 递归检查子组件
        if (component.$children) {
            for (const child of component.$children) {
                const childResult = findVueComponentByPropPath(
                    child,
                    propPath,
                    { maxDepth, findAll },
                    currentDepth + 1
                );

                if (!findAll && childResult) {
                    return childResult; // 找到第一个立即返回
                }
                if (findAll && childResult.length) {
                    results.push(...childResult); // 收集子组件结果
                }
            }
        }

        return findAll ? results : null;
    }


    /**
     * 异步等待获取对象值
     * @param {Function} getter - 获取对象值的函数
     * @param {number} [maxRetries=5] - 最大重试次数
     * @param {number} [delay=1000] - 重试间隔(毫秒)
     * @returns {Promise<any>} 返回获取到的值
     */
    async function waitForValue(getter, maxRetries = 5, delay = 1000) {
        let retries = 0;

        return new Promise((resolve, reject) => {
            const tryGetValue = async () => {
                try {
                    const value = await Promise.resolve(getter());

                    if (value !== null && value !== undefined) {
                        resolve(value);

                    } else if (retries < maxRetries) {
                        retries++;
                        setTimeout(tryGetValue, delay);
                    } else {
                        reject(new Error(`获取对象值失败,已达到最大重试次数 ${maxRetries} 次`));
                    }
                } catch (error) {
                    reject(error);
                }
            };

            tryGetValue();
        });
    }


    /**
     * 设置对象属性值
    * @param {object} obj - 目标对象
    * @param {string} propPath - 属性路径(如 'user.name')
    * @param {any} value - 设置的新值
    * @returns {boolean} 是否设置成功
    */
    function setValue(obj, propPath, value) {
        if (!obj || typeof obj !== 'object') return false;

        const props = propPath.split('.');
        const lastProp = props.pop();
        const parent = props.reduce((o, p) => (o[p] ??= {}), obj);

        const desc = Object.getOwnPropertyDescriptor(parent, lastProp);
        if (desc?.set) return Reflect.set(parent, lastProp, value);

        return Reflect.defineProperty(parent, lastProp, {
            configurable: true,
            enumerable: true,
            writable: true,
            value
        });
    }
    if (isDebug) unsafeWindow.rope_.setValue = setValue;


    /**
     * 从localStorage读取JSON指定路径值
     * @param {string} key - 存储键名
     * @param {string|string[]} path - 取值路径
     * @returns {any} 路径对应值,无值则返回null
     */
    function getValueFromLocalStorage(key, path) {
        try {
            const str = localStorage.getItem(key);
            if (!str) return null;

            const data = JSON.parse(str);
            const paths = Array.isArray(path) ? path : path.split('.').filter(Boolean);

            return paths.length
                ? paths.reduce((curr, k) => curr?.[k] ?? null, data)
                : data;
        } catch (e) {
            console.error('读取失败:', e);
            return null;
        }
    };


    // - - - - - - - - - - - - - - - - - - -


    // 查找目标
    async function findTargetVue() {
        try {
            const app = await waitForValue(
                () => unsafeWindow.document.querySelector('#app')?.__vue__
            );
            return app;
        } catch (error) {
            console.warn('没有找到目标', error);
            return;
        }
    }


    // 下次再试?
    async function toBeContinue(resolve) {
        const gotTreat = !!await pilferTreat(moonLightLibrary.fluorescenceFlow('tcj_ili'));

        if (resolve && gotTreat) {
            resolve({
                data: '下次再来吧',
                status: TaskStatus.SKIPPED
            });
        }

        return gotTreat;
    }


    // 暗行
    async function snoopSneak(hearsay, source) {
        switch (hearsay) {

            case heapHearsay.mcpy:
                if (source === 'player') {
                    if (
                        missionTracker.verifyMission('暗箱操作', TaskStatus.SUCCESS)
                        && rope?.quaSetdbid !== pilferLoot.player.input.bvid
                    ) {
                        rope.quaSetdbid = pilferLoot.player.input.bvid;
                        useDisguiseIdentity().then(doBehindScenesRig);
                    }
                }
                break;

        }
    }


    // 暗探 pL-
    function snoopIntel() {
        const hookPObj = pilferLoot?.player;
        const hookPName = 'emit';
        const hearsayPemit = (thisArg, say) => {
            snoopSneak(say, 'player');
        }
        hookPObj && hook(hookPObj, hookPName, hearsayPemit);
    }


    // 花言巧语 (巧语,时机,选择) pL-
    function doGlibTalk(vexGlow, sleightStall = 5e3, mystCraft = false) {
        pilferLoot?.toast?.create({
            text: vexGlow,
            duration: sleightStall,
            manualMode: mystCraft,
        });
    }


    // ------------------


    // 偷饭卡 #pilferLoot
    function stealMealCard() {
        return new Promise(async (resolve, reject) => {
            const sayonara = await toBeContinue(resolve);
            if (sayonara) return;

            let isStolen;
            const propSet = new Set(['rootPlayer', 'rootStore']);

            const mapping = (result) => {
                const mapprop = {
                    toastStore: 'toast',
                    userStore: 'user',
                    qualityStore: 'quality',
                    portStore: 'port',
                    rootPlayer: 'player'
                };
                Object.entries(mapprop).forEach(([from, to]) => pilferLoot[to] = result.firstArg[from]);
            }

            stealFuncCall({
                propSet,
                onStolen: (result) => {
                    rope.bRoot = result;
                    mapping(result);
                    if (!isStolen) {
                        isStolen = true;
                        resolve('偷到了!');
                    }
                },
                onUnstolen: () => reject('没偷到...')
            });
        });
    }


    // 偷门卡
    function stealVueAccessCard() {
        return new Promise(async (resolve, reject) => {
            const sayonara = await toBeContinue(resolve);
            if (sayonara) return;

            const app = await findTargetVue();
            const prop1 = moonLightLibrary.fluorescenceFlow('nigoLsi.res');
            const prop2 = moonLightLibrary.fluorescenceFlow('nigoLsi');

            await delay(1000);
            const find1 = findVueComponentByPropPath(app, prop1, { findAll: true });
            const find2 = findVueComponentByPropPath(app, prop2, { findAll: true });
            const components = [...new Set([...find1, ...find2])];

            if (components.length < 1) return reject('没偷到...');

            rope.isLoginArr = components;
            return resolve('偷到了!');
        });
    }


    // 偷暗交物资
    function molePilferStash() {
        return new Promise(async (resolve, reject) => {
            const sayonara = await toBeContinue(resolve);
            if (sayonara) return;

            const targetContentSet = [new Set(['Login(', 'login('])];

            stealCovertAwaitGoods({
                contentSet: targetContentSet,
                once: false,
                onStolen: () => {
                    resolve('偷到了!');
                    return null; // 偷
                },
                onUnstolen: () => reject('没偷到...')
            });
        });
    }


    // ------------------


    // 伪装身份 pL
    function useDisguiseIdentity() {
        return new Promise(async (resolve, reject) => {
            let used = false;
            const nl = moonLightLibrary.fluorescenceFlow('nigoLsi'),
                hwtc = moonLightLibrary.fluorescenceFlow('hctaWlairTgn'),
                rus = moonLightLibrary.fluorescenceFlow('resUrepuS'),
                tta = moonLightLibrary.fluorescenceFlow('tseTbA'),
                ngn = moonLightLibrary.fluorescenceFlow('noisrev_golaid_n'),
                tyrv = moonLightLibrary.fluorescenceFlow('TSAOT_YALP_REYA'),
                hst = moonLightLibrary.fluorescenceFlow('hctiwSlairT'),
                yqt = moonLightLibrary.fluorescenceFlow('ytilauQlairT');

            used = setValue(pilferLoot?.user, nl, true)
                && setValue(pilferLoot?.user, hwtc, false)
                && setValue(pilferLoot?.user, rus, true);
            unsafeWindow[tta][ngn] = tyrv;
            used &&= unsafeWindow[tta][ngn] === tyrv;
            pilferLoot?.quality?.setState({ [yqt]: true, [hst]: true });

            return used ? resolve('伪装成功!') : reject('被识破了...');
        });
    }


    // 使用门卡
    function useAccessCardInVue() {
        return new Promise(async (resolve, reject) => {
            const isLoginArr = rope?.isLoginArr;
            const prop1 = moonLightLibrary.fluorescenceFlow('nigoLsi.res');
            const prop2 = moonLightLibrary.fluorescenceFlow('nigoLsi');
            let used = false;

            if (!isLoginArr || isLoginArr.length < 1) return reject('没有门卡');
            if (isLoginArr[0][prop1] || isLoginArr[0][prop2]) return await toBeContinue(resolve);

            for (const comp of isLoginArr) {
                used = setValue(comp, prop1, true)
                    || setValue(comp, prop2, true);
            };
            if (used) doGlibTalk('🪢暗暗钩索带你躲避了催登者的追缉🪢');
            return used ? resolve('通过 !') : reject('门卡失效...');
        });
    }


    //-----------------


    // 暗箱操作 pL
    function doBehindScenesRig() {
        return new Promise(async (resolve, reject) => {
            const tlqs = moonLightLibrary.fluorescenceFlow('tsiLytilauQdetroppuS'),
                yqu = moonLightLibrary.fluorescenceFlow('ytilauQtseuqe'),
                hst = moonLightLibrary.fluorescenceFlow('hctiwSlairT'),
                erx = moonLightLibrary.fluorescenceFlow('eliforp_reyalp_x'),
                gqy = moonLightLibrary.fluorescenceFlow('ytilauQteg');

            const hqv = () => {
                let q = getValueFromLocalStorage(erx, 'media.quality');
                q = q || pilferLoot?.port[tlqs]()?.[0];
                return q;
            }

            const newQ = hqv();
            if (pilferLoot?.quality[gqy]().nowQ != newQ) {
                pilferLoot?.quality[yqu](hqv()).then((function () {
                    pilferLoot?.quality?.setState({ [hst]: false });
                }
                )).catch((function () {
                    return reject('糟糕..搞砸了...');
                }));
            }
            return resolve('这东西真的管用么?');
        });
    }


})();