Google News Filter

Removes blacklisted articles and news sources from Google News.

  1. // ==UserScript==
  2. // @name Google News Filter
  3. // @namespace http://www.google-news-filter.com
  4. // @description Removes blacklisted articles and news sources from Google News.
  5. // @include *//news.google.com/*
  6. // @grant none
  7. // @version 3.0.5
  8. // @require http://code.jquery.com/jquery-latest.min.js
  9. // @require https://openuserjs.org/src/libs/sizzle/GM_config.js
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // ==/UserScript==
  13.  
  14. $(function() {
  15.  
  16. // **************** //
  17.  
  18. // Initialize user settings window
  19. // Persistent user settings for greasemonkey scripts using local storage are made possible by the GM_config library:
  20. // https://github.com/sizzlemctwizzle/GM_config
  21. function gnf_settings() {
  22.  
  23. // define gm_config_panel div
  24. var gm_config_panel = document.createElement('div');
  25. gm_config_panel.draggable=true;
  26. document.body.appendChild(gm_config_panel);
  27.  
  28. GM_config.init({
  29. 'id': 'gnf_settings_dialog', // id for this instance of GM_config
  30. 'title': 'Google News Filter settings',
  31. 'fields':
  32. {
  33. 'blacklist_terms': // field id
  34. {
  35. 'label': '<div style="margin:1em 0 0;padding:0;">Blacklisted Terms <span style="font-weight:normal;color:gray;">(<i>comma-separated, case-insensitive</i>)</span></div>',
  36. 'type': 'textarea',
  37. 'default': ''
  38. },
  39. 'blacklist_sources': // field id
  40. {
  41. 'label': '<div style="margin:1em 0 0;padding:0;">Blacklisted News Sources <span style="font-weight:normal;color:gray;">(<i>comma-separated, case-insensitive</i>)</span></div>',
  42. 'type': 'textarea',
  43. 'default': ''
  44. },
  45. 'position': // field id
  46. {
  47. 'label': 'Position:',
  48. 'type': 'radio',
  49. 'options': ['Left','Right'],
  50. 'default': 'Right'
  51. },
  52. 'disable': // field id
  53. {
  54. 'label': 'Disable Filtering:',
  55. 'type': 'checkbox',
  56. 'default': false
  57. },
  58. 'hide_sidebar': // field id
  59. {
  60. 'label': 'Hide Sidebar:',
  61. 'type': 'checkbox',
  62. 'default': false
  63. }
  64. },
  65. 'events': // Callback functions object
  66. {
  67. // 'init': function() { alert('onInit()'); },
  68. // 'open': function() { alert('onOpen()'); },
  69. 'save': function() { location.reload(); },
  70. // 'close': function() { alert('onClose()'); },
  71. // 'reset': function() { }
  72. },
  73. 'css': '#gnf_settings_dialog { width:70% !important;border:0!important;border-radius:3px!important;padding:3em 1em 1em !important;height:auto !important;box-shadow:0 0 32px #000000 !important;line-height:unset; font-size:1em; } textarea { width:-moz-calc(100% - 2em - 2px) !important;width:calc(100% - 2em - 2px)!important;height:8em;margin:0!important;padding:0.5em 1em;color:grey!important;font-family:monospace !important;font-size:0.875em!important;line-height:1.5!important; border-color:grey; border-radius:3px; } textarea:focus { color:black!important; } #gnf_settings_dialog_header { font-size:1.25em !important;position:absolute;top:0;right:0;left:0;height:1.618em;background: -moz-linear-gradient(top,#cfcfcf 0%,#a8a8a8 100%); background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cfcfcf), color-stop(100%,#a8a8a8)); background: -webkit-linear-gradient(top,#cfcfcf 0%,#a8a8a8 100%); background: -ms-linear-gradient(top, #cfcfcf 0%,#a8a8a8 100%); background: linear-gradient(top,#cfcfcf 0%,#a8a8a8 100%);box-shadow:0px 1px 0px rgba(255,255,255,0.5) inset,0px 1px 0px #515151; padding:0.5em 0 0;text-shadow:0px 1px 0px rgba(255,255,255,0.25);color:#444444; } #gnf_settings_dialog_position_var { margin-top:1em!important;} #gnf_settings_dialog_position_var,#gnf_settings_dialog_disable_var,#gnf_settings_dialog_hide_sidebar_var { margin-right:2em!important;float:left; } #gnf_settings_dialog_position_var { display:block; clear:both; } #gnf_settings_dialog_disable_var { clear:left; } #gnf_settings_dialog_blacklist_terms_field_label,#gnf_settings_dialog_blacklist_sources_field_label { float:left !important; margin-bottom:0.618em !important; } #gnf_settings_dialog_field_position,#gnf_settings_dialog_position_field_label { float:left; } #gnf_settings_dialog_field_position label { margin-right:1em; } #gnf_settings_dialog_buttons_holder {float:right; } #gnf_settings_dialog_saveBtn,#gnf_settings_dialog_closeBtn{width:6em;text-align:center;color:white!important;border-radius:3px;margin-top:0!important;margin-bottom:0!important;padding:0.5em 1em!important; } #gnf_settings_dialog_saveBtn { background:cornflowerblue !important;border:solid 1px cornflowerblue!important; } #gnf_settings_dialog_closeBtn{background:white!important;color:#444444 !important;border:solid 1px #444444 !important; } #gnf_settings_dialog_saveBtn:hover{background:#2e8b57!important;border:solid 1px #2e8b57!important; } #gnf_settings_dialog_saveBtn:active{border:solid 1px #2e8b57!important; } #gnf_settings_dialog_closeBtn:active { background:cornflowerblue!important;color:white!important;border:solid 1px cornflowerblue!important; } .reset_holder { display:none!important; }',
  74. 'frame':gm_config_panel
  75. });
  76. }
  77. gnf_settings();
  78.  
  79. // **************** //
  80.  
  81. $('#gnf_wrapper').remove();
  82.  
  83. // Create Google News Filter settings element
  84. var $gnf_el = '<div id="gnf_wrapper" style="background-color:white;position:absolute;top:0;right:0;padding:0.125em 1em;z-index:9000;cursor:pointer;border-bottom-left-radius:3px;border-bottom-right-radius:3px;box-shadow:0 0 12px #AAAAAA;color:#888888;"><div id="gnf_title" style="display:block;font-weight:bold;position:relative;z-index:1001;" title="Click to reload.">Google News Filter</div><div id="gnf_statistics" title="Click to show matched terms."></div><div id="gnf_settings" title="Click to show settings.">Settings</div></div>';
  85. $('.pGxpHc').css('position','relative').after($gnf_el);
  86. $('#gnf_statistics,#gnf_settings').hide();
  87.  
  88. // define variables
  89. var $gnf_wrapper = $('#gnf_wrapper');
  90. var $gnf_statistics = $('#gnf_statistics');
  91. var $gnf_settings = $('#gnf_settings');
  92. var $count = 0;
  93. var $matched = '';
  94. var $matchedArray = [];
  95. var $story = '';
  96.  
  97. function google_news_filter() {
  98.  
  99. // Open GM_config window, focus blacklist textarea, change default "close window" text
  100. $gnf_settings.on('click',function() {
  101. GM_config.open();
  102. $('#gnf_settings_dialog').css({'position':'absolute','top':'4em','left':'15%'});
  103. $('#gnf_settings_dialog_field_blacklist_terms').focus().add('#gnf_settings_dialog_field_blacklist_sources').css({'font-family':'monospace'});
  104. $('#gnf_settings_dialog_closeBtn').text('Cancel');
  105. return false;
  106. });
  107.  
  108. // Main Google News Filter function: the magic happens here!
  109. if ( GM_config.get('disable') == 1 ) {
  110. $gnf_statistics.attr('title','').append('<span style="color:red">! Filtering disabled</span>');
  111. } else {
  112. // get blacklist terms from GM_config local storage, convert to lowercase, trim whitespace, escape punctuation:
  113. var $blacklist_terms = GM_config.get('blacklist_terms').toLowerCase().trim().replace(/\s+,\s+|,\s+|\s+,|,,|\r/g,',').replace(/,$/,'').replace(/'/g,"\'").replace(/"/g,'\"');
  114. var $blacklist = $blacklist_terms.split(','); // create array from blacklist
  115. $blacklist = $blacklist.filter(function(n,i) { return n !== ''; }); // remove empty terms
  116. $blacklist = [...new Set($blacklist)]; // remove duplicate terms
  117.  
  118. var $blacklist_sources = GM_config.get('blacklist_sources').toLowerCase().trim().replace(/\s+,\s+|,\s+|\s+,|,,|\r/g,',').replace(/,$/,'').replace(/'/g,"\'").replace(/"/g,'\"');
  119. var $sources = $blacklist_sources.split(','); // create array from blacklist sources
  120. $sources = $sources.filter(function(n,i) { return n !== ''; }); // remove empty terms
  121. $sources = [...new Set($sources)]; // remove duplicate terms
  122.  
  123. // remove blacklisted stories
  124. $('.v4IxVd,.M1Uqc,.Q3vG6d > a,.Q3vG6d,.nuEeue').each(function() { // elements to search ,.Q3vG6d,.hzdq5d,.nuEeue
  125. var $titletext = $(this).text().toLowerCase();
  126. for ( var i=0; i < $blacklist.length; i++ ) { // for each blacklist term...
  127. if ( $titletext.indexOf( $blacklist[i] ) > -1 ) { // ...if the term is found...
  128. $(this).parents('.PaqQNc,.M1Uqc,.HzT8Gd').remove(); // ...remove the parent element,...
  129. $count += 1; // ...and increment count of stories removed.
  130. $matchedArray.push($blacklist[i]);
  131. }
  132. if ( $count == 1 ) { $story = " story"; } else { $story = " stories"; }
  133. }
  134. // update statistics and add matched terms:
  135. var obj = {};
  136. $matchedArray.forEach(function(item) {
  137. if (typeof obj[item] == 'number') {
  138. obj[item]++;
  139. } else {
  140. obj[item] = 1;
  141. }
  142. });
  143. // make list of removed items and append to statistics:
  144. $matched = Object.keys(obj).map(function(item) {
  145. return item + (obj[item] == 1 ? ' (1)' : ' (' + obj[item] + ')');
  146. }).join('<br>');
  147. $gnf_statistics.text($count + $story +' removed').append('<p id="matched" style="display:none;margin:0 0 0.5em 1em;-moz-columns:2;columns:2;">'+$matched+'</p>');
  148. });
  149.  
  150. // remove blacklisted sources
  151. $('.IH8C7b.Pc0Wt').each(function() {
  152. var $sourcetext = $(this).text().toLowerCase();
  153. var $parentContainer = $(this).closest('c-wiz');
  154. for (var i=0; i < $sources.length; i++) {
  155. if ( $sourcetext.indexOf( $sources[i] ) > -1 ) {
  156. $parentContainer.remove(); //.append($related).prepend('<div class="esc-lead-article-title-wrapper"><p><span class="titletext">[ blacklisted story source removed: '+ $sourcetext +' ]</span></p></div>');
  157. }
  158. }
  159. });
  160. } // end else
  161.  
  162. // Events
  163. // show statistics and settings labels on hover
  164. $gnf_wrapper.on('click','#gnf_title',function(e) {
  165. e.stopPropagation();
  166. });
  167. // hover colors
  168. $gnf_wrapper.on('mouseenter',function() {
  169. $(this).css({'color':'#444444'});
  170. });
  171. $gnf_wrapper.on('mouseleave',function() {
  172. $('#gnf_statistics p').hide();
  173. $(this).css({'color':'#888888'});
  174. });
  175. $gnf_wrapper.find('#gnf_settings,#gnf_statistics').hover(function() {
  176. $(this).css({'color':'#000000'});
  177. }, function() {
  178. $(this).css({'color':'unset'});
  179. });
  180.  
  181. } // end google_news_filter function
  182.  
  183. google_news_filter();
  184.  
  185. // Click "Google News Filter" title to reload Google News.
  186. $gnf_wrapper.find('#gnf_title').on('click',function() { location.reload(); });
  187. // Reload page when clicking Google News section links (needed in order to fire google_news_filter function).
  188. $('#sdgBod,.adH5zf').on('click',function() {
  189. var $thisHref = $(this).attr('href');
  190. if ( $thisHref ) { location.assign($thisHref); }
  191. });
  192.  
  193. // **************** //
  194.  
  195. $gnf_wrapper.on('mouseenter mouseleave',function(e) {
  196. e.stopPropagation();
  197. $('#gnf_statistics,#gnf_settings').toggle();
  198. });
  199. // show/hide matched terms on click:
  200. $gnf_wrapper.on('click',$gnf_statistics,function(e) {
  201. e.stopPropagation();
  202. if ( $('#matched:visible').length ) {
  203. $('#matched').hide(500);
  204. } else {
  205. $('#matched').show(500);
  206. }
  207. });
  208.  
  209. // Google News Filter options
  210.  
  211. // position Google News Filter element
  212. function gnf_el_position() {
  213. var $position = GM_config.get('position');
  214. if ( $position == 'Left' ) {
  215. $gnf_wrapper.css({'left':0,
  216. 'right':'unset'});
  217. }
  218. }
  219. gnf_el_position();
  220.  
  221. // Hide Sidebar
  222. if ( GM_config.get('hide_sidebar') == 1 ) {
  223. $('div[aria-label="Main menu"]').click().blur();
  224. }
  225.  
  226. // Experimental: use keyboard to cancel or save settings
  227. $('body').on('keydown','#gnf_settings_dialog,#gnf_settings_dialog_closeBtn,#gnf_settings_dialog_saveBtn',function(e) {
  228. if ( e.metaKey && e.which == 190 ) { $('#gnf_settings_dialog_closeBtn').click(); }
  229. if ( e.which == 13 ) { $('#gnf_settings_dialog_saveBtn').click(); }
  230. });
  231.  
  232. dragSettings();
  233. function dragSettings() {
  234. const state = { mouseDown:1 };
  235. // Experimental: make settings window draggable
  236. var $gnf_settings_dialog = $('#gnf_settings_dialog');
  237. $(document).on("mousedown", "#gnf_settings_dialog_header", function() {
  238. eleMouseDown();
  239. return false;
  240. });
  241. function eleMouseDown(e) {
  242. state.mouseDown = 1;
  243. clientX = e.offsetX;
  244. clientY = e.offsetY;
  245. $(document).on("mousemove", function() { eleMouseMove(); return false; });
  246. $(document).on("mouseup" , function() { eleMouseUp(); return false; });
  247. }
  248. function eleMouseMove(ev) {
  249. ev.preventDefault();
  250. if (state.mouseDown == 1) {
  251. state.mouseDown = 2;
  252. return;
  253. }
  254. if (stateMouseDown == 2){
  255. var pX = ev.pageX;
  256. var pY = ev.pageY;
  257. $gnf_settings_dialog.css('left',pX - clientX + "px");
  258. $gnf_settings_dialog.css('top',pY - clientY + "px");
  259. }
  260. }
  261. function eleMouseUp(e) {
  262. e.preventDefault();
  263. state.mouseDown = 0;
  264. document.removeEventListener ("mousemove" , eleMouseMove , false);
  265. document.removeEventListener ("mouseup" , eleMouseUp , false);
  266. }
  267. }
  268.  
  269.  
  270. });

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址