Pzdcflix Volume Control - Right Click + Wheel

Управление громкостью на pzdcflix.live: правая кнопка мыши + колесо

ეს სკრიპტი არ უნდა იყოს პირდაპირ დაინსტალირებული. ეს ბიბლიოთეკაა, სხვა სკრიპტებისთვის უნდა ჩართეთ მეტა-დირექტივაში // @require https://update.greasyfork.org/scripts/588222/1882996/Pzdcflix%20Volume%20Control%20-%20Right%20Click%20%2B%20Wheel.js.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Pzdcflix Volume Control - Right Click + Wheel
// @namespace    http://tampermonkey.net/
// @version      2.1.1
// @description  Управление громкостью на pzdcflix.live: правая кнопка мыши + колесо
// @author       YOSS
// @match        https://pzdcflix.live/*
// @grant        none
// @resource     JetBrainsMono https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap
// ==/UserScript==

(function() {
    'use strict';

    let volumeStep = 0.05;
    let volumeDisplay = null;
    let hideTimeout = null;
    let isRightButtonPressed = false;
    let isOverPlayer = false;

    // Подключаем шрифт JetBrains Mono
    function loadFont() {
        const link = document.createElement('link');
        link.href = 'https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&display=swap';
        link.rel = 'stylesheet';
        document.head.appendChild(link);
    }

    // Создаем элемент для отображения громкости
    function createVolumeDisplay() {
        volumeDisplay = document.createElement('div');
        volumeDisplay.id = 'volume-control-display';
        volumeDisplay.style.cssText = `
            position: fixed;
            top: 25%;
            left: 50%;
            transform: translate(-50%, -50%);
            color: rgba(220, 220, 220, 0.9);
            padding: 10px 20px;
            font-size: 20px;
            font-family: 'JetBrains Mono', monospace;
            font-weight: 400;
            z-index: 999999;
            pointer-events: none;
            display: none;
            text-align: center;
            text-shadow: 1px 1px 3px rgba(0, 0, 0, 0.4);
            letter-spacing: 1px;
            transition: opacity 0.2s ease;
        `;
        document.body.appendChild(volumeDisplay);
    }

    // Показать уровень громкости
    function showVolume(volume) {
        if (!volumeDisplay) createVolumeDisplay();

        const volumePercent = Math.round(volume * 100);

        // Позиционируем индикатор относительно проигрывателя
        const video = getActiveVideo();
        if (video) {
            const player = getPlayerContainer(video);
            if (player) {
                const rect = player.getBoundingClientRect();
                volumeDisplay.style.top = `${rect.top + rect.height * 0.25}px`;
                volumeDisplay.style.left = `${rect.left + rect.width / 2}px`;
            }
        }

        // Добавляем плавное появление
        volumeDisplay.style.opacity = '0';
        volumeDisplay.textContent = `${volumePercent}%`;
        volumeDisplay.style.display = 'block';

        requestAnimationFrame(() => {
            volumeDisplay.style.opacity = '1';
        });

        clearTimeout(hideTimeout);
        hideTimeout = setTimeout(() => {
            volumeDisplay.style.opacity = '0';
            setTimeout(() => {
                volumeDisplay.style.display = 'none';
            }, 200);
        }, 1500);
    }

    // Найти активный видеоэлемент
    function getActiveVideo() {
        const videos = document.querySelectorAll('video');

        for (let video of videos) {
            if (!video.paused && video.readyState >= 2) {
                return video;
            }
        }

        for (let video of videos) {
            if (video.offsetParent !== null) {
                return video;
            }
        }

        return videos[0] || null;
    }

    // Найти контейнер проигрывателя
    function getPlayerContainer(video) {
        if (!video) return null;

        const selectors = [
            '.player-container',
            '.video-container',
            '.video-wrapper',
            '.video-player',
            '.player-wrapper',
            '#player',
            '#video-player',
            '[class*="player"]',
            '[class*="video-container"]',
            '[id*="player"]'
        ];

        for (let selector of selectors) {
            const container = video.closest(selector);
            if (container) return container;
        }

        let element = video.parentElement;
        let bestMatch = video;
        let maxArea = 0;

        while (element && element !== document.body && element !== document.documentElement) {
            const rect = element.getBoundingClientRect();
            const area = rect.width * rect.height;

            if (rect.width >= 400 && rect.height >= 300 && area > maxArea) {
                const bodyRect = document.body.getBoundingClientRect();
                if (rect.width < bodyRect.width * 0.9 || rect.height < bodyRect.height * 0.9) {
                    bestMatch = element;
                    maxArea = area;
                }
            }

            element = element.parentElement;
        }

        return bestMatch;
    }

    // Проверяем, находится ли курсор над проигрывателем
    function isCursorOverPlayer(event) {
        const video = getActiveVideo();
        if (!video) return false;

        const player = getPlayerContainer(video);
        if (!player) return false;

        const rect = player.getBoundingClientRect();
        const mouseX = event.clientX;
        const mouseY = event.clientY;

        return mouseX >= rect.left &&
               mouseX <= rect.right &&
               mouseY >= rect.top &&
               mouseY <= rect.bottom;
    }

    // Изменение громкости
    function changeVolume(deltaY) {
        const video = getActiveVideo();
        if (!video) return false;

        const oldVolume = video.volume;
        let newVolume;

        if (deltaY > 0) {
            newVolume = Math.max(0, oldVolume - volumeStep);
        } else {
            newVolume = Math.min(1, oldVolume + volumeStep);
        }

        if (newVolume !== oldVolume) {
            video.volume = newVolume;
            showVolume(newVolume);

            try {
                localStorage.setItem('pzdcflix_volume', newVolume);
            } catch (e) {}
            return true;
        }
        return false;
    }

    // Восстановление громкости
    function restoreVolume(video) {
        if (!video) video = getActiveVideo();
        if (!video) return;

        const savedVolume = localStorage.getItem('pzdcflix_volume');
        if (savedVolume !== null) {
            video.volume = parseFloat(savedVolume);
        }
    }

    // Настройка обработчиков
    function setupEventHandlers() {
        document.addEventListener('mousemove', function(e) {
            isOverPlayer = isCursorOverPlayer(e);
        });

        document.addEventListener('contextmenu', function(e) {
            if (isRightButtonPressed && isOverPlayer) {
                e.preventDefault();
                e.stopPropagation();
                return false;
            }
        }, true);

        document.addEventListener('mousedown', function(e) {
            if (e.button === 2 && isCursorOverPlayer(e)) {
                isRightButtonPressed = true;
                e.preventDefault();
                e.stopPropagation();

                const video = getActiveVideo();
                if (video) {
                    showVolume(video.volume);
                }
            }
        }, true);

        document.addEventListener('mouseup', function(e) {
            if (e.button === 2) {
                isRightButtonPressed = false;

                clearTimeout(hideTimeout);
                if (volumeDisplay) {
                    volumeDisplay.style.opacity = '0';
                    setTimeout(() => {
                        volumeDisplay.style.display = 'none';
                    }, 200);
                }
            }
        }, true);

        document.addEventListener('wheel', function(e) {
            if (isRightButtonPressed && isOverPlayer) {
                e.preventDefault();
                e.stopPropagation();

                if (changeVolume(e.deltaY)) {
                    clearTimeout(hideTimeout);
                    hideTimeout = setTimeout(() => {
                        if (volumeDisplay) {
                            volumeDisplay.style.opacity = '0';
                            setTimeout(() => {
                                volumeDisplay.style.display = 'none';
                            }, 200);
                        }
                    }, 1500);
                }
            }
        }, { passive: false, capture: true });

        document.addEventListener('mouseleave', function() {
            if (isRightButtonPressed) {
                isRightButtonPressed = false;
                isOverPlayer = false;
                if (volumeDisplay) {
                    volumeDisplay.style.display = 'none';
                }
            }
        });

        window.addEventListener('blur', function() {
            isRightButtonPressed = false;
            isOverPlayer = false;
            if (volumeDisplay) {
                volumeDisplay.style.display = 'none';
            }
        });
    }

    // Настройка наблюдения за DOM
    function setupObservers() {
        const observer = new MutationObserver(function(mutations) {
            mutations.forEach(function(mutation) {
                mutation.addedNodes.forEach(function(node) {
                    if (node.nodeName === 'VIDEO') {
                        node.addEventListener('play', function() {
                            restoreVolume(node);
                        });
                        restoreVolume(node);
                    }
                    if (node.querySelectorAll) {
                        const videos = node.querySelectorAll('video');
                        videos.forEach(function(video) {
                            video.addEventListener('play', function() {
                                restoreVolume(video);
                            });
                            restoreVolume(video);
                        });
                    }
                });
            });
        });

        observer.observe(document.body, {
            childList: true,
            subtree: true
        });

        setInterval(() => {
            const video = getActiveVideo();
            if (video) restoreVolume(video);
        }, 2000);
    }

    // Инициализация
    function init() {
        loadFont();
        setupEventHandlers();
        setupObservers();

        setTimeout(() => {
            const video = getActiveVideo();
            if (video) {
                restoreVolume(video);
            }
        }, 1000);
    }

    // Запускаем после полной загрузки страницы
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();