5-Minute Auto-Next Chapter with Audio Controls

Automatically clicks the next chapter button after customizable time with audio controls and navigation features

目前為 2025-04-16 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         5-Minute Auto-Next Chapter with Audio Controls
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Automatically clicks the next chapter button after customizable time with audio controls and navigation features
// @author       You
// @match        https://inovel12.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// ==/UserScript==

(function() {
    'use strict';
    
    // Configuration
    const DEFAULT_COUNTDOWN_MINUTES = 5;
    const DEFAULT_MAX_CHAPTERS = 4; // Default maximum number of chapters
    
    // Load user preferences from localStorage or use defaults
    let userSettings = JSON.parse(localStorage.getItem('autoNextSettings')) || {};
    let COUNTDOWN_MINUTES = userSettings.timerMinutes || DEFAULT_COUNTDOWN_MINUTES;
    let MAX_CHAPTERS = userSettings.maxChapters || DEFAULT_MAX_CHAPTERS;
    let isMinimized = userSettings.isMinimized || false;
    let audioPlaybackRate = userSettings.audioPlaybackRate || 0.7; // Default to 0.7x
    
    // Selector for the next chapter button
    const NEXT_BUTTON_SELECTOR = 'a.nextchap[rel="next"]';
    // Selector for the previous chapter button
    const PREV_BUTTON_SELECTOR = 'a.prevchap[rel="prev"]';
    // Selector for the audio element
    const AUDIO_SELECTOR = 'audio[controls]';
    
    // Convert minutes to milliseconds
    let countdownMs = COUNTDOWN_MINUTES * 60 * 1000;
    
    // Chapter counter - initialize or retrieve from session storage
    let chaptersNavigated = parseInt(sessionStorage.getItem('auto_next_chapters_count') || '0');
    
    // Check if this is a "next chapter" page by checking session storage
    const isFirstPage = !sessionStorage.getItem('auto_next_started');
    
    // Timer states
    let isRunning = false;
    let isPaused = false;
    let startTime = 0;
    let endTime = 0;
    let remainingTime = countdownMs;
    let countdownInterval;
    let settingsPanelOpen = false;
    
    // Audio states
    let audioElement = null;
    let isAudioPlaying = false;
    
    // Create main container
    const mainContainer = document.createElement('div');
    mainContainer.style.cssText = `
        position: fixed;
        bottom: 80px;
        left: 20px;
        z-index: 9999;
    `;
    document.body.appendChild(mainContainer);
    
    // Create the expanded view container
    const expandedView = document.createElement('div');
    expandedView.className = 'auto-next-expanded';
    expandedView.style.cssText = `
        background-color: rgba(0, 0, 0, 0.7);
        color: white;
        padding: 15px;
        border-radius: 8px;
        font-size: 16px;
        font-family: Arial, sans-serif;
        display: flex;
        flex-direction: column;
        align-items: center;
        gap: 10px;
        min-width: 180px;
        max-width: 250px;
        touch-action: manipulation;
    `;
    
    // Create minimized bubble view with timer
    const bubbleView = document.createElement('div');
    bubbleView.className = 'auto-next-bubble';
    bubbleView.style.cssText = `
        width: 70px;
        height: 70px;
        border-radius: 50%;
        background-color: rgba(0, 0, 0, 0.7);
        display: flex;
        flex-direction: column;
        justify-content: center;
        align-items: center;
        cursor: pointer;
        padding: 5px;
    `;
    
    // Create timer icon
    const bubbleIcon = document.createElement('div');
    bubbleIcon.style.cssText = `
        font-size: 20px;
        margin-bottom: 2px;
    `;
    bubbleIcon.innerHTML = '⏱️';
    
    // Create timer text for bubble
    const bubbleTimer = document.createElement('div');
    bubbleTimer.style.cssText = `
        font-size: 12px;
        color: white;
        font-weight: bold;
    `;
    bubbleTimer.textContent = COUNTDOWN_MINUTES + ':00';
    
    bubbleView.appendChild(bubbleIcon);
    bubbleView.appendChild(bubbleTimer);
    
    // Function to toggle between views
    function toggleView() {
        isMinimized = !isMinimized;
        updateViewState();
        
        // Save state
        userSettings.isMinimized = isMinimized;
        localStorage.setItem('autoNextSettings', JSON.stringify(userSettings));
    }
    
    // Function to update the view based on minimized state
    function updateViewState() {
        if (isMinimized) {
            // Show bubble view, hide expanded view
            if (mainContainer.contains(expandedView)) {
                mainContainer.removeChild(expandedView);
            }
            if (!mainContainer.contains(bubbleView)) {
                mainContainer.appendChild(bubbleView);
            }
        } else {
            // Show expanded view, hide bubble view
            if (mainContainer.contains(bubbleView)) {
                mainContainer.removeChild(bubbleView);
            }
            if (!mainContainer.contains(expandedView)) {
                mainContainer.appendChild(expandedView);
            }
        }
    }
    
    // Add click handler to bubble
    bubbleView.addEventListener('click', toggleView);
    
    // Create timer text element
    const timerText = document.createElement('div');
    timerText.className = 'timer-text';
    timerText.style.cssText = `
        font-size: 18px;
        font-weight: bold;
        margin-bottom: 5px;
        text-align: center;
        width: 100%;
    `;
    timerText.textContent = `Next chapter in: ${COUNTDOWN_MINUTES}:00`;
    expandedView.appendChild(timerText);
    
    // Create chapter counter text element
    const chapterCounterText = document.createElement('div');
    chapterCounterText.className = 'chapter-counter-text';
    chapterCounterText.style.cssText = `
        font-size: 14px;
        color: #ffcc00;
        margin-bottom: 5px;
        text-align: center;
        width: 100%;
    `;
    chapterCounterText.textContent = `Chapters: ${chaptersNavigated}/${MAX_CHAPTERS}`;
    expandedView.appendChild(chapterCounterText);
    
    // Create settings panel (initially hidden)
    const settingsPanel = document.createElement('div');
    settingsPanel.style.cssText = `
        background-color: rgba(40, 40, 40, 0.95);
        padding: 12px;
        border-radius: 5px;
        margin-top: 8px;
        display: none;
        width: 100%;
    `;
    
    // Create minutes input with label
    const timerSettingContainer = document.createElement('div');
    timerSettingContainer.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 10px;
    `;
    
    const timerLabel = document.createElement('label');
    timerLabel.textContent = 'Timer (minutes):';
    timerLabel.style.marginRight = '10px';
    
    const timerInput = document.createElement('input');
    timerInput.type = 'number';
    timerInput.min = '0.5';
    timerInput.max = '60';
    timerInput.step = '0.5';
    timerInput.value = COUNTDOWN_MINUTES;
    timerInput.style.cssText = `
        width: 60px;
        background-color: #333;
        color: white;
        border: 1px solid #555;
        border-radius: 3px;
        padding: 4px;
    `;
    
    timerSettingContainer.appendChild(timerLabel);
    timerSettingContainer.appendChild(timerInput);
    
    // Create max chapters input with label
    const maxChaptersContainer = document.createElement('div');
    maxChaptersContainer.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: space-between;
        margin-bottom: 10px;
    `;
    
    const maxChaptersLabel = document.createElement('label');
    maxChaptersLabel.textContent = 'Max Chapters:';
    maxChaptersLabel.style.marginRight = '10px';
    
    const maxChaptersInput = document.createElement('input');
    maxChaptersInput.type = 'number';
    maxChaptersInput.min = '1';
    maxChaptersInput.max = '20';
    maxChaptersInput.step = '1';
    maxChaptersInput.value = MAX_CHAPTERS;
    maxChaptersInput.style.cssText = `
        width: 60px;
        background-color: #333;
        color: white;
        border: 1px solid #555;
        border-radius: 3px;
        padding: 4px;
    `;
    
    maxChaptersContainer.appendChild(maxChaptersLabel);
    maxChaptersContainer.appendChild(maxChaptersInput);
    
    // Create audio playback rate slider with label
    const audioRateContainer = document.createElement('div');
    audioRateContainer.style.cssText = `
        display: flex;
        flex-direction: column;
        align-items: flex-start;
        justify-content: space-between;
        margin-bottom: 10px;
        width: 100%;
    `;
    
    const audioRateLabel = document.createElement('label');
    audioRateLabel.textContent = 'Audio Speed:';
    audioRateLabel.style.marginBottom = '5px';
    
    const audioRateSliderContainer = document.createElement('div');
    audioRateSliderContainer.style.cssText = `
        display: flex;
        align-items: center;
        justify-content: space-between;
        width: 100%;
    `;
    
    const audioRateSlider = document.createElement('input');
    audioRateSlider.type = 'range';
    audioRateSlider.min = '0.5';
    audioRateSlider.max = '2.5';
    audioRateSlider.step = '0.1';
    audioRateSlider.value = audioPlaybackRate;
    audioRateSlider.style.cssText = `
        flex-grow: 1;
        margin-right: 10px;
    `;
    
    const audioRateValue = document.createElement('span');
    audioRateValue.textContent = audioPlaybackRate + 'x';
    audioRateValue.style.width = '30px';
    
    audioRateSliderContainer.appendChild(audioRateSlider);
    audioRateSliderContainer.appendChild(audioRateValue);
    
    audioRateContainer.appendChild(audioRateLabel);
    audioRateContainer.appendChild(audioRateSliderContainer);
    
    // Add event listener for audio rate slider
    audioRateSlider.addEventListener('input', function() {
        const newRate = parseFloat(this.value);
        audioRateValue.textContent = newRate.toFixed(1) + 'x';
        setAudioPlaybackRate(newRate);
    });
    
    // Create save and cancel buttons
    const settingsButtonContainer = document.createElement('div');
    settingsButtonContainer.style.cssText = `
        display: flex;
        justify-content: space-between;
        margin-top: 10px;
    `;
    
    const saveButton = document.createElement('button');
    saveButton.textContent = 'Save';
    saveButton.style.cssText = `
        background-color: #4CAF50;
        border: none;
        color: white;
        padding: 5px 10px;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
    `;
    
    const cancelButton = document.createElement('button');
    cancelButton.textContent = 'Cancel';
    cancelButton.style.cssText = `
        background-color: #f44336;
        border: none;
        color: white;
        padding: 5px 10px;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
    `;
    
    settingsButtonContainer.appendChild(saveButton);
    settingsButtonContainer.appendChild(cancelButton);
    
    // Add components to settings panel
    settingsPanel.appendChild(timerSettingContainer);
    settingsPanel.appendChild(maxChaptersContainer);
    settingsPanel.appendChild(audioRateContainer);
    settingsPanel.appendChild(settingsButtonContainer);
    
    // Add settings panel to expanded view
    expandedView.appendChild(settingsPanel);
    
    // Create a button container for all controls
    const buttonContainer = document.createElement('div');
    buttonContainer.style.cssText = `
        display: flex;
        flex-direction: column;
        gap: 10px;
        margin-top: 5px;
        width: 100%;
    `;
    expandedView.appendChild(buttonContainer);
    
    // Create the main multi-function button (Row 1)
    const actionButton = document.createElement('button');
    actionButton.textContent = isFirstPage ? 'Start' : 'Pause';
    actionButton.style.cssText = `
        background-color: ${isFirstPage ? '#2196F3' : '#4CAF50'};
        border: none;
        color: white;
        padding: 10px 15px;
        text-align: center;
        text-decoration: none;
        font-size: 17px;
        font-weight: bold;
        cursor: pointer;
        border-radius: 6px;
        width: 100%;
    `;
    buttonContainer.appendChild(actionButton);
    
    // Create container for time adjustment buttons (Row 2)
    const adjustButtonsContainer = document.createElement('div');
    adjustButtonsContainer.style.cssText = `
        display: flex;
        justify-content: space-between;
        width: 100%;
        gap: 10px;
    `;
    
    // Create -30s button
    const minusButton = document.createElement('button');
    minusButton.textContent = '-30s';
    minusButton.style.cssText = `
        background-color: #FF9800;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    
    // Create +30s button
    const plusButton = document.createElement('button');
    plusButton.textContent = '+30s';
    plusButton.style.cssText = `
        background-color: #9C27B0;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    
    // Add time adjustment buttons to their container
    adjustButtonsContainer.appendChild(minusButton);
    adjustButtonsContainer.appendChild(plusButton);
    buttonContainer.appendChild(adjustButtonsContainer);
    
    // Create container for audio control buttons (New Row)
    const audioControlContainer = document.createElement('div');
    audioControlContainer.style.cssText = `
        display: flex;
        justify-content: space-between;
        width: 100%;
        gap: 10px;
    `;
    
    // Create audio play/pause button
    const audioToggleButton = document.createElement('button');
    audioToggleButton.innerHTML = '▶️ Play Audio';
    audioToggleButton.style.cssText = `
        background-color: #03A9F4;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 2;
    `;
    
    // Create speed down button
    const speedDownButton = document.createElement('button');
    speedDownButton.innerHTML = '🐢';
    speedDownButton.style.cssText = `
        background-color: #795548;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    
    // Create speed up button
    const speedUpButton = document.createElement('button');
    speedUpButton.innerHTML = '🐇';
    speedUpButton.style.cssText = `
        background-color: #009688;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    
    // Add audio control buttons to their container
    audioControlContainer.appendChild(audioToggleButton);
    audioControlContainer.appendChild(speedDownButton);
    audioControlContainer.appendChild(speedUpButton);
    buttonContainer.appendChild(audioControlContainer);
    
    // Create container for minimize and settings buttons
    const controlButtonsContainer = document.createElement('div');
    controlButtonsContainer.style.cssText = `
        display: flex;
        justify-content: space-between;
        width: 100%;
        gap: 10px;
    `;
    
    // Create minimize button with text and icon
    const minimizeButton = document.createElement('button');
    minimizeButton.innerHTML = '− Minimize';
    minimizeButton.style.cssText = `
        background-color: #607D8B;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    minimizeButton.addEventListener('click', toggleView);
    
    // Create settings button with text and icon
    const settingsButton = document.createElement('button');
    settingsButton.innerHTML = '⚙️ Settings';
    settingsButton.style.cssText = `
        background-color: #2196F3;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    
    // Add minimize and settings buttons to their container
    controlButtonsContainer.appendChild(minimizeButton);
    controlButtonsContainer.appendChild(settingsButton);
    buttonContainer.appendChild(controlButtonsContainer);
    
    // Create Stop button
    const stopButton = document.createElement('button');
    stopButton.textContent = '⛔ Stop Permanently';
    stopButton.style.cssText = `
        background-color: #f44336;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        font-weight: bold;
        cursor: pointer;
        border-radius: 4px;
        width: 100%;
        margin-top: 5px;
    `;
    buttonContainer.appendChild(stopButton);
    
    // Create container for navigation buttons
    const navButtonsContainer = document.createElement('div');
    navButtonsContainer.style.cssText = `
        display: flex;
        justify-content: space-between;
        width: 100%;
        gap: 10px;
        margin-top: 10px;
    `;
    
    // Create Previous Chapter button
    const prevChapterButton = document.createElement('button');
    prevChapterButton.innerHTML = '⬅️ Previous';
    prevChapterButton.style.cssText = `
        background-color: #FF9800;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    
    // Create Next Chapter button
    const nextChapterButton = document.createElement('button');
    nextChapterButton.innerHTML = 'Next ➡️';
    nextChapterButton.style.cssText = `
        background-color: #4CAF50;
        border: none;
        color: white;
        padding: 8px 0;
        text-align: center;
        text-decoration: none;
        font-size: 14px;
        cursor: pointer;
        border-radius: 4px;
        flex: 1;
    `;
    
    // Add navigation buttons to their container
    navButtonsContainer.appendChild(prevChapterButton);
    navButtonsContainer.appendChild(nextChapterButton);
    buttonContainer.appendChild(navButtonsContainer);
    
    // Function to get the audio element
    function getAudioElement() {
        if (!audioElement) {
            audioElement = document.querySelector(AUDIO_SELECTOR);
        }
        return audioElement;
    }
    
    // Function to toggle audio play/pause
    function toggleAudio() {
        const audio = getAudioElement();
        if (audio) {
            if (audio.paused) {
                audio.play();
                isAudioPlaying = true;
                audioToggleButton.innerHTML = '⏸️ Pause Audio';
            } else {
                audio.pause();
                isAudioPlaying = false;
                audioToggleButton.innerHTML = '▶️ Play Audio';
            }
        } else {
            audioToggleButton.innerHTML = '❌ No Audio Found';
            setTimeout(() => {
                audioToggleButton.innerHTML = isAudioPlaying ? '⏸️ Pause Audio' : '▶️ Play Audio';
            }, 2000);
        }
    }
    
    // Function to set audio playback rate
    function setAudioPlaybackRate(rate) {
        const audio = getAudioElement();
        if (audio) {
            audio.playbackRate = rate;
            audioPlaybackRate = rate;
            
            // Save to user settings
            userSettings.audioPlaybackRate = rate;
            localStorage.setItem('autoNextSettings', JSON.stringify(userSettings));
        }
    }
    
    // Function to decrease audio speed
    function decreaseAudioSpeed() {
        const newRate = Math.max(0.5, audioPlaybackRate - 0.1);
        setAudioPlaybackRate(newRate);
        
        // Update slider and display
        if (audioRateSlider) {
            audioRateSlider.value = newRate;
            audioRateValue.textContent = newRate.toFixed(1) + 'x';
        }
        
        // Show temporary feedback
        const originalText = speedDownButton.innerHTML;
        speedDownButton.innerHTML = newRate.toFixed(1) + 'x';
        setTimeout(() => {
            speedDownButton.innerHTML = originalText;
        }, 1000);
    }
    
    // Function to increase audio speed
    function increaseAudioSpeed() {
        const newRate = Math.min(2.5, audioPlaybackRate + 0.1);
        setAudioPlaybackRate(newRate);
        
        // Update slider and display
        if (audioRateSlider) {
            audioRateSlider.value = newRate;
            audioRateValue.textContent = newRate.toFixed(1) + 'x';
        }
        
        // Show temporary feedback
        const originalText = speedUpButton.innerHTML;
        speedUpButton.innerHTML = newRate.toFixed(1) + 'x';
        setTimeout(() => {
            speedUpButton.innerHTML = originalText;
        }, 1000);
    }
    
    // Function to toggle settings panel
    function toggleSettingsPanel() {
        settingsPanelOpen = !settingsPanelOpen;
        settingsPanel.style.display = settingsPanelOpen ? 'block' : 'none';
        
        // Reset input values to current settings
        timerInput.value = COUNTDOWN_MINUTES;
        maxChaptersInput.value = MAX_CHAPTERS;
        audioRateSlider.value = audioPlaybackRate;
        audioRateValue.textContent = audioPlaybackRate.toFixed(1) + 'x';
    }
    
    // Function to save settings
    function saveSettings() {
        // Get and validate timer minutes
        const newTimerMinutes = parseFloat(timerInput.value);
        
        if (isNaN(newTimerMinutes) || newTimerMinutes < 0.5 || newTimerMinutes > 60) {
            alert('Please enter a valid time between 0.5 and 60 minutes.');
            return;
        }
        
        // Get and validate max chapters
        const newMaxChapters = parseInt(maxChaptersInput.value);
        
        if (isNaN(newMaxChapters) || newMaxChapters < 1 || newMaxChapters > 20) {
            alert('Please enter a valid number of chapters between 1 and 20.');
            return;
        }
        
        // Update settings
        COUNTDOWN_MINUTES = newTimerMinutes;
        countdownMs = COUNTDOWN_MINUTES * 60 * 1000;
        
        // Update max chapters
        MAX_CHAPTERS = newMaxChapters;
        chapterCounterText.textContent = `Chapters: ${chaptersNavigated}/${MAX_CHAPTERS}`;
        
        // Get and save audio rate
        const newAudioRate = parseFloat(audioRateSlider.value);
        setAudioPlaybackRate(newAudioRate);
        
        // If timer is not running, update the remaining time
        if (!isRunning) {
            remainingTime = countdownMs;
            updateCountdown();
        }
        
        // Save to localStorage
        userSettings.timerMinutes = COUNTDOWN_MINUTES;
        userSettings.maxChapters = MAX_CHAPTERS;
        userSettings.audioPlaybackRate = audioPlaybackRate;
        localStorage.setItem('autoNextSettings', JSON.stringify(userSettings));
        
        // Close settings panel
        toggleSettingsPanel();
    }
    
    // Settings button click handler
    settingsButton.addEventListener('click', toggleSettingsPanel);
    
    // Save button click handler
    saveButton.addEventListener('click', saveSettings);
    
    // Cancel button click handler
    cancelButton.addEventListener('click', toggleSettingsPanel);
    
    // Function to start the timer
    function startTimer() {
        isRunning = true;
        isPaused = false;
        startTime = Date.now();
        endTime = startTime + remainingTime;
        
        // Store in session storage that we've started
        sessionStorage.setItem('auto_next_started', 'true');
        
        // Update button
        actionButton.textContent = 'Pause';
        actionButton.style.backgroundColor = '#4CAF50';
        
        // Start the countdown interval
        if (!countdownInterval) {
            countdownInterval = setInterval(updateCountdown, 1000);
        }
    }
    
    // Function to pause the timer
    function pauseTimer() {
        isPaused = true;
        isRunning = false;
        
        // Store the remaining time when paused
        remainingTime = Math.max(0, endTime - Date.now());
        
        // Update button
        actionButton.textContent = 'Resume';
        actionButton.style.backgroundColor = '#f44336';
    }
    
    // Function to resume the timer
    function resumeTimer() {
        isPaused = false;
        isRunning = true;
        
        // Recalculate the end time based on the remaining time
        endTime = Date.now() + remainingTime;
        
        // Update button
        actionButton.textContent = 'Pause';
        actionButton.style.backgroundColor = '#4CAF50';
    }
    
    // Update the countdown display
    function updateCountdown() {
        if (isRunning && !isPaused) {
            remainingTime = Math.max(0, endTime - Date.now());
        }
        
        const minutesLeft = Math.floor(remainingTime / 60000);
        const secondsLeft = Math.floor((remainingTime % 60000) / 1000);
        const formattedTime = `${minutesLeft}:${secondsLeft.toString().padStart(2, '0')}`;
        
        // Update the timer text in expanded view
        timerText.textContent = `Next chapter in: ${formattedTime}`;
        
        // Update the timer text in bubble view
        if (bubbleTimer) {
            bubbleTimer.textContent = formattedTime;
        }
        
        if (remainingTime <= 0 && isRunning && !isPaused) {
            clearInterval(countdownInterval);
            countdownInterval = null;
            clickNextChapter();
        }
    }
    
    // Button click handler - cycles through Start, Pause, Resume
    actionButton.addEventListener('click', function() {
        if (!isRunning && !isPaused) {
            // Start the timer
            startTimer();
        } else if (isRunning && !isPaused) {
            // Pause the timer
            pauseTimer();
        } else if (!isRunning && isPaused) {
            // Resume the timer
            resumeTimer();
        }
    });
    
    // Add 30 seconds to the timer
    plusButton.addEventListener('click', function() {
        // Only allow adjustment if timer is running or paused
        if (isRunning || isPaused) {
            // If paused, just adjust the remaining time
            if (isPaused) {
                remainingTime += 30000; // 30 seconds in milliseconds
            } else {
                // If running, adjust the end time
                endTime += 30000;
            }
            
            // Update the display immediately
            updateCountdown();
        }
    });
    
    // Subtract 30 seconds from the timer
    minusButton.addEventListener('click', function() {
        // Only allow adjustment if timer is running or paused
        if (isRunning || isPaused) {
            if (isPaused) {
                // Don't let it go below zero
                remainingTime = Math.max(0, remainingTime - 30000);
            } else {
                // Adjust end time but don't let it go below current time
                endTime = Math.max(Date.now(), endTime - 30000);
                // Recalculate remaining time
                remainingTime = Math.max(0, endTime - Date.now());
            }
            
            // Update the display immediately
            updateCountdown();
            
            // If we reduced to zero, trigger next chapter
            if (remainingTime <= 0 && isRunning) {
                clearInterval(countdownInterval);
                countdownInterval = null;
                clickNextChapter();
            }
        }
    });
    
    // Audio control button click handlers
    audioToggleButton.addEventListener('click', toggleAudio);
    speedDownButton.addEventListener('click', decreaseAudioSpeed);
    speedUpButton.addEventListener('click', increaseAudioSpeed);
    
    // Function to check if we should stop due to chapter limit
    function checkChapterLimit() {
        if (chaptersNavigated >= MAX_CHAPTERS) {
            // Update the UI to show we've reached the limit
            timerText.textContent = `Reached limit of ${MAX_CHAPTERS} chapters`;
            chapterCounterText.textContent = `Chapters: ${chaptersNavigated}/${MAX_CHAPTERS} - Limit reached!`;
            chapterCounterText.style.color = '#ff6666';
            
            // Reset the chapter counter after reaching the limit
            chaptersNavigated = 0;
            sessionStorage.setItem('auto_next_chapters_count', '0');
            
            // Stop the timer
            stopPermanently();
            
            return true;
        }
        return false;
    }
    
    // Function to click the next chapter button
    function clickNextChapter() {
        // Increment chapter counter before checking
        chaptersNavigated++;
        sessionStorage.setItem('auto_next_chapters_count', chaptersNavigated.toString());
        
        // Update chapter counter display
        chapterCounterText.textContent = `Chapters: ${chaptersNavigated}/${MAX_CHAPTERS}`;
        
        // Check if we've reached the limit
        if (checkChapterLimit()) {
            // We've reached the limit, don't proceed
            return;
        }
        
        // Update the timer text
        timerText.textContent = 'Moving to next chapter...';
        
        // Try to find the next chapter button
        const nextButton = document.querySelector(NEXT_BUTTON_SELECTOR);
        
        if (nextButton) {
            // Highlight the button being clicked
            const originalBackground = nextButton.style.backgroundColor;
            const originalTransition = nextButton.style.transition;
            
            nextButton.style.transition = 'background-color 0.3s ease';
            nextButton.style.backgroundColor = 'yellow';
            
            // Store flag to auto-play audio after navigation
            sessionStorage.setItem('auto_play_audio', 'true');
            
            // Click after a short delay to show the highlight
            setTimeout(() => {
                nextButton.click();
                
                // If for some reason we're still on the page after clicking
                setTimeout(() => {
                    nextButton.style.backgroundColor = originalBackground;
                    nextButton.style.transition = originalTransition;
                    timerText.textContent = 'Click failed or redirecting...';
                }, 1000);
            }, 500);
        } else {
            timerText.textContent = 'Next button not found! Adjust the selector in the script.';
            
            // Error message will remain visible
        }
    }
    
    // Function to permanently stop the script
    function stopPermanently() {
        // Clear any running intervals
        if (countdownInterval) {
            clearInterval(countdownInterval);
            countdownInterval = null;
        }
        
        // Reset states
        isRunning = false;
        isPaused = false;
        
        // Reset chapter counter
        chaptersNavigated = 0;
        sessionStorage.setItem('auto_next_chapters_count', '0');
        
        // Update UI
        timerText.textContent = 'Timer stopped permanently';
        chapterCounterText.textContent = `Chapters: ${chaptersNavigated}/${MAX_CHAPTERS}`;
        chapterCounterText.style.color = '#ffcc00'; // Reset color
        
        if (bubbleTimer) {
            bubbleTimer.textContent = 'Stopped';
        }
        
        // Disable all buttons except settings and audio controls
        actionButton.disabled = true;
        minusButton.disabled = true;
        plusButton.disabled = true;
        stopButton.disabled = true;
        prevChapterButton.disabled = true;
        nextChapterButton.disabled = true;
        
        // Change button appearances
        actionButton.style.backgroundColor = '#999';
        minusButton.style.backgroundColor = '#999';
        plusButton.style.backgroundColor = '#999';
        stopButton.style.backgroundColor = '#999';
        prevChapterButton.style.backgroundColor = '#999';
        nextChapterButton.style.backgroundColor = '#999';
        stopButton.textContent = 'Stopped';
    }
    
    // Function to navigate to previous chapter
    function goToPrevChapter() {
        const prevButton = document.querySelector(PREV_BUTTON_SELECTOR);
        if (prevButton) {
            // Highlight the button being clicked
            const originalBackground = prevButton.style.backgroundColor;
            const originalTransition = prevButton.style.transition;
            
            prevButton.style.transition = 'background-color 0.3s ease';
            prevButton.style.backgroundColor = 'yellow';
            
            // Click after a short delay to show the highlight
            setTimeout(() => {
                prevButton.click();
            }, 300);
        } else {
            timerText.textContent = 'Previous chapter button not found!';
        }
    }
    
    // Function to navigate to next chapter immediately
    function goToNextChapter() {
        const nextButton = document.querySelector(NEXT_BUTTON_SELECTOR);
        if (nextButton) {
            // Increment chapter counter (just like the auto-next function)
            chaptersNavigated++;
            sessionStorage.setItem('auto_next_chapters_count', chaptersNavigated.toString());
            
            // Update chapter counter display
            chapterCounterText.textContent = `Chapters: ${chaptersNavigated}/${MAX_CHAPTERS}`;
            
            // Check if we've reached the limit before navigating
            if (checkChapterLimit()) {
                // We've reached the limit, don't proceed
                return;
            }
            
            // Highlight the button being clicked
            const originalBackground = nextButton.style.backgroundColor;
            const originalTransition = nextButton.style.transition;
            
            nextButton.style.transition = 'background-color 0.3s ease';
            nextButton.style.backgroundColor = 'yellow';
            
            // Store flag to auto-play audio after navigation
            sessionStorage.setItem('auto_play_audio', 'true');
            
            // Click after a short delay to show the highlight
            setTimeout(() => {
                nextButton.click();
            }, 300);
        } else {
            timerText.textContent = 'Next chapter button not found!';
        }
    }
    
    // Add stop button click handler
    stopButton.addEventListener('click', stopPermanently);
    
    // Add click handlers for navigation buttons
    prevChapterButton.addEventListener('click', goToPrevChapter);
    nextChapterButton.addEventListener('click', goToNextChapter);
    
    // Initialize audio controls
    function initializeAudio() {
        // Try to get the audio element
        const audio = getAudioElement();
        
        if (audio) {
            // Set the initial playback rate
            audio.playbackRate = audioPlaybackRate;
            
            // Check if audio is playing and update UI accordingly
            isAudioPlaying = !audio.paused;
            audioToggleButton.innerHTML = isAudioPlaying ? '⏸️ Pause Audio' : '▶️ Play Audio';
            
            // Add an event listener to update UI when audio state changes
            audio.addEventListener('play', function() {
                isAudioPlaying = true;
                audioToggleButton.innerHTML = '⏸️ Pause Audio';
            });
            
            audio.addEventListener('pause', function() {
                isAudioPlaying = false;
                audioToggleButton.innerHTML = '▶️ Play Audio';
            });
            
            // Add an event listener to handle audio ending
            audio.addEventListener('ended', function() {
                isAudioPlaying = false;
                audioToggleButton.innerHTML = '▶️ Play Audio';
            });
            
            // Check if we should auto-play audio after navigation
            if (sessionStorage.getItem('auto_play_audio') === 'true') {
                // Clear the flag
                sessionStorage.removeItem('auto_play_audio');
                
                // Add notification
                timerText.textContent = 'Auto-playing audio in 3 seconds...';
                
                // Auto-play after 3 seconds
                setTimeout(() => {
                    audio.play();
                    timerText.textContent = 'Audio playing automatically';
                    
                    // Restore normal timer display after notification
                    setTimeout(() => {
                        updateCountdown();
                    }, 2000);
                }, 3000);
            }
        }
    }
    
    // Function to handle page visibility changes
    function handleVisibilityChange() {
        if (document.hidden) {
            // Page is hidden (user switched tabs, minimized window, etc.)
            // No need to pause audio automatically
        } else {
            // Page is visible again
            // Reinitialize audio controls to sync with actual state
            initializeAudio();
        }
    }
    
    // Add visibility change listener
    document.addEventListener('visibilitychange', handleVisibilityChange);
    
    // Check if we've already reached the chapter limit
    if (chaptersNavigated >= MAX_CHAPTERS) {
        checkChapterLimit();
    } else {
        // Set initial view state based on preference
        updateViewState();
        
        // Initialize audio controls
        initializeAudio();
        
        // Automatically start timer if it's not the first page
        if (!isFirstPage) {
            startTimer();
        }
        
        // Update countdown initially
        updateCountdown();
    }
    
    // Check for new audio elements if they get added dynamically
    const audioObserver = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            if (mutation.addedNodes.length) {
                // Check if any of the added nodes are audio elements or contain them
                mutation.addedNodes.forEach(function(node) {
                    if (node.nodeName === 'AUDIO' || 
                        (node.nodeType === 1 && node.querySelector(AUDIO_SELECTOR))) {
                        // Reset audio element cache and reinitialize
                        audioElement = null;
                        initializeAudio();
                    }
                });
            }
        });
    });
    
    // Start observing the document with the configured parameters
    audioObserver.observe(document.body, { childList: true, subtree: true });
})();