Youtube video blocker

Allows you to block videos from youtube

当前为 2017-05-29 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Youtube video blocker
  3. // @namespace Danielv123
  4. // @version 1.2
  5. // @description Allows you to block videos from youtube
  6. // @author Danielv123
  7. // @match https://www.youtube.com/*
  8. // @grant none
  9. // @require https://code.jquery.com/jquery.js
  10. // ==/UserScript==
  11.  
  12. //'use strict';
  13. /*
  14. Videos in sidebar
  15.  
  16. Get video ID
  17. document.querySelectorAll(".video-list-item .yt-uix-simple-thumb-wrap")[0].dataset.vid
  18. Get video title
  19. document.querySelectorAll(".video-list-item .content-wrapper a:nth-child(1)")[2].title
  20. Get username
  21. document.querySelectorAll(".video-list-item .content-wrapper .stat.attribution span")[2].innerHTML
  22. Hide
  23. document.querySelectorAll(".video-list-item")[2].style.display = "none";
  24. */
  25. var sidebar = {
  26. ID: function(x) {
  27. return document.querySelectorAll(".video-list-item .yt-uix-simple-thumb-wrap")[x].dataset.vid;
  28. },
  29. title: function(x) {
  30. return document.querySelectorAll(".video-list-item .content-wrapper a:nth-child(1)")[x].title;
  31. },
  32. username: function(x) {
  33. return document.querySelectorAll(".video-list-item .content-wrapper .stat.attribution span")[x].innerHTML;
  34. },
  35. hide: function(x) {
  36. document.querySelectorAll(".video-list-item")[x].style.display = "none";
  37. }
  38. };
  39. /*
  40. Videos on subscriptions page
  41.  
  42. Get video ID
  43. document.querySelectorAll(".yt-shelf-grid-item > div")[0].dataset.contextItemId
  44. Get video title
  45. document.querySelectorAll(".yt-shelf-grid-item .yt-lockup-content .yt-lockup-title a")[0].title
  46. Get username
  47. document.querySelectorAll(".yt-shelf-grid-item .yt-lockup-content .yt-lockup-byline a")[0].innerHTML
  48. Hide
  49. document.querySelectorAll(".yt-shelf-grid-item")[0].style.display = "none"
  50. */
  51. var shelfvideos = {
  52. ID: function(x) {
  53. return document.querySelectorAll(".yt-shelf-grid-item > div")[x].dataset.contextItemId;
  54. },
  55. title: function(x) {
  56. return document.querySelectorAll(".yt-shelf-grid-item .yt-lockup-content .yt-lockup-title a")[x].title;
  57. },
  58. username: function(x) {
  59. return document.querySelectorAll(".yt-shelf-grid-item .yt-lockup-content .yt-lockup-byline a")[x].innerHTML;
  60. },
  61. hide: function(x) {
  62. document.querySelectorAll(".yt-shelf-grid-item")[x].style.display = "none";
  63. }
  64. };
  65. /*
  66. Videos on autolplay list
  67.  
  68. Title
  69. document.querySelector("#watch-related > li:nth-child(1) > div.related-item-dismissable > div.content-wrapper > a > span.title")
  70. Username
  71. document.querySelector("#watch7-sidebar-modules > div:nth-child(1) > div > div.watch-sidebar-body > ul > li > div.content-wrapper > a > span.stat.attribution > span")
  72.  
  73. */
  74. // Code goes here and onwards
  75.  
  76. function main() {
  77. if(!localStorage.blockedUsers){
  78. localStorage.blockedUsers = JSON.stringify([]);
  79. }
  80. if(!localStorage.blockedTitles){
  81. localStorage.blockedTitles = JSON.stringify([]);
  82. }
  83. if(!localStorage.blockedRegex){
  84. localStorage.blockedRegex = JSON.stringify([]);
  85. }
  86. //hideSidebarVideos("","PewDiePie");
  87. //hideShelfVideos("","nigahiga");
  88. //hideShelfVideos("","","s");
  89. injectScripts();
  90. makeFilterGui();
  91.  
  92. // Hide videos
  93. let userFilters = JSON.parse(localStorage.blockedUsers);
  94. let titleFilters = JSON.parse(localStorage.blockedTitles);
  95. let regexFilters = JSON.parse(localStorage.blockedRegex);
  96. // Loop until we are through the larges of our filter sets
  97. for(let i = 0; i < Math.max(regexFilters.length, Math.max(userFilters.length, titleFilters.length));i++){
  98. // hideSidebarVideos(id, username, title, regex)
  99. let id = "";
  100. let user = userFilters[i] || "";
  101. let title = titleFilters[i] || "";
  102. let regex = regexFilters[i] || "";
  103. hideSidebarVideos(id, user, title);
  104. hideShelfVideos(id, user, title);
  105. }
  106. }
  107. setTimeout(main, 500);
  108.  
  109. function makeFilterGui() {
  110. let HTML = '<div id="youtubeBlockerGui" style="">';
  111. // Close button
  112. HTML += '<div id="youtubeBlockerGuiCloseButton"><img src="http://www.drodd.com/images14/x23.png"></img></div>';
  113. HTML += '<h1>Youtube Blocker</h1><p>Below are a few textfields. Enter , (comma) seperated lists of titles and/or channels to exclude from your youtube feed.</p><p>Video titles don\'t have to match completely, just having part of the title is enough. Ex "porn,1000 degree,prank" will match "1000 degree knife vs water baloon EPIC"<br>';
  114. HTML += '<h2>Blocked channels</h2><p><i>All channels with this excact name will be hidden</i></p><textarea id="blockedChannels"></textarea>';
  115. HTML += '<h2>Blocked videos by name</h2><p><i>All videos with this in their names will be hidden</i></p><textarea id="blockedVideos"></textarea>';
  116. HTML += '<h2>Regex blocks</h2><p><i>All video titles matching this regex will be hidden</i></p><textarea id="blockedRegex"></textarea>';
  117. // Save button
  118. HTML += '<div id="saveButton"><h2>Save</h2></div>';
  119. // Close everything
  120. HTML += '</div>';
  121. // Open settings button in botttom right corner
  122. HTML += '<div id="gearwheelButton"><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/b/bd/Simpleicons_Interface_gear-wheel-in-black.svg/2000px-Simpleicons_Interface_gear-wheel-in-black.svg.png"></img></div>';
  123. // inject into body
  124. let container = document.createElement('div');
  125. container.innerHTML = HTML;
  126. (document.body || document.head || document.documentElement).appendChild(container);
  127.  
  128. // Populate textareas with old settings
  129. let x = JSON.parse(localStorage.blockedUsers);
  130. let y = "";
  131. for(let i in x) {
  132. y += x[i]+",\n";
  133. }
  134. $("textarea#blockedChannels")[0].value = y;
  135. x = JSON.parse(localStorage.blockedTitles);
  136. y = "";
  137. for(let i in x) {
  138. y += x[i]+",\n";
  139. }
  140. $("textarea#blockedVideos")[0].value = y;
  141. x = JSON.parse(localStorage.blockedRegex);
  142. y = "";
  143. for(let i in x) {
  144. y += x[i]+",\n";
  145. }
  146. $("textarea#blockedRegex")[0].value = y;
  147.  
  148. document.querySelector("#youtubeBlockerGui #youtubeBlockerGuiCloseButton").onclick = toggleGuiDisplay;
  149. document.querySelector("#gearwheelButton").onclick = toggleGuiDisplay;
  150. document.querySelector("#saveButton").onclick = function(){
  151. console.log("Saving lists of blocked channels, users and regexes");
  152. // Regex to replace linebreaks
  153. localStorage.blockedUsers = JSON.stringify($("textarea#blockedChannels")[0].value.replace(/(\r\n|\n|\r)/gm,"").split(","));
  154. localStorage.blockedTitles = JSON.stringify($("textarea#blockedVideos")[0].value.replace(/(\r\n|\n|\r)/gm,"").split(","));
  155. localStorage.blockedRegex = JSON.stringify($("textarea#blockedRegex")[0].value.replace(/(\r\n|\n|\r)/gm,"").split(","));
  156. };
  157. }
  158. function readBlockSettings(){
  159. return $("#youtubeBlockerGui textarea")[0].value.replace(/(\r\n|\n|\r)/gm,"").split(",");
  160. }
  161. function toggleGuiDisplay(){
  162. let gui = $("#youtubeBlockerGui")[0];
  163. if(gui.style.display == "none"){
  164. gui.style.display = "block";
  165. } else {
  166. gui.style.display = "none";
  167. }
  168. }
  169. function injectScripts(){
  170. // jQuery
  171. var s=document.createElement('script');
  172. s.setAttribute('src','https://code.jquery.com/jquery.js');
  173. document.getElementsByTagName('head')[0].appendChild(s);
  174. // CSS
  175. var d=document.createElement('style');
  176. d.innerHTML = "#youtubeBlockerGui {"+
  177. "display:none;"+
  178. "width:60%;"+
  179. "height:80%;"+
  180. "background-color:white;"+
  181. "position:fixed;"+
  182. "top:10%;"+
  183. "left:20%;"+
  184. "border:1px solid lightgrey;"+
  185. // damn, the youtube sidebar apparently has a z index of 1999999999...
  186. "z-index:2000000000;"+
  187. "}"+
  188. // red X on gui to close
  189. "#youtubeBlockerGuiCloseButton {"+
  190. "float:right;"+
  191. "height:30px;"+
  192. "width:30px;"+
  193. "cursor:pointer;"+
  194. "}"+
  195. "#youtubeBlockerGuiCloseButton img {"+
  196. "height:100%;"+
  197. "width:100%;"+
  198. "}"+
  199. // gearwheel in bottom right corner
  200. "#gearwheelButton {"+
  201. "position:fixed;"+
  202. "height:30px;"+
  203. "width:30px;"+
  204. "bottom:0px;"+
  205. "right:0px;"+
  206. "cursor:pointer;"+
  207. "}"+
  208. "#gearwheelButton img {"+
  209. "height:100%;"+
  210. "width:100%;"+
  211. "}"+
  212. "#saveButton {"+
  213. "cursor:pointer;"+
  214. "}"
  215. ;
  216. document.getElementsByTagName('body')[0].appendChild(d);
  217. }
  218. function hideShelfVideos(id, username,title, regex) {
  219. let videos = document.querySelectorAll(".yt-shelf-grid-item");
  220. for(let i = 0; i < videos.length; i++){
  221. let hideVideo = function(number, filter){
  222. // document.querySelectorAll(".yt-shelf-grid-item")[number].style.display = "none";
  223. shelfvideos.hide(number);
  224. console.log("Filter: " + filter + " Hidden: " + document.querySelectorAll(".yt-shelf-grid-item .yt-lockup-content .yt-lockup-title a")[number].title);
  225. };
  226. // Check by video ID
  227. if(id && id == shelfvideos.ID(i)){
  228. hideVideo(i, id);
  229. }
  230. // Check by channel name
  231. if(username && username.toLowerCase() == shelfvideos.username(i).toLowerCase()){
  232. hideVideo(i, username);
  233. }
  234. // Check if video title contains title
  235. if(title && title != " " && shelfvideos.title(i).toLowerCase().includes(title.toLowerCase())){
  236. hideVideo(i, title);
  237. }
  238. // Check if title matches regex
  239. if(regex && shelfvideos.title(i).match(regex)){
  240. hideVideo(i, regex);
  241. }
  242. }
  243. }
  244. function hideSidebarVideos(id, username, title, regex) {
  245. let videos = document.querySelectorAll(".video-list-item");
  246. for(let i = 0; i < videos.length; i++){
  247. let hideVideo = function(number, filter){
  248. // document.querySelectorAll(".video-list-item")[number].style.display = "none";
  249. sidebar.hide(number);
  250. console.log("Filter: " + filter + " Hidden: " + document.querySelectorAll(".video-list-item .content-wrapper a:nth-child(1)")[number].title);
  251. };
  252. // Check by video ID
  253. if(id == sidebar.ID(i)){
  254. hideVideo(i, id);
  255. }
  256. // Check by channel name
  257. if(username.toLowerCase() == sidebar.username(i).toLowerCase()){
  258. hideVideo(i, username);
  259. }
  260. // Check if video title contains title
  261. if(title && title != " " && sidebar.title(i).toLowerCase().includes(title.toLowerCase())){
  262. hideVideo(i, title);
  263. }
  264. // Check if title matches regex
  265. if(regex && sidebar.title(i).match(regex)){
  266. hideVideo(i, regex);
  267. }
  268. }
  269. }
  270.  
  271.  
  272. // https://stackoverflow.com/questions/3219758/detect-changes-in-the-dom
  273. var observeDOM = (function(){
  274. var MutationObserver = window.MutationObserver || window.WebKitMutationObserver,
  275. eventListenerSupported = window.addEventListener;
  276.  
  277. return function(obj, callback){
  278. if( MutationObserver ){
  279. // define a new observer
  280. var obs = new MutationObserver(function(mutations, observer){
  281. if( mutations[0].addedNodes.length || mutations[0].removedNodes.length )
  282. callback();
  283. });
  284. // have the observer observe foo for changes in children
  285. obs.observe( obj, { childList:true, subtree:true });
  286. }
  287. else if( eventListenerSupported ){
  288. obj.addEventListener('DOMNodeInserted', callback, false);
  289. obj.addEventListener('DOMNodeRemoved', callback, false);
  290. }
  291. };
  292. })();
  293. observeDOM( document.querySelector("#content") ,function(){
  294. console.log('dom changed, hiding videos...');
  295. main();
  296. });