Reddit Filter Plus

By burger Last update Nov 17, 2011 — Installed 5,130 times.

There are 15 previous versions of this script.

// ==UserScript==
// @name	Reddit Filter Plus
// @license	GPL version 2 http://www.gnu.org/licenses/gpl-2.0.html
// @description	Hide or highlight links by user, title, url or subreddit. Preferences are found on the regular reddit preferences page. Highlight colors may be entered as HTML colors (#123456) or with simple names.
// @include	https://ssl.reddit.com/prefs/
// @include	http://www.reddit.com/prefs/
// @include	http://www.reddit.com/*
// @exclude	http://www.reddit.com/user/*
// @exclude	http://www.reddit.com/info/*
// @exclude	http://www.reddit.com/r/*/comments/*
// ==/UserScript==

var hidden_headlines = [];

if (typeof GM_log === "undefined") {
  GM_log = function (msg) {};
}
if (typeof GM_setValue === "undefined") {
  GM_setValue = function (name, value) {
    var expdate = new Date();
    expdate.setTime(expdate.getTime() + 64800000000);//~2 years
    var expires = "; expires=" + expdate.toGMTString();
    document.cookie = name+"="+value+expires+"; path=/";
  }
}
if (typeof GM_getValue === "undefined") {
  GM_getValue = function (name) {
    var regex = new RegExp(';?\s*'+escape(name)+'=([^;]+)');
    return document.cookie.match(regex);
  }
}

rf_foreach=function(seq, callback){
  for(var i=0;i<seq.length;++i){
    callback(seq[i]);
  }
}

rf_loadFilters = function() {
  var json = GM_getValue('rf_filters');
  GM_log('Loading filters: ' + json);
  
  var filters = eval('(' + json + ')');
  return filters ? filters : [];
}

rf_saveFilters = function(filters) {
  var json = '[';// convert to JSON
  for (var i = 0; i < filters.length; ++i) {
    var filter = filters[i];
    
    if (i > 0) {
      json += ', ';
    }
    json +=
        '{ ' +
          "'titles' : '" + filter.titles + "', " +
          "'urls' : '" + filter.urls + "'," +
          "'users' : '" + filter.users + "'," +
          "'subreddits' : '" + filter.subreddits + "', " +
          "'highlight' : " + filter.highlight + ", " +
          "'color' : '" + filter.color + "'" +
        ' }';
  }
  json += ']';
  
  GM_log('Saving filters: ' + json);
  GM_setValue('rf_filters', json);
}

rf_buildPatterns = function(filters) {
  var patternTable = [];
  
  for (var i = 0; i < filters.length; ++i) {
    var filter = filters[i];
    
    var filterPatterns = { 'user' : [], 'subreddit' : [], 'url' : [], 'title' : [], 'highlight' : false, 'color' : 'yellow' };
    
    if (filter.titles) {
      // add title matches
      rf_foreach(filter.titles.split(/\s*,\s*/),function(pattern){
        filterPatterns.title.push(new RegExp(pattern, 'i'));
      });
    }
    
    if (filter.urls) {
      // add url matches
      rf_foreach(filter.urls.split(/\s*,\s*/),function(pattern){
        filterPatterns.url.push(new RegExp(pattern, 'i'));
      });
    }
    
    if (filter.users) {
      // add user patterns
      rf_foreach(filter.users.split(/\s*,\s*/),function(pattern){
        filterPatterns.user.push('http://www.reddit.com/user/' + pattern.toLowerCase() + '/');
      });
    }
    
    if (filter.subreddits) {
      // add subreddit patterns
      rf_foreach(filter.subreddits.split(/\s*,\s*/),function(pattern){
        filterPatterns.subreddit.push('http://www.reddit.com/r/' + pattern.toLowerCase() + '/');
      });
    }
    
    filterPatterns.highlight = filter.highlight;
    filterPatterns.color = filter.color;
    
    patternTable.push(filterPatterns);
  }

  return patternTable;
}

rf_highlight = function(elem, color)
{
  elem.style.backgroundColor = color;
}

rf_hide = function(elem)
{
  elem.style.display = 'none';
  hidden_headlines.push(elem);
}

rf_doFilter = function()
{
  var filters = rf_buildPatterns(rf_loadFilters());
  var divs = document.getElementsByTagName('div');

  for (var i = 0; i < divs.length; ++i) {
    var div = divs[i];

    if (!(/thing/.test(div.className))) continue;

    var match = false;
    var links = div.getElementsByTagName('a');
    for (var j = 0; !match && j < links.length; ++j) {
      var link = links[j];

      for (var k = 0; k < filters.length; ++k) {
        var filter = filters[k];
        
        if (/^title/.test(link.className)) {
          
          // title match
          for (var l = 0; !match && l < filter.title.length; ++l) {
            var pattern = filter.title[l];
            
            if (pattern.test(link.innerHTML)) {
              match = true;
              break;
            }
          }// [end]for each title
  
          // url match
          for (var l = 0; !match && l < filter.url.length; ++l) {
            var pattern = filter.url[l];
            
            if (pattern.test(link.href)) {
              match = true;
              break;
            }
          }// [end]for each url
        } else if (/\/domain\//.test(link.href)) {
		  // domain match
          for (var l = 0; !match && l < filter.url.length; ++l) {
            var pattern = filter.url[l];
            
            if (pattern.test(link.href)) {
              match = true;
              break;
            }
          }// [end]for each url
		} else if (link.className == 'author') {
  
          // user match
          for (var l = 0; !match && l < filter.user.length; ++l) {
            var pattern = filter.user[l];
            
            if (pattern == link.href.toLowerCase()) {
              match = true;
              break;
            }
          }// [end]for each user
        } else if (/^subreddit/.test(link.className)) {
  
          // subreddit match
          for (var l = 0; !match && l < filter.subreddit.length; ++l) {
            var pattern = filter.subreddit[l];
            
            if (pattern == link.href.toLowerCase()) {
              match = true;
              break;
            }
          }// [end]for each subreddit
        }
        
        if (match) {
          rf_highlight(div, filter.color);
          if (!filter.highlight) {
            rf_hide(div);
          }
          break;
        }
      }// [end]for each filter

    }// [end]for each link
  }// [end]for each div

  rf_report(hidden_headlines.length);
}

rf_reSerialize = function() {
  var filters = [];
  var container = document.getElementById('rf_filters');
  
  for (var i = 0; i < container.childNodes.length; ++i) {
    var node = container.childNodes[i];
    var filter = {'titles' : '', 'urls' : '', 'users' : '', 'subreddits' : '', 'highlight' : false, 'color' : 'yellow'};
    
    var subnodes = node.getElementsByTagName('input');
    for (var j = 0; j < subnodes.length; ++j) {
      var input = subnodes[j];
      
      if (input.type == 'text' && input.value) {
        if (input.className == 'rf_titles') {
          filter.titles = input.value;
        } else if (input.className == 'rf_urls') {
          filter.urls = input.value;
        } else if (input.className == 'rf_users') {
          filter.users = input.value;
        } else if (input.className == 'rf_subreddits') {
          filter.subreddits = input.value;
        } else if (input.className == 'rf_color') {
          filter.color = input.value;
        }
      } else if (input.type == 'checkbox') {
        filter.highlight = input.checked;
      }
    }
    filters.push(filter);
    
  }
  
  return filters;
}

rf_deSerialize = function(filters) {
  for (var i = 0; i < filters.length; ++i) {
    var filter = filters[i];
    
    rf_prefsAddFilter(filter.titles, filter.urls, filter.users, filter.subreddits, filter.highlight, filter.color);
  }
}

rf_doPrefs = function() {
  var newForm = document.createElement('form');
  newForm.className = 'pretty-form';
  newForm.innerHTML = '<hr><h1>Reddit Filter Plus</h1><div id="rf_filters"></div><hr><input id="rf_addfilter" type="button" class="btn" value="add filter" /><input id="rf_savefilters" type="button" class="btn" value="save filters" /><span id="rf_savestatus" style="display: none">saved</span><br><a href="http://www.reddit.com/">return to main</a>';

  // append the filter preferences in an appropriate spot
  var forms = document.getElementsByTagName('form');
  for (var i = 0; i < forms.length; ++i) {
    var form = forms[i];
    
    if (form.className == 'pretty-form short-text') {
      form.parentNode.insertBefore(newForm, form.nextSibling);
    }
  }

  document.getElementById('rf_addfilter').addEventListener('click', function() {rf_prefsAddFilter('', '', '', '', true, 'yellow');}, false);
  document.getElementById('rf_savefilters').addEventListener('click', function() {
      rf_saveFilters(rf_reSerialize());
      window.setTimeout(function() {
        document.getElementById('rf_savestatus').style.display = 'none';
      }, 4000);
      document.getElementById('rf_savestatus').style.display = '';
    document.getElementById('rf_savestatus').innerHTML = 'saved';}, false);

  rf_deSerialize(rf_loadFilters());
}

rf_prefsAddFilter = function(titles, urls, users, subreddits, highlight, color) {
  var container = document.getElementById('rf_filters');
  var newFilter = document.createElement('div');
  var removeButton = document.createElement('input');

  newFilter.style.border = '1px solid black';
  newFilter.innerHTML = '<table class="content preftable">' +
      '<tr><th>title filters</th><td class="prefright"><input class="rf_titles" type="text" value="' + (titles ? titles : '') + '" /></td></tr>' +
      '<tr><th>url filters</th><td class="prefright"><input class="rf_urls" type="text" value="' + (urls ? urls : '') + '" /></td></tr>' +
      '<tr><th>user filters</th><td class="prefright"><input class="rf_users" type="text" value="' + (users ? users : '') + '" /></td></tr>' +
      '<tr><th>subreddit filters</th><td class="prefright"><input class="rf_subreddits" type="text" value="' + (subreddits ? subreddits : '') + '" /></td></tr>' +
      '<tr><th>highlight</th><td class="prefright"><input type="checkbox" "class="rf_highlight" ' + (highlight ? 'checked ' : '' ) +' /> (if unchecked, anything matching this filter will be hidden)</td></tr>' +
      '<tr><th>highlight color</th><td class="prefright"><input class="rf_color" type="text" value="' + (color ? color : '') + '" /></td></tr>' +
      '</table>';
  
  removeButton.type = 'button';
  removeButton.class = 'btn';
  removeButton.value = 'remove this filter';
  removeButton.addEventListener('click', function() {container.removeChild(newFilter);}, false);
  
  newFilter.appendChild(removeButton);
  container.appendChild(newFilter);
}

rf_unhide = function() {
  for (var i = 0; i < hidden_headlines.length; ++i) {
    hidden_headlines[i].style.display = '';
  }
  document.getElementById('rf_report').style.display = 'none';
}

rf_report = function(num) {
  var msg = num + ' headlines filtered';
  GM_log(msg);

  if (num > 0) {
    var div = document.createElement('div');
    div.innerHTML = '<p id="rf_report"><i>' + msg + ': <a id="rf_unhide" onClick="rf_unhide()">[unhide]</a><i></p>';
    
    var siteTable = document.getElementById('siteTable');
	if (typeof(siteTable) == "undefined") siteTable = document.getElementById('siteTable_organic');
	if (!siteTable) return;
    siteTable.parentNode.insertBefore(div, siteTable.nextSibling);
    document.getElementById('rf_unhide').addEventListener('click', rf_unhide, false);
  }
}

// do stuff
if (/\/prefs\//.test(window.location.href)) {
  rf_doPrefs();
} else {
  rf_doFilter();
}