Nút Picture-in-Picture (PIP) Đa Năng

Bản tối ưu: Giao diện cài đặt mới. Hỗ trợ shortcut, cài đặt, tự động dịch và tự đóng. Tối ưu cấu trúc và sửa lỗi tương thích.

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Nút Picture-in-Picture (PIP) Đa Năng
// @namespace    http://tampermonkey.net/
// @version      5.5
// @description  Bản tối ưu: Giao diện cài đặt mới. Hỗ trợ shortcut, cài đặt, tự động dịch và tự đóng. Tối ưu cấu trúc và sửa lỗi tương thích.
// @author       Lu (Refactored by Gemini)
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Gom các giá trị hằng số vào một nơi để dễ quản lý.
    const CONSTANTS = {
        SETTINGS_PANEL_Z_INDEX: 10001,
        BUTTON_CONTAINER_Z_INDEX: 10000,
        SETTINGS_PANEL_HIDE_DELAY: 3000, // ms
        SETTINGS_PANEL_FORCE_HIDE_DELAY: 7000, // ms
    };

    // --- MODULE QUẢN LÝ CÀI ĐẶT ---
    const Settings = {
        config: {},
        defaults: {
            isAlwaysOn: false,
            customShortcut: 'CMD+SHIFT+P',
            language: 'auto',
            loopButtonEnabled: true,
        },
        load() {
            for (const key in this.defaults) {
                this.config[key] = GM_getValue(key, this.defaults[key]);
            }
        },
        save(key, value) {
            this.config[key] = value;
            GM_setValue(key, value);
        }
    };

    // --- MODULE ĐA NGÔN NGỮ ---
    const I18n = {
        translations: {
            en: { settingsTitle: "PIP Settings", alwaysOnLabel: "Always show buttons", shortcutLabel: "Shortcut Key", shortcutPrefix: "CMD/CTRL + SHIFT +", languageLabel: "Language", autoLang: "Auto-detect", loopButtonLabel: "Show Loop button", loopButtonTitle: "Toggle Loop", recordingShortcut: "Press a key...", blockedWarning: "This shortcut is blocked by the browser!", conflictWarning: "Note: May conflict with other extensions.", settingButtonTitle: "PIP Settings" },
            vi: { settingsTitle: "Cài đặt PIP", alwaysOnLabel: "Luôn hiển thị nút", shortcutLabel: "Phím tắt", shortcutPrefix: "CMD/CTRL + SHIFT +", languageLabel: "Ngôn ngữ", autoLang: "Tự động", loopButtonLabel: "Hiển thị nút Lặp lại", loopButtonTitle: "Bật/Tắt Lặp lại", recordingShortcut: "Nhấn một phím...", blockedWarning: "Phím tắt này bị trình duyệt chặn!", conflictWarning: "Lưu ý: Có thể trùng với tiện ích khác.", settingButtonTitle: "Cài đặt PIP" }
        },
        getLang() {
            const lang = Settings.config.language;
            return lang === 'auto' ? (navigator.language.startsWith('vi') ? 'vi' : 'en') : lang;
        },
        t(key) {
            const lang = this.getLang();
            // Sửa lỗi tương thích ESLint bằng cách bỏ Optional Chaining (`?.`)
            return (this.translations[lang] && this.translations[lang][key]) || this.translations.en[key];
        }
    };

    // --- MODULE QUẢN LÝ GIAO DIỆN ---
    const UI = {
        settingsPanel: null,
        panelCloseTimer: null,
        isRecordingShortcut: false,
        BLOCKED_SHORTCUTS: ['CMD+SHIFT+Q', 'CTRL+SHIFT+Q', 'CMD+SHIFT+W', 'CTRL+SHIFT+W', 'CMD+SHIFT+T', 'CTRL+SHIFT+T', 'CMD+SHIFT+R', 'CTRL+SHIFT+R', 'CMD+SHIFT+L', 'CTRL+SHIFT+L', 'CMD+SHIFT+F', 'CTRL+SHIFT+F', 'CMD+SHIFT+N', 'CTRL+SHIFT+N'],

        createIcon(type, size = 'default') {
            const iconSizes = {
                small: { iconSize: 16, dimensions: { w: 16, h: 11, lw: 1.2, rW: 6, rH: 4, rX: 8, rY: 5 } },
                medium: { iconSize: 18, dimensions: { w: 18, h: 13, lw: 1.5, rW: 7, rH: 5, rX: 9, rY: 6 } },
                default: { iconSize: 22, dimensions: { w: 22, h: 16, lw: 2, rW: 9, rH: 6, rX: 11, rY: 8 } }
            };
            const { iconSize, dimensions } = iconSizes[size];

            if (type === 'pip') {
                const canvas = document.createElement('canvas');
                canvas.width = dimensions.w;
                canvas.height = dimensions.h;
                const ctx = canvas.getContext('2d');
                if (ctx) {
                    ctx.strokeStyle = 'white';
                    ctx.lineWidth = dimensions.lw;
                    ctx.strokeRect(1, 1, dimensions.w - 2, dimensions.h - 2);
                    ctx.fillStyle = 'white';
                    ctx.fillRect(dimensions.rX, dimensions.rY, dimensions.rW, dimensions.rH);
                }
                return canvas;
            }
            // Sử dụng template literal để SVG dễ đọc hơn.
            if (type === 'settings') return `
                <svg xmlns="http://www.w3.org/2000/svg" width="${iconSize}" height="${iconSize}" viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M12 2a10 10 0 1 0 10 10c0-2.28-.81-4.4-2.18-6.08a10.04 10.04 0 0 0-1.82-2.32A10.04 10.04 0 0 0 12 2zm0 13a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/>
                    <path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"/>
                </svg>`;
            if (type === 'loop') return `
                <svg width="${iconSize}" height="${iconSize}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
                    <path d="M17 1l4 4-4 4"/><path d="M3 11V9a4 4 0 0 1 4-4h14"/>
                    <path d="M7 23l-4-4 4-4"/><path d="M21 13v2a4 4 0 0 1-4 4H3"/>
                </svg>`;
        },

        injectStyles() {
            const styles = `
                .Lu-pip-settings-panel {
                    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
                    position: fixed; z-index: ${CONSTANTS.SETTINGS_PANEL_Z_INDEX};
                    background-color: rgba(40, 40, 40, 0.8);
                    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
                    color: white; border-radius: 0.75rem; padding: 1rem;
                    box-shadow: 0 4px 12px rgba(0,0,0,0.4); display: none;
                    width: 17.5rem; border: 1px solid rgba(255, 255, 255, 0.1);
                }
                .Lu-pip-settings-panel h3 { margin: 0 0 0.75rem 0; font-size: 1rem; border-bottom: 1px solid #444; padding-bottom: 0.5rem; }
                .Lu-pip-settings-row { display: flex; align-items: center; justify-content: space-between; font-size: 0.875rem; padding: 0.5rem 0.25rem; }
                .settings-group { margin-top: 0.5rem; padding-top: 0.5rem; border-top: 1px solid rgba(255, 255, 255, 0.1); }
                .shortcut-container { display: flex; align-items: center; gap: 0.3125rem; }
                #Lu-pip-language-select { background-color: #333; color: white; border: 1px solid #555; border-radius: 0.375rem; padding: 0.375rem; cursor: pointer; }
                #Lu-pip-shortcut-input { border: 1px solid #555; background-color: #333; padding: 0.375rem 0.625rem; border-radius: 0.375rem; text-align: center; font-weight: 500; min-width: 3.125rem; transition: all 0.2s; cursor: pointer; }
                #Lu-pip-shortcut-input.recording { background-color: #007aff; color: white; border-color: #007aff; }
                #Lu-pip-shortcut-warning { color: #ffcc00; font-size: 0.6875rem; text-align: right; margin-top: 0.25rem; height: 0.875rem; }
                .Lu-pip-control-button { background-color: transparent; border: none; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; transition: background-color 0.2s ease-in-out, transform 0.2s ease-in-out; }
                .Lu-pip-control-button:hover { background-color: rgba(255, 255, 255, 0.15); transform: scale(1.1); }
                .Lu-pip-loop-button.active { background-color: #007aff; }
                .Lu-pip-loop-button.active:hover { background-color: #0056b3; }
                .switch { position: relative; display: inline-block; width: 34px; height: 20px; flex-shrink: 0; }
                .switch input { opacity: 0; width: 0; height: 0; }
                .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #444; transition: .4s; border-radius: 20px; }
                .slider:before { position: absolute; content: ""; height: 14px; width: 14px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; }
                input:checked + .slider { background-color: #007aff; }
                input:checked + .slider:before { transform: translateX(14px); }
            `;
            const styleSheet = document.createElement("style");
            styleSheet.innerText = styles;
            document.head.appendChild(styleSheet);
        },

        createSettingsPanel() {
            this.injectStyles();
            const panel = document.createElement('div');
            panel.className = 'Lu-pip-settings-panel';
            panel.innerHTML = `
                <h3 data-lang-key="settingsTitle"></h3>
                <div class="Lu-pip-settings-row">
                    <span data-lang-key="languageLabel"></span>
                    <select id="Lu-pip-language-select">
                        <option value="auto" data-lang-key="autoLang"></option>
                        <option value="en">English</option><option value="vi">Tiếng Việt</option>
                    </select>
                </div>
                <div class="settings-group">
                    <div class="Lu-pip-settings-row">
                        <span data-lang-key="alwaysOnLabel"></span>
                        <label class="switch"><input type="checkbox" id="Lu-pip-always-on"><span class="slider"></span></label>
                    </div>
                    <div class="Lu-pip-settings-row">
                        <span data-lang-key="loopButtonLabel"></span>
                        <label class="switch"><input type="checkbox" id="Lu-pip-loop-enabled"><span class="slider"></span></label>
                    </div>
                </div>
                <div class="settings-group">
                    <div class="Lu-pip-settings-row">
                        <span data-lang-key="shortcutLabel"></span>
                        <div class="shortcut-container">
                            <span data-lang-key="shortcutPrefix"></span>
                            <div id="Lu-pip-shortcut-input"></div>
                        </div>
                    </div>
                    <div class="Lu-pip-settings-row" style="justify-content: flex-end;">
                        <small id="Lu-pip-shortcut-warning"></small>
                    </div>
                </div>
            `;
            document.body.appendChild(panel);
            this.settingsPanel = panel;
            this.bindPanelEvents();
            this.updatePanelUI();
        },

        updatePanelUI() {
            this.settingsPanel.querySelectorAll('[data-lang-key]').forEach(el => {
                el.textContent = I18n.t(el.dataset.langKey);
            });
            this.settingsPanel.querySelector('#Lu-pip-always-on').checked = Settings.config.isAlwaysOn;
            this.settingsPanel.querySelector('#Lu-pip-loop-enabled').checked = Settings.config.loopButtonEnabled;
            this.settingsPanel.querySelector('#Lu-pip-shortcut-input').textContent = Settings.config.customShortcut.split('+').pop();
            this.settingsPanel.querySelector('#Lu-pip-language-select').value = Settings.config.language;
        },

        bindPanelEvents() {
            const { settingsPanel } = this;
            const alwaysOnCheckbox = settingsPanel.querySelector('#Lu-pip-always-on');
            const loopCheckbox = settingsPanel.querySelector('#Lu-pip-loop-enabled');
            const shortcutInput = settingsPanel.querySelector('#Lu-pip-shortcut-input');
            const langSelect = settingsPanel.querySelector('#Lu-pip-language-select');

            const hidePanel = () => {
                if (settingsPanel.style.display === 'block') {
                    settingsPanel.style.display = 'none';
                }
                clearTimeout(this.panelCloseTimer);
                if (this.isRecordingShortcut) {
                    this.stopRecordingShortcut(shortcutInput, true); // Cancel recording
                }
            };

            document.addEventListener('click', hidePanel);
            settingsPanel.addEventListener('click', (e) => e.stopPropagation());
            settingsPanel.addEventListener('mouseenter', () => clearTimeout(this.panelCloseTimer));
            settingsPanel.addEventListener('mouseleave', () => {
                this.panelCloseTimer = setTimeout(hidePanel, CONSTANTS.SETTINGS_PANEL_HIDE_DELAY);
            });

            langSelect.addEventListener('change', () => {
                Settings.save('language', langSelect.value);
                this.updatePanelUI();
            });

            alwaysOnCheckbox.addEventListener('change', () => {
                Settings.save('isAlwaysOn', alwaysOnCheckbox.checked);
                document.querySelectorAll('.Lu-pip-button-container').forEach(container => {
                    this.updateButtonVisibility(container, container.parentElement);
                });
            });

            loopCheckbox.addEventListener('change', () => {
                Settings.save('loopButtonEnabled', loopCheckbox.checked);
                document.querySelectorAll('.Lu-pip-loop-button').forEach(btn => {
                    btn.style.display = Settings.config.loopButtonEnabled ? 'flex' : 'none';
                });
            });

            shortcutInput.addEventListener('click', () => this.startRecordingShortcut(shortcutInput));
        },

        startRecordingShortcut(inputEl) {
            if (this.isRecordingShortcut) return;
            this.isRecordingShortcut = true;

            inputEl.textContent = '...';
            inputEl.classList.add('recording');
            this.settingsPanel.querySelector('#Lu-pip-shortcut-warning').textContent = I18n.t('recordingShortcut');

            const handleRecording = (e) => {
                e.preventDefault();
                e.stopPropagation();

                const key = e.key.toUpperCase();
                if (!['CONTROL', 'SHIFT', 'ALT', 'META'].includes(key) && key.length === 1 && /[A-Z0-9]/.test(key)) {
                    const newShortcut = `CMD+SHIFT+${key}`;
                    const newShortcutCtrl = `CTRL+SHIFT+${key}`;
                    if (this.BLOCKED_SHORTCUTS.includes(newShortcut) || this.BLOCKED_SHORTCUTS.includes(newShortcutCtrl)) {
                        this.settingsPanel.querySelector('#Lu-pip-shortcut-warning').textContent = I18n.t('blockedWarning');
                    } else {
                        Settings.save('customShortcut', newShortcut);
                        this.settingsPanel.querySelector('#Lu-pip-shortcut-warning').textContent = I18n.t('conflictWarning');
                    }
                }
                this.stopRecordingShortcut(inputEl);
            };

            const captureOptions = { capture: true, once: true };
            window.addEventListener('keydown', handleRecording, captureOptions);
        },

        stopRecordingShortcut(inputEl, cancelled = false) {
            if (!this.isRecordingShortcut) return;
            if (!cancelled) {
                inputEl.textContent = Settings.config.customShortcut.split('+').pop();
            } else {
                // Restore previous text if cancelled
                this.updatePanelUI();
                this.settingsPanel.querySelector('#Lu-pip-shortcut-warning').textContent = '';
            }
            inputEl.classList.remove('recording');
            this.isRecordingShortcut = false;
        },
        
        showSettingsPanel(anchorButton) {
            clearTimeout(this.panelCloseTimer);
            const buttonRect = anchorButton.getBoundingClientRect();

            // Calculate position before showing to avoid flicker
            this.settingsPanel.style.visibility = 'hidden';
            this.settingsPanel.style.display = 'block';
            const panelRect = this.settingsPanel.getBoundingClientRect();
            
            let top = buttonRect.top - panelRect.height - 10; // Position above button
            let left = buttonRect.right - panelRect.width;

            // Adjust if out of viewport
            if (top < 10) top = buttonRect.bottom + 10;
            if (top + panelRect.height > window.innerHeight - 10) top = window.innerHeight - panelRect.height - 10;
            if (left < 10) left = 10;
            
            this.settingsPanel.style.top = `${top}px`;
            this.settingsPanel.style.left = `${left}px`;
            
            this.settingsPanel.style.visibility = 'visible';
            
            this.panelCloseTimer = setTimeout(() => {
                this.settingsPanel.style.display = 'none';
            }, CONSTANTS.SETTINGS_PANEL_FORCE_HIDE_DELAY);
        },

        updateButtonVisibility(container, parent) {
            const isHovering = parent.matches(':hover');
            const shouldBeVisible = Settings.config.isAlwaysOn || isHovering;
            container.style.opacity = shouldBeVisible ? '1' : '0';
            container.style.pointerEvents = shouldBeVisible ? 'auto' : 'none';
        },

        addButtonsToVideo(videoElement) {
            if (videoElement.dataset.pipButtonsAdded) return;
            videoElement.dataset.pipButtonsAdded = 'true';

            const parent = videoElement.parentElement;
            if (getComputedStyle(parent).position === 'static') {
                parent.style.position = 'relative';
            }

            const buttonContainer = document.createElement('div');
            buttonContainer.className = 'Lu-pip-button-container';
            Object.assign(buttonContainer.style, {
                position: 'absolute', top: '10px', right: '10px',
                zIndex: CONSTANTS.BUTTON_CONTAINER_Z_INDEX,
                backgroundColor: 'rgba(28, 28, 28, 0.8)',
                borderRadius: '9999px', padding: '4px',
                display: 'flex', gap: '4px',
                opacity: '0', pointerEvents: 'none',
                transition: 'opacity 0.2s ease-in-out, right 0.2s ease-in-out, top 0.2s ease-in-out',
            });

            const createButton = (className, title, innerHTML) => {
                const button = document.createElement('button');
                button.className = `Lu-pip-control-button ${className}`;
                button.title = title;
                if (innerHTML) button.innerHTML = innerHTML;
                buttonContainer.appendChild(button);
                return button;
            };

            const loopButton = createButton('Lu-pip-loop-button', I18n.t('loopButtonTitle'));
            const pipButton = createButton('Lu-pip-button', 'Picture-in-Picture');
            const settingsButton = createButton('Lu-pip-settings-button', I18n.t('settingButtonTitle'));
            parent.appendChild(buttonContainer);
            
            const updateButtonAttributes = () => {
                const videoHeight = videoElement.clientHeight;
                let size = 'default';
                if (videoHeight < 200) size = 'small';
                else if (videoHeight < 360) size = 'medium';

                const buttonSizes = { small: 28, medium: 32, default: 40 };
                const buttonSize = buttonSizes[size];

                pipButton.innerHTML = ''; pipButton.appendChild(this.createIcon('pip', size));
                settingsButton.innerHTML = this.createIcon('settings', size);
                loopButton.innerHTML = this.createIcon('loop', size);

                [pipButton, settingsButton, loopButton].forEach(btn => {
                    btn.style.width = `${buttonSize}px`;
                    btn.style.height = `${buttonSize}px`;
                });

                // Logic to avoid overlapping existing buttons
                let topPos = 10;
                const parentRect = parent.getBoundingClientRect();
                const nativeControls = parent.querySelectorAll('button, [role="button"]');
                for (const control of nativeControls) {
                    if (control.closest('.Lu-pip-button-container') || control.offsetParent === null) continue;
                    const controlRect = control.getBoundingClientRect();
                    // If a control is in the top-right corner area
                    if (controlRect.top - parentRect.top < 45 && parentRect.right - controlRect.right < 150) {
                        topPos = 50;
                        break;
                    }
                }
                buttonContainer.style.top = `${topPos}px`;
            };

            updateButtonAttributes();
            new ResizeObserver(updateButtonAttributes).observe(videoElement);

            pipButton.addEventListener('click', async (e) => {
                e.stopPropagation();
                try {
                    if (videoElement !== document.pictureInPictureElement) {
                        await videoElement.requestPictureInPicture();
                    } else {
                        await document.exitPictureInPicture();
                    }
                } catch (error) {
                    console.error('PIP Error:', error);
                }
            });
            
            settingsButton.addEventListener('click', (e) => {
                e.stopPropagation();
                this.showSettingsPanel(settingsButton);
            });
            
            loopButton.addEventListener('click', (e) => {
                e.stopPropagation();
                videoElement.loop = !videoElement.loop;
                loopButton.classList.toggle('active', videoElement.loop);
            });

            loopButton.style.display = Settings.config.loopButtonEnabled ? 'flex' : 'none';
            loopButton.classList.toggle('active', videoElement.loop);

            parent.addEventListener('mouseenter', () => this.updateButtonVisibility(buttonContainer, parent));
            parent.addEventListener('mouseleave', () => this.updateButtonVisibility(buttonContainer, parent));
            
            // Initial visibility check
            this.updateButtonVisibility(buttonContainer, parent);
        }
    };

    // --- MODULE ỨNG DỤNG CHÍNH ---
    const App = {
        uiInitialized: false,

        isElementInViewport(el) {
            const rect = el.getBoundingClientRect();
            return rect.bottom > 0 && rect.right > 0 && rect.top < window.innerHeight && rect.left < window.innerWidth;
        },

        async handlePipShortcut(e) {
            if (UI.isRecordingShortcut) return;

            const shortcutParts = Settings.config.customShortcut.split('+');
            const key = shortcutParts.pop();
            const isModifierPressed = e.shiftKey && (e.metaKey || e.ctrlKey);

            if (e.key.toUpperCase() === key && isModifierPressed) {
                e.preventDefault();
                try {
                    if (document.pictureInPictureElement) {
                        await document.exitPictureInPicture();
                        return;
                    }
                    
                    const videos = Array.from(document.querySelectorAll('video'))
                        .filter(v => this.isElementInViewport(v) && v.readyState > 2 && v.disablePictureInPicture === false)
                        .sort((a, b) => {
                            // Ưu tiên video đang phát
                            if (!a.paused && b.paused) return -1;
                            if (a.paused && !b.paused) return 1;
                            // Ưu tiên video có diện tích lớn hơn
                            const areaA = a.clientWidth * a.clientHeight;
                            const areaB = b.clientWidth * b.clientHeight;
                            return areaB - areaA;
                        });

                    if (videos.length > 0) {
                        await videos[0].requestPictureInPicture();
                    }
                } catch (error) {
                    console.error('PIP Shortcut Error:', error);
                }
            }
        },

        scanForVideos() {
            const videos = document.querySelectorAll('video:not([data-pip-buttons-added])');
            if (videos.length > 0) {
                if (!this.uiInitialized) {
                    this.activateFeatures();
                }
                videos.forEach(video => UI.addButtonsToVideo(video));
            }
        },

        activateFeatures() {
            if (this.uiInitialized) return;
            this.uiInitialized = true;
            UI.createSettingsPanel();
            document.addEventListener('keydown', (e) => this.handlePipShortcut(e));
        },

        init() {
            Settings.load();
            
            this.scanForVideos();

            const observer = new MutationObserver(() => this.scanForVideos());
            observer.observe(document.body, { childList: true, subtree: true });
        }
    };

    // --- KHỞI CHẠY SCRIPT ---
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => App.init());
    } else {
        App.init();
    }
})();