YouTube Watch Later Remove Button on Hover

Show a remove button on hover over video thumbnails in the Watch Later list

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         YouTube Watch Later Remove Button on Hover
// @namespace    http://tampermonkey.net/
// @version      0.6.2
// @description  Show a remove button on hover over video thumbnails in the Watch Later list
// @license MIT
// @match        https://www.youtube.com/*
// @run-at              document-start
// @grant               none
// @inject-into         page
// ==/UserScript==

(function () {
    'use strict';

    let scriptEnable = false;

    const insp = o => o ? (o.polymerController || o.inst || o || 0) : (o || 0);

    function getItemData(menu) {
        if (!menu) return;
        let items = ((menu || 0).menuRenderer || 0).items || 0;
        if (!(items.length >= 1)) return;
        const filtered = items.filter((entry) => {
            if (!entry || typeof entry !== 'object') return false;
            try {
                const t = (JSON.stringify(entry) || '');
                return t.includes('ACTION_REMOVE_VIDEO');
            } catch (e) {
                return false;
            }
        });
        if (filtered.length !== 1) return;
        let itemData = filtered[0];
        itemData = Object.values(itemData).filter(e => e.serviceEndpoint || e.command)[0];
        if (!itemData) return;
        return itemData;
    }

    const removeButtonOnclick = function (e) {
        const button = this;
        if (!scriptEnable) return;

        let videoElement = button.closest('ytd-thumbnail');
        if (!videoElement) return;
        let renderer = videoElement.closest('ytd-playlist-video-renderer.style-scope.ytd-playlist-video-list-renderer');
        if (!renderer) return;

        let data = insp(renderer).data || 0;
        const itemData = getItemData(data.menu);
        if (!itemData) return;

        e.preventDefault(); // Prevent the default action of the event
        e.stopPropagation(); // Stop the event from bubbling up
        e.stopImmediatePropagation(); // Prevents other listeners of the same event from being called

        const cntNode = (document.querySelector('ytd-app') || renderer);

        (function (data) {

            const a = data.serviceEndpoint;
            const b = data.command;

            a && this.ytComponentBehavior.resolveCommand(a);
            b && this.ytComponentBehavior.resolveCommand(b);

        }).call(insp(cntNode), itemData);

    };

    function createRemoveButton(videoElement) {
        let removeButton = document.createElement('button');
        removeButton.className = 'watch-later-remove-button';
        removeButton.textContent = 'Remove';
        removeButton.style.position = 'absolute';
        removeButton.style.top = '5px';
        removeButton.style.right = '5px';
        removeButton.style.zIndex = '1000';

        removeButton.onclick = removeButtonOnclick;
        videoElement.appendChild(removeButton);
    }

    const mouseenterHandler = function (e) {
        if (!e || !(e.target instanceof HTMLElement)) return;
        if (!scriptEnable) return;
        if (!e.target.classList.contains('ytd-playlist-video-renderer')) return;
        let videoElement = e.target.closest('ytd-thumbnail');
        if (!videoElement) return;
        let renderer = videoElement.closest('ytd-playlist-video-renderer.style-scope.ytd-playlist-video-list-renderer');
        if (!renderer || renderer.is !== 'ytd-playlist-video-renderer') return;
        let data = insp(renderer).data || 0;
        let itemData = getItemData(data.menu);
        if (!itemData) return;
        let button = videoElement.querySelector('button.watch-later-remove-button')
        if (!button) {
            createRemoveButton(videoElement);
        } else {
            button.style.display = '';
        }
    };

    const mouseleaveHandler = function (e) {
        if (!e || !(e.target instanceof HTMLElement)) return;
        if (!e.target.classList.contains('ytd-playlist-video-renderer')) return;
        let button = e.target.querySelector('button.watch-later-remove-button');
        if (button) {
            button.style.display = 'none';
        }
    };


    document.addEventListener('yt-navigate-finish', () => {

        const newEnable = location.pathname === '/playlist' && location.search.includes('list=WL');

        if (scriptEnable ^ newEnable) {

            if (scriptEnable) {
                scriptEnable = false;
                document.removeEventListener('mouseenter', mouseenterHandler, true);
                document.removeEventListener('mouseleave', mouseleaveHandler, true);
            } else if (newEnable) {
                scriptEnable = true;
                document.addEventListener('mouseenter', mouseenterHandler, true);
                document.addEventListener('mouseleave', mouseleaveHandler, true);
            }

        }

    }, false);

})();