HUSH+ Control Panel

HTML5 Universal Speed Hack PLUS với menu vuông kéo thả

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         HUSH+ Control Panel
// @namespace    http://tampermonkey.net/
// @version      2.0
// @description  HTML5 Universal Speed Hack PLUS với menu vuông kéo thả
// @author       Dựa trên HUSH+
// @match        *://88bet.hiphop/*
// @match        *://rt.ccvgame.mobi/*
// @match        *://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_addStyle
// @run-at       document-start
// ==/UserScript==

(function() {
    'use strict';
    
    // --- Cấu hình mặc định ---
    const defaultConfig = {
        speed: GM_getValue("hush-speed", 1.0),
        cbSetIntervalChecked: GM_getValue("hush-si", true),
        cbSetTimeoutChecked: GM_getValue("hush-st", true),
        cbPerformanceNowChecked: GM_getValue("hush-pn", true),
        cbDateNowChecked: GM_getValue("hush-dn", true),
        cbRequestAnimationFrameChecked: GM_getValue("hush-raf", false)
    };

    // ==================== PHẦN 1: CORE LOGIC (TỪ contentScript.js) ====================
    function pageScript() {
        let speedConfig = {
            speed: 1.0,
            cbSetIntervalChecked: true,
            cbSetTimeoutChecked: true,
            cbPerformanceNowChecked: true,
            cbDateNowChecked: true,
            cbRequestAnimationFrameChecked: false,
        };

        const emptyFunction = () => {};

        const originalClearInterval = window.clearInterval;
        const originalclearTimeout = window.clearTimeout;

        const originalSetInterval = window.setInterval;
        const originalSetTimeout = window.setTimeout;

        const originalPerformanceNow = window.performance.now.bind(
            window.performance
        );

        const originalDateNow = Date.now;

        const originalRequestAnimationFrame = window.requestAnimationFrame;

        let timers = [];
        const reloadTimers = () => {
            console.log(timers);
            const newtimers = [];
            timers.forEach((timer) => {
                originalClearInterval(timer.id);
                if (timer.customTimerId) {
                    originalClearInterval(timer.customTimerId);
                }
                if (!timer.finished) {
                    const newTimerId = originalSetInterval(
                        timer.handler,
                        speedConfig.cbSetIntervalChecked
                            ? timer.timeout / speedConfig.speed
                            : timer.timeout,
                        ...timer.args
                    );
                    timer.customTimerId = newTimerId;
                    newtimers.push(timer);
                }
            });
            timers = newtimers;
        };

        window.addEventListener("message", (e) => {
            if (e.data.command === "setSpeedConfig") {
                speedConfig = e.data.config;
                reloadTimers();
            }
        });

        window.postMessage({ command: "getSpeedConfig" });

        window.clearInterval = (id) => {
            originalClearInterval(id);
            timers.forEach((timer) => {
                if (timer.id == id) {
                    timer.finished = true;
                    if (timer.customTimerId) {
                        originalClearInterval(timer.customTimerId);
                    }
                }
            });
        };

        window.clearTimeout = (id) => {
            originalclearTimeout(id);
            timers.forEach((timer) => {
                if (timer.id == id) {
                    timer.finished = true;
                    if (timer.customTimerId) {
                        originalclearTimeout(timer.customTimerId);
                    }
                }
            });
        };

        window.setInterval = (handler, timeout, ...args) => {
            console.log("timeout  ", timeout);
            if (!timeout) timeout = 0;
            const id = originalSetInterval(
                handler,
                speedConfig.cbSetIntervalChecked ? timeout / speedConfig.speed : timeout,
                ...args
            );
            timers.push({
                id: id,
                handler: handler,
                timeout: timeout,
                args: args,
                finished: false,
                customTimerId: null,
            });
            return id;
        };

        window.setTimeout = (handler, timeout, ...args) => {
            if (!timeout) timeout = 0;
            return originalSetTimeout(
                handler,
                speedConfig.cbSetTimeoutChecked ? timeout / speedConfig.speed : timeout,
                ...args
            );
        };

        // performance.now
        (function () {
            let performanceNowValue = null;
            let previusPerformanceNowValue = null;
            window.performance.now = () => {
                const originalValue = originalPerformanceNow();
                if (performanceNowValue) {
                    performanceNowValue +=
                        (originalValue - previusPerformanceNowValue) *
                        (speedConfig.cbPerformanceNowChecked ? speedConfig.speed : 1);
                } else {
                    performanceNowValue = originalValue;
                }
                previusPerformanceNowValue = originalValue;
                return Math.floor(performanceNowValue);
            };
        })();

        // Date.now
        (function () {
            let dateNowValue = null;
            let previusDateNowValue = null;
            Date.now = () => {
                const originalValue = originalDateNow();
                if (dateNowValue) {
                    dateNowValue +=
                        (originalValue - previusDateNowValue) *
                        (speedConfig.cbDateNowChecked ? speedConfig.speed : 1);
                } else {
                    dateNowValue = originalValue;
                }
                previusDateNowValue = originalValue;
                return Math.floor(dateNowValue);
            };
        })();

        // requestAnimationFrame
        (function () {
            let dateNowValue = null;
            let previusDateNowValue = null;
            const callbackFunctions = [];
            const callbackTick = [];
            const newRequestAnimationFrame = (callback) => {
                return originalRequestAnimationFrame((timestamp) => {
                    const originalValue = originalDateNow();
                    if (dateNowValue) {
                        dateNowValue +=
                            (originalValue - previusDateNowValue) *
                            (speedConfig.cbRequestAnimationFrameChecked
                                ? speedConfig.speed
                                : 1);
                    } else {
                        dateNowValue = originalValue;
                    }
                    previusDateNowValue = originalValue;

                    const dateNowValue_MathFloor = Math.floor(dateNowValue);

                    const index = callbackFunctions.indexOf(callback);
                    let tickFrame = null;
                    if (index == -1) {
                        callbackFunctions.push(callback);
                        callbackTick.push(0);
                        callback(dateNowValue_MathFloor);
                    } else if (speedConfig.cbRequestAnimationFrameChecked) {
                        tickFrame = callbackTick[index];
                        tickFrame += speedConfig.speed;

                        if (tickFrame >= 1) {
                            while (tickFrame >= 1) {
                                callback(dateNowValue_MathFloor);
                                window.requestAnimationFrame = emptyFunction;
                                tickFrame -= 1;
                            }
                            window.requestAnimationFrame = newRequestAnimationFrame;
                        } else {
                            window.requestAnimationFrame(callback);
                        }
                        callbackTick[index] = tickFrame;
                    } else {
                        callback(dateNowValue_MathFloor);
                    }
                });
            };
            window.requestAnimationFrame = newRequestAnimationFrame;
        })();
    }

    // Hàm chèn pageScript vào trang web
    function injectScript() {
        const script = document.createElement("script");
        script.setAttribute("type", "text/javascript");
        script.textContent = `!${pageScript.toString()}()\n//# sourceURL=pageScript.js`;
        document.documentElement.appendChild(script);
    }
    // ==================== KẾT THÚC PHẦN 1 ====================

    // Chạy injectScript ngay lập tức
    injectScript();

    // --- Cấu hình và lưu trữ ---
    let speedConfig = {
        speed: GM_getValue("hush-speed", 1.0),
        cbSetIntervalChecked: GM_getValue("hush-si", true),
        cbSetTimeoutChecked: GM_getValue("hush-st", true),
        cbPerformanceNowChecked: GM_getValue("hush-pn", true),
        cbDateNowChecked: GM_getValue("hush-dn", true),
        cbRequestAnimationFrameChecked: GM_getValue("hush-raf", false)
    };

    // Lắng nghe yêu cầu cấu hình từ pageScript
    window.addEventListener("message", (e) => {
        if (e.data.command === "getSpeedConfig") {
            window.postMessage({
                command: "setSpeedConfig",
                config: speedConfig,
            }, "*");
        }
    });

    // Gửi cấu hình mới đến pageScript và lưu lại
    function updateConfig(newConfig) {
        for (let key in newConfig) {
            if (newConfig.hasOwnProperty(key)) {
                speedConfig[key] = newConfig[key];
            }
        }
        window.postMessage({
            command: "setSpeedConfig",
            config: speedConfig,
        }, "*");
        
        GM_setValue("hush-speed", speedConfig.speed);
        GM_setValue("hush-si", speedConfig.cbSetIntervalChecked);
        GM_setValue("hush-st", speedConfig.cbSetTimeoutChecked);
        GM_setValue("hush-pn", speedConfig.cbPerformanceNowChecked);
        GM_setValue("hush-dn", speedConfig.cbDateNowChecked);
        GM_setValue("hush-raf", speedConfig.cbRequestAnimationFrameChecked);
    }

    // ==================== TẠO GIAO DIỆN MENU VUÔNG ====================
    
    // Thêm CSS
    GM_addStyle(`
        /* Menu vuông nhỏ */
        #hush-square-menu {
            position: fixed;
            top: 20px;
            right: 20px;
            width: 50px;
            height: 50px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 12px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.3);
            cursor: move;
            z-index: 999998;
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-size: 24px;
            font-weight: bold;
            transition: transform 0.2s;
            user-select: none;
            border: 2px solid rgba(255,255,255,0.2);
        }
        #hush-square-menu:hover {
            transform: scale(1.05);
            box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
        }
        
        /* Bảng điều khiển chính */
        #hush-control-panel {
            position: fixed;
            top: 80px;
            right: 20px;
            width: 300px;
            background: white;
            border-radius: 16px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.2);
            z-index: 999999;
            display: none;
            overflow: hidden;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
            border: 1px solid #e0e0e0;
            backdrop-filter: blur(10px);
            animation: slideIn 0.3s ease;
        }
        
        @keyframes slideIn {
            from {
                opacity: 0;
                transform: translateY(-10px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }
        
        #hush-control-panel.show {
            display: block;
        }
        
        /* Header của bảng */
        .hush-panel-header {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 15px;
            font-weight: bold;
            font-size: 16px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            cursor: move;
        }
        
        .hush-panel-header span {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .hush-close-btn {
            background: rgba(255,255,255,0.2);
            border: none;
            color: white;
            width: 24px;
            height: 24px;
            border-radius: 6px;
            cursor: pointer;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 18px;
            transition: background 0.2s;
        }
        
        .hush-close-btn:hover {
            background: rgba(255,255,255,0.3);
        }
        
        /* Nội dung bảng */
        .hush-panel-content {
            padding: 20px;
            background: white;
        }
        
        /* Slider */
        .hush-slider-container {
            margin-bottom: 20px;
        }
        
        .hush-slider-label {
            display: flex;
            justify-content: space-between;
            margin-bottom: 8px;
            color: #333;
            font-weight: 500;
        }
        
        .hush-speed-value {
            color: #667eea;
            font-weight: bold;
        }
        
        .hush-slider {
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: #e0e0e0;
            outline: none;
            -webkit-appearance: none;
        }
        
        .hush-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            width: 20px;
            height: 20px;
            border-radius: 50%;
            background: #667eea;
            cursor: pointer;
            box-shadow: 0 2px 6px rgba(102,126,234,0.4);
            transition: transform 0.1s;
        }
        
        .hush-slider::-webkit-slider-thumb:hover {
            transform: scale(1.1);
        }
        
        .hush-minimap {
            display: flex;
            justify-content: space-between;
            margin-top: 6px;
            color: #999;
            font-size: 10px;
            padding: 0 2px;
        }
        
        /* Checkbox group */
        .hush-checkbox-group {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        
        .hush-checkbox-group label {
            display: flex;
            align-items: center;
            gap: 10px;
            color: #444;
            cursor: pointer;
            font-size: 14px;
            padding: 4px 0;
        }
        
        .hush-checkbox-group input[type="checkbox"] {
            width: 18px;
            height: 18px;
            cursor: pointer;
            accent-color: #667eea;
        }
        
        /* Footer */
        .hush-panel-footer {
            padding: 15px 20px;
            background: #f8f9fa;
            border-top: 1px solid #e0e0e0;
            font-size: 12px;
            color: #666;
            text-align: center;
        }
        
        /* Trạng thái active cho menu */
        #hush-square-menu.active {
            background: linear-gradient(135deg, #5a67d8 0%, #6b46a1 100%);
            box-shadow: 0 0 20px rgba(102,126,234,0.6);
        }
    `);

    // Tạo menu vuông
    const squareMenu = document.createElement('div');
    squareMenu.id = 'hush-square-menu';
    squareMenu.innerHTML = '⚡';
    squareMenu.title = 'HUSH+ Speed Control';

    // Tạo bảng điều khiển
    const controlPanel = document.createElement('div');
    controlPanel.id = 'hush-control-panel';
    controlPanel.innerHTML = `
        <div class="hush-panel-header" id="hush-panel-header">
            <span>
                <span>⚡</span>
                HUSH+ Speed Control
            </span>
            <button class="hush-close-btn" id="hush-close-btn">✕</button>
        </div>
        <div class="hush-panel-content">
            <div class="hush-slider-container">
                <div class="hush-slider-label">
                    <span>Tốc độ</span>
                    <span class="hush-speed-value" id="hush-speed-display">${speedConfig.speed.toFixed(2)}x</span>
                </div>
                <input type="range" class="hush-slider" id="hush-speed-slider" 
                       min="0.05" max="25" step="0.05" value="${speedConfig.speed}">
                <div class="hush-minimap">
                    <span>0x</span><span>5x</span><span>10x</span><span>15x</span><span>20x</span><span>25x</span>
                </div>
            </div>
            
            <div class="hush-checkbox-group">
                <label>
                    <input type="checkbox" id="cb-si" ${speedConfig.cbSetIntervalChecked ? 'checked' : ''}>
                    <span>Override setInterval</span>
                </label>
                <label>
                    <input type="checkbox" id="cb-st" ${speedConfig.cbSetTimeoutChecked ? 'checked' : ''}>
                    <span>Override setTimeout</span>
                </label>
                <label>
                    <input type="checkbox" id="cb-pn" ${speedConfig.cbPerformanceNowChecked ? 'checked' : ''}>
                    <span>Override performance.now</span>
                </label>
                <label>
                    <input type="checkbox" id="cb-dn" ${speedConfig.cbDateNowChecked ? 'checked' : ''}>
                    <span>Override Date.now</span>
                </label>
                <label>
                    <input type="checkbox" id="cb-raf" ${speedConfig.cbRequestAnimationFrameChecked ? 'checked' : ''}>
                    <span>Override requestAnimationFrame</span>
                </label>
            </div>
        </div>
        <div class="hush-panel-footer">
            Click ⚡ để mở/đóng • Kéo để di chuyển
        </div>
    `;

    // Thêm vào body khi trang đã sẵn sàng
    if (document.body) {
        document.body.appendChild(squareMenu);
        document.body.appendChild(controlPanel);
    } else {
        window.addEventListener('DOMContentLoaded', () => {
            document.body.appendChild(squareMenu);
            document.body.appendChild(controlPanel);
        });
    }

    // ==================== KẾT NỐI SỰ KIỆN ====================

    const speedSlider = document.getElementById('hush-speed-slider');
    const speedDisplay = document.getElementById('hush-speed-display');
    const cbSi = document.getElementById('cb-si');
    const cbSt = document.getElementById('cb-st');
    const cbPn = document.getElementById('cb-pn');
    const cbDn = document.getElementById('cb-dn');
    const cbRaf = document.getElementById('cb-raf');
    const closeBtn = document.getElementById('hush-close-btn');

    // Xử lý mở/đóng bảng
    squareMenu.addEventListener('click', (e) => {
        e.stopPropagation();
        controlPanel.classList.toggle('show');
        squareMenu.classList.toggle('active');
    });

    // Nút đóng
    closeBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        controlPanel.classList.remove('show');
        squareMenu.classList.remove('active');
    });

    // Click outside để đóng
    document.addEventListener('click', (e) => {
        if (!controlPanel.contains(e.target) && !squareMenu.contains(e.target)) {
            controlPanel.classList.remove('show');
            squareMenu.classList.remove('active');
        }
    });

    // Hàm gửi cập nhật từ UI
    function sendUpdateFromUI() {
        const newConfig = {
            speed: parseFloat(speedSlider.value),
            cbSetIntervalChecked: cbSi.checked,
            cbSetTimeoutChecked: cbSt.checked,
            cbPerformanceNowChecked: cbPn.checked,
            cbDateNowChecked: cbDn.checked,
            cbRequestAnimationFrameChecked: cbRaf.checked,
        };
        speedDisplay.textContent = newConfig.speed.toFixed(2) + 'x';
        updateConfig(newConfig);
    }

    speedSlider.addEventListener('input', sendUpdateFromUI);
    cbSi.addEventListener('change', sendUpdateFromUI);
    cbSt.addEventListener('change', sendUpdateFromUI);
    cbPn.addEventListener('change', sendUpdateFromUI);
    cbDn.addEventListener('change', sendUpdateFromUI);
    cbRaf.addEventListener('change', sendUpdateFromUI);

    // ==================== TÍNH NĂNG KÉO THẢ ====================

    // Kéo menu vuông
    let isDraggingSquare = false;
    let squareOffsetX, squareOffsetY;

    squareMenu.addEventListener('mousedown', (e) => {
        if (e.target === squareMenu) {
            isDraggingSquare = true;
            squareOffsetX = e.clientX - squareMenu.offsetLeft;
            squareOffsetY = e.clientY - squareMenu.offsetTop;
            squareMenu.style.cursor = 'grabbing';
            e.preventDefault();
        }
    });

    // Kéo bảng điều khiển (qua header)
    let isDraggingPanel = false;
    let panelOffsetX, panelOffsetY;
    const panelHeader = document.getElementById('hush-panel-header');

    panelHeader.addEventListener('mousedown', (e) => {
        isDraggingPanel = true;
        panelOffsetX = e.clientX - controlPanel.offsetLeft;
        panelOffsetY = e.clientY - controlPanel.offsetTop;
        panelHeader.style.cursor = 'grabbing';
        e.preventDefault();
    });

    document.addEventListener('mousemove', (e) => {
        if (isDraggingSquare) {
            const newLeft = e.clientX - squareOffsetX;
            const newTop = e.clientY - squareOffsetY;
            
            // Giới hạn trong viewport
            squareMenu.style.left = Math.max(0, Math.min(window.innerWidth - squareMenu.offsetWidth, newLeft)) + 'px';
            squareMenu.style.top = Math.max(0, Math.min(window.innerHeight - squareMenu.offsetHeight, newTop)) + 'px';
            squareMenu.style.right = 'auto';
        }
        
        if (isDraggingPanel) {
            const newLeft = e.clientX - panelOffsetX;
            const newTop = e.clientY - panelOffsetY;
            
            controlPanel.style.left = Math.max(0, Math.min(window.innerWidth - controlPanel.offsetWidth, newLeft)) + 'px';
            controlPanel.style.top = Math.max(0, Math.min(window.innerHeight - controlPanel.offsetHeight, newTop)) + 'px';
            controlPanel.style.right = 'auto';
        }
    });

    document.addEventListener('mouseup', () => {
        if (isDraggingSquare) {
            isDraggingSquare = false;
            squareMenu.style.cursor = 'move';
        }
        if (isDraggingPanel) {
            isDraggingPanel = false;
            panelHeader.style.cursor = 'move';
        }
    });

    // Chặn kéo thả ảnh hưởng đến các sự kiện khác
    squareMenu.addEventListener('dragstart', (e) => e.preventDefault());
    panelHeader.addEventListener('dragstart', (e) => e.preventDefault());

})();