convertSpeedUnit

将网速单位从bit转换为Byte

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name         convertSpeedUnit
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  将网速单位从bit转换为Byte
// @author       ExcuseLme
// @namespace    https://github.com/ExcuseLme
// @match        *://fast.com/*
// @icon         https://fast.com/assets/new-logo-vert-37861c.svg
// @grant        none
// @run-at       document-start
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    const CONFIG = {
        targets: [
            { id: 'speed-value', type: 'value' },
            { id: 'speed-units', type: 'unit' },
            { id: 'upload-value', type: 'value' },
            { id: 'upload-units', type: 'unit' }
        ]
    };

    /**
     * 核心转换逻辑
     */
    function convertValue(raw) {
        let val = parseFloat(raw) / 8;
        if (isNaN(val)) return raw;
        // 遵循原站 Math.round 步进逻辑
        if (val < 9.95) return (Math.round(10 * val) / 10).toFixed(1);
        if (val < 100) return Math.round(val).toString();
        return (10 * Math.round(val / 10)).toString();
    }

    function convertUnit(raw) {
        return raw.replace('Kbps', 'KB/s')
                  .replace('Mbps', 'MB/s')
                  .replace('Gbps', 'GB/s');
    }

    /**
     * 同步并输出审计日志
     */
    function sync(target, original, shadow) {
        const rawText = original.innerText.trim();
        if (!rawText) return;

        let convertedText = (target.type === 'value') ? convertValue(rawText) : convertUnit(rawText);

        if (shadow.innerText !== convertedText) {
            shadow.innerText = convertedText;

            // 日志审计逻辑:仅在数值更新时输出完整链路,避免单位更新时重复输出
            if (target.type === 'value') {
                const isUpload = target.id.includes('upload');
                const unitId = isUpload ? 'upload-units' : 'speed-units';
                const rawUnit = document.getElementById(unitId)?.innerText.trim() || '';
                const convUnit = convertUnit(rawUnit);

                console.log(`%c[speedConvertScript] %c${rawText}${rawUnit} %c-> %c${convertedText}${convUnit}`,
                    "color: #00ADED; font-weight: bold;",
                    "color: #ff4757;",
                    "color: #2f3542;",
                    "color: #2ed573; font-weight: bold;");
            }
        }
    }

    /**
     * 初始化与 DOM 挂载
     */
    function processElement(target) {
        const original = document.getElementById(target.id);
        if (!original || original.dataset.hasShadow) return;

        const shadow = document.createElement(original.tagName);
        shadow.id = `shadow-${target.id}`;
        shadow.className = original.className;

        // 隐藏原件
        original.style.setProperty('display', 'none', 'important');
        original.parentNode.insertBefore(shadow, original);
        original.dataset.hasShadow = 'true';

        // 监听变动
        const observer = new MutationObserver(() => sync(target, original, shadow));
        observer.observe(original, { characterData: true, childList: true, subtree: true });

        // 初始同步
        sync(target, original, shadow);
    }

    // 全局 DOM 守卫
    const mainObserver = new MutationObserver(() => CONFIG.targets.forEach(processElement));

    const init = () => {
        if (document.body) {
            mainObserver.observe(document.body, { childList: true, subtree: true });
            CONFIG.targets.forEach(processElement);
        } else {
            setTimeout(init, 50);
        }
    };

    init();
})();