Now shoosh!

By Vitor Peres Last update Sep 11, 2009 — Installed 1,437 times. Daily Installs: 2, 4, 2, 3, 2, 0, 2, 0, 1, 2, 2, 4, 2, 0, 1, 5, 6, 2, 6, 4, 6, 2, 1, 1, 6, 0, 3, 1, 2, 0, 4, 1

There are 11 previous versions of this script.

// Now shoosh!, v0.4.3
// Copyright (c) 2008, Vitor Peres
// Released under the GPL license
// http://www.gnu.org/copyleft/gpl.html
// Updated: Thu May 28 20:11:26 2009
//
// ==UserScript==
// @name           Now shoosh!
// @namespace      http://userscripts.org/scripts/show/33629
// @description    A boon to twitter sanity, "Now shoosh!" allows you to mute people you don't really wanna read right now.
// @include        http://twitter.com/
// @include        http://twitter.com/home
// ==/UserScript==

function $(id) {
  return document.getElementById(id);
}

function $x(xPath, parent) {
  var result = [];
  var scope = parent ? parent : document;
  var data = document.evaluate(xPath, scope, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
  for(var i = 0; i < data.snapshotLength; i++) {
    var datum = data.snapshotItem(i);
    result.push(datum);
  }
  return result;
}

function contactsInTimeline(timeline) {
  var contacts = [];
  for(var i = 0; i < toots.length; i++) {
    var toot = toots[i];
    contacts.push(getAuthorName(toot));
  }
  return contacts;
}

function getTimeline() {
  return $x("/html/body[@id='home']/div[@id='container']/table/tbody/tr/td[@id='content']/div/div[3]/ol[@id='timeline']//li");
}

function muteToot(toot) {
  toot.style.visible = false;
  toot.style.display = 'none';
}

function onMuteUser(contact) {
  muteUser(contact);
  sayNoMore(contact);
  addContactToMutedDisplayList(contact, getContactImageURL(contact));
}

function muteUser(contact) {
  var users = retrieveMutedContacts();
  users.push(contact);
  storeMutedContacts(users);
}

function sayNoMore(contact) {
  var toots = filterTootsFromContact(contact);
  toots.forEach(muteToot);
}

function makeMutable(toot) {
  var body = $x("id('" + toot.id + "')/span[2]")[0];
  var contents = $x("id('" + toot.id + "')/span[2]/span[1]")[0];
  var container = document.createElement('span');
  var mute = container.appendChild(document.createElement('a'));
  mute.href = 'javascript:;';
  mute.appendChild(document.createTextNode('(mute) '));
  mute.style.fontSize = 'small';
  mute.addEventListener('click', (function(a) { return function() { onMuteUser(a);} })(getAuthorName(toot)), false);
  body.insertBefore(container, contents);
}

function getAuthorElement(toot) {
  var xpath = "id('" + toot.id + "')/span[2]/strong/a";
  return $x(xpath)[0];
}

function getAuthorName(toot) {
  return getAuthorElement(toot).innerHTML;
}

function retrieveMutedContacts(contacts) {
  var users = GM_getValue('mutedContacts', null);
  if(users) {
    return users.split(';');
  }
  else {
    return [];
  }
}

function storeMutedContacts(contacts) {
  GM_setValue('mutedContacts', contacts.join(';'));
}

function findMutedInTimeline(contacts) {
  var allmuted = retrieveMutedContacts();
  return contacts.filter(function(c) { return allmuted.indexOf(c) != -1; });
}

function addContactToMutedDisplayList(contact, img_url) {
  var list = getMutedDisplayList();
  var tr   = list.appendChild(document.createElement('tr'));
  var imgcont = tr.appendChild(document.createElement('td'));
  imgcont.setAttribute('class', 'vcard');
  imgcont.setAttribute('valign', 'top');
  var link = imgcont.appendChild(document.createElement('a'));
  link.href = 'http://twitter.com/' + contact;
  var img = link.appendChild(document.createElement('img'));
  img.src = img_url;
  var name = tr.appendChild(document.createElement('td'));
  name.setAttribute('valign', 'top');
  name.appendChild(document.createTextNode(contact));
  var unmcont = tr.appendChild(document.createElement('td'));
  unmcont.setAttribute('valign', 'top');
  var unmute  = unmcont.appendChild(document.createElement('a'));
  unmute.setAttribute('class', 'section-links');
  unmute.href = 'javascript:;';
  unmute.addEventListener('click', (function(c) { return function() { onUnmuteContact(c); } })(contact), false);
  unmute.appendChild(document.createTextNode('unmute'));
}

function onUnmuteContact(contact) {
  filterTootsFromContact(contact).forEach(function OUC_showToot(t) {
	                                    t.style.display = 'table-row';
	                                    t.style.visible = 'true';
                                          });
  removeFromMutedDisplayList(contact);
  unmuteContact(contact);
}

function unmuteContact(contact) {
  var contacts = retrieveMutedContacts();
  var unmuted  = contacts.filter(function(mc) { return contact != mc; });
  storeMutedContacts(unmuted);
}

function removeFromMutedDisplayList(contact) {
  var isContact = function(row) {
    return row.childNodes[1].innerHTML == contact;
  };
  var list  = getMutedDisplayList();
  var entries = $x('./tr', list);
  var entry   = entries.filter(isContact)[0];
  list.removeChild(entry);
}

function filterTootsFromContact(contact, toots) {
  var toots = toots ? toots : getTimeline();
  return toots.filter(function(t) { return getAuthorName(t) == contact; });
}

function getMutedDisplayList() {
  var pane = $x("//div[@id='muted_pane']")[0];
  if(pane) {
    return $x("./table[@id='muted_list']", pane)[0];
  }
  else {
    return createMutedDisplayList();
  }
}

function createMutedDisplayList() {
  var sidepane = $('side');
  var pane = sidepane.appendChild(document.createElement('div'));
  pane.id = 'muted_pane';
  pane.setAttribute('class', 'section');
  var header = pane.appendChild(document.createElement('div'));
  header.setAttribute('class', 'section-header');
  var title  = header.appendChild(document.createElement('h1'));
  title.appendChild(document.createTextNode('Muted People'));
  var list  = pane.appendChild(document.createElement('table'));
  list.id = 'muted_list';
  list.cellPadding = 0;
  list.cellSpacing = 0;
  return list;
}

function getContactImageURL(contact, alltoots) {
  var base = 'http://twitter.com/users/show/';
  var req = new XMLHttpRequest();
  var img = null;
  alltoots = toots ? toots : getTimeline();
  var toots = filterTootsFromContact(contact, alltoots);
  if(toots.length > 0) {
    img = $x("id('" + toots[0].id + "')/span[1]/a/img")[0].src;
  }
  else {
    req.open('GET', base + contact + '.json', false);
    req.send(null);
    if(req.status == 200) {
      var details = eval("[" + req.responseText + "]")[0];
      img = details["profile_image_url"];
    }
  }
  img = img.replace(/_normal\./, '_mini.');
  return img;
}

function showMutedList(toots) {
  retrieveMutedContacts().forEach(function SMC_addToList(c) {
 	                            addContactToMutedDisplayList(c, getContactImageURL(c))
                                  });
}

/* This was added to provide GreaseKit support, as my wife is desperate with so
 * much crap invading her life.
 * Taken from: http://groups.google.com/group/greasekit-users/browse_thread/thread/d8135ac1f006493e?pli=1
 */

var Cookie = {
  PREFIX:'_greasekit',
  get: function(name, defaultValue) {
    var nameEQ = escape(Cookie._buildName(name)) + "=", ca =
document.cookie.split(';');
    for (var i = 0, c; i < ca.length; i++) {
      c = ca[i];
      while (c.charAt(0) == ' ') c = c.substring(1, c.length);
      if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
    }
    return defaultValue;
  },
  set: function(name, value, options){
    options = (options || {});
    if (options.expiresInOneYear) {
      var today = new Date();
      today.setFullYear(today.getFullYear()+1, today.getMonth, today.getDay());
      options.expires = today;
    }
    var curCookie = escape(Cookie._buildName(name)) + "=" + escape(value) +
      ((options.expires) ? "; expires=" + options.expires.toGMTString() : "") +
      ((options.path)    ? "; path="    + options.path : "") +
      ((options.domain)  ? "; domain="  + options.domain : "") +
      ((options.secure)  ? "; secure" : "");
    document.cookie = curCookie;
  },
  hasCookie: function( name ){
    return document.cookie.indexOf( escape(Cookie._buildName(name)) ) > -1;
  },
  _buildName: function(name){
    return Cookie.PREFIX + '_' + name;
  }

};

if(typeof GM_getValue === "undefined") GM_getValue = Cookie.get;
if(typeof GM_setValue === "undefined") GM_setValue = Cookie.set;

/* Where the magic happens */
var toots = getTimeline();
toots.forEach(makeMutable);
var contacts = contactsInTimeline(toots);
findMutedInTimeline(contacts).forEach(sayNoMore);
showMutedList(toots);