zomberi / YouTube AdBlocker N Annoyances Remover

// ==UserScript==
// @name        YouTube AdBlocker N Annoyances Remover
// @namespace   com.vsubhash.js.youtube-ad-blocker-and-annoyances-remover
// @description Disables ads, swithces off autoplay, adds RSS link, deletes "recommended for you" videos, unhides description, displays all comments, changes profile link to videos page; and changes region to US. Supports Firefox-based browser up to version 36. Newer versions should use a UserAgent (UA) spoofer add-on. YouTube loads a lighter version of the YouTube page for older browsers. This script will require the GreaseMonkey add-on to be executed by the Firefox browser.
// @include     https://www.youtube.com/watch*
// @include     https://www.youtube.com/channel*
// @include     https://www.youtube.com/user*
// @version     2019.02
// @copyright		2019, V. Subhash (www.vsubhash.com)
// @license			MIT
// @homepageURL https://gist.github.com/vsubhash
// @author			zomberi
// @grant       none
// ==/UserScript==

var sAdStyle = " { visibility: none!important; display: none!important; }";
document.addEventListener("readystatechange", fixYouTubeAnnoyances, false);


function fixYouTubeAnnoyances() {
	console.log("YAD: Here");
	if ((document.readyState == "interactive") || (document.readyState == "complete")) {
		console.log("YAD: loaded");
		try {
			pauseVideos();
		  window.setTimeout(showDescription, 1*200);    
		  window.setTimeout(closeVideoAds, 2*200);
		  window.setTimeout(changeRegion, 3*200);

		  window.setTimeout(addRssButton, 1*1000);
		  window.setTimeout(changeProfileLink, 2*1000); 
		  window.setTimeout(pauseVideos, 3*1000);    
		  window.setTimeout(removeRecommendedForYouAds, 4*1000);  
		  window.setTimeout(disableAndHideAdContainers, 5*1000);
		  window.setTimeout(disableAutoPlay, 6*1000);
		  window.setTimeout(addVideoDownloadList, 7*1000);

		  window.setTimeout(loadAllComments, 15*1000);

		} catch (e) {
		  console.error("YAD Error: " + e);
		}
	}
}


function addRssButton() { 
  console.log("YAD: addRssButton")
	var oLink, oLinkEl, oChannelTag, oRssImg, oRssLink, sChannel, sChannelName, sUserName, sFeedUrl;
	
	// Android 1.6
	oLink = document.querySelector("div.tv span.gmb a");
	oChannelTag = document.querySelector("div.tv span.gmb a span");
	if (oLink == null) {
		// Android 3+
		oLink = document.querySelector("a.slim-owner-icon-and-title");
		oChannelTag = document.querySelector("a.slim-owner-icon-and-title div h3");
	}
	if (oLink == null) {
		// Android 46
		oLink = document.querySelector("div.yt-user-info a");
		oChannelTag = document.querySelector("div.yt-user-info a");
	}
	if (oLink == null) {
		// Android 60
		oLink = document.querySelector("div#owner-container *#owner-name a");
		oChannelTag = document.querySelector("div#owner-container *#owner-name a");
	}
	
	if ((oLink ==null) || (oChannelTag == null)) { return; } else {
		console.log("YAD: Channel name found.");
		sChannelName = oChannelTag.textContent;
		sChannelName = sChannelName.replace(/^\s+|\s+$/g, '');
		console.log("YAD: Channel link found.");
	  if (oLink.getAttribute("href").indexOf("/channel/") == 0) {
			sChannel = oLink.getAttribute("href").substr("/channel/".length);
			sFeedUrl = "https://www.youtube.com/feeds/videos.xml?channel_id=" + sChannel;
			console.log("YAD: " + sChannelName + " = " + sFeedUrl);
		} else if (oLink.getAttribute("href").indexOf("/user/") == 0) {
		  sUserName = oLink.getAttribute("href").substr("/user/".length);
		  sFeedUrl = "https://www.youtube.com/feeds/videos.xml?user=" + sUserName;
			console.log("YAD: " + sChannelName + " = " + sFeedUrl);
		} else { return; }
		oLinkEl = document.createElement("link");
    oLinkEl.setAttribute("rel", "alternate");			
    oLinkEl.setAttribute("title", sChannelName);
    oLinkEl.setAttribute("type", "application/rss+xml");
    oLinkEl.setAttribute("href", sFeedUrl);
    document.getElementsByTagName("head")[0].appendChild(oLinkEl);
    
    oRssImg = document.createElement("img");
    oRssImg.setAttribute("style", "margin: auto 1em; ");
    oRssImg.setAttribute("alt", "RSS");
    oRssImg.setAttribute("src", "https://www.google.com/images/rss.png");
    
    oRssLink = document.createElement("a");
    oRssLink.setAttribute("id", "mvytRssFeedLink");
    oRssLink.setAttribute("href", sFeedUrl);
    oRssLink.setAttribute("title", "RSS feed link for this channel");
    oRssLink.setAttribute("style", "text-decoration: none; border-style: none; ");
    oRssLink.appendChild(oRssImg);
    
    if (document.getElementById("mvytRssFeedLink") == null) {
    	oChannelTag.appendChild(oRssLink);
    }
  }
}


function pauseVideos() {
  console.error("YAD: Pausing videos");
  try {
    var oVideoEls = document.getElementsByTagName("video");
    for (var i = 0; i < oVideoEls.length; i++) {
    	oVideoEls[i].pause();    
    	oVideoEls[i].muted = true;
    	if (oVideoEls[i].src.indexOf("pltype=adhost") > -1) {
    		console.error("YAD: Video ad found... closing tab");
				window.open(location.href, '_blank');
				window.close();
    	}
    	console.error("YAD: Pausing video " + (i+1));
    	if (!oVideoEls[i].paused) {
    		oVideoEls[i].pause();	
    	}      
      //oVideoEls[i].volume = 0.6;  // custom controls do not update
      // oVideoEls[i].muted = true;
      oVideoEls[i].removeAttribute("autoplay");
      oVideoEls[i].removeAttribute("loop");
      oVideoEls[i].removeAttribute("controls");      
      oVideoEls[i].setAttribute("preload", "none");
      oVideoEls[i].pause();
    }
    var oButtons = document.getElementsByTagName("button");
    for (var i = 0; i < oButtons.length; i++) {
    	if (oButtons[i].className) {
    		if (oButtons[i].className.indexOf("ytp-mute-button") > -1) {
    			console.log("YAD: Mute button " + oButtons[i].className);
		  		oButtons[i].click();
		  		oButtons[i].click();		  		
		  	}
    	}
    }
  } catch (e) {
	  console.error("YAD: Error - " + e);
  }
}


function showDescription() {
  console.log("YAD: Finding description...");
  if (document.getElementById("action-panel-details") != null) {
    document.getElementById("action-panel-details").className = "action-panel-content yt-uix-expander yt-card yt-card-has-padding";
  }
  console.log("YAD: Description unhidden.");
}


function closeVideoAds() {
  console.log("YAD: Detecting video ads...");        
  if ((document.getElementsByClassName("videoAdUiTopButtons").length > 0) || (document.getElementsByClassName("videoAdUi").length > 0)) {
    console.log("YAD: Video ad found");      
    window.open(location.href, '_blank');
    window.close();
 	} else {  
    console.log("YAD: No video ad");
  }
}


function disableAutoPlay() {
  var oEl = document.getElementById("autoplay-checkbox"); 
  if (oEl == null) {
  	console.log("YAD: Did not find autoplay button.");
  } else if (oEl.hasAttribute("checked")) {
  	console.log("YAD: Disabling autoplay...");  	
  	oEl.click();
  } else {
  	console.log("YAD: Autoplay already disabled.");  	  
  }
}


function removeRecommendedForYouAds() {
  console.log("YAD: Removing recommended videos");
  var oRelatedColumn = document.getElementById("watch-related");
  if (oRelatedColumn != null) {
    var arRelatedVids = oRelatedColumn.getElementsByTagName("li");
    var j = 0;
    if (arRelatedVids.length > 0) {
      for (var i = arRelatedVids.length-1; i > -1; i--) {        
        if (arRelatedVids[i].textContent.indexOf("Recommended for you") != -1) {
          //console.log("YAD: Removing " + arRelatedVids[i].textContent);
          arRelatedVids[i].parentNode.removeChild(arRelatedVids[i]);
          ++j;
        }
      }
    }
    console.log("YAD: Removed " + j  + " recommended videos");      
  }
}


function disableAndHideAdContainers() {
  console.log("YAD: Disabling/deleting ad containers...");
  var arDivIds = ["AdSense", "watch7-sidebar-ads", "promotion-shelf", "live-chat-iframe"];
  var arDivClasses = [ "adDisplay", "annotation", "html5-endscreen", "iv-promo", "videoAdUiBottomBar", "ytp-endscreen-content", "ytp-cards-button", "ytp-cards-teaser" ];

  for (var i = 0; i < arDivIds.length; i++) {
    var oDiv = document.getElementById(arDivIds[i]);
    if (oDiv != null) {
      oDiv.style.visibility = "hidden!important";
      oDiv.style.display = "none!important";          
      oDiv.parentNode.removeChild(oDiv);
      console.log("YAD: Removed " + arDivIds[i] + " by ID");
    } else {
      console.log("YAD: Not found: " + arDivIds[i] + " by ID");
    }      
    sAdStyle = "#" + arDivIds[i] +  ((i==0)?" ":" , ") + sAdStyle;      
  }
  for (var i = 0; i < arDivClasses.length; i++) {
    var oDivs = document.getElementsByClassName(arDivClasses[i]);
    if (oDivs != null) {
      for (var j = 0; j < oDivs.length; j++) {
        oDivs[j].style.visibility = "hidden!important";
        oDivs[j].style.display = "none!important";          
        oDivs[j].parentNode.removeChild(oDivs[j]);
      }
    } else {
      console.log("YAD: Not found: " + oDivs[j] + " by ID");
    }
    sAdStyle = "*." + arDivClasses[i] +  " , " + sAdStyle;      
  }
  document.getElementsByTagName("head")[0].innerHTML = document.getElementsByTagName("head")[0].innerHTML + "\n<style>" + sAdStyle + "\n</style>";
}


function changeRegion() {
	var oLangButton = document.getElementById("yt-picker-country-button");
	if (oLangButton != null) {
		if (oLangButton.textContent.indexOf("United States") == -1) {
			oLangButton.click();
			window.setTimeout(
				function() {
					var arRegions = document.getElementsByClassName("yt-picker-item");
					for (var i = 0; i < arRegions.length; i++) {
						if (arRegions[i].textContent.indexOf("United States") > -1) {
							arRegions[i].click();
							break;
						}
					}
				}, 3*1000);
		}
	}
	
}


function changeProfileLink() { 
  console.log("YAD: Changing profile link")
  var oDivs = document.getElementsByTagName("div");
  if ((oDivs != null) && (oDivs.length > 0)) {
    for (var i = 0; i < oDivs.length; i++) { if (oDivs[i].className == "yt-user-info") { 
      var oAnchors = oDivs[i].getElementsByTagName("a"); 
      if ((oAnchors != null) && (oDivs.length>1)) {
          var bFound = false;
          for (var j = 0; j < oAnchors.length; j++) {
            if (oAnchors[j].href.substring(0, "https://www.youtube.com/channel/".length) == "https://www.youtube.com/channel/") {
              oAnchors[j].href = oAnchors[j].href + "/videos";
              bFound = true;
              break;
            }
          }
          if (bFound) { break; }
        }
      }
    }
  }
}


var iLoadAllCommentsTimeout = 0;
function loadAllComments() {
  if (iLoadAllCommentsTimeout > 0) {
  	window.clearTimeout(iLoadAllCommentsTimeout);
  }
  var oDiv = document.getElementById("watch-discussion");
  if (oDiv == null) { return; }
  var oButtons = oDiv.getElementsByClassName("comment-section-renderer-paginator");
  if (oButtons != null) {
  	console.log("YAD: Comments");
		if (oButtons[0] != null) {
			oButtons[0].click();
			iLoadAllCommentsTimeout = window.setTimeout(loadAllComments, 20*1000);
		}
  }

}

function parseYTPlayer() {
  console.error("Inside parser" );
  console.error("Title" + ytplayer.config.args.title);
  console.error("Format" + unescape(ytplayer.config.args.adaptive_fmts));
  
  try { 
    if (document.getElementsByTagName("video")[0] && (document.getElementsByTagName("video")[0].pause)) {
      document.getElementsByTagName("video")[0].pause();
    }
  } catch (e) {
    window.alert(e);
  }
  
  var arFormatParams, arFormats, i, j, sURL, sQuality, sMimeType, sExtension;
  var oDlList, oDlListItem;
  
  oDlList = document.getElementById("mvyJsList");
  if (oDlList == null) { 
    return;
  }
  
  
  arFormats = ytplayer.config.args.url_encoded_fmt_stream_map.split(",");
  for (i = 0; i < arFormats.length; i++) {
    //console.error("Format " + i + ". " + arFormats[i]);
    
    arFormatParams = arFormats[i].split("&")
    sURL = "";
    for (j = 0; j < arFormatParams.length; j++) {
      // console.error("\tFormat parameter " + arFormatParams[j]);
      if (arFormatParams[j].indexOf("url=") > -1) {
        sURL = unescape(arFormatParams[j].substring("url=".length));
      } else {
        if (arFormatParams[j].indexOf("type=") > -1) {
          sMimeType = unescape(arFormatParams[j].substring("type=".length));
        }
        
        if (arFormatParams[j].indexOf("quality=") > -1) {
          sQuality = arFormatParams[j].substring("quality=".length);
        }
      } 
    }
    
    if ((sURL.length > 0) && (sQuality.length > 0) && (sMimeType.length > 0)) {
      sURL = sURL + 
             "&ptk=youtube_none&pltype=contentugc" +
             "&title=" + 
             encodeURI(ytplayer.config.args.title);
      oDlListItem = document.createElement("li");
      oDlListItem.innerHTML = "<a title=\"" + document.title + "\" download=\"download\" style=\"color: navy; font-weight: bold; \" target=\"_blank\" href=\"" + sURL + "\">Q: " + sQuality + " - M: " + sMimeType + "</a>";
      oDlList.appendChild(oDlListItem);
    }
  }
  
} 


function addCurrentPlayURL() {
  var oList = document.getElementById("mvyJsList");
  if (oList != null) {
		if (document.getElementById("movie_player") != null) {
			if (document.getElementById("movie_player").getElementsByTagName("video") != null) {
				var oVideo = document.getElementById("movie_player").getElementsByTagName("video")[0];
				oList.innerHTML += "<li><a download=\"download\" style=\"color: navy; font-weight: bold; \" target=\"_blank\" href=\"" + oVideo.src + "&title=" + encodeURI(document.title) + "\">" + document.title + "</a></li>";
			}
		}		
	}
}


function addVideoDownloadList() {
  console.log("Executing YouTube detector");
  var i, n, oDlButtonEl, oDlDiv, oVideosList;
  
  if (location.href.indexOf("youtube.com/watch") > -1) {
	  oDlDiv = document.createElement("div");
	  oDlDiv.setAttribute("id", "mvyJsDiv");
	  oDlDiv.setAttribute("style", "background-color: orange!important; border: 2px dashed firebrick; font-size: 0.34cm!important; font-family: sans-serif!important; line-height: 0.4cm!important; margin: 1em auto; padding: 1em;  ");
	  oDlDiv.innerHTML = "Download video from:";
	  oDlList = document.createElement("ul");
	  oDlList.setAttribute("style", "display: block; list-style: disc inside none; margin-left: 1em!important; ");
	  oDlList.setAttribute("id", "mvyJsList");
	  oDlDiv.appendChild(oDlList);
    document.getElementById("watch-headline-title").appendChild(oDlDiv);
    addCurrentPlayURL();
    parseYTPlayer();
    
  }
}