YouTube Split (Improved + Sound + Panel Buttons + Under Video - Fixed)

Устанавливает сплит по времени (только после нажатия "НАЧАТЬ СПЛИТ"), выводит панель управления под видео с кнопками настройки и громкости, показывает оверлей "СПЛИТ НЕ ОПЛАЧЕН" с кнопками продления и проигрывает звук при достижении порога. Исправлены ошибки.

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

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         YouTube Split (Improved + Sound + Panel Buttons + Under Video - Fixed)
// @namespace    http://tampermonkey.net/
// @version      1.9 // Повышаем версию
// @author       sosal
// @match        *://www.youtube.com/watch*
// @grant        none
// @description Устанавливает сплит по времени (только после нажатия "НАЧАТЬ СПЛИТ"), выводит панель управления под видео с кнопками настройки и громкости, показывает оверлей "СПЛИТ НЕ ОПЛАЧЕН" с кнопками продления и проигрывает звук при достижении порога. Исправлены ошибки.
// ==/UserScript==

(function() {
    'use strict';

    // --- Конфигурация ---
    let splitMinutes = 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; /* Сброс line-height для этой метки */
         }
         #split-volume-control input[type="range"] {
             flex-grow: 1; /* Занимает доступное место */
             min-width: 80px; /* Минимальная ширина слайдера */
             -webkit-appearance: none; /* Удаляем стандартный стиль Chrome/Safari */
             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;
         }

         /* Стили для ползунка (Chrome/Safari) */
        #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%; /* Круглый ползунок */
        }

        /* Стили для ползунка (Firefox) */
        #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-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;
        }
    }

     // Функция для изменения значения в поле ввода сплита
     // Эта функция вызывается кнопками +/- и меняет ТОЛЬКО ПОЛЕ ВВОДА
     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;
     }

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

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

    // Создание панели управления сплитом и вставка ее под видео
    // Эта функция вызывается, когда нужный контейнер уже найден и panelAdded === false
    function addControlPanel(primaryContainer) {
        if (panelAdded) { // Дополнительная проверка, хотя setupElementsAndPanel тоже проверяет
            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; // Устанавливаем активный сплит из поля ввода
                // updateSplitDisplay(); // Не вызываем здесь, чтобы не мешать modifySplitInput

                 if (splitMinutes > 0) {
                     startSplitCheckInterval(); // Запускаем проверку если сплит > 0

                     // Проверяем условие сразу после установки, только если видео найдено
                     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();
                              // Если видео было на паузе *до* нажатия "НАЧАТЬ СПЛИТ" (т.е. сплит был null), и новое время сплита не достигнуто, запускаем
                             if (video.paused && oldSplitMinutes === null) {
                                 video.play();
                             }
                         }
                     }

                 } else { // splitMinutes === 0
                     stopSplitCheckInterval();
                     splitTriggered = false;
                     removeOverlay();
                     if (video && video.paused && oldSplitMinutes !== null && oldSplitMinutes > 0) {
                         video.play();
                     }
                 }
                 // Убеждаемся, что поле ввода показывает актуальное *активное* значение после нажатия
                 updateSplitDisplay();


            } 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);
        // --- Конец Исправления TrustedHTML ---


        // --- Группа ввода сплита и +/- кнопок ---
        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";
        // Начальное значение будет установлено функцией updateSplitDisplay при добавлении
        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 = this.value;
             }
             // Сохраняем значение в localStorage
             localStorage.setItem(localStorageVolumeKey, this.value);
        });

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

        // Применяем громкость к аудиоплееру сразу после создания панели,
        // т.к. audioPlayer мог быть создан до панели.
        if (audioPlayer) {
             audioPlayer.volume = savedVolume;
        }


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


        // Вставляем панель в найденный контейнер (#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) {
        if (splitMinutes === null) return;

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

        const thresholdSeconds = splitMinutes * 60;

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

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

        // Проверяем условие сплита только если 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();
        }
        // ensurePanelPosition() убрана отсюда
    }

    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() НЕ вызывается здесь, чтобы не сбрасывать поле ввода
             }

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

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

    // Запускаем интервал для поиска элементов и настройки.
    // Этот интервал будет работать постоянно на страницах *://www.youtube.com/watch*
    // и будет пытаться добавить панель и найти видео/контейнер каждые 500мс.
    if (!setupIntervalId) {
        setupIntervalId = setInterval(setupElementsAndPanel, 500); // Проверяем каждые 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; // Сплит не активен по умолчанию на новой странице
            video = null; // Видео будет найдено заново в setupElementsAndPanel
            splitTriggered = false;
            panelAdded = false; // Сбрасываем флаг добавления панели

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

    // Наблюдаем за изменениями в body для отслеживания SPA навигации.
     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; // Удаляем объект Audio при окончательной выгрузке
         }
        if (urlObserver) {
             urlObserver.disconnect();
        }
    });


})();