YouTube Split

Устанавливает сплит по времени

当前为 2025-04-18 提交的版本,查看 最新版本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         YouTube Split
// @namespace    http://tampermonkey.net/
// @version      2.0
// @author       sosal
// @match        *://www.youtube.com/watch*
// @grant        none
// @description Устанавливает сплит по времени 
// ==/UserScript==

(function() {
    'use strict';

    // --- Конфигурация ---
    let splitMinutes = null;    // Значение сплита в минутах, по умолчанию null (сплит не активен)
    let totalVideoMinutes = null; // Общая длительность видео в минутах (округленная вверх), null пока не определена
    const extendCost = 300;     // Стоимость продления +1 минуты в условных рублях
    // ВСТАВЬТЕ СЮДА ПРЯМУЮ ССЫЛКУ НА ВАШ ЗВУК!
    const splitSoundUrl = 'https://github.com/lardan099/donat/raw/refs/heads/main/alert_orig.mp3';
    const localStorageVolumeKey = 'ytSplitAlertVolume'; // Ключ для сохранения громкости в localStorage


    // --- Глобальные переменные состояния ---
    let video = null;           // Элемент видео
    let overlay = null;         // Элемент оверлея
    let splitTriggered = false; // Флаг, что сплит активирован (видео остановлено)
    let audioPlayer = null;     // Для проигрывания звука
    let splitCheckIntervalId = null; // ID интервала проверки сплита (для логики сплита)
    let setupIntervalId = null;      // ID интервала для поиска элементов и добавления панели
    let panelAdded = false; // Флаг, чтобы добавлять панель только один раз

    // --- CSS Стили для улучшения внешнего вида ---
    const styles = `
        /* Стили для панели управления */
        #split-control-panel {
            margin-top: 10px;
            margin-bottom: 15px;
            padding: 10px 15px;
            background: var(--yt-spec-badge-chip-background);
            border: 1px solid var(--yt-spec-border-div);
            border-radius: 8px;
            display: flex;
            flex-wrap: wrap;
            align-items: center;
            gap: 10px 20px;
            color: var(--yt-spec-text-primary);
            font-family: "Roboto", Arial, sans-serif;
            font-size: 14px;
            max-width: var(--ytd-watch-flexy-width);
            width: 100%;
            box-sizing: border-box;
        }

        ytd-watch-flexy:not([use- Sarkis]) #primary #split-control-panel {
            margin-left: auto;
            margin-right: auto;
        }

        #split-control-panel label {
            font-weight: 500;
            color: var(--yt-spec-text-secondary);
            flex-shrink: 0;
            line-height: 1.3;
        }

        #split-control-panel label i {
             font-style: normal;
             font-size: 12px;
             color: var(--yt-spec-text-disabled);
        }

         /* Контейнер для поля ввода и кнопок модификации */
        #split-input-group {
            display: flex;
            align-items: center;
            gap: 5px;
        }

        #split-control-panel input[type="number"] {
            width: 60px;
            padding: 8px 10px;
            background: var(--yt-spec-filled-button-background);
            color: var(--yt-spec-text-primary);
            border: 1px solid var(--yt-spec-action-simulate-border);
            border-radius: 4px;
            text-align: center;
            font-size: 15px;
            -moz-appearance: textfield;
        }

        #split-control-panel input[type="number"]::-webkit-outer-spin-button,
        #split-control-panel input[type="number"]::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }

        /* Стили для всех кнопок внутри панели */
        #split-control-panel button {
            padding: 8px 15px;
            font-size: 15px;
            cursor: pointer;
            background: var(--yt-spec-grey-1);
            color: var(--yt-spec-text-primary);
            border: none;
            border-radius: 4px;
            transition: background 0.2s ease-in-out;
            font-weight: 500;
            flex-shrink: 0;
        }

        #split-control-panel button:hover {
             background: var(--yt-spec-grey-2);
        }

         /* Стили для кнопок модификации сплита (+1, +5 и т.д.) */
        #split-input-group button {
            padding: 8px 10px;
            font-size: 14px;
            background: var(--yt-spec-filled-button-background);
            border: 1px solid var(--yt-spec-action-simulate-border);
        }
         #split-input-group button:hover {
            background: var(--yt-spec-grey-2);
         }

        #split-control-panel button#set-split-button {
             background: var(--yt-spec-brand-suggested-action);
             color: var(--yt-spec-text-reverse);
             order: -1;
             margin-right: auto;
        }
         #split-control-panel button#set-split-button:hover {
             background: var(--yt-spec-brand-suggested-action-hover);
        }

        /* Стили для регулятора громкости */
        #split-volume-control {
             display: flex;
             align-items: center;
             gap: 5px;
        }
         #split-volume-control label {
             font-weight: 500;
             color: var(--yt-spec-text-secondary);
             flex-shrink: 0;
             line-height: normal;
         }
         #split-volume-control input[type="range"] {
             flex-grow: 1;
             min-width: 80px;
             -webkit-appearance: none;
             appearance: none;
             height: 8px;
             background: var(--yt-spec-grey-1);
             outline: none;
             opacity: 0.7;
             transition: opacity .2s;
             border-radius: 4px;
         }
         #split-volume-control input[type="range"]:hover {
             opacity: 1;
         }

        #split-volume-control input[type="range"]::-webkit-slider-thumb {
             -webkit-appearance: none;
             appearance: none;
             width: 15px;
             height: 15px;
             background: var(--yt-spec-brand-button-background);
             cursor: pointer;
             border-radius: 50%;
        }

        #split-volume-control input[type="range"]::-moz-range-thumb {
             width: 15px;
             height: 15px;
             background: var(--yt-spec-brand-button-background);
             cursor: pointer;
             border-radius: 50%;
        }

        /* Стили для элемента с статистикой минут */
        #split-stats {
            font-size: 15px;
            color: var(--yt-spec-text-primary);
            font-weight: 500;
            margin-left: 10px; /* Отступ от других элементов */
        }


        /* Стили для оверлея */
        #split-overlay {
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.95);
            color: white;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            z-index: 99999;
            font-family: "Roboto", Arial, sans-serif;
            text-align: center;
            padding: 20px;
            box-sizing: border-box;
        }

        #split-overlay #split-warning-message {
            font-size: clamp(24px, 4vw, 36px);
            margin-bottom: 15px;
            color: yellow;
            font-weight: bold;
            text-shadow: 0 0 8px rgba(255, 255, 0, 0.5);
        }

        #split-overlay #split-main-message {
            font-size: clamp(40px, 8vw, 72px);
            font-weight: bold;
            margin-bottom: 40px;
            color: red;
            text-shadow: 0 0 15px rgba(255, 0, 0, 0.7);
        }

        #split-extend-buttons {
            display: flex;
            gap: 15px;
            flex-wrap: wrap;
            justify-content: center;
        }

        #split-extend-buttons button {
            padding: 12px 25px;
            font-size: clamp(18px, 3vw, 24px);
            cursor: pointer;
            background: var(--yt-spec-red-500);
            border: none;
            color: white;
            border-radius: 4px;
            font-weight: bold;
            transition: background 0.2s ease-in-out;
        }

        #split-extend-buttons button:hover {
            background: var(--yt-spec-red-600);
        }
    `;

    // --- Вспомогательная функция для внедрения CSS ---
    function injectStyles() {
        if (document.getElementById('yt-split-styles')) {
            return;
        }
        const styleElement = document.createElement("style");
        styleElement.id = 'yt-split-styles';
        styleElement.textContent = styles;
        document.head.appendChild(styleElement);
         console.log("YouTube Split: Стили внедрены.");
    }

    // Обновление отображения значения сплита в спинере
    // Эта функция теперь вызывается только при добавлении панели и при изменении global splitMinutes
    function updateSplitDisplay() {
        const inputField = document.getElementById("split-input");
        if (inputField) {
            inputField.valueAsNumber = splitMinutes === null ? 0 : splitMinutes;
        }
        updateSplitStatsDisplay(); // Обновляем также статистику
    }

    // Обновление отображения статистики выкупленных/всего минут
    function updateSplitStatsDisplay() {
        const statsElement = document.getElementById("split-stats");
        if (statsElement) {
             const boughtMinutes = splitMinutes === null ? 0 : splitMinutes;
             const totalMinutesText = totalVideoMinutes !== null ? `${totalVideoMinutes}` : '?';
             statsElement.textContent = `Выкуплено: ${boughtMinutes} / Всего: ${totalMinutesText} минут`;
        }
    }


     // Функция для изменения значения в поле ввода сплита
     // Эта функция вызывается кнопками +/- и меняет ТОЛЬКО ПОЛЕ ВВОДА
     function modifySplitInput(minutesToModify) {
         const inputField = document.getElementById("split-input");
         if (!inputField) return;

         let currentVal = inputField.valueAsNumber;

         if (isNaN(currentVal)) {
             currentVal = 0;
         }

         let newVal = currentVal + minutesToModify;

         if (newVal < 0) {
             newVal = 0;
         }

         inputField.valueAsNumber = newVal;
         // Не обновляем global splitMinutes здесь и не вызываем updateSplitDisplay()
     }

    // Функция для запуска интервала проверки сплита
    function startSplitCheckInterval() {
        if (!splitCheckIntervalId) {
            splitCheckIntervalId = setInterval(checkSplitCondition, 500);
             console.log("YouTube Split: Запущена проверка сплита (interval).");
        }
    }

    // Функция для остановки интервала проверки сплита
    function stopSplitCheckInterval() {
        if (splitCheckIntervalId) {
            clearInterval(splitCheckIntervalId);
            splitCheckIntervalId = null;
             console.log("YouTube Split: Проверка сплита остановлена.");
        }
    }

    // Создание панели управления сплитом и вставка ее под видео
    // Эта функция вызывается, когда нужный контейнер уже найден и panelAdded === false
    function addControlPanel(primaryContainer) {
        if (panelAdded) {
            ensurePanelPosition();
            updateSplitDisplay(); // Обновим поле ввода и статистику на существующей панели
            return;
        }

        if (!primaryContainer) {
             console.error("YouTube Split: addControlPanel вызвана без primaryContainer!");
             return;
        }

        const panel = document.createElement("div");
        panel.id = "split-control-panel";

        // --- Кнопка "НАЧАТЬ СПЛИТ" ---
        const setButton = document.createElement("button");
        setButton.id = "set-split-button";
        setButton.textContent = "НАЧАТЬ СПЛИТ"; // Начальный текст
        setButton.addEventListener("click", function() {
            const inputField = document.getElementById("split-input");
            const inputVal = inputField.valueAsNumber;

            if (!isNaN(inputVal) && inputVal >= 0) {
                const oldSplitMinutes = splitMinutes;
                splitMinutes = inputVal; // Устанавливаем активный сплит из поля ввода

                 if (splitMinutes > 0) {
                     startSplitCheckInterval(); // Запускаем проверку если сплит > 0
                      setButton.textContent = "СПЛИТ НАЧАТ"; // Меняем текст кнопки
                       setButton.style.background = 'var(--yt-spec-call-to-action)'; // Опционально: меняем цвет кнопки

                     if (video) {
                         const thresholdSeconds = splitMinutes * 60;
                         if (video.currentTime >= thresholdSeconds) {
                             video.pause();
                             splitTriggered = true;
                             showOverlay();
                             if(splitSoundUrl && audioPlayer && audioPlayer.src !== 'ВАША_ПРЯМАЯ_ССЫЛКА_НА_ЗВУКОВОЙ_ФАЙЛ_ТУТ'){
                                 audioPlayer.pause();
                                 audioPlayer.currentTime = 0;
                                 audioPlayer.play().catch(e => console.error("YouTube Split: Ошибка при воспроизведении звука:", e));
                             }
                         } else {
                             splitTriggered = false;
                             removeOverlay();
                             if (video.paused && oldSplitMinutes === null) {
                                 video.play();
                             }
                         }
                     }

                 } else { // splitMinutes === 0
                     stopSplitCheckInterval();
                     splitTriggered = false;
                     removeOverlay();
                     setButton.textContent = "НАЧАТЬ СПЛИТ"; // Возвращаем текст кнопки
                     setButton.style.background = 'var(--yt-spec-brand-suggested-action)'; // Возвращаем цвет кнопки

                     if (video && video.paused && oldSplitMinutes !== null && oldSplitMinutes > 0) {
                         video.play();
                     }
                 }
                 // Убеждаемся, что поле ввода и статистика показывают актуальное *активное* значение после нажатия
                 updateSplitDisplay();
                 updateSplitStatsDisplay(); // Обновляем статистику
            } else {
                alert("Введите корректное число минут.");
            }
        });

        // --- Метка "Сплит (мин):" (Исправление TrustedHTML) ---
        const label = document.createElement("label");
        label.setAttribute("for", "split-input");

        const labelTextMain = document.createTextNode("Сплит (мин):");
        const breakElement = document.createElement("br");
        const italicElement = document.createElement("i");
        const labelTextInstruction = document.createTextNode("(уст. перед \"Начать\")");

        label.appendChild(labelTextMain);
        label.appendChild(breakElement);
        italicElement.appendChild(labelTextInstruction);
        label.appendChild(italicElement);

        // --- Группа ввода сплита и +/- кнопок ---
        const inputGroup = document.createElement("div");
        inputGroup.id = "split-input-group";

        const inputField = document.createElement("input");
        inputField.type = "number";
        inputField.id = "split-input";
        inputField.min = "0";
        inputField.valueAsNumber = splitMinutes === null ? 0 : splitMinutes;

         const modifyButtons = [
             { text: '-10', minutes: -10 },
             { text: '-5', minutes: -5 },
             { text: '-1', minutes: -1 },
             { text: '+1', minutes: 1 },
             { text: '+5', minutes: 5 },
             { text: '+10', minutes: 10 },
             { text: '+20', minutes: 20 }
         ];

         modifyButtons.forEach(btnInfo => {
             const button = document.createElement("button");
             button.textContent = btnInfo.text;
             button.addEventListener("click", () => modifySplitInput(btnInfo.minutes));
             inputGroup.appendChild(button);
         });

        inputGroup.insertBefore(inputField, inputGroup.children[0]);


        // --- Регулятор громкости алерта ---
        const volumeControlGroup = document.createElement("div");
        volumeControlGroup.id = "split-volume-control";

        const volumeLabel = document.createElement("label");
        volumeLabel.setAttribute("for", "split-volume-slider");
        volumeLabel.textContent = "Громкость алерта:";

        const volumeSlider = document.createElement("input");
        volumeSlider.type = "range";
        volumeSlider.id = "split-volume-slider";
        volumeSlider.min = "0";
        volumeSlider.max = "1"; // HTMLMediaElement volume is typically 0 to 1
        volumeSlider.step = "0.05"; // Adjust step for finer control

         // Установка начального значения громкости из localStorage (или дефолт)
        let savedVolume = localStorage.getItem(localStorageVolumeKey);
        if (savedVolume === null) {
             savedVolume = '0.5'; // Громкость по умолчанию 50%
        }
        volumeSlider.value = savedVolume;

        // Обработчик изменения громкости
        volumeSlider.addEventListener("input", function() {
             // Применяем громкость к аудиоплееру, если он есть
             if (audioPlayer) {
                 audioPlayer.volume = parseFloat(this.value); // Убедимся, что это число
             }
             // Сохраняем значение в localStorage
             localStorage.setItem(localStorageVolumeKey, this.value);
        });

        volumeControlGroup.appendChild(volumeLabel);
        volumeControlGroup.appendChild(volumeSlider);


        // --- Статистика выкупленных/всего минут ---
        const statsElement = document.createElement("span");
        statsElement.id = "split-stats";
        // Начальный текст будет установлен функцией updateSplitStatsDisplay

        // --- Собираем панель ---
        panel.appendChild(setButton);
        panel.appendChild(label);
        panel.appendChild(inputGroup);
        panel.appendChild(volumeControlGroup); // Добавляем регулятор громкости
        panel.appendChild(statsElement); // Добавляем статистику


        // Вставляем панель в найденный контейнер (#primary) как первый дочерний элемент
        primaryContainer.insertBefore(panel, primaryContainer.firstChild);
        panelAdded = true; // Устанавливаем флаг, что панель добавлена
        console.log("YouTube Split: Панель управления добавлена под видео.");

        // Убедимся, что поле ввода и статистика показывают актуальное значение после добавления
        updateSplitDisplay(); // Обновляет и поле ввода, и статистику
    }

     // Функция для проверки и корректировки позиции панели
     // Вызывается из setupElementsAndPanel
     function ensurePanelPosition() {
         if (!panelAdded) return;

         const panel = document.getElementById("split-control-panel");
         const primaryContainer = document.querySelector("ytd-watch-flexy #primary");

         // Проверяем, существует ли панель и правильный ли у нее родитель
         if (panel && primaryContainer) {
             if (primaryContainer.firstChild !== panel) {
                  console.log("YouTube Split: Панель сместилась, перемещаем обратно.");
                  primaryContainer.insertBefore(panel, primaryContainer.firstChild);
             }
         }
          // Если панель есть, а контейнера нет, setupElementsAndPanel ее удалит.
     }


    function addMinutesToActiveSplit(minutesToAdd) {
        // Эта функция вызывается только когда сплит уже активен (splitMinutes не null)
        if (splitMinutes === null) return;

        splitMinutes += minutesToAdd;
        updateSplitDisplay(); // Обновляем поле ввода на панели и статистику

        const thresholdSeconds = splitMinutes * 60;

        if (video && video.currentTime < thresholdSeconds) {
            removeOverlay();
            splitTriggered = false;
            video.play();
        }
         // Оверлей остается, если продления недостаточно
    }

    // Проверка времени видео (вызывается только когда splitCheckIntervalId активен)
    function checkSplitCondition() {
        // Ищем видео каждый раз, на случай его пересоздания YouTube
        if (!video) {
            video = document.querySelector("video");
            if (!video) {
                 console.log("YouTube Split: Видеоэлемент не найден в checkSplitCondition, останавливаем проверку сплита.");
                 stopSplitCheckInterval();
                 splitTriggered = false;
                 removeOverlay();
                 return;
            }
             // Убеждаемся, что аудио плеер есть и громкость применена
             initAudioPlayer();
             const volumeSlider = document.getElementById('split-volume-slider');
             if(audioPlayer && volumeSlider) audioPlayer.volume = parseFloat(volumeSlider.value); // Применяем актуальную громкость
        }

        // Обновляем totalVideoMinutes, если он еще не определен и duration доступна
        if (totalVideoMinutes === null && video && isFinite(video.duration) && video.duration > 0) {
             totalVideoMinutes = Math.ceil(video.duration / 60); // Округляем вверх
             console.log(`YouTube Split: Общая длительность видео определена: ${totalVideoMinutes} минут.`);
             updateSplitStatsDisplay(); // Обновляем статистику с новым значением total
        }


        // Проверяем условие сплита только если splitMinutes активно (не null и > 0)
        if (splitMinutes !== null && splitMinutes > 0) {
            const thresholdSeconds = splitMinutes * 60;

            if (video.currentTime >= thresholdSeconds && !splitTriggered) {
                video.pause();
                splitTriggered = true;
                showOverlay();
                 // Воспроизводим звук при первом триггере
                if(splitSoundUrl && audioPlayer && audioPlayer.src !== 'ВАША_ПРЯМАЯ_ССЫЛКА_НА_ЗВУКОВОЙ_ФАЙЛ_ТУТ'){
                     audioPlayer.pause();
                     audioPlayer.currentTime = 0;
                     audioPlayer.play().catch(e => console.error("YouTube Split: Ошибка при воспроизведении звука:", e));
                }
            }
            if (splitTriggered && video.currentTime < thresholdSeconds) {
                removeOverlay();
                splitTriggered = false;
                video.play();
            }
        } else {
             // Если splitMinutes стал null или 0 во время работы проверки
             stopSplitCheckInterval();
             splitTriggered = false;
             removeOverlay();
             if (video && video.paused) video.play();
        }
    }

    function showOverlay() {
        if (overlay) return;

        overlay = document.createElement("div");
        overlay.id = "split-overlay";

        const warningMessage = document.createElement("div");
        warningMessage.id = "split-warning-message";
        warningMessage.textContent = "⚠️ НУЖНО ДОНАТНОЕ ТОПЛИВО ⚠️";

        const splitMessage = document.createElement("div");
        splitMessage.id = "split-main-message";
        splitMessage.textContent = "СПЛИТ НЕ ОПЛАЧЕН";

        const extendButtonsContainer = document.createElement("div");
        extendButtonsContainer.id = "split-extend-buttons";

        const extendButtonConfigs = [
             { minutes: 1, cost: extendCost },
             { minutes: 5, cost: extendCost * 5 },
             { minutes: 10, cost: extendCost * 10 },
             { minutes: 20, cost: extendCost * 20 }
        ];

        extendButtonConfigs.forEach(config => {
            const button = document.createElement("button");
            button.textContent = `+ ${config.minutes} минут${getMinuteEnding(config.minutes)} - ${config.cost} рублей`;
            button.addEventListener("click", function() {
                addMinutesToActiveSplit(config.minutes);
            });
            extendButtonsContainer.appendChild(button);
        });

        overlay.appendChild(warningMessage);
        overlay.appendChild(splitMessage);
        overlay.appendChild(extendButtonsContainer);

        document.body.appendChild(overlay);
        console.log("YouTube Split: Оверлей показан.");
    }

    function getMinuteEnding(count) {
        const lastDigit = count % 10;
        const lastTwoDigits = count % 100;

        if (lastTwoDigits >= 11 && lastTwoDigits <= 14) {
            return '';
        }
        if (lastDigit === 1) {
            return 'а';
        }
        if (lastDigit >= 2 && lastDigit <= 4) {
            return 'ы';
        }
        return '';
    }

    function removeOverlay() {
        if (overlay) {
            overlay.remove();
            overlay = null;
            if (audioPlayer) {
                 audioPlayer.pause();
                 audioPlayer.currentTime = 0;
            }
             console.log("YouTube Split: Оверлей убран.");
        }
    }

     // Инициализация аудио плеера и установка громкости
     function initAudioPlayer() {
         if (splitSoundUrl && splitSoundUrl !== 'ВАША_ПРЯМАЯ_ССЫЛКА_НА_ЗВУКОВОЙ_ФАЙЛ_ТУТ') {
             if (!audioPlayer || audioPlayer.src !== splitSoundUrl) {
                  if (audioPlayer) {
                     audioPlayer.pause();
                     audioPlayer = null;
                  }
                 audioPlayer = new Audio(splitSoundUrl);
                 audioPlayer.preload = 'auto';
                 audioPlayer.onerror = (e) => console.error("YouTube Split: Не удалось загрузить или воспроизвести звук:", e);
                 console.log("YouTube Split: Аудио плеер инициализирован.");

                 // Применяем сохраненную громкость после создания плеера
                 let savedVolume = localStorage.getItem(localStorageVolumeKey);
                 if (savedVolume !== null) {
                      audioPlayer.volume = parseFloat(savedVolume);
                 } else {
                      audioPlayer.volume = 0.5; // Громкость по умолчанию
                 }
             }
         } else {
             console.warn("YouTube Split: URL звука для сплита не указан или является плейсхолдером.");
              if (audioPlayer) {
                 audioPlayer.pause();
                 audioPlayer = null;
             }
         }
     }

    // --- Главная функция, вызываемая по интервалу для поиска элементов и настройки ---
    function setupElementsAndPanel() {
        injectStyles();
        initAudioPlayer(); // Инициализируем аудио плеер

        video = document.querySelector("video"); // Обновляем ссылку на видео
        const primaryContainer = document.querySelector("ytd-watch-flexy #primary");
        const panel = document.getElementById("split-control-panel");


        if (video && primaryContainer) {
             // Элементы найдены
             if (!panelAdded) {
                 console.log("YouTube Split: Видео и контейнер #primary найдены. Добавляем панель.");
                 addControlPanel(primaryContainer); // Передаем найденный контейнер
             } else {
                  ensurePanelPosition();
                  // updateSplitDisplay() НЕ вызывается здесь
                  // updateSplitStatsDisplay() НЕ вызывается здесь
                  // updateSplitDisplay() вызывается при изменении splitMinutes
                  // updateSplitStatsDisplay() вызывается при изменении splitMinutes И totalVideoMinutes
             }

             // Проверяем длительность видео, если она еще не определена
            if (totalVideoMinutes === null && isFinite(video.duration) && video.duration > 0) {
                totalVideoMinutes = Math.ceil(video.duration / 60);
                console.log(`YouTube Split: Общая длительность видео определена: ${totalVideoMinutes} минут.`);
                 if (panelAdded) { // Если панель уже есть, обновляем статистику
                     updateSplitStatsDisplay();
                 }
            }


        } else {
            // Элементы еще не найдены
            if (panelAdded) {
                 console.log("YouTube Split: Необходимые элементы отсутствуют, удаляем панель и сбрасываем состояние.");
                 const existingPanel = document.getElementById("split-control-panel");
                 if(existingPanel) existingPanel.remove();
                 panelAdded = false; // Сбрасываем флаг
                 // Не сбрасываем splitMinutes на null здесь
            }
             video = null; // Сбрасываем видео, если оно пропало
             totalVideoMinutes = null; // Сбрасываем длительность, если видео пропало
        }
    }

    // --- Запуск скрипта ---

    if (!setupIntervalId) {
        setupIntervalId = setInterval(setupElementsAndPanel, 500);
         console.log("YouTube Split: Запущен основной интервал поиска элементов.");
    }


    // Очистка при уходе со страницы или навигации по SPA
    let lastUrl = location.href;
    const urlObserver = new MutationObserver(() => {
        if (location.href !== lastUrl) {
            lastUrl = location.href;
            console.log("YouTube Split: URL changed, cleaning up and re-initializing.");

            stopSplitCheckInterval();
            if (setupIntervalId) {
                 clearInterval(setupIntervalId);
                 setupIntervalId = null;
            }

             if (audioPlayer) {
                 audioPlayer.pause();
             }
             removeOverlay();

            const oldPanel = document.getElementById("split-control-panel");
            if (oldPanel) {
                oldPanel.remove();
            }
            const oldStyles = document.getElementById("yt-split-styles");
             if(oldStyles) oldStyles.remove();

            splitMinutes = null; // Сбрасываем сплит
            totalVideoMinutes = null; // Сбрасываем общую длительность
            video = null;
            splitTriggered = false;
            panelAdded = false; // Сбрасываем флаг

            if (!setupIntervalId) {
                 setupIntervalId = setInterval(setupElementsAndPanel, 500);
                 console.log("YouTube Split: Перезапущен основной интервал поиска элементов после смены URL.");
            }
        }
    });

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


    window.addEventListener('beforeunload', function() {
         console.log("YouTube Split: Очистка при выгрузке страницы.");
        stopSplitCheckInterval();
        if (setupIntervalId) {
            clearInterval(setupIntervalId);
            setupIntervalId = null;
        }
         if (audioPlayer) {
            audioPlayer.pause();
            audioPlayer = null;
         }
        if (urlObserver) {
             urlObserver.disconnect();
        }
    });


})();