L1lith / Crunchyroll Clickable Timestamps

// ==UserScript==
// @name         Crunchyroll Clickable Timestamps
// @namespace    http://openuserjs.org/
// @version      0.1
// @description  Click on a timestamp in the comment section to skip there immediately!
// @author       L1lith
// @match        https://www.crunchyroll.com/*
// @license      MIT
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function() {
    const episodeURLRegex = /^[\/]?[a-z0-9\-]+\/[a-z\-0-9]+$/
    if (!episodeURLRegex.test(window.location.pathname)) return
    const customStyles = (
`.smart-timestamp:hover {
     text-decoration: underline !important;
}`)
    const timestampRegex = /^[0-9]+\:[0-9]{1,2}$/
    const maxRetries = 10
    let currentCommentLength = 0
    const stylesDiv = document.createElement("style")
    stylesDiv.innerText = customStyles
    document.body.appendChild(stylesDiv)
    const commentsHolder = document.getElementById("allCommentsList")
    if (!commentsHolder) throw new Error("Could Not Find Comments Holder")
    makeTimestampsInteractive(commentsHolder)
    const timestampedDivs = []
    const moreCommentsButton = document.getElementsByClassName('more_comments')[0]
    moreCommentsButton.addEventListener('click', makeTimestampsInteractive.bind(null, commentsHolder))
    function makeTimestampsInteractive(commentsDiv, retryCount=0) {
        if (retryCount >= maxRetries) throw new Error("Exceeded Max Retry Limit")
        const commentContentDivs = [...commentsDiv.getElementsByClassName('guestbook-body')]
        if (commentContentDivs.length <= currentCommentLength) return setTimeout(makeTimestampsInteractive.bind(null, commentsDiv, retryCount + 1), 500)
        currentCommentLength = commentContentDivs.length
        commentContentDivs.forEach(div => {
            if (timestampedDivs.includes(div)) return
            timestampedDivs.push(div)
            const words = div.innerText.split(' ')
            div.innerText = "";
            [...div.children].forEach(child => div.removeChild(child))
            words.forEach(word => {
                 div.appendChild(document.createTextNode(" "))
                 if (timestampRegex.test(word)) {
                     const node = document.createElement("a")
                     node.className = "smart-timestamp"
                     node.innerText = word
                     div.appendChild(node)
                     div.addEventListener("click", goToTime.bind(null, word))
                 } else {
                      div.appendChild(document.createTextNode(word))
                 }
            })
        })
    }
    function goToTime(time){
        const minutes = parseInt(time.split(':')[0])
        const seconds = parseInt(time.split(':')[1])
        window.VILOS_PLAYERJS.setCurrentTime(minutes * 60 + seconds)
        document.getElementById('vilos-player').scrollIntoView()
    }
})();