YouTube Timestamp Keeper

Keep recent timestamp in URL on YouTube

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         YouTube Timestamp Keeper
// @namespace    Violentmonkey Scripts
// @version      0.1
// @description  Keep recent timestamp in URL on YouTube
// @author       EtiamNullam
// @match        https://www.youtube.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=youtube.com
// @license GPL-3.0-only
// ==/UserScript==
(function() {
    'use strict'

    /**
     * @param {number} durationMs
     */
    function Watcher(durationMs) {
        const watcher = {}
        let interval = null

        function check() {
            const player = getPlayer()

            if (!player || player.paused) {
                watcher.stop()
            } else {
                updateTimestamp()
            }
        }

        watcher.stop = () => {
            clearInterval(interval)

            interval = null
        }

        watcher.start = () => {
            watcher.stop()

            interval = setInterval(check, durationMs)
        }

        return watcher
    }

    const TIMESTAMP_UPDATE_INTERVAL_MS = 900
    const PLAYER_RETRY_DELAY_MS = 1000

    const watcher = Watcher(TIMESTAMP_UPDATE_INTERVAL_MS)

    const playerActionEvents = [
        { event: 'pause', action: updateTimestamp },
        { event: 'seeked', action: updateTimestamp },
        { event: 'play', action: watcher.start },
        { event: 'pause', action: watcher.stop },
    ]


    function getPlayer() {
        return document.querySelector('video')
    }

    function updateTimestamp() {
        const player = getPlayer()

        if (!player) {
            console.warn('Cannot find player')
            return
        }

        const currentUrl = new URL(window.location.href)
        const secondsElapsed = Math.floor(player.currentTime)
        const { searchParams } = currentUrl

        searchParams.set('t', secondsElapsed + 's')

        currentUrl.search = searchParams.toString()

        window.history.replaceState({}, '', currentUrl)
    }

    function setup() {
        if (window.location.pathname !== '/watch') {
            return
        }

        const player = getPlayer()

        if (!player) {
            console.warn('Cannot find player')
            setTimeout(setup, PLAYER_RETRY_DELAY_MS)

            return
        }

        for (const actionEvent of playerActionEvents) {
            player.addEventListener(actionEvent.event, actionEvent.action)
        }

        updateTimestamp()

        if (!player.paused) {
            watcher.start()
        }
    }

    function cleanUp() {
        const player = getPlayer()

        for (const actionEvent of playerActionEvents) {
            player.removeEventListener(actionEvent.event, actionEvent.action)
        }
    }

    window.addEventListener('yt-navigate-start', cleanUp)
    window.addEventListener('yt-navigate-finish', setup)
    window.addEventListener('beforeunload', updateTimestamp)
})()