YouTube Volume Booster 600% (v4.0 Clear One-Time Restore on Video Change)

Adds a floating volume slider with up to 600% boost. Features: Global Volume (per-tab persistence), Remember Per Video (manual save), and One-Time Restore for browser restarts (now with a toggle, and data for previous video is cleared on new video load).

目前為 2025-06-07 提交的版本,檢視 最新版本

// ==UserScript==
// @name        YouTube Volume Booster 600% (v4.0 Clear One-Time Restore on Video Change)
// @name:vi     YouTube - Tăng Âm Lượng 600% (v4.0 Xóa Khôi Phục Một Lần Khi Đổi Video)
// @namespace   http://tampermonkey.net/
// @version     4.0
// @description Adds a floating volume slider with up to 600% boost. Features: Global Volume (per-tab persistence), Remember Per Video (manual save), and One-Time Restore for browser restarts (now with a toggle, and data for previous video is cleared on new video load).
// @description:vi Thêm thanh trượt âm lượng nổi, tăng âm lượng đến 600%. Các tính năng: Âm lượng toàn tab (duy trì trên mỗi tab), Ghi nhớ từng video (lưu thủ công), và Khôi phục một lần cho lần khởi động lại trình duyệt (giờ có nút bật/tắt, và dữ liệu của video trước đó sẽ bị xóa khi tải video mới).
// @author      Gemini & Developer
// @match       *://*.youtube.com/*
// @grant       GM_addStyle
// @grant       GM_setValue
// @grant       GM_getValue
// @icon        https://www.youtube.com/s/desktop/10a70246/img/favicon_32x32.png
// ==/UserScript==

(function() {
    'use strict';

    // --- GLOBAL VARIABLES AND SETTINGS ---
    let audioContext, gainNode, sourceNode;
    let currentVideoId = null; // Current video ID
    let previousVideoId = null; // Stores the ID of the video watched just before the current one
    let currentTabVolume = 100; // Default volume for the current tab (in-memory, will be loaded/saved per tab)
    let tabId = null; // Unique ID for the current browser tab, persisted via sessionStorage

    // Feature states (will be loaded from GM_getValue)
    let isGlobalVolumeEnabled = false; // Controls if volume is persisted per tab for current session & browser restore
    let isRememberPerVideoEnabled = false; // Controls if manual save button for per-video is active
    let isOneTimeRestoreEnabled = true; // NEW: Controls if one-time restore is active (default ON)

    let currentLanguage = 'vi'; // Default language: 'vi' for Vietnamese, 'en' for English

    // NEW: Variables for draggable toolbar position
    let isDragging = false;
    let dragOffsetX, dragOffsetY; // These will store the mouse's offset from the container's left/top edge
    const STORAGE_KEY_TOOLBAR_POSITION = 'youtubeBoosterToolbarPosition'; // Key to save toolbar position

    const translations = {
        'vi': {
            globalVolumeTitle: 'Âm lượng toàn tab',
            globalVolumeEnabled: 'Âm lượng toàn tab: Đã bật (Nhấn để tắt)',
            globalVolumeDisabled: 'Âm lượng toàn tab: Đã tắt (Nhấn để bật)',
            rememberPerVideoTitle: 'Ghi nhớ từng video',
            rememberPerVideoEnabled: 'Ghi nhớ từng video: Đã bật (Nhấn để tắt)',
            rememberPerVideoDisabled: 'Ghi nhớ từng video: Đã tắt (Nhấn để bật)',
            savePerVideoTitle: 'Lưu âm lượng cho video này',
            savePerVideoEnabledHint: 'Lưu âm lượng cho video này (Tính năng ghi nhớ đang hoạt động)',
            savePerVideoDisabledHint: 'Chỉ hoạt động khi "Ghi nhớ từng video" bật.',
            oneTimeRestoreTitle: 'Khôi phục một lần',
            oneTimeRestoreEnabled: 'Khôi phục một lần: Đã bật (Nhấn để tắt)',
            oneTimeRestoreDisabled: 'Khôi phục một lần: Đã tắt (Nhấn để bật)',
            languageToggleTitle: 'Ngôn ngữ',
            languageToggleHint: 'Chuyển đổi ngôn ngữ (hiện tại: Tiếng Việt)',
            languageToggleHintEnglish: 'Switch language (current: English)',
            manualSaveSuccess: 'Đã lưu âm lượng thủ công',
            manualSaveNotAllowed: 'Lưu thủ công không được phép. "Ghi nhớ từng video" đang tắt hoặc không có ID video.',
            globalVolumeEnabledUser: '"Âm lượng toàn tab" đã BẬT bởi người dùng.',
            globalVolumeDisabledUser: '"Âm lượng toàn tab" đã TẮT bởi người dùng.',
            rememberPerVideoEnabledUser: '"Ghi nhớ từng video" đã BẬT.',
            rememberPerVideoDisabledUser: '"Ghi nhớ từng video" đã TẮT.',
            oneTimeRestoreEnabledUser: '"Khôi phục một lần" đã BẬT bởi người dùng.',
            oneTimeRestoreDisabledUser: '"Khôi phục một lần" đã TẮT bởi người dùng.',
            boosterInitializedGlobal: 'Khởi tạo - Trạng thái tính năng Âm lượng Toàn cầu:',
            boosterInitializedPerVideo: 'Khởi tạo - Trạng thái chuyển đổi tính năng Mỗi Video:',
            boosterInitializedOneTime: 'Khởi tạo - Trạng thái chuyển đổi tính năng Khôi phục Một lần:',
            tabIdNotInitialized: 'ID tab chưa được khởi tạo hoặc không có sẵn.'
        },
        'en': {
            globalVolumeTitle: 'Global Volume',
            globalVolumeEnabled: 'Global Volume: Enabled (Click to disable)',
            globalVolumeDisabled: 'Global Volume: Disabled (Click to enable)',
            rememberPerVideoTitle: 'Remember Per Video',
            rememberPerVideoEnabled: 'Remember Per Video: Enabled (Click to disable)',
            rememberPerVideoDisabled: 'Remember Per Video: Disabled (Click to enable)',
            savePerVideoTitle: 'Save volume for this video',
            savePerVideoEnabledHint: 'Save volume for this video (Remember feature is active)',
            savePerVideoDisabledHint: 'Only active when "Remember Per Video" is on.',
            oneTimeRestoreTitle: 'One-Time Restore',
            oneTimeRestoreEnabled: 'One-Time Restore: Enabled (Click to disable)',
            oneTimeRestoreDisabled: 'One-Time Restore: Disabled (Click to enable)',
            languageToggleTitle: 'Language',
            languageToggleHint: 'Switch language (current: Vietnamese)',
            languageToggleHintEnglish: 'Switch language (current: English)',
            manualSaveSuccess: 'Manually saved volume',
            manualSaveNotAllowed: 'Manual save not allowed. "Remember Volume Per Video" is off or no video ID.',
            globalVolumeEnabledUser: '"Global Volume for Current Tab" feature ENABLED by user.',
            globalVolumeDisabledUser: '"Global Volume for Current Tab" feature DISABLED by user.',
            rememberPerVideoEnabledUser: '"Remember Per Video" feature ENABLED.',
            rememberPerVideoDisabledUser: '"Remember Per Video" feature DISABLED.',
            oneTimeRestoreEnabledUser: '"One-Time Restore" feature ENABLED by user.',
            oneTimeRestoreDisabledUser: '"One-Time Restore" feature DISABLED by user.',
            boosterInitializedGlobal: 'Initializing - Global Volume Feature State:',
            boosterInitializedPerVideo: 'Initializing - Per Video Feature Toggle State:',
            boosterInitializedOneTime: 'Initializing - One-Time Restore Feature Toggle State:',
            tabIdNotInitialized: 'Tab ID not yet initialized or available.'
        }
    };

    // Tampermonkey storage keys
    const STORAGE_KEY_PER_VIDEO = 'youtubeVolumeSettings_v2'; // Saves volume per video explicitly (persisted indefinitely until manually changed/deleted)
    const STORAGE_KEY_GLOBAL_FEATURE_STATE = 'youtubeGlobalVolumeFeatureState_v2'; // Saves state of 'Global Volume for Current Tab' feature (on/off, persisted)
    const STORAGE_KEY_PER_VIDEO_FEATURE_STATE = 'youtubePerVideoFeatureState_v2'; // Saves state of 'Remember Volume Per Video' feature (on/off, persisted)
    const STORAGE_KEY_ONE_TIME_RESTORE_FEATURE_STATE = 'youtubeOneTimeRestoreFeatureState_v1'; // NEW: Saves state of 'One-Time Restore' feature (on/off, persisted)
    const STORAGE_KEY_TAB_VOLUME_PREFIX = 'youtubeGlobalVolumePerTab_v2_'; // Prefix for storing global volume per tab ID (persisted indefinitely until manually changed/deleted by global volume logic)
    const STORAGE_KEY_LANGUAGE = 'youtubeBoosterLanguage_v1'; // Tampermonkey storage key for language setting

    // This key stores a MAP of {videoId: volume} for ONE-TIME restore on browser close/reopen
    const STORAGE_KEY_ONE_TIME_RESTORE_VOLUMES = 'youtubeRestoreVolume_v3_videoId_map';
    // Session storage for tab-specific state (Tab ID is still needed for global volume per tab)
    const SESSION_STORAGE_TAB_ID_KEY = 'youtubeBoosterTabId_v2';
    // This key is used to track if this specific tab instance has already processed the one-time restore for the current video.
    const SESSION_STORAGE_ONE_TIME_PROCESSED_KEY_PREFIX = 'youtubeBoosterOneTimeProcessed_';

    // Debounce variables
    let initializeTimeout = null;
    const DEBOUNCE_DELAY = 100; // Milliseconds to wait before actually calling initialize

    // --- CSS FOR UI ---
    GM_addStyle(`
        #volume-booster-container-abs {
            position: absolute; /* Giữ lại thuộc tính position: absolute */
            /* ĐÃ BỎ: bottom: 55px; right: 15px; để JS quản lý vị trí ban đầu */
            z-index: 9999;
            background-color: rgba(28, 28, 28, 0.85); padding: 6px 12px;
            border-radius: 8px; display: flex; align-items: center; gap: 8px; /* Add space between elements */
            opacity: 0; transition: opacity 0.3s ease-in-out, bottom 0.3s ease-in-out, right 0.3s ease-in-out; /* Add right for transition */
            pointer-events: none;
            cursor: grab; /* Indicate it's draggable */
        }
        #volume-booster-container-abs.dragging {
            cursor: grabbing; /* Indicate dragging */
            transition: none; /* Disable transition during drag */
        }
        #movie_player:hover #volume-booster-container-abs {
            opacity: 1; pointer-events: auto;
        }
        .volume-booster-slider-abs {
            -webkit-appearance: none; appearance: none;
            width: 100px; height: 5px; background: #777;
            outline: none; cursor: pointer; border-radius: 3px; margin: 0;
        }
        .volume-booster-slider-abs::-webkit-slider-thumb {
            -webkit-appearance: none; appearance: none;
            width: 16px; height: 16px; background: #ff0000;
            cursor: pointer; border-radius: 50%;
        }
        .volume-booster-slider-abs::-moz-range-thumb {
            width: 16px; height: 16px; background: #ff0000;
            cursor: pointer; border-radius: 50%; border: none;
        }
        .volume-booster-label-abs {
            color: white; font-size: 13px; font-weight: bold;
            margin-left: 0; /* Spacing handled by gap */
            min-width: 50px; text-shadow: 1px 1px 2px black;
            text-align: right;
        }
        .volume-booster-setting-icon {
            cursor: pointer; width: 20px;
            height: 20px;
            background-color: #ffffff; /* Default white color */
            mask-size: contain; mask-repeat: no-repeat;
            mask-position: center;
            transition: background-color 0.2s ease-in-out;
            border-radius: 4px; /* Slight border-radius */
            padding: 2px; /* Add padding so icon doesn't touch edges */
        }
        .volume-booster-setting-icon.enabled {
            background-color: #4CAF50; /* Green when enabled */
        }
        .volume-booster-setting-icon.global-volume {
            mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.09-.75-1.72-1.03L13.73 2.2c-.06-.2-.25-.3-.46-.3h-4c-.21 0-.4.1-.46.3L9.23 4.87c-.63.28-1.2.63-1.72 1.03l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.12.22-.07.49.12.64l2.11 1.65c-.04.32-.07.64-.07.98s.03.66.07-.98l-2.11 1.65c-.19.15-.24-.42-.12-.64l2 3.46c.12.22.39-.3.61.22l2.49-1c.52.4 1.09.75 1.72 1.03l.44 2.69c.06.2.25.3.46.3h4c.21 0 .4-.1.46-.3l.44-2.69c.63-.28 1.2-.63 1.72-1.03l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zm-1.93-1.93c.33.33.56.73.69 1.13l.11.4c.03.1.06.2.06.3s-.03.2-.06.3l-.11-.4c-.13.4-.36.8-.69 1.13-.33.33-.73-.56-1.13-.69l-.4-.11c-.1.03-.2.06-.3.06s-.2-.03-.3-.06l-.4-.11c-.4-.13-.8-.36-1.13-.69-.33-.33-.56-.73-.69-1.13l-.11-.4c-.03-.1-.06-.2-.06-.3s-.03.2.06-.3l-.11-.4c.13-.4.36-.8.69-1.13.33.33.73-.56 1.13-.69l-.4-.11c.1-.03.2-.06.3.06s-.2.03.3.06l-.4.11c.4.13.8.36 1.13.69zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/></svg>');
        }
        .volume-booster-setting-icon.per-video-toggle {
            mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M17 3H7c-1.1 0-2 .9-2 2v16l7-3 7 3V5c0-1.1-.9-2-2-2z"/></svg>');
        }
        .volume-booster-setting-icon.save-per-video {
            mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"/></svg>');
            opacity: 0.5; /* Default to dimmed */
            pointer-events: none; /* Default to not clickable */
        }
        .volume-booster-setting-icon.one-time-restore-toggle {
            mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M12 4V1l-4 4 4 4V6c3.31 0 6 2.69 6 6 0 1.01-.25 1.97-.7 2.8l1.46 1.46C19.54 15.01 20 13.57 20 12c0-4.42-3.58-8-8-8zm0 14c-3.31 0-6-2.69-6-6 0-1.01.25-1.97.7-2.8L5.24 7.74C4.46 8.97 4 10.43 4 12c0 4.42 3.58 8 8 8V23l4-4-4-4v3z"/></svg>');
        }
        .volume-booster-setting-icon.language-toggle {
            mask-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.07-1.74-.27-3.4-.59-4.96C16.39 3.5 17.72 5.06 18.92 8zM12 4.04c.83 1.22 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.74 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2s.06 1.34.14 2H4.26zm.82 2h2.95c.07 1.74-.27 3.4-.59 4.96C7.61 20.5 6.28 18.94 5.08 16zM8.07 19.96c-.83-1.22-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.74-1.91 3.96zM11.99 20c-.83-1.22-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.74-1.91 3.96zM12 19.96c-.83-1.22-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.74-1.91 3.96zM11.99 4.04c-.83 1.22-1.48 2.53-1.91 3.96h3.82c-.43-1.43-1.08-2.74-1.91-3.96z"/></svg>');
        }
        /* Class for click feedback */
        .volume-booster-setting-icon.clicked {
            background-color: #007bff; /* Blue for click feedback */
        }
    `);
    // --- FUNCTIONS TO SAVE AND LOAD SETTINGS ---

    // Get a unique ID for the current tab, create if it doesn't exist
    function getTabId() {
        let id = sessionStorage.getItem(SESSION_STORAGE_TAB_ID_KEY);
        if (!id) {
            id = crypto.randomUUID(); // Generate a new unique ID
            sessionStorage.setItem(SESSION_STORAGE_TAB_ID_KEY, id);
            console.log(`Booster v${GM_info.script.version}: New tab ID generated: ${id}`);
        } else {
            console.log(`Booster v${GM_info.script.version}: Existing tab ID loaded: ${id}`);
        }
        return id;
    }

    function getVideoId() {
        const urlParams = new URLSearchParams(window.location.search);
        return urlParams.get('v');
    }

    async function getVolumeSetting(videoId) {
        if (!videoId) return null; // Return null if no videoId, indicating no specific setting
        const allSettings = await GM_getValue(STORAGE_KEY_PER_VIDEO, {});
        return allSettings[videoId] !== undefined ? allSettings[videoId] : null;
    }

    async function saveVolumeSetting(videoId, volume) {
        if (!videoId) return;
        const allSettings = await GM_getValue(STORAGE_KEY_PER_VIDEO, {});

        if (volume === 100) {
            // If volume is 100, delete the setting for this video to keep storage clean
            if (allSettings.hasOwnProperty(videoId)) {
                delete allSettings[videoId];
                console.log(`Booster v${GM_info.script.version}: Deleted saved volume for video ${videoId} as it was set to 100%.`);
            }
        } else {
            // Otherwise, save the specific volume
            allSettings[videoId] = volume;
            console.log(`Booster v${GM_info.script.version}: Saved volume ${volume}% for video ${videoId}.`);
        }
        await GM_setValue(STORAGE_KEY_PER_VIDEO, allSettings);
    }

    async function getFeatureState(key, defaultValue = false) {
        return await GM_getValue(key, defaultValue); // Use a default value
    }

    async function saveFeatureState(key, state) {
        await GM_setValue(key, state);
    }

    // Function to save the current volume for the current video for ONE-TIME restore on browser restart
    async function saveOneTimeRestoreVolume(videoId, volume) {
        if (!videoId) return;
        // Only save if the feature is enabled
        if (!isOneTimeRestoreEnabled) {
            console.log(`Booster v${GM_info.script.version}: One-time restore feature is disabled. Skipping save for video ${videoId}.`);
            return;
        }

        let restoreData = await GM_getValue(STORAGE_KEY_ONE_TIME_RESTORE_VOLUMES, {});
        // Always save the current volume, even if it's 100%, to ensure it's the last known state.
        restoreData[videoId] = volume;
        await GM_setValue(STORAGE_KEY_ONE_TIME_RESTORE_VOLUMES, restoreData);
        console.log(`Booster v${GM_info.script.version}: One-time restore volume saved: ${volume}% for video ${videoId}.`);
    }

    // Function to load and clear one-time restore volume for the current video
    async function loadAndClearOneTimeRestoreVolume(videoId) {
        if (!videoId) return null;
        // Check if the feature is enabled
        if (!isOneTimeRestoreEnabled) {
            console.log(`Booster v${GM_info.script.version}: One-time restore feature is disabled. Skipping load for video ${videoId}.`);
            return null;
        }

        // Check session storage to see if this video's one-time restore has already been processed in this tab instance.
        const oneTimeProcessedKey = SESSION_STORAGE_ONE_TIME_PROCESSED_KEY_PREFIX + videoId;
        const hasProcessedOneTime = sessionStorage.getItem(oneTimeProcessedKey);
        if (hasProcessedOneTime) {
            console.log(`Booster v${GM_info.script.version}: One-time restore already processed for video ${videoId} in this tab instance. Skipping.`);
            return null;
        }

        let restoreData = await GM_getValue(STORAGE_KEY_ONE_TIME_RESTORE_VOLUMES, {});
        let restoredVolume = restoreData[videoId];
        if (restoredVolume !== undefined) {
            // Do NOT delete here immediately. We will delete the *previous* video's data on navigation.
            // This ensures that the one-time restore value is available until a new video is loaded.
            // This is the core change for v3.9.17's specific request.
            // Mark as processed in session storage so it's not re-applied in this tab.
            sessionStorage.setItem(oneTimeProcessedKey, 'true');
            console.log(`Booster v${GM_info.script.version}: Restored volume ${restoredVolume}% for video ${videoId}. (Will be cleared on next video load).`);
            return restoredVolume;
        }
        return null; // Default if no saved volume for this video
    }

    // NEW: Function to clear one-time restore data for a specific video ID
    async function clearOneTimeRestoreVolume(videoIdToClear) {
        if (!videoIdToClear) return;
        let restoreData = await GM_getValue(STORAGE_KEY_ONE_TIME_RESTORE_VOLUMES, {});
        if (restoreData.hasOwnProperty(videoIdToClear)) {
            delete restoreData[videoIdToClear];
            await GM_setValue(STORAGE_KEY_ONE_TIME_RESTORE_VOLUMES, restoreData);
            console.log(`Booster v${GM_info.script.version}: Cleared one-time restore data for previous video: ${videoIdToClear}.`);
        }
        // Also clear session storage flag for the cleared video ID, just in case.
        sessionStorage.removeItem(SESSION_STORAGE_ONE_TIME_PROCESSED_KEY_PREFIX + videoIdToClear);
    }

    // NEW: Function to save toolbar position
    async function saveToolbarPosition(bottom, right) {
        await GM_setValue(STORAGE_KEY_TOOLBAR_POSITION, { bottom, right });
        console.log(`Booster v${GM_info.script.version}: Saved toolbar position: bottom ${bottom}px, right ${right}px.`);
    }

    // NEW: Function to load toolbar position
    async function loadToolbarPosition() {
        return await GM_getValue(STORAGE_KEY_TOOLBAR_POSITION, null);
    }

    // --- CORE SCRIPT FUNCTIONS ---

    /**
     * Sets up the audio booster only once.
     */
    function setupAudioBoosterOnce(videoElement) {
        if (audioContext) return; // Only run once

        console.log(`Booster v${GM_info.script.version}: Setting up AudioContext for the first time.`);
        audioContext = new (window.AudioContext || window.webkitAudioContext)();
        sourceNode = audioContext.createMediaElementSource(videoElement);
        gainNode = audioContext.createGain();
        sourceNode.connect(gainNode);
        gainNode.connect(audioContext.destination);
    }

    /**
     * Updates the volume displayed on UI and applied to gainNode.
     */
    function applyVolumeToUIAndGain(volume) {
        if (!gainNode) return;
        gainNode.gain.value = volume / 100;

        const slider = document.querySelector('.volume-booster-slider-abs');
        const label = document.querySelector('.volume-booster-label-abs');
        if (slider) slider.value = volume;
        if (label) label.textContent = `${volume}%`;
        console.log(`Booster v${GM_info.script.version}: Applied volume ${volume}% to UI and GainNode.`);
    }

    function updateUIText() {
        const lang = currentLanguage;

        // Update titles and hints for setting icons
        const settingsIconGlobal = document.querySelector('.volume-booster-setting-icon.global-volume');
        if (settingsIconGlobal) {
            settingsIconGlobal.title = isGlobalVolumeEnabled ? translations[lang].globalVolumeEnabled : translations[lang].globalVolumeDisabled;
        }

        const settingsIconPerVideo = document.querySelector('.volume-booster-setting-icon.per-video-toggle');
        if (settingsIconPerVideo) {
            settingsIconPerVideo.title = isRememberPerVideoEnabled ? translations[lang].rememberPerVideoEnabled : translations[lang].rememberPerVideoDisabled;
        }

        const saveVolumeIcon = document.querySelector('.volume-booster-setting-icon.save-per-video');
        if (saveVolumeIcon) {
            if (isRememberPerVideoEnabled) {
                saveVolumeIcon.title = translations[lang].savePerVideoEnabledHint;
            } else {
                saveVolumeIcon.title = translations[lang].savePerVideoDisabledHint;
            }
        }

        const oneTimeRestoreToggle = document.querySelector('.volume-booster-setting-icon.one-time-restore-toggle');
        if (oneTimeRestoreToggle) {
            oneTimeRestoreToggle.title = isOneTimeRestoreEnabled ? translations[lang].oneTimeRestoreEnabled : translations[lang].oneTimeRestoreDisabled;
        }

        const languageToggleIcon = document.querySelector('.volume-booster-setting-icon.language-toggle');
        if (languageToggleIcon) {
             languageToggleIcon.title = lang === 'vi' ? translations['vi'].languageToggleHint : translations['en'].languageToggleHintEnglish;
        }
    }

    /**
     * Creates the volume slider UI (runs only if not already present).
     */
    async function createVolumeSliderUI() { // Made async to await loadToolbarPosition
        if (document.getElementById('volume-booster-container-abs')) return;
        const playerContainer = document.querySelector('#movie_player');
        if (!playerContainer) return;

        console.log(`Booster v${GM_info.script.version}: Creating UI...`);
        const container = document.createElement('div');
        container.id = 'volume-booster-container-abs';
        const slider = document.createElement('input');
        slider.className = 'volume-booster-slider-abs';
        slider.type = 'range';
        slider.min = '0'; slider.max = '600'; slider.step = '10';
        const label = document.createElement('span');
        label.className = 'volume-booster-label-abs';

        // 'Global Volume for Current Tab' settings button
        const settingsIconGlobal = document.createElement('div');
        settingsIconGlobal.className = 'volume-booster-setting-icon global-volume';
        settingsIconGlobal.title = translations[currentLanguage].globalVolumeTitle; // Default title, will be updated by updateGlobalVolumeIconState

        // 'Remember Volume Per Video' toggle button
        const settingsIconPerVideo = document.createElement('div');
        settingsIconPerVideo.className = 'volume-booster-setting-icon per-video-toggle';
        if (isRememberPerVideoEnabled) {
            settingsIconPerVideo.classList.add('enabled');
        }
        settingsIconPerVideo.title = isRememberPerVideoEnabled ?
        translations[currentLanguage].rememberPerVideoEnabled : translations[currentLanguage].rememberPerVideoDisabled;

        // 'Save Volume Per Video' button
        const saveVolumeIcon = document.createElement('div');
        saveVolumeIcon.className = 'volume-booster-setting-icon save-per-video';
        saveVolumeIcon.title = translations[currentLanguage].savePerVideoTitle;

        // NEW: 'One-Time Restore' toggle button
        const oneTimeRestoreToggle = document.createElement('div');
        oneTimeRestoreToggle.className = 'volume-booster-setting-icon one-time-restore-toggle';
        if (isOneTimeRestoreEnabled) { // Check initial state
            oneTimeRestoreToggle.classList.add('enabled');
        }
        oneTimeRestoreToggle.title = isOneTimeRestoreEnabled ?
        translations[currentLanguage].oneTimeRestoreEnabled : translations[currentLanguage].oneTimeRestoreDisabled;

        // NEW: Language Toggle button
        const languageToggleIcon = document.createElement('div');
        languageToggleIcon.className = 'volume-booster-setting-icon language-toggle';
        // Icon for language toggle (e.g., a globe icon)
        languageToggleIcon.style.maskImage = `url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zm6.93 6h-2.95c-.07-1.74-.27-3.4-.59-4.96C16.39 3.5 17.72 5.06 18.92 8zM12 4.04c.83 1.22 1.48 2.53 1.91 3.96h-3.82c.43-1.43 1.08-2.74 1.91-3.96zM4.26 14C4.1 13.36 4 12.69 4 12s.1-1.36.26-2h3.38c-.08.66-.14 1.32-.14 2s.06 1.34.14 2H4.26zm.82 2h2.95c.07 1.74-.27 3.4-.59 4.96C7.61 20.5 6.28 18.94 5.08 16zM8.07 19.96c-.83-1.22-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.74-1.91 3.96zM11.99 20c-.83-1.22-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.74-1.91 3.96zM12 19.96c-.83-1.22-1.48-2.53-1.91-3.96h3.82c-.43 1.43-1.08 2.74-1.91 3.96zM11.99 4.04c-.83 1.22-1.48 2.53-1.91 3.96h3.82c-.43-1.43-1.08-2.74-1.91-3.96z"/></svg>')`;
        languageToggleIcon.title = currentLanguage === 'vi' ? translations['vi'].languageToggleHint : translations['en'].languageToggleHintEnglish;

        // Helper to update the state of the save button
        function updateSaveButtonState() {
            if (isRememberPerVideoEnabled) {
                saveVolumeIcon.style.opacity = '1';
                saveVolumeIcon.style.pointerEvents = 'auto';
                saveVolumeIcon.title = translations[currentLanguage].savePerVideoEnabledHint;
            } else {
                saveVolumeIcon.style.opacity = '0.5'; // Dim when not active
                saveVolumeIcon.style.pointerEvents = 'none'; // Make not clickable
                saveVolumeIcon.title = translations[currentLanguage].savePerVideoDisabledHint;
            }
        }
        updateSaveButtonState(); // Set initial state

        // Helper to update the state of the Global Volume icon
        function updateGlobalVolumeIconState() {
            if (isGlobalVolumeEnabled) {
                settingsIconGlobal.classList.add('enabled');
                settingsIconGlobal.title = translations[currentLanguage].globalVolumeEnabled;
            } else {
                settingsIconGlobal.classList.remove('enabled');
                settingsIconGlobal.title = translations[currentLanguage].globalVolumeDisabled;
            }
        }
        updateGlobalVolumeIconState(); // Set initial state

        // Helper to update the state of the One-Time Restore toggle icon
        function updateOneTimeRestoreIconState() {
            if (isOneTimeRestoreEnabled) {
                oneTimeRestoreToggle.classList.add('enabled');
                oneTimeRestoreToggle.title = translations[currentLanguage].oneTimeRestoreEnabled;
            } else {
                oneTimeRestoreToggle.classList.remove('enabled');
                oneTimeRestoreToggle.title = translations[currentLanguage].oneTimeRestoreDisabled;
            }
        }
        updateOneTimeRestoreIconState(); // Set initial state

        slider.addEventListener('input', async () => {
            const boostValue = parseInt(slider.value, 10);
            applyVolumeToUIAndGain(boostValue); // Apply to gainNode and update label
            currentTabVolume = boostValue; // Update in-memory currentTabVolume

            // If Global Volume is ENABLED, also save this to persistent tab storage
            if (isGlobalVolumeEnabled) {
                await GM_setValue(STORAGE_KEY_TAB_VOLUME_PREFIX + tabId, currentTabVolume);
                console.log(`Booster v${GM_info.script.version}: Global Volume ENABLED. Setting and saving tab volume for tab ${tabId}: ${currentTabVolume}%`);
            } else {
                console.log(`Booster v${GM_info.script.version}: Global Volume DISABLED. Slider adjusted to ${currentTabVolume}%, not persistently saved for tab.`);
            }
            // Always save for one-time restore immediately on input, if the feature is enabled
            if (isOneTimeRestoreEnabled) {
                await saveOneTimeRestoreVolume(currentVideoId, currentTabVolume);
            }
        });

        settingsIconGlobal.addEventListener('click', async () => {
            isGlobalVolumeEnabled = !isGlobalVolumeEnabled;
            await saveFeatureState(STORAGE_KEY_GLOBAL_FEATURE_STATE, isGlobalVolumeEnabled); // Save the feature state persistently
            updateGlobalVolumeIconState(); // Update icon state
            updateUIText(); // Update all UI texts

            // Add click feedback
            settingsIconGlobal.classList.add('clicked');
            setTimeout(() => {
                settingsIconGlobal.classList.remove('clicked');
            }, 200); // Remove 'clicked' class after 200ms

            if (isGlobalVolumeEnabled) {
                console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].globalVolumeEnabledUser}`);
                // When explicitly enabling, save the current active 'currentTabVolume' to persistent tab storage.
                await GM_setValue(STORAGE_KEY_TAB_VOLUME_PREFIX + tabId, currentTabVolume);
                console.log(`Booster v${GM_info.script.version}: Global Volume ENABLED. Current tab volume ${currentTabVolume}% saved persistently.`);
            } else {
                console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].globalVolumeDisabledUser}`);
            }
            // After changing global volume state, re-evaluate and apply volume for current video.
            debouncedInitialize();
        });

        settingsIconPerVideo.addEventListener('click', async () => {
            isRememberPerVideoEnabled = !isRememberPerVideoEnabled;
            await saveFeatureState(STORAGE_KEY_PER_VIDEO_FEATURE_STATE, isRememberPerVideoEnabled);
            if (isRememberPerVideoEnabled) {
                settingsIconPerVideo.classList.add('enabled');
                settingsIconPerVideo.title = translations[currentLanguage].rememberPerVideoEnabled;
                console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].rememberPerVideoEnabledUser}`);
            } else {
                settingsIconPerVideo.classList.remove('enabled');
                settingsIconPerVideo.title = translations[currentLanguage].rememberPerVideoDisabled;
                console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].rememberPerVideoDisabledUser}`);
            }
            updateSaveButtonState(); // Update save button state based on this toggle
            updateUIText(); // Update all UI texts

            // Add click feedback
            settingsIconPerVideo.classList.add('clicked');
            setTimeout(() => {
                settingsIconPerVideo.classList.remove('clicked');
            }, 200); // Remove 'clicked' class after 200ms

            // After changing per-video state, re-evaluate and apply volume for current video.
            debouncedInitialize();
        });

        saveVolumeIcon.addEventListener('click', async () => {
            // The save button only works if 'Remember Volume Per Video' is enabled.
            if (isRememberPerVideoEnabled && currentVideoId) {
                const currentSliderValue = parseInt(slider.value, 10);
                await saveVolumeSetting(currentVideoId, currentSliderValue);

                currentTabVolume = currentSliderValue; // Update in-memory tab volume to match manual save
                applyVolumeToUIAndGain(currentTabVolume); // Ensure UI is updated
                // Also save to one-time restore if enabled, as this is the latest user-set volume
                if (isOneTimeRestoreEnabled) {
                    await saveOneTimeRestoreVolume(currentVideoId, currentTabVolume);
                }
                console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].manualSaveSuccess} ${currentTabVolume}% for video ${currentVideoId}.`);

                // Visual feedback for saving
                saveVolumeIcon.classList.add('clicked'); // Use the general clicked class
                setTimeout(() => {
                    saveVolumeIcon.classList.remove('clicked');
                }, 500);
            } else {
                console.warn(`Booster v${GM_info.script.version}: ${translations[currentLanguage].manualSaveNotAllowed}`);
            }
        });

        // NEW: Event listener for One-Time Restore toggle button
        oneTimeRestoreToggle.addEventListener('click', async () => {
            isOneTimeRestoreEnabled = !isOneTimeRestoreEnabled;
            // Default value for One-Time Restore is true, so only save if it's explicitly set to false
            // or if it's explicitly set to true after being false.
            await saveFeatureState(STORAGE_KEY_ONE_TIME_RESTORE_FEATURE_STATE, isOneTimeRestoreEnabled); // Save the feature state persistently
            updateOneTimeRestoreIconState(); // Update icon state
            updateUIText(); // Update all UI texts

            // Add click feedback
            oneTimeRestoreToggle.classList.add('clicked');
            setTimeout(() => {
                oneTimeRestoreToggle.classList.remove('clicked');
            }, 200); // Remove 'clicked' class after 200ms

            if (isOneTimeRestoreEnabled) {
                console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].oneTimeRestoreEnabledUser}`);
                // If enabled, save the current volume so it can be restored on next browser restart
                await saveOneTimeRestoreVolume(currentVideoId, currentTabVolume);
            } else {
                console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].oneTimeRestoreDisabledUser}`);
                // If disabled, clear existing one-time restore data for ALL videos (more robust clean-up)
                // Or only for the current video, depending on desired strictness. Let's stick to current video for now for clarity.
                await clearOneTimeRestoreVolume(currentVideoId); // Clear for the current video
            }
            // After changing one-time restore state, re-evaluate and apply volume for current video.
            debouncedInitialize();
        });

        // Add event listener for language toggle
        languageToggleIcon.addEventListener('click', async () => {
            currentLanguage = (currentLanguage === 'vi') ? 'en' : 'vi';
            await saveFeatureState(STORAGE_KEY_LANGUAGE, currentLanguage); // Save new language setting
            updateUIText(); // Update all UI texts

            // Add click feedback
            languageToggleIcon.classList.add('clicked');
            setTimeout(() => {
                languageToggleIcon.classList.remove('clicked');
            }, 200); // Remove 'clicked' class after 200ms

            console.log(`Booster v${GM_info.script.version}: Language switched to: ${currentLanguage === 'vi' ? 'Vietnamese' : 'English'}.`);
        });


        container.appendChild(slider);
        container.appendChild(label);
        container.appendChild(settingsIconGlobal);
        container.appendChild(settingsIconPerVideo);
        container.appendChild(saveVolumeIcon); // Add the new save button
        container.appendChild(oneTimeRestoreToggle); // NEW: Add the one-time restore toggle button
        container.appendChild(languageToggleIcon); // NEW: Add the language toggle button
        playerContainer.appendChild(container);

        // NEW DRAGGABLE FUNCTIONALITY
        // Load saved position, or set a default if none saved
        const savedPos = await loadToolbarPosition();
        if (savedPos) {
            container.style.bottom = `${savedPos.bottom}px`;
            container.style.right = `${savedPos.right}px`;
            console.log(`Booster v${GM_info.script.version}: Loaded saved toolbar position: bottom ${savedPos.bottom}px, right ${savedPos.right}px.`);
        } else {
            // Set default initial position if no saved position exists
            container.style.bottom = '55px'; // Vị trí mặc định theo bottom
            container.style.right = '15px';  // Vị trí mặc định theo right
            console.log(`Booster v${GM_info.script.version}: No saved position, setting default: bottom 55px, right 15px.`);
            // Bạn có thể chọn lưu vị trí mặc định này ngay lập tức để nó được giữ nguyên cho lần tải sau
            // await saveToolbarPosition(55, 15);
        }
        container.style.position = 'absolute'; // Đảm bảo position là absolute.

        container.addEventListener('mousedown', (e) => {
            // Only start dragging if left mouse button is pressed and not clicking on input/button elements
            if (e.button === 0 && !e.target.closest('input, .volume-booster-setting-icon')) {
                isDragging = true;
                container.classList.add('dragging');

                const containerRect = container.getBoundingClientRect(); // Lấy vị trí của thanh toolbar so với viewport

                // dragOffsetX là khoảng cách từ vị trí X của chuột đến cạnh trái của thanh toolbar
                // dragOffsetY là khoảng cách từ vị trí Y của chuột đến cạnh trên của thanh toolbar
                // (Đây là offset của chuột so với góc trên bên trái của toolbar khi click)
                dragOffsetX = e.clientX - containerRect.left;
                dragOffsetY = e.clientY - containerRect.top;

                // Vô hiệu hóa transition trong quá trình kéo để di chuyển mượt mà
                container.style.transition = 'none';

                e.preventDefault(); // Ngăn chặn hành vi kéo mặc định của trình duyệt (ví dụ: kéo ảnh)
            }
        });

        document.addEventListener('mousemove', (e) => {
            if (!isDragging) return;

            const playerRect = playerContainer.getBoundingClientRect(); // Lấy vị trí của movie_player so với viewport
            const containerWidth = container.offsetWidth;
            const containerHeight = container.offsetHeight;

            // *** ĐIỀU CHỈNH CHỖ NÀY ***
            // 1. Tính toán vị trí chuột TƯƠNG ĐỐI với góc trên bên trái của player
            const mouseXRelativeToPlayer = e.clientX - playerRect.left;
            const mouseYRelativeToPlayer = e.clientY - playerRect.top;

            // 2. Tính toán vị trí mong muốn của toolbar (left/top) TƯƠNG ĐỐI với player
            // Chúng ta dùng dragOffsetX/Y đã lưu để giữ nguyên khoảng cách từ chuột đến cạnh toolbar
            let newContainerLeftRelativeToPlayer = mouseXRelativeToPlayer - dragOffsetX;
            let newContainerTopRelativeToPlayer = mouseYRelativeToPlayer - dragOffsetY;

            // 3. Giới hạn (clamping) vị trí này để toolbar không ra khỏi khung của movie_player
            newContainerLeftRelativeToPlayer = Math.max(0, newContainerLeftRelativeToPlayer);
            newContainerLeftRelativeToPlayer = Math.min(newContainerLeftRelativeToPlayer, playerRect.width - containerWidth);

            newContainerTopRelativeToPlayer = Math.max(0, newContainerTopRelativeToPlayer);
            newContainerTopRelativeToPlayer = Math.min(newContainerTopRelativeToPlayer, playerRect.height - containerHeight);

            // 4. Chuyển đổi từ left/top (tương đối với player) sang right/bottom (tương đối với player)
            // Vì container đang có position: absolute và parent là movie_player,
            // right = (width của player) - (left của container) - (width của container)
            // bottom = (height của player) - (top của container) - (height của container)
            let newRight = playerRect.width - (newContainerLeftRelativeToPlayer + containerWidth);
            let newBottom = playerRect.height - (newContainerTopRelativeToPlayer + containerHeight);
            // *** HẾT ĐIỀU CHỈNH ***

            container.style.right = `${newRight}px`;
            container.style.bottom = `${newBottom}px`;
        });

        document.addEventListener('mouseup', async () => {
            if (isDragging) {
                isDragging = false;
                container.classList.remove('dragging');
                // Bật lại transition sau khi kết thúc kéo
                container.style.transition = 'opacity 0.3s ease-in-out, bottom 0.3s ease-in-out, right 0.3s ease-in-out';

                // Lưu vị trí mới
                const currentBottom = parseFloat(container.style.bottom);
                const currentRight = parseFloat(container.style.right);
                await saveToolbarPosition(currentBottom, currentRight);
            }
        });


        updateUIText(); // Call this to set initial text based on currentLanguage
    }

    /**
     * Main initialization function, tracks video changes and sets initial volume.
     */
    async function initialize() {
        // Only run initialize logic if it's the right type of YouTube URL
        if (!window.location.hostname.includes('youtube.com') || !window.location.pathname.startsWith('/watch')) {
            const container = document.getElementById('volume-booster-container-abs');
            if (container) container.remove();
            currentVideoId = null;
            previousVideoId = null; // Reset previous video ID too
            return;
        }

        const newVideoId = getVideoId();
        // If there's no video element or no video ID, return early
        const videoElement = document.querySelector('video');
        if (!videoElement || !newVideoId) {
            console.log(`Booster v${GM_info.script.version}: No video element or video ID found, or not on a watch page.`);
            const container = document.getElementById('volume-booster-container-abs');
            if (container) container.remove();
            currentVideoId = null;
            previousVideoId = null; // Reset previous video ID too
            return;
        }

        // --- Core logic to run only when video ID changes or on initial load ---
        if (newVideoId === currentVideoId) {
             // If video ID hasn't changed and we already initialized for this video, skip full re-initialization
             // unless it's the very first time and currentVideoId was null, in which case proceed.
             if (currentVideoId !== null) {
                 console.log(`Booster v${GM_info.script.version}: Video ID ${newVideoId} is the same. Skipping full re-initialization.`);
                 return;
             }
        }

        console.log(`Booster v${GM_info.script.version}: Video ID changed from ${currentVideoId} to ${newVideoId}. Proceeding with initialization.`);
        // *** NEW LOGIC: Clear one-time restore data for the PREVIOUS video ***
        if (previousVideoId && previousVideoId !== newVideoId && isOneTimeRestoreEnabled) {
            await clearOneTimeRestoreVolume(previousVideoId);
        }

        previousVideoId = currentVideoId; // Update previousVideoId before updating currentVideoId
        currentVideoId = newVideoId; // Update global currentVideoId

        // Get or create the unique tab ID (needed for global volume feature)
        tabId = getTabId();
        // Load feature states (whether the features themselves are enabled/disabled)
        isGlobalVolumeEnabled = await getFeatureState(STORAGE_KEY_GLOBAL_FEATURE_STATE, false);
        isRememberPerVideoEnabled = await getFeatureState(STORAGE_KEY_PER_VIDEO_FEATURE_STATE, false);
        isOneTimeRestoreEnabled = await getFeatureState(STORAGE_KEY_ONE_TIME_RESTORE_FEATURE_STATE, true); // Default to true
        currentLanguage = await getFeatureState(STORAGE_KEY_LANGUAGE, 'vi'); // Load saved language, default to 'vi'

        let volumeToDetermine = 100; // This is the temporary volume for determination

        // Read values from storage for comparison
        const restoredVolumeOnBrowserRestore = await loadAndClearOneTimeRestoreVolume(currentVideoId); // Will be null if feature disabled
        const perVideoVolume = await getVolumeSetting(currentVideoId);
        const globalTabVolume = await GM_getValue(STORAGE_KEY_TAB_VOLUME_PREFIX + tabId, 100);

        // --- PRIORITY LOGIC ---
        // 1. One-Time Restore (highest priority, if enabled and available)
        if (restoredVolumeOnBrowserRestore !== null) {
            volumeToDetermine = restoredVolumeOnBrowserRestore;
            console.log(`Booster v${GM_info.script.version}: Priority 1: Applied One-Time Restore volume (${volumeToDetermine}%) for video ${currentVideoId}.`);
        }
        // 2. Per-Video Save (if enabled and available, takes precedence over Global)
        else if (isRememberPerVideoEnabled && perVideoVolume !== null) {
            volumeToDetermine = perVideoVolume;
            console.log(`Booster v${GM_info.script.version}: Priority 2: Video ${currentVideoId} has a manually saved volume (${perVideoVolume}%) and "Remember Per Video" is enabled.`);
        }
        // 3. Global Volume for Current Tab (if enabled)
        else if (isGlobalVolumeEnabled) {
            volumeToDetermine = globalTabVolume;
            console.log(`Booster v${GM_info.script.version}: Priority 3: "Global Volume for Current Tab" is ENABLED. Loading last tab volume: ${volumeToDetermine}%.`);
        }
        // 4. Default to 100%
        else {
            volumeToDetermine = 100;
            console.log(`Booster v${GM_info.script.version}: Priority 4: No higher priority settings found. Defaulting to 100%.`);
        }

        // Set the in-memory currentTabVolume to whatever was determined.
        currentTabVolume = volumeToDetermine;
        console.log(`Booster v${GM_info.script.version}: Determined 'currentTabVolume' for this tab: ${currentTabVolume}%`);

        // If Global Volume is ENABLED, explicitly save this determined 'currentTabVolume'
        // This ensures that if a per-video saved value (P2) or one-time restore (P1) was applied,
        // it now becomes the saved 'Global Volume' for this tab for *subsequent* video loads within the same tab.
        if (isGlobalVolumeEnabled) {
            await GM_setValue(STORAGE_KEY_TAB_VOLUME_PREFIX + tabId, currentTabVolume);
            console.log(`Booster v${GM_info.script.version}: Global Volume ENABLED. Saved currentTabVolume ${currentTabVolume}% to persistent tab storage for future use.`);
        }

        // ALWAYS save the determined 'currentTabVolume' for one-time restore immediately on initialization,
        // but only if the feature is enabled. This ensures that the last known volume for the video
        // is recorded for the *next* browser restart.
        if (isOneTimeRestoreEnabled) {
            await saveOneTimeRestoreVolume(currentVideoId, currentTabVolume);
            console.log(`Booster v${GM_info.script.version}: On initialization, saved ${currentTabVolume}% for one-time restore for video ${currentVideoId} for the NEXT browser session.`);
        }


        console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].boosterInitializedGlobal} ${isGlobalVolumeEnabled ? 'ENABLED' : 'DISABLED'}`);
        console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].boosterInitializedPerVideo} ${isRememberPerVideoEnabled ? 'ENABLED' : 'DISABLED'}`);
        console.log(`Booster v${GM_info.script.version}: ${translations[currentLanguage].boosterInitializedOneTime} ${isOneTimeRestoreEnabled ? 'ENABLED' : 'DISABLED'}`);
        // Setup the booster for the first time
        setupAudioBoosterOnce(videoElement);
        // Create UI if it doesn't exist
        await createVolumeSliderUI(); // Await this call now
        // Apply the determined volume to the audio context and UI
        applyVolumeToUIAndGain(currentTabVolume);
        // Ensure audio context is resumed (important for playback)
        if (audioContext && audioContext.state === 'suspended') {
            audioContext.resume();
        }
    }

    // Debounced version of initialize
    function debouncedInitialize() {
        clearTimeout(initializeTimeout);
        initializeTimeout = setTimeout(initialize, DEBOUNCE_DELAY);
        console.log(`Booster v${GM_info.script.version}: Debounced initialize called.`);
    }


    // Use MutationObserver to track page changes
    // This handles navigation within YouTube (e.g., clicking on a new video)
    const observer = new MutationObserver(mutations => {
        let shouldDebounceInitialize = false;
        const newVideoIdInURL = getVideoId();

        // If the URL changes and it's a new video ID, trigger initialization
        if (newVideoIdInURL && newVideoIdInURL !== currentVideoId) {
            shouldDebounceInitialize = true;
        }

        for (const mutation of mutations) { // Iterate through each mutation
            // Also listen for changes on #movie_player or video element
            // This can catch cases where the video element itself is re-rendered
            if (mutation.target.matches('#movie_player') || (mutation.target.tagName === 'VIDEO' && mutation.type === 'attributes')) {
                shouldDebounceInitialize = true;
                break;
            }

            // Additionally, if it's the main player element being added/removed
            if (mutation.type === 'childList') {
                for (const addedNode of mutation.addedNodes) {
                     if (addedNode.id === 'movie_player') {
                         shouldDebounceInitialize = true;
                         break;
                     }
                 }
            }
        }


        if (shouldDebounceInitialize) {
            debouncedInitialize();
        }
    });

    // Observe changes on the body with subtree: true to capture deep changes
    observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['src', 'id'] }); // Added 'id' to attributeFilter

    // Initial run when the script loads
    debouncedInitialize();
    // Listen for YouTube's custom navigation events for better compatibility
    // These events are usually more reliable than MutationObserver for YouTube navigation
    window.addEventListener('yt-page-data-updated', debouncedInitialize);
    window.addEventListener('yt-navigate-finish', debouncedInitialize);

    // --- Debug function to inspect GM storage (can be called from Console) ---
    // Usage: Call `window.checkBoosterStorage()` in the browser console.
    window.checkBoosterStorage = async function() {
        console.log("--- YouTube Volume Booster Storage Inspection ---");
        console.log("Global Volume Feature State:", await GM_getValue(STORAGE_KEY_GLOBAL_FEATURE_STATE, false));
        console.log("Remember Per Video Feature State:", await GM_getValue(STORAGE_KEY_PER_VIDEO_FEATURE_STATE, false));
        console.log("One-Time Restore Feature State:", await GM_getValue(STORAGE_KEY_ONE_TIME_RESTORE_FEATURE_STATE, true)); // Default true
        console.log("Per Video Saved Volumes:", await GM_getValue(STORAGE_KEY_PER_VIDEO, {}));
        console.log("One-Time Restore Volumes (Map of videoId -> volume):", await GM_getValue(STORAGE_KEY_ONE_TIME_RESTORE_VOLUMES, {}));
        if (tabId) {
            console.log(`Global Volume for current tab (${tabId}):`, await GM_getValue(STORAGE_KEY_TAB_VOLUME_PREFIX + tabId, 100));
        } else {
            console.log(translations[currentLanguage].tabIdNotInitialized); // Use translation
        }
        // NEW: Log saved toolbar position
        console.log("Saved Toolbar Position:", await GM_getValue(STORAGE_KEY_TOOLBAR_POSITION, null));
        console.log("Current Language:", currentLanguage); // NEW: Display current language
        console.log("------------------------------------------");
    };


})();