Greasy Fork

NBA.com - Spoiler Blocker

Enhances NBA.com by hiding video lengths and adding fictitious durations to the progress bar to prevent spoilers. This script also adds custom buttons for skipping predefined intervals such as timeouts and halftimes, enhancing the viewing experience. It also hides spoilers on the front page.

目前为 2024-04-21 提交的版本。查看 最新版本

// ==UserScript==
// @name         NBA.com - Spoiler Blocker
// @version      0.1
// @description  Enhances NBA.com by hiding video lengths and adding fictitious durations to the progress bar to prevent spoilers. This script also adds custom buttons for skipping predefined intervals such as timeouts and halftimes, enhancing the viewing experience. It also hides spoilers on the front page.
// @author       You
// @match        *://*.nba.com/*
// @license      MIT
// @grant        none
// @run-at       document-start
// @namespace https://greasyfork.org/users/1291378
// ==/UserScript==

(function() {
    'use strict';

    // Inject CSS to hide specific elements as soon as the page starts loading.
    // This prevents the element from being seen even momentarily.
    const css = '.MaxWidthContainer_mwc__ID5AG { display: none !important; }';
    const head = document.head || document.getElementsByTagName('head')[0];
    const style = document.createElement('style');
    style.type = 'text/css';
    if (style.styleSheet){
      // IE8 and below
      style.styleSheet.cssText = css;
    } else {
      // Other browsers
      style.appendChild(document.createTextNode(css));
    }
    head.appendChild(style);

    // Function to create and append skip buttons to the video player control bar.
    function createAndAppendButton(container, label, seconds) {
        const button = document.createElement('button');
        button.textContent = label;
        button.style.padding = '8px';
        button.style.marginLeft = '5px';
        button.style.background = '#FFF';
        button.style.color = '#000';
        button.style.border = 'none';
        button.style.cursor = 'pointer';

        // When clicked, the button adjusts the current time of the video.
        button.onclick = function() {
            const video = document.querySelector('video');
            if (video) {
                video.currentTime += seconds;
            }
        };

        container.appendChild(button);
    }

    // Generate a random maximum length between 3 and 4 hours to obscure the true length of videos.
    function getRandomMaxLength() {
        const threeHoursInSeconds = 3 * 60 * 60; // 3 hours in seconds
        const oneHourInSeconds = 60 * 60; // 1 hour in seconds
        return threeHoursInSeconds + Math.floor(Math.random() * oneHourInSeconds);
    }

    // Store the random max length so it's used consistently throughout the session.
    const standardMaxLength = getRandomMaxLength();

    // Apply the random max length to video progress bars to obscure their real length.
    function randomizeProgressBar() {
        const progressBar = document.getElementById('progress-bar');
        const rangeInput = document.querySelector('.sc-beqWaB.bpZMgR input[type="range"]');
        if (progressBar && rangeInput) {
            progressBar.max = standardMaxLength;
            rangeInput.max = standardMaxLength;
            rangeInput.setAttribute('aria-valuemax', standardMaxLength);
        }
    }

    // Function to hide elements that show video time, preventing spoilers.
    function hideTimeElements() {
        const timePattern = /\b\d{2}:\d{2}:\d{2}\b/;
        const spans = document.querySelectorAll('span');
        spans.forEach(span => {
            if (timePattern.test(span.innerText)) {
                span.style.display = 'none';
            }
        });
    }

    // Monitor for dynamic changes in the DOM to reapply the hiding functions and check for control bars to add buttons.
    const observer = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
            if (mutation.type === 'childList' || mutation.type === 'attributes') {
                hideTimeElements();
                addSkipButtonsIfControlBarExists();
            }
        });
    });

    // Ensure custom buttons are added to the video player control bar.
    function addSkipButtonsIfControlBarExists() {
        const controlBar = document.querySelector('.sc-lnAgIa.hfaRgm.controlbar');
        if (controlBar && !controlBar.dataset.skipButtonsAdded) {
            controlBar.dataset.skipButtonsAdded = 'true';

            createAndAppendButton(controlBar, 'Skip Short Timeout (30sec)', 30);
            createAndAppendButton(controlBar, 'Skip Timeout (90sec)', 90);
            createAndAppendButton(controlBar, 'Skip Free Throws (1min)', 60);
            createAndAppendButton(controlBar, 'Skip Halftime (15min)', 900);
        }
    }

    // Start the mutation observer to handle dynamic content changes.
    observer.observe(document.body, {
        attributes: true,
        childList: true,
        subtree: true
    });

    // Periodically apply randomization to the progress bar to maintain the fictitious length.
    setInterval(randomizeProgressBar, 1000);
    // Perform initial hiding of time elements and button addition.
    hideTimeElements();
    addSkipButtonsIfControlBarExists();
})();