将网速单位从bit转换为Byte
// ==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();
})();