YouTube - 點擊留言時間戳記時防止捲動到最上方

點留言時間戳記時不讓頁面自動捲動到最上方,這樣就能開子母畫面看留言,又不用擔心點時間戳記會被拉到最上面。

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name                YouTube – Prevent Scrolling to Top When Clicking Timestamps
// @name:zh-TW          YouTube - 點擊留言時間戳記時防止捲動到最上方
// @namespace           https://github.com/micr0dust
// @version             1.0.0
// @description         Prevents YouTube from scrolling to the top when clicking timestamps in comments. This makes it easier to use picture-in-picture mode while reading comments, without being pulled back to the top of the page.
// @description:zh-tw   點留言時間戳記時不讓頁面自動捲動到最上方,這樣就能開子母畫面看留言,又不用擔心點時間戳記會被拉到最上面。
// @match               https://www.youtube.com/*
// @grant               none
// @icon                https://www.google.com/s2/favicons?domain=youtube.com
// @license             MIT
// ==/UserScript==

(function () {
    'use strict';
    if (history.scrollRestoration) {
        try {
            history.scrollRestoration = 'manual';
        } catch (ex) {
            // ignore error
        }
    }

    const observer = new MutationObserver(() => {
        const commentSection = document.querySelector('ytd-comments');
        if (commentSection) {
            observer.disconnect();
            attachListeners();
        }
    });

    observer.observe(document.body, { childList: true, subtree: true });

    function attachListeners() {
        document.body.addEventListener('click', function (e) {
            const link = e.target.closest('a');
            if (!link || !link.href || !link.href.includes('t=') || !link.href.includes('/watch?v=')) {
                return;
            }

            const commentsContainer = document.querySelector('ytd-comments');
            if (commentsContainer && commentsContainer.contains(link)) {
                e.preventDefault();
                e.stopPropagation();
                e.stopImmediatePropagation(); // key point:prevent other handlers from listening

                const url = new URL(link.href);
                const timeStr = url.searchParams.get('t');
                if (!timeStr) return;

                const seconds = parseTime(timeStr);
                if (isNaN(seconds)) return;

                const video = document.querySelector('video.html5-main-video');
                if (video) {
                    video.currentTime = seconds;
                    video.play().catch(() => {});
                }
            }
        }, true);
    }

    function parseTime(t) {
        if (!t) return 0;
        if (/^\d+$/.test(t)) {
            return parseInt(t, 10);
        }
        const regex = /(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?/;
        const match = t.match(regex);
        if (!match) return 0;
        const h = parseInt(match[1] || '0', 10);
        const m = parseInt(match[2] || '0', 10);
        const s = parseInt(match[3] || '0', 10);
        return h * 3600 + m * 60 + s;
    }
})();