Do not watch later!

Videos from “Watch Later” become a carousel on the home page.

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

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.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

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  Do not watch later!
// @name:pt-BR  Não deixe para assistir mais tarde!
// @name:es  ¡No lo veas más tarde!
// @name:zh-CN  别想着以后再看!
// @name:ko  나중에 보지 마세요!
// @name:fr  Ne regardez pas plus tard !
// @version      v1
// @description  Videos from “Watch Later” become a carousel on the home page.
// @description:pt-BR Os vídeos do "Assistir mais tarde" transformam-se num carrossel na página inicial.
// @description:es Los videos de "Ver más tarde" se convierten en un carrusel en la página de inicio.
// @description:zh-CN “稍后观看”中的视频在主页上以轮播形式呈现
// @description:ko "나중에 보기"에 저장된 동영상은 홈 화면에서 캐러셀로 표시됩니다
// @description:fr Les vidéos de la section "À regarder plus tard" apparaissent sous forme de carrousel sur la page d'accueil.
// @author       Isac
// @match        https://www.youtube.com/*
// @license     MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @grant        GM_addStyle
// @namespace https://greasyfork.org/users/1570114
// ==/UserScript==

(function() {
    'use strict';

  /*!
  * Copyright (c) 2026, Isac. All rights reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  * copies of the Software, and to permit persons to whom the Software is
  * furnished to do so, subject to the following conditions:
  *
  * The above copyright notice and this permission notice shall be included in
  * all copies or substantial portions of the Software.
  *
  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  *
  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  * SOFTWARE.
  */

    function isHomePage() {
        const path = window.location.pathname;
        return (
            path === "/"
        );
    }

    // ── Primary function ────────────────────
    function initCarousel() {

        console.log("[Do not watch later] Cleaning carousel");
        document.querySelectorAll('.carousel-wrapper, .script-title').forEach(el => el.remove());

        // ────────────────────────────────────────────────
        // Languages
        // ────────────────────────────────────────────────
        const translations = {
            'pt': {
                later: 'Videos do “Assistir mais tarde”',
                feed: 'Feed inicial',
                noVideos: 'Sem vídeos no "Assistir mais Tarde"',
            },
            'en': {
                later: '"Watch Later" Videos',
                feed: 'Home Feed',
                noVideos: 'No videos in “Watch Later”',
            },
            'es': {
                later: 'Videos de "Ver más tarde"',
                feed: 'Feed principal',
                noVideos: 'No hay videos en "Ver más tarde"',
            },
            'zh': {
                later: '稍后观看视频',
                feed: '首页动态',
                noVideos: '“稍后观看”中没有视频',
            },
            'ko': {
                later: '“나중에 보기” 동영상',
                feed: '홈 피드',
                noVideos: '“나중에 보기”에 동영상이 없습니다',
            },
            'fr': {
                later: 'Vidéos "À regarder plus tard"',
                feed: 'Accueil Flux',
                noVideos: 'Aucune vidéo dans "À regarder plus tard"',
            },
        };

        function getYouTubeLanguage() {
            let lang = document.documentElement.lang.split('-')[0];
            if (!translations[lang]) {
                lang = 'en'
            }
            return lang;
        }

    // ────────────────────────────────────────────────
    // CSS (carousel + cards + arrows)
    // ────────────────────────────────────────────────
    GM_addStyle(`
        .script-title {
            margin: 16px 24px 0px;
            font-size: 2.2rem;
            font-weight: 700;
            color: var(--yt-spec-text-primary);
            align-self: flex-start;
            display: inline-flex;
            align-items: center;
            vertical-align: middle;
        }

        .script-title svg {
            vertical-align: middle;
            margin-right: 12px;
            width: 28px;
            height: 28px;
        }

        .script-no-video-title {
            width: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            text-align: center;
            font-size: 2.0rem;
            font-weight: 700;
            color: var(--yt-spec-text-primary);
            padding: 5px 20px;
            margin: 0;
        }

        .carousel-wrapper {
            position: relative;
            padding: 0 24px;
            width: 100%;
            margin-top: 24px;
            box-sizing: border-box;
        }

        #laterDiv {
            width: 100%;
            overflow: hidden;
            scroll-behavior: smooth;
            display: flex;
            flex-direction: row;
            gap: 16px;

            margin-left: 0 !important;
            margin-right: 0 !important;
            padding: 0;
            box-sizing: border-box;
        }

        .video-card {
            flex: 0 0 auto;
            width: 360px;
            text-decoration: none !important;
            color: inherit;
            display: flex;
            flex-direction: column;
            transition: transform 0.15s ease;
        }

        .video-card:hover {
            transform: scale(0.98);
            z-index: 2;
        }

        .thumb-div {
            position: relative;
            width: 100%;
            border-radius: 12px;
            overflow: hidden;
            aspect-ratio: 16 / 9;
        }

        .video-card-thumb {
            width: 100%;
            height: 100%;
            object-fit: cover;
            display: block;
        }

        .video-time-thumb {
            position: absolute;
            bottom: 8px;
            right: 8px;
            background: rgba(0,0,0,0.6);
            color: white;
            font-size: 1.2rem;
            font-weight: 500;
            padding: 1px 4px;
            border-radius: 4px;
            line-height: 1.8rem;
            pointer-events: none;
        }

        .video-card-title {
            margin: 12px 0 2px;
            font-size: 1.55rem;
            line-height: 2.1rem;
            font-weight: 500;
            display: -webkit-box;
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
            color: var(--yt-spec-text-primary);
            -webkit-line-clamp: 2;
            -webkit-box-orient: vertical;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: normal;
        }

        .video-card-infs {
            font-size: 1.38rem;
            line-height: 1.9rem;
            color: var(--yt-spec-text-secondary);
            margin-top: 2px;
        }

        .channel-name-inf {
            color: var(--yt-spec-text-secondary);
            width: fit-content;
            text-decoration: none;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            display: block;
            max-width: 100%;
        }

        .channel-name-inf:hover:not(.no-link) {
            color: var(--yt-spec-text-primary);
        }

        .video-card-infs .delimiter {
            margin: 0 4px;
            font-size: 1.1rem;
            vertical-align: middle;
            color: var(--yt-spec-text-tertiary);
        }

        /* Arrows */
        .carousel-nav {
            position: absolute;
            top: 50%;
            transform: translateY(-50%) scale(1);
            background: rgba(15, 15, 15);
            box-shadow: 0px 0px 15px 3px black;
            color: white;
            border: none;
            width: 44px;
            height: 44px;
            border-radius: 50%;
            font-size: 1.8rem;
            cursor: pointer;
            display: flex;
            align-self: center;
            align-items: center;
            justify-content: center;
            z-index: 10;
            transition: transform 0.2s ease, background-color 0.2s ease, opacity 0.2s ease;
            opacity: 0;
            pointer-events: none;
        }

        .carousel-nav svg {
            fill: currentColor;
        }

        .carousel-wrapper:hover .carousel-nav:not(:disabled),
        .carousel-wrapper:focus-within .carousel-nav:not(:disabled) {
            opacity: 1;
            pointer-events: auto;
        }

        .carousel-nav:hover:not(:disabled):hover {
            background: rgba(63, 63, 63);
        }

        .carousel-nav.left  { left: 28px; }
        .carousel-nav.right { right: 28px; }

        .carousel-nav:disabled {
            cursor: not-allowed;
            pointer-events: none;
            opacity: 0 !important;
            transform: translateY(-50%) scale(0.8);
        }
    `);

    // ────────────────────────────────────────────────
    // Waiting to load the main feed
    // ────────────────────────────────────────────────
    const clock = setInterval(async () => {
        let candidates = document.querySelectorAll('#contents');
        let contents = null;

        for (const candidate of candidates) {
            const next = candidate.nextElementSibling;
            if (next && next.id === "reload-content") {
                contents = candidate;
                break;
            }
        }

        if (!contents) {
            console.log("[Do not watch later] Waiting for content with grid variables...");
            return;
        }
        clearInterval(clock);
        console.log("[Do not watch later] #contents found! Starting carousel...");

         // ── Carousel title ──────────────────────

        function createTitleIcon(pathData) {
            const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            svg.setAttribute("width", "24");
            svg.setAttribute("height", "24");
            svg.setAttribute("viewBox", "0 0 24 24");
            svg.setAttribute("fill", "currentColor");

            const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
            path.setAttribute("d", pathData);
            svg.appendChild(path);

            return svg;
        }

        // ── Titles ──────────────────────
        const translatedTexts = translations[getYouTubeLanguage()]

        const laterH2 = document.createElement("h2");
        laterH2.className = "script-title";

        // 1° SVG
        const laterIcon = createTitleIcon("M12 1C5.925 1 1 5.925 1 12s4.925 11 11 11 11-4.925 11-11S18.075 1 12 1Zm0 2a9 9 0 110 18.001A9 9 0 0112 3Zm0 3a1 1 0 00-1 1v5.565l.485.292 3.33 2a1 1 0 001.03-1.714L13 11.435V7a1 1 0 00-1-1Z");
        laterH2.appendChild(laterIcon);

        // 2° Text
        laterH2.appendChild(document.createTextNode(translatedTexts.later));

        contents.before(laterH2);

        const feedH2 = document.createElement("h2");
        feedH2.className = "script-title feed-title";

        // 1° SVG
        const feedIcon = createTitleIcon("m11.485 2.143-8 4.8-2 1.2a1 1 0 001.03 1.714L3 9.567V20a2 2 0 002 2h6v-7h2v7h6a2 2 0 002-2V9.567l.485.29a1 1 0 001.03-1.714l-2-1.2-8-4.8a1 1 0 00-1.03 0ZM5 8.366l7-4.2 7 4.2V20h-4v-5.5a1.5 1.5 0 00-1.5-1.5h-3A1.5 1.5 0 009 14.5V20H5V8.366Z");
        feedH2.appendChild(feedIcon);

        // 2° Text
        feedH2.appendChild(document.createTextNode(translatedTexts.feed));

        // ── Carousel wrapper (to position arrows) ──
        const wrapper = document.createElement("div");
        wrapper.className = "carousel-wrapper";
        contents.before(wrapper);

        // ── Carousel container ───────────────────
        const laterDiv = document.createElement("div");
        laterDiv.id = "laterDiv";
        wrapper.appendChild(laterDiv);

        // ── Navigation buttons ──────────────────────
        function createChevronSvg(isRight = true) {
            const svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
            svg.setAttribute("height", "24");
            svg.setAttribute("viewBox", "0 0 24 24");
            svg.setAttribute("width", "24");
            svg.setAttribute("focusable", "false");
            svg.setAttribute("aria-hidden", "true");

            svg.style.pointerEvents = "none";
            svg.style.display = "inherit";
            svg.style.width = "100%";
            svg.style.height = "100%";

            const path = document.createElementNS("http://www.w3.org/2000/svg", "path");

            if (isRight) {
                // Right arrow
                path.setAttribute("d", "M8.793 5.293a1 1 0 000 1.414L14.086 12l-5.293 5.293a1 1 0 101.414 1.414L16.914 12l-6.707-6.707a1 1 0 00-1.414 0Z");
            } else {
                // Left arrow
                path.setAttribute("d", "M15.207 5.293a1 1 0 010 1.414L9.914 12l5.293 5.293a1 1 0 01-1.414 1.414l-6-6a1 1 0 010-1.414l6-6a1 1 0 011.414 0Z");
            }

            svg.appendChild(path);
            return svg;
        }

        const btnLeft = document.createElement("button");
        btnLeft.className = "carousel-nav left";
        btnLeft.disabled = true;
        btnLeft.appendChild(createChevronSvg(false));

        const btnRight = document.createElement("button");
        btnRight.className = "carousel-nav right";
        btnRight.appendChild(createChevronSvg(true));

        wrapper.append(btnLeft, btnRight);

        // ── Scroll with arrows ──────────────────────
        const scrollAmount = 380; // ≈ width card (360) + gap (16) + margin

        btnLeft.addEventListener("click", () => {
            laterDiv.scrollBy({ left: -scrollAmount, behavior: "smooth" });
        });

        btnRight.addEventListener("click", () => {
            laterDiv.scrollBy({ left: scrollAmount, behavior: "smooth" });
        });

        const updateButtons = () => {
            btnLeft.disabled = laterDiv.scrollLeft <= 0;
            btnRight.disabled = laterDiv.scrollLeft + laterDiv.clientWidth >= laterDiv.scrollWidth - 1;
        };

        laterDiv.addEventListener("scroll", updateButtons);
        window.addEventListener("resize", updateButtons);

        // ── Get data from the WL playlist ───────────────
        try {
            const res = await fetch("https://www.youtube.com/playlist?list=WL");
            const text = await res.text();
            const start = text.indexOf("var ytInitialData = ") + 20;
            const end = text.indexOf(";</script>", start);
            const jsonStr = text.slice(start, end);
            const data = JSON.parse(jsonStr);

            const contentsList = data?.contents
                ?.twoColumnBrowseResultsRenderer?.tabs?.[0]
                ?.tabRenderer?.content?.sectionListRenderer?.contents?.[0]
                ?.itemSectionRenderer?.contents?.[0]
                ?.playlistVideoListRenderer?.contents;

            if (!Array.isArray(contentsList) || contentsList.length === 0) {
                console.warn("No videos found in the WL playlist");
                btnRight.disabled = true;
                // ── Creating "no videos" screen ──────────────────────
                const textNoVideos = document.createElement('p');
                textNoVideos.textContent = translatedTexts.noVideos;
                textNoVideos.className = "script-no-video-title";
                laterDiv.appendChild(textNoVideos);
            } else {
                contentsList.forEach(item => {
                const r = item?.playlistVideoRenderer;
                if (!r) return;

                const video = {
                    videoId: r.videoId,
                    title: r.title?.runs?.[0]?.text || "Untitled",
                    thumb: r.thumbnail?.thumbnails?.at(-1)?.url || r.thumbnail?.thumbnails?.[0]?.url || "",
                    duration: r.lengthText?.simpleText || "—",
                    channelName: r.shortBylineText?.runs?.[0]?.text || "Unknown channel",
                    channelUrl: r.shortBylineText?.runs?.[0]?.navigationEndpoint?.commandMetadata?.webCommandMetadata?.url || "",
                    views: r.videoInfo?.runs?.[0]?.text || "",
                    published: r.videoInfo?.runs?.[2]?.text || "",
                };

                const a = document.createElement("a");
                a.className = "video-card";
                a.href = `https://www.youtube.com/watch?v=${video.videoId}`;

                const thumbDiv = document.createElement("div");
                thumbDiv.className = "thumb-div";

                const img = document.createElement("img");
                img.className = "video-card-thumb";
                img.src = video.thumb;
                img.alt = video.title;
                img.loading = "lazy";

                const time = document.createElement("div");
                time.className = "video-time-thumb";
                time.textContent = video.duration;

                const title = document.createElement("div");
                title.className = "video-card-title";
                title.textContent = video.title;

                const channel = document.createElement("a");
                channel.className = "video-card-infs channel-name-inf";
                channel.textContent = video.channelName;
                if (video.channelUrl) {
                    channel.href = "https://www.youtube.com" + video.channelUrl;
                } else {
                    channel.className += " no-link"
                }

                const infs = document.createElement("div");
                infs.className = "video-card-infs";

                if (video.views) {
                    const views = document.createElement("span");
                    views.textContent = video.views;
                    infs.appendChild(views);

                    const dot = document.createElement("span");
                    dot.className = "delimiter";
                    dot.textContent = "•";
                    infs.appendChild(dot);
                }

                if (video.published) {
                    const date = document.createElement("span");
                    date.textContent = video.published;
                    infs.appendChild(date);
                }

                thumbDiv.append(img, time);
                a.append(thumbDiv, title, channel, infs);
                laterDiv.appendChild(a);
            });
                console.log(`[Do not watch later] ${contentsList.length} videos added to the carousel`);
            }
            setTimeout(updateButtons, 300);
        } catch (err) {
            console.error("[Do not watch later] Error loading WL:", err);
            btnRight.disabled = true;
        }

        // ── Normal feed title ────────────────────
        contents.before(feedH2);
    }, 800); };
    // ── End of main function ────────────────────
    // Listen to YouTube SPA navigations
    window.addEventListener('yt-navigate-finish', () => {
        console.log("[Do not watch later] Navigation detected - pathname:", window.location.pathname);

        if (isHomePage()) {
            console.log("[Do not watch later] calling initCarousel");
            initCarousel();
        } else {
            console.log("[Do not watch later] It's not home → cleaning carousel");
            document.querySelectorAll('.carousel-wrapper, .script-title').forEach(el => el.remove());
        }
    });
})();