Filter, Highlight & Delete

Highlights, Lowlights, or Deletes page elements based on their text.

当前为 2019-09-23 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Filter, Highlight & Delete
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.1.2
  5. // @description Highlights, Lowlights, or Deletes page elements based on their text.
  6. // @author listfilterErick
  7. // @grant none
  8.  
  9. // @match *://news.google.com/*
  10. // @match *://www.youtube.com/*
  11. // @match *://www.reddit.com/r/*
  12.  
  13. // @require https://code.jquery.com/jquery-3.4.1.min.js
  14. // @require https://greasyfork.org/scripts/5392-waitforkeyelements/code/WaitForKeyElements.js?version=115012
  15.  
  16. // @licence CC-BY-NC-SA-4.0; https://creativecommons.org/licenses/by-nc-sa/4.0/
  17. // @licence GPL-3.0-or-later; http://www.gnu.org/licenses/gpl-3.0.txt
  18. // ==/UserScript==
  19. /* jshint esversion: 6 */
  20. /*
  21. Update 1.1.2 (09-22-2019)
  22. - logged matches now includes matched rules.
  23. - code cleanup
  24.  
  25. Filter searches through the delete list, then the lowlight rules and, finally the highlight rules.
  26. If it matches something earlier in the lists, it won't check lower lists such as
  27. if there was a match in the delete list, lowlight and highlight rules aren't checked.
  28. This can be changed by changing the checkBlock() function.
  29.  
  30. Google News: Only works for the front page of google news. Need a more robust selector for other special sections.
  31. Reddit: Only works for compact view.
  32.  
  33. Search for these markers for locations where you need to add new selectors for new sites.
  34. markA: define selector for block to apply css rules to. (needs to be valid for jquery and css)
  35. markB: define selector for the text of the block.
  36.  
  37. The applied highlight/lowlight classes are:
  38. lf-highlight1 (strong highlight)
  39. lf-highlight2
  40. lf-lowlight1
  41. lf-lowlight2 (strong lowlight)
  42. */
  43.  
  44. (function () {
  45. 'use strict';
  46.  
  47. // ==== filter lists ==========================================================================|
  48. if (1) {
  49. //strong highlight
  50. var highlight1 = [
  51. /apple/i,
  52. ];
  53. //weak highlight
  54. var highlight2 = [
  55. /gamestop/i,
  56. ];
  57. //weak lowlight
  58. var lowlight1 = [
  59. /goodbye/i,
  60. ];
  61. //strong lowlight
  62. var lowlight2 = [
  63. /\btv\b/i,
  64. ];
  65. //delete block
  66. var delete1 = [
  67. /throne|dany|\bgot\b/i,
  68. ];
  69. }
  70.  
  71. const domainName = window.location.hostname;
  72. const hrefString = window.location.href; //href lets you be more specific
  73. let blockSelector = "article";
  74. // ==== markA start ===========================================================================|
  75. if (/news\.google\.com/gi.test(domainName)) {
  76. blockSelector = "main>c-wiz>div>div";
  77. } else if (/www\.youtube\.com/gi.test(domainName)) {
  78. blockSelector = "ytd-compact-video-renderer";
  79. } else if (/www\.reddit\.com/gi.test(domainName)) {
  80. blockSelector = ".scrollerItem>div>div:nth-child(2)";
  81. }
  82. // ==== markA end =============================================================================|
  83.  
  84. // ==== script options ========================================================================|
  85. const addFilterButton = 0; // set to 1 to show a button to manually run this script.
  86. const buttonTransparency = .3; // set to a value between 0 and 1, 1 is no transparency, .5 is 50% transparency.
  87. const dynamicChecking = 1; // set to 1 to run the script automatically when new block elements are detected.
  88.  
  89. const enableLogMessages = 0; // set to 1 to enable console messages, required for the following message options.
  90. const logMatches = 1; // set to 1 to log to console what was matched.
  91. const logRuntime = 1; // set to 1 to log to console how long this takes to run.
  92.  
  93. function consolelog(text) {
  94. if (enableLogMessages) {
  95. console.log(text);
  96. }
  97. }
  98. consolelog("#### list filter script start. ####");
  99.  
  100. // ==== function definitions ==================================================================|
  101.  
  102. // checks string against given list of regular expressions.
  103. let regexLog = "";
  104. function checkRegex(string, regexList) {
  105. for (let i = 0; i < regexList.length; i++) {
  106. if (regexList[i].test(string)) {
  107. if (regexLog) {
  108. regexLog = regexLog +", "+ regexList[i];
  109. }else {
  110. regexLog = regexList[i];
  111. }
  112. return true;
  113. }
  114. }
  115. return false;
  116. }
  117.  
  118. let elementCounter = 0;
  119.  
  120. // check attributes of a block to choose what class to add to it.
  121. function checkBlock(index, element) {
  122.  
  123. let searchText;
  124.  
  125. // ==== markA start =======================================================================|
  126. if (/news\.google\.com/gi.test(domainName)) {
  127. searchText = jQuery(this).find("div>article>h3").eq(0).text().trim();
  128. } else if (/www\.youtube\.com/gi.test(domainName)) {
  129. searchText = jQuery(this).find("span#video-title").text().trim();
  130. } else if (/www\.reddit\.com/gi.test(domainName)) {
  131. searchText = jQuery(this).find("span>a>h2").text().trim();
  132. }
  133. // ==== markA end =========================================================================|
  134.  
  135. // class list identifies what was checked in past iterations
  136. let classList = "";
  137. if (jQuery(this).attr("class")) {
  138. classList = jQuery(this).attr("class");
  139. //consolelog(classList);
  140. }
  141.  
  142. if (searchText && (!classList || !/\blf-/.test(classList))) {
  143. //if ( searchText ) {
  144. var matchCode = "n1";
  145.  
  146. // stops after the first rule matched.
  147. if (checkRegex(searchText, delete1)) {
  148. matchCode = "d1";
  149. jQuery(this).remove();
  150. } else if (checkRegex(searchText, lowlight2)) {
  151. matchCode = "l2";
  152. jQuery(this).addClass("lf-lowlight2");
  153. } else if (checkRegex(searchText, lowlight1)) {
  154. matchCode = "l1";
  155. jQuery(this).addClass("lf-lowlight1");
  156. } else if (checkRegex(searchText, highlight1)) {
  157. matchCode = "h1";
  158. jQuery(this).addClass("lf-highlight1");
  159. } else if (checkRegex(searchText, highlight2)) {
  160. matchCode = "h2";
  161. jQuery(this).addClass("lf-highlight2");
  162. } else {
  163. jQuery(this).addClass("lf-checked");
  164. }
  165.  
  166. if (enableLogMessages && logMatches && !/n1/.test(matchCode)) { //shows all matches
  167. //if (enableLogMessages && logMatches && /d|l/.test(matchCode)) { //shows only lowlight and delete matches
  168. elementCounter++;
  169. consolelog(elementCounter +" ("+ matchCode +"): "+ searchText +" | "+ regexLog);
  170. regexLog = "";
  171. }
  172. }
  173.  
  174. } // end function checkBlock()
  175.  
  176. function checkBlocks() {
  177. if (enableLogMessages && logRuntime) {
  178. var startTime = performance.now();
  179. }
  180.  
  181. jQuery(blockSelector).each(checkBlock);
  182.  
  183. if (enableLogMessages && logRuntime) {
  184. const endTime = performance.now();
  185. const runTime = ((endTime - startTime) / 1000).toFixed(2);
  186. if (runTime < 1) {
  187. console.log('(H/L) finished in less than 1 second.');
  188. }else {
  189. console.log('(H/L) finished after ' + runTime + ' seconds.');
  190. }
  191. }
  192. }
  193.  
  194. if (dynamicChecking) {
  195. waitForKeyElements(blockSelector, checkBlocks);
  196. } else {
  197. checkBlocks();
  198. }
  199.  
  200. // ==== optional button code ==================================================================|
  201. if (addFilterButton) {
  202. if (!jQuery("#wt-buttons").length) {
  203. consolelog("(H/L) created #wt-buttons.");
  204. jQuery("body").prepend('<div id="wt-buttons"><div id="lf-reset">H/L</div><div id="wt-close">&times;</div></div>');
  205. jQuery("#wt-close").click(function () { jQuery("#wt-buttons").remove(); });
  206.  
  207. const webToolsCss =
  208. `<style type="text/css">
  209. #wt-buttons {
  210. width: 40px;
  211. display: block !important;
  212. position: fixed;
  213. top: 0px;
  214. right: 0px;
  215. z-index: 9000;
  216. opacity: `+ buttonTransparency + `;
  217. }
  218. #wt-buttons:hover {
  219. opacity: 1;
  220. }
  221. #wt-buttons div {
  222. display: block !important;
  223. padding: 5px;
  224. border-radius: 5px;
  225. margin-top: 2px;
  226. font-size: initial !important;
  227. font-weight: bold;
  228. color: white;
  229. cursor: pointer;
  230. }
  231. #wt-close {
  232. background: #777777;
  233. text-align: center;
  234. }
  235. </style>`;
  236. jQuery(document.body).append(webToolsCss);
  237. } else {
  238. jQuery("#wt-buttons").prepend('<div id="lf-reset">H/L</div>');
  239. }
  240. const listFilterCss =
  241. `<style>
  242. #lf-reset {
  243. background: #177e14;
  244. }
  245. </style>`;
  246. jQuery(document.body).append(listFilterCss);
  247. jQuery("#lf-reset").click(function () {
  248. elementCounter = 0;
  249. checkBlocks();
  250. });
  251. }
  252.  
  253. var filterCss =
  254. `<style>
  255. `+ blockSelector +`.lf-highlight1 {
  256. background: #baffc9;/*green*/
  257. }
  258. `+ blockSelector +`.lf-highlight2 {
  259. background: #ffffba;/*yellow*/
  260. }
  261. `+ blockSelector +`.lf-lowlight1 {
  262. background: #ffdfba;/*orange*/
  263. opacity: .3;
  264. }
  265. `+ blockSelector +`.lf-lowlight2 {
  266. background: #ffccca;/*red*/
  267. opacity: .5;
  268. }
  269. </style>`;
  270. jQuery(document.body).append(filterCss);
  271.  
  272. consolelog("#### list filter script finished. ####");
  273. })();