HH3D Video Player - Lệ Phi Vũ

Tua, auto next, menu nổi khi xem phim trên hoathinh3d.gg/xem-phim

// ==UserScript==
// @name         HH3D Video Player - Lệ Phi Vũ
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  Tua, auto next, menu nổi khi xem phim trên hoathinh3d.gg/xem-phim
// @match        https://hoathinh3d.gg/xem-phim*
// @author       Lệ Phi Vũ
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function () {
    'use strict';

    // === Load từ localStorage
    const savedSec = localStorage.getItem("vh_seek_sec") || "60";
    const savedPercent = localStorage.getItem("vh_auto_next") || "95";

    const style = `
    #vh-menu {
        position: fixed;
        top: 100px;
        left: 20px;
        background: rgba(0, 0, 0, 0.9);
        color: gold;
        padding: 10px;
        border-radius: 12px;
        z-index: 999999;
        font-family: Arial, sans-serif;
        user-select: none;
        min-width: 200px;
    }
    #vh-menu h3 {
        margin: 0;
        font-size: 14px;
        cursor: pointer;
        text-align: center;
        border-bottom: 1px solid gold;
        border-radius: 12px;
        padding-bottom: 4px;
    }
    #vh-body {
        margin-top: 6px;
    }
    #vh-body.hidden {
        display: none;
    }
    #vh-body input {
        width: 60px;
        background: black;
        color: gold;
        border: 1px solid gold;
        border-radius: 4px;
        margin-left: 5px;
    }
    `;
    const styleTag = document.createElement('style');
    styleTag.innerHTML = style;
    document.head.appendChild(styleTag);

    const menu = document.createElement('div');
    menu.id = 'vh-menu';
    menu.innerHTML = `
        <h3 id="vh-title">🎬 HH3D Xem Phim</h3>
        <div id="vh-body">
            <div>
                Tua đến (giây): <input id="vh-seek-sec" type="number" min="0" value="${savedSec}">
            </div>
            <div>
                Auto Next (%): <input id="vh-next-percent" type="number" min="0" max="100" value="${savedPercent}">
            </div>
        </div>
    `;
    document.body.appendChild(menu);

    // === Cập nhật nhãn tên phim + tập + tiến trình
    function updateTitle() {
        const titleEl = document.querySelector('h1.entry-title a');
        const video = getVideo();
        let titleText = '🎬 HH3D Xem Phim';
        if (titleEl) {
            const fullTitle = titleEl.textContent.trim();
            const match = fullTitle.match(/(.+?) Tập (\d+)/);
            if (match) {
                const name = match[1];
                const ep = match[2];
                titleText = `📺 ${name} - Tập ${ep}`;
            }
        }
        if (video && video.duration) {
            const percent = ((video.currentTime / video.duration) * 100).toFixed(0);
            titleText += ` (${percent}%)`;
        }
        document.getElementById('vh-title').textContent = titleText;
    }

    // === Thu gọn khi click tiêu đề
    document.getElementById('vh-title').addEventListener('click', () => {
        const body = document.getElementById('vh-body');
        body.classList.toggle('hidden');
    });

    // === Lưu khi người dùng thay đổi (chỉ chấp nhận số)
    document.getElementById('vh-seek-sec').addEventListener('change', e => {
        const value = parseFloat(e.target.value);
        if (!isNaN(value) && value >= 0) {
            localStorage.setItem("vh_seek_sec", value.toString());
        } else {
            e.target.value = localStorage.getItem("vh_seek_sec") || "60";
        }
    });
    document.getElementById('vh-next-percent').addEventListener('change', e => {
        const value = parseFloat(e.target.value);
        if (!isNaN(value) && value >= 0 && value <= 100) {
            localStorage.setItem("vh_auto_next", value.toString());
        } else {
            e.target.value = localStorage.getItem("vh_auto_next") || "95";
        }
    });

    // === Tìm video
    function getVideo() {
        return document.querySelector('video');
    }

    // === Theo dõi thời lượng video và cập nhật tiêu đề
    setInterval(() => {
        const video = getVideo();
        if (video && video.duration) {
            const percent = ((video.currentTime / video.duration) * 100).toFixed(1);
            const threshold = parseFloat(document.getElementById('vh-next-percent').value || "95");
            if (percent >= threshold && !video.__nexted) {
                video.__nexted = true;
                const nextBtn = document.querySelector('.epfull .active + a');
                if (nextBtn) {
                    window.location.href = nextBtn.href;
                }
            }
            updateTitle(); // Cập nhật tiêu đề với tiến trình
        }
    }, 1000);

    // === Tua video đến số giây được chỉ định
    function seekToSavedTime() {
        const video = getVideo();
        if (video) {
            const sec = parseFloat(document.getElementById('vh-seek-sec').value);
            if (!isNaN(sec) && sec >= 0) {
                video.currentTime = sec;
            }
        }
    }

    // === Phím tắt
    document.addEventListener('keydown', (e) => {
        const video = getVideo();
        if (!video) return;

        switch (e.key) {
            case '+': {
                const nextBtn = document.querySelector('.luotxem.halim-next-episode');
                if (nextBtn) {
                    nextBtn.click();
                    setTimeout(seekToSavedTime, 1000); // Chờ video tải rồi tua
                }
                break;
            }
            case '-': {
                const prevBtn = document.querySelector('.luotxem.halim-prev-episode');
                if (prevBtn) {
                    prevBtn.click();
                    setTimeout(seekToSavedTime, 1000); // Chờ video tải rồi tua
                }
                break;
            }
            case '*': {
                const sec = parseFloat(document.getElementById('vh-seek-sec').value);
                if (!isNaN(sec) && sec >= 0) video.currentTime = sec;
                break;
            }
        }
    });

    // === Di chuyển menu (hỗ trợ 4 hướng)
    let isDragging = false;
    let offsetX = 0, offsetY = 0;
    const title = document.getElementById('vh-title');

    title.addEventListener('mousedown', (e) => {
        isDragging = true;
        offsetX = e.clientX - menu.offsetLeft;
        offsetY = e.clientY - menu.offsetTop;
        e.preventDefault();
    });

    document.addEventListener('mouseup', () => isDragging = false);
    document.addEventListener('mousemove', (e) => {
        if (isDragging) {
            menu.style.left = `${e.clientX - offsetX}px`;
            menu.style.top = `${e.clientY - offsetY}px`;
        }
    });

    // === Đảm bảo menu hiển thị khi fullscreen
    const ensureMenuInFullscreen = () => {
        const fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
        if (fullscreenElement && !fullscreenElement.contains(menu)) {
            fullscreenElement.appendChild(menu);
            menu.style.zIndex = '999999';
        } else if (!document.body.contains(menu)) {
            document.body.appendChild(menu);
        }
    };

    // Theo dõi sự kiện thay đổi toàn màn hình
    document.addEventListener('fullscreenchange', ensureMenuInFullscreen);
    document.addEventListener('webkitfullscreenchange', ensureMenuInFullscreen);
    document.addEventListener('mozfullscreenchange', ensureMenuInFullscreen);
    document.addEventListener('MSFullscreenChange', ensureMenuInFullscreen);

    // Gọi lần đầu để đảm bảo menu hiển thị đúng
    ensureMenuInFullscreen();
})();