Greasy Fork is available in English.

Youtube: expand description and long comments; show all the replies

Video description, long comments and list of subscriptions are expanded automatically; all the replies are shown after pressing "Show more replies" button

// ==UserScript==
// @name          Youtube: expand description and long comments; show all the replies
// @description   Video description, long comments and list of subscriptions are expanded automatically; all the replies are shown after pressing "Show more replies" button
// @author        MK
// @namespace     max44
// @homepage      https://greasyfork.org/en/users/309172-max44
// @match         *://*.youtube.com/*
// @match         *://*.youtu.be/*
// @icon          https://cdn.icon-icons.com/icons2/1488/PNG/512/5295-youtube-i_102568.png
// @version       1.2.9
// @license       MIT
// @grant         none
// @require       https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// @run-at        document-end
// ==/UserScript==

(function () {
  'use strict';

  var videoIdAtLastCheck = "";
  var btnClick = null;
  var waitVideo;
  var i;

  var observerBody = null;
  var observerSubs = null;
  var flgSubsDone = false;
  var observerDesc = null;
  var observerComments = null;
  //var observerCommentsTabview = null;
  var observerCommentsNotif = null;
  var observerComPost = null;

  //---
  //--- Listen to global page changes
  //---
  const callbackBody = function (mutationsList, observer) {

    var pathArray = window.location.pathname.split('/');
    var firstPath = pathArray[1];
    var lastPath = pathArray[pathArray.length - 1];

    //Check whether video is new to expand description
    if (firstPath === "watch") {
      //var player = $( "div#content ytd-watch-flexy" );
      var player = document.querySelectorAll("div#content ytd-watch-flexy");
      if (player != null && player.length > 0) {
        clearInterval(waitVideo); //Stop waiting for video
        var videoId = player[0].getAttribute("video-id");
        player = null;

        if (videoIdAtLastCheck != videoId) {
          videoIdAtLastCheck = videoId;
          expandDesc();
        }
      }
    }

/*    //---
    //--- Listen to description and expand it
    //---
    if (observerDesc == null) {
      const callbackDesc = function (mutationsList, observer) {
        //Check whether video is new to expand description
        if (firstPath === "watch") {
          var player = $( "div#content ytd-watch-flexy" );
          if (player != null && player.length > 0) {
            clearInterval(waitVideo); //Stop waiting for video
            var videoId = player[0].getAttribute("video-id");
            player = null;

            if (videoIdAtLastCheck != videoId) {
              videoIdAtLastCheck = videoId;
              console.log("new video");
              expandDesc();
            }
          }
        }
      }
      let nodeDesc = document.querySelector("#player");//document.querySelector(".watch-active-metadata");
      if (nodeDesc != null) {
        observerDesc = new MutationObserver(callbackDesc);
        observerDesc.observe(nodeDesc, {childList: true, subtree: true, attributes: true, characterData: false});
        console.log("desc observer added");
      }
    }*/

    //Remove subscriptions observer after subscriptions have been expanded
    if (flgSubsDone && observerSubs != null) {
      observerSubs.disconnect(); //Expand subscriptions only once
      observerSubs = null;
    }

    //---
    //--- Listen to community posts and expand them
    //---
    if (observerComPost == null && lastPath === "community") {
      const callbackComPost = function (mutationsList, observer) {
        expandComPosts();
      }
      let nodeComPost = document.querySelector("#primary #contents #contents");
      if (nodeComPost != null) {
        observerComPost = new MutationObserver(callbackComPost);
        observerComPost.observe(nodeComPost, {childList: true, subtree: true, attributes: true, characterData: false});
      }
    }
    //Remove community post observer on non-community pages
    if (observerComPost != null && lastPath != "community") {
      observerComPost.disconnect();
      observerComPost = null;
    }

    //---
    //--- Listen to comments and expand them
    //---
    if (observerComments == null && (firstPath === "watch" || firstPath === "post" || firstPath === "shorts" || lastPath === "community")) {
      const callbackComments = function (mutationsList, observer) {
        expandComments();
      }
      let nodeComments = null;
      let nodeCommentsTabview = null;
      if (firstPath === "shorts") {
        nodeComments = document.querySelector("ytd-shorts ytd-comments:not([hidden='']");
        if (nodeComments != null) {
          observerComments = new MutationObserver(callbackComments);
          observerComments.observe(nodeComments, {childList: true, subtree: true, attributes: true, characterData: false});
        }
      } else {
        nodeComments = document.querySelector("#primary ytd-comments:not([hidden='']");
        if (nodeComments != null) {
          observerComments = new MutationObserver(callbackComments);
          observerComments.observe(nodeComments, {childList: true, subtree: true, attributes: true, characterData: false});
        }
        nodeCommentsTabview = document.querySelector("#right-tabs ytd-comments:not([hidden='']");
        if (nodeCommentsTabview != null) {
          observerComments = new MutationObserver(callbackComments);
          observerComments.observe(nodeCommentsTabview, {childList: true, subtree: true, attributes: true, characterData: false});
        }
      }
    }
    //Remove comments observer
    if (observerComments != null && firstPath != "watch" && firstPath != "shorts" && firstPath != "post" && lastPath != "community") {
      observerComments.disconnect();
      observerComments = null;
    }

    //---
    //--- Listen to comments in notification submenu and expand them
    //---
    if (observerCommentsNotif == null) {
      const callbackCommentsNotif = function (mutationsList, observer) {
        expandCommentsNotif();
      }
      let nodeCommentsNotif = null;
      nodeCommentsNotif = document.querySelector("ytd-popup-container #contentWrapper");
      if (nodeCommentsNotif != null) {
        observerCommentsNotif = new MutationObserver(callbackCommentsNotif);
        observerCommentsNotif.observe(nodeCommentsNotif, {childList: true, subtree: true, attributes: true, characterData: false});
      }
    }
  }

  let nodeBody = document.querySelector("body");
  if (nodeBody != null) {
    const observerBody = new MutationObserver(callbackBody);
    observerBody.observe(nodeBody, {childList: true, subtree: true, attributes: true, characterData: false});
  }

  //---
  //--- Listen to subscriptions and expand them
  //---
  const callbackSubs = function (mutationsList, observer) {
    expandSubs();
  }
  let nodeSubs = document.querySelector("div#guide-wrapper");
  if (nodeSubs != null) {
    observerSubs = new MutationObserver(callbackSubs);
    observerSubs.observe(nodeSubs, {childList: true, subtree: true, attributes: true, characterData: false});
  }

  /*//Check what buttons to click after each scroll of main window
  $( window ).scroll(function() {
    //expandComPosts();
    expandComments();
  });*/


  //---------------------------------------
  // Expand description
  //---------------------------------------
  function expandDesc() {
    //Expand description
    /*btnClick = $( "div#description ytd-text-inline-expander tp-yt-paper-button#expand[role='button']:not([hidden=''])" );
    if (btnClick != null && btnClick.length > 0) {// && isVisible(btnClick)) {
      btnClick[0].click();
    }*/

    //Expand description - suggested by gcobc12632
    //btnClick = $( "yt-interaction#description-interaction" );
    btnClick = document.querySelector("yt-interaction#description-interaction");
    if (btnClick != null) {// && isVisible(btnClick)) {
      btnClick.click();
    }

    //Expand description after 7ktTube | 2016 REDUX script
    //btnClick = $( "div#meta-contents ytd-video-secondary-info-renderer div ytd-expander tp-yt-paper-button#more:not([hidden=''])" );
    btnClick = document.querySelectorAll("div#meta-contents ytd-video-secondary-info-renderer div ytd-expander tp-yt-paper-button#more:not([hidden=''])");
    if (btnClick != null && btnClick.length > 0) {// && isVisible(btnClick)) {
      btnClick[0].click();
    }
  }

  //---------------------------------------
  // Expand post in community section
  //---------------------------------------
  function expandComPosts() {
    //btnClick = $( "div#post tp-yt-paper-button#more:not([hidden='']) > span.more-button" );
    btnClick = document.querySelectorAll("#post tp-yt-paper-button#more:not([hidden='']) > span.more-button");
    if (btnClick != null && btnClick.length > 0) {
      for (i = 0; i < btnClick.length; i++) {
        btnClick[i].click();
        btnClick[i].parentNode.previousElementSibling.setAttribute("style", "display:none;"); //Hide "Show less" button
      }
    }
  }

  //---------------------------------------
  // Expand comments
  //---------------------------------------
  function expandComments() {
    //Expand long comments and hide "show less" button in comments section
    btnClick = document.querySelectorAll("ytd-comments tp-yt-paper-button#more:not([hidden='']) > span.more-button");
    if (btnClick != null) {
      for (i = 0; i < btnClick.length; i++) {
        btnClick[i].click();
        btnClick[i].setAttribute("clicked-by-script", "true"); //Do not click it again
        btnClick[i].parentNode.previousElementSibling.setAttribute("style", "display:none;"); //Hide "Show less" button
      }
    }

    //Show all replies upon pressing "Show more replies" button (not in notification submenu)
    btnClick = document.querySelectorAll("#primary div#replies div#expander div#expander-contents div#button.ytd-continuation-item-renderer:not([hidden]) ytd-button-renderer.ytd-continuation-item-renderer button.yt-spec-button-shape-next:not([clicked-by-script='true'])");
    if (btnClick != null) {
      for (i = 0; i < btnClick.length; i++) {
        btnClick[i].click();
        btnClick[i].setAttribute("clicked-by-script", "true"); //Do not click it again
      }
    }
    //Rearm "Show more replies" button
    btnClick = document.querySelectorAll("#primary div#replies div#expander div#expander-contents div#button.ytd-continuation-item-renderer[hidden=''] ytd-button-renderer.ytd-continuation-item-renderer button.yt-spec-button-shape-next[clicked-by-script='true']");
    if (btnClick != null) {
      for (i = 0; i < btnClick.length; i++) {
        btnClick[i].removeAttribute("clicked-by-script", "true"); //Click it again when it becomes not hidden
      }
    }

    //Show all replies upon pressing "View more comments" button (7ktTube | 2016 REDUX script)
    btnClick = document.querySelectorAll("#primary div#replies div#expander div#expander-contents div#button.ytd-continuation-item-renderer:not([hidden]) ytd-button-renderer tp-yt-paper-button#button[role='button']:not([clicked-by-script='true'])");
    if (btnClick != null) {
      for (i = 0; i < btnClick.length; i++) {
        btnClick[i].click();
        btnClick[i].setAttribute("clicked-by-script", "true"); //Do not click it again
      }
    }
    //Rearm "View more comments" button (7ktTube | 2016 REDUX script)
    btnClick = document.querySelectorAll("#primary div#replies div#expander div#expander-contents div#button.ytd-continuation-item-renderer[hidden=''] ytd-button-renderer tp-yt-paper-button#button[role='button'][clicked-by-script='true']");
    if (btnClick != null) {
      for (i = 0; i < btnClick.length; i++) {
        btnClick[i].click();
        btnClick[i].removeAttribute("clicked-by-script", "true"); //Click it again when it becomes not hidden
      }
    }
  }

  //---------------------------------------
  // Expand comments in notification submenu
  //---------------------------------------
  function expandCommentsNotif() {
    //Expand long comments and hide "show less" button in notification submenu
    //btnClick = $( "#submenu ytd-comment-renderer #comment-content tp-yt-paper-button#more:not([hidden='']) > span.more-button[slot='more-button']:not([clicked-by-script='true'])" );
    btnClick = document.querySelectorAll("#submenu tp-yt-paper-button#more:not([hidden='']) > span.more-button[slot='more-button']:not([clicked-by-script='true'])");
    if (btnClick != null) {
      for (i = 0; i < btnClick.length; i++) {
        btnClick[i].click();
        btnClick[i].setAttribute("clicked-by-script", "true"); //Do not click it again
        btnClick[i].parentNode.previousElementSibling.setAttribute("style", "display:none;"); //Hide "Show less" button
      }
    }
  }

  //---------------------------------------
  // Show all subscriptions
  //---------------------------------------
  function expandSubs() {
    //btnClick = $( "#guide div#sections div#items ytd-guide-collapsible-entry-renderer.ytd-guide-section-renderer[can-show-more=''] #expander-item" );
    btnClick = document.querySelectorAll("#guide div#sections div#items ytd-guide-collapsible-entry-renderer.ytd-guide-section-renderer[can-show-more=''] #expander-item");
    if (btnClick != null) {
      for (i = 0; i < btnClick.length; i++) {
        if (isVisible(btnClick[i])) {
          btnClick[i].click();
          flgSubsDone = true;
        }
      }
    }
  }

  //---------------------------------------
  // Check all the parents of element to find whether it is visible or not
  //---------------------------------------
  function isVisible(pObj) {
    if (pObj != null) {
      var checkNext = true;
      var vObj = pObj;

      while (checkNext) {
        checkNext = false;
        //console.log("checking element " + vObj.tagName + "#" + vObj.id + ": '" + document.defaultView.getComputedStyle(vObj,null)['display'] + "'");
        if (document.defaultView.getComputedStyle(vObj,null)['display'] != "none") {
          if (vObj.parentElement != null) {
            vObj = vObj.parentElement;
            checkNext = true;
          }
        } else {
          return false;
        }
      }
      return true;
    }
    return false;
  }

})();

    /*//Detect spinner at main comments
    var spinnerMain = $( "#primary div#replies div#expander tp-yt-paper-spinner#spinner[active]" );
    if (spinnerMain != null && spinnerMain.length > 0) {
      console.log("main active spinner detected");
      spinnerActive = true;

      //Listen to spinner changes
      const spinnerCallback = function (mutationsList, observer) {
        expandComments();

        //spinnerMain = $( "#primary div#replies div#expander tp-yt-paper-spinner#spinner[active]" );
        if (spinnerMain[0].getAttribute("active") == null || spinnerMain[0].getAttribute("active") == "") {
          console.log("main spinner deactivated");
          spinnerObserver.disconnet();
        }
      }

      var spinnerNode = document.querySelector("#primary div#replies div#expander tp-yt-paper-spinner#spinner[active]");
      if (spinnerNode != null) {
        const spinnerObserver = new MutationObserver(spinnerCallback);
        spinnerObserver.observe(spinnerNode, {childList: true, subtree: true, attributes: true, characterData: true});
      }

    } else if (spinnerActive) {
      console.log("spinner stopped");
      spinnerActive = false;
      expandComments();
    }*/