Noise Reduction for Google & Bing

By smogami Last update Aug 24, 2010 — Installed 8,465 times.

There are 23 previous versions of this script.

// ==UserScript==
// @name          Google Noise Reduction
// @namespace     http://exoego.net/
// @description   Domainname-based filtering for Google's search results.
// @include       http://www.google.tld/search*
// @include       http://www.google.tld/webhp*
// @include       http://www.google.tld/#hl*
// @include       http://www.google.tld/
// @include       http://www.bing.com/search*
// @require       http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.js
// @version       0.2.9
// ==/UserScript==

(function(w, $){ // window, jQuery

/*    Setting
=============================================================================*/
var FilterDefault = [
    // "swik.net",
    // "pastebin.ca",
    // "search.yahoo.com",
]//

var SITEINFO = [
    {
        url:         "http://www\.google\.(?:[^.]+|[^.]{2,3}\.[^.]{2,3})/(?:search|#hl|webhp)*",
        linkNode:    "li h3 a.l", //"#res li.g h3 a.l",
        depthOfMeta: "2"
    }
    ,{
        url:         "http://www\.bing\.com/search*",
        linkNode:    "li h3 a",
        depthOfMeta: "2"
    }
]

/*===========================================================================*/

function launchGNR(list){//
    if (!(SITEINFO instanceof Array)) return; // initialized
    filterInit();
    if (SITEINFO instanceof Array){
        var count = 0;
        var tid = setInterval(function(){
            filterInit();
            if (SITEINFO instanceof Array) {
                if (count++ > 20) {
                    clearInterval(tid);
                }
            } else {
                clearInterval(tid);
                success();
            }
        }, 500);

        w.addEventListener("hashchange",function(){
            setTimeout(function(){
                if (SITEINFO instanceof Array) return;
                clearInterval(tid);
                $(SITEINFO.linkNode).each(function(index, node){
                    Filter.check(node); // google
                });
            }, 500);
        },false);
    } else {
        success()
    }

    function success(){
        GM_addStyle(style);

        Filter.init();
        Dialog.init();

        $(SITEINFO.linkNode).each(function(index, node){
            Filter.check(node);
        });

        if(window.AutoPagerize.addFilter)
            window.AutoPagerize.addFilter(function(page) {
                var autopagerize_linkNode = SITEINFO.linkNode.replace(/^\S+/,"");
                $(autopagerize_linkNode, page).each(function(index, node){
                       Filter.check(node);
                });
            });
    }
    function filterInit() {
        for (var i=0, len=list.length; i < len; ++i) {
            var reg = list[i].url.replace(".","\.").replace("*", "(?:.*)");
            if (location.href.match(reg) == null) {
                log("no match: " + reg);
            }
            else if ($(list[i].linkNode).length === 0) {
                warn("link not found: " + reg);
            }
            else {
                log("filter found:" + reg);
                SITEINFO = list[i];
                SITEINFO.depthOfLink = depthOfRepeatingUnit($(SITEINFO.linkNode));
                break;
            }
        }
    }
}

/*===========================================================================*/

var Dialog = {
    init: function(){
        var self = this;
        this.header = $('<h1>' + Lexicon["Click to remove filter"] + '</h1>');
        this.list   = $('<ul/>');
        this.buttonCancel  = $('<input/>')
            .attr({ type:"button", id:"GNR_cancel", value:Lexicon.closeDialog })
            .click(function(){ self.close(); });
        this.buttonSave = $('<input/>')
            .attr({ type:"button", id:"GNR_save", value:Lexicon.saveEdit })
            .click(function(){ self.saveEdit(); })
        this.title   = $('<input/>')
            .attr({type:"button", id:"GNR_title", value:Lexicon["View All Filters"] })
            .click(function(){ self.openInEditMode(); });
        this.footer  = $('<p/>')
            .append(this.title, this.buttonSave, this.buttonCancel);
        this.wrapper = $('<div/>').attr({id:'GNR_dialog'})
            .append(this.header, this.list, this.footer)
            .appendTo("body")
            .hover(function(){ // in
                w.clearTimeout(self.timer);
            },function(){ // out
                self.timer = w.setTimeout(function(){ self.close() },
                    /*self.isEditMode ? 5000 :*/ 5000)
            });
        $('<a id="GNR_open_editor" href="#"/>').text("Noise Reduction")
            .appendTo("body").click(function(){ self.openInEditMode() });
        GM_registerMenuCommand(Lexicon.commandName, function(){
            Dialog.openInEditMode();
        });
    },
    timer: 0,
    isEditMode: false,
    open: function(buttonLink){
        if (this.isEditMode) {
            this.quitEditMode();
        }
        var pos = $(buttonLink).position();
        this.wrapper.css({
            left: pos.left  + "px",
            top:  (pos.top+ this.wrapper.height()  )  + "px"
        }).show();
    },
    close: function(){
        if (this.isEditMode) this.quitEditMode();
        w.clearTimeout(this.time);
        this.wrapper.fadeOut("fast");
    },
    update: function(elmAddButton, domains) {
        var keys = domains.map(function(key){
            var li = $("<li />")
                    .attr({data:key}).html(key)
                    .click(function(){
                        Filter.add( this.getAttribute("data") );
                        Filter.save();
                        $(getLinkBlock(elmAddButton, SITEINFO.depthOfMeta)).remove();
                    Dialog.close();
                })[0];
            return li;
        });
        this.list.empty().append(keys)
    },
    saveEdit: function(){
        this.list.find("li.remove").each(function(index, elm){
            Filter.remove(elm.innerHTML)
        })
        Filter.save();
        this.close();
    },
    quitEditMode: function(){
        this.isEditMode = false;
        this.list.unbind("click");
        this.wrapper.fadeOut(function(){ Dialog.wrapper.removeClass("editMode") });
    },
    openInEditMode: function(){
        this.wrapper.hide();
        this.isEditMode = true;
        var tmp = [];
        for(var key in Filter.data) if (Filter.data.hasOwnProperty(key)) {
            tmp.push(key)
        }
        tmp = tmp.sort().map(function(item){ return "<li>"+item+"</li>"; }).join("");
        this.list.html(tmp).click(function(e){
            var item = e.originalTarget || null;
            if (!item || item.nodeName !== "LI") return;
            $(item).toggleClass("remove");
        })
        this.wrapper.css({top:"24px"}).addClass("editMode").show();
    }
}

/*===========================================================================*/
var Filter = {
    data:{},
    add: function(item){
        this.data[item] = true;
        this.save();
    },
    remove: function(item){
        if (this.data[item]) delete this.data[item];
    },
    save: function(){
        GM_setValue("blackList", this.data.toSource());
    },
    init: function(){
        var self = this;
        this.data = eval(GM_getValue("blackList")) || {};
        if (FilterDefault instanceof Array) {
            FilterDefault.forEach(function(item){
                if(typeof item === "string")
                    self.add(item)
            })
        }
    },
    check: function(link){
        var domains = listupDomain(link);
        if (domains.length === 0) return;
        var self = this;
        var linkBlock = getLinkBlock(link, SITEINFO.depthOfLink);
        if (domains.some(function(key){ return self.data[key]; })) {
            $(linkBlock).remove();
            return;
        }

        var addToGNR = $("<a />").attr({
            "class": "GNR_filter_this_site",
            href:"javascript:"
        }).append(Lexicon.addToGNR).click(function(){
            Dialog.update(this, domains);
            Dialog.open(this);
            return false;
        });
        $(link).after(addToGNR);
     }
}

function getLinkBlock(node, num){
    for (var i=0, num=+num; i<num; ++i) node = node.parentNode;
    return node;
}

/*===========================================================================*/
var ccSLD = /^(?:net?|com?|gov?|org?|ac|edu?|gr)$/;

function listupDomain(link) {
    if (link && link.tagName === "A") {
        var host = link.hostname;
        var path = link.pathname.split("/")[1];
        var subs = host.split(".");
        subs.pop(); // remove TLD (com, jp, net, ...)
        if (ccSLD.test(subs[subs.length-1])) subs.pop(); // remove ccSLD( co, ne, ac, ...)

        for (var i=0, urls=[host], limit=subs.length - 1; i<limit; ++i)
            urls.push( urls[i].replace(subs[i]+".", "") );

        if (path) urls.unshift(host+"/"+path);
        return urls;
    } else {
        warn("can't list up domains". link);
        return [];
    }
}

var style = <><![CDATA[
#GNR_dialog {
color             : #fff;
background        : url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAAA1BMVEUAAACnej3aAAAAAXRSTlPM0jRW/QAAAAxJREFUeJxjYBjcAAAAoAABsAZiGAAAAABJRU5ErkJggg==");
position          : absolute;
top               : 50px;
display           : none;
left              : 25%;
-moz-border-radius: 4px;
z-index           : 99999995;
padding           : 5px 10px 10px 10px;
}
#GNR_dialog.editMode{
top  : 50px;
left : 10px !important;
right: 10px !important;
}
#GNR_dialog h1 {
display      : none;
font-size    : 16px;
border-bottom: 1px solid #666;
}
#GNR_dialog.editMode h1 {
display: block;
}
#GNR_dialog ul {
padding: 0 10px 0 0;
margin : 0;
}
#GNR_dialog.editMode ul {
-moz-column-gap  : 10px;
-moz-column-width: 14em;
}
#GNR_dialog li {
font-size : 16px;
padding   : 0;
margin    : 3px 0;
cursor    : pointer;
list-style: none;
overflow  : hidden;
}
#GNR_dialog.editMode li {
font-size:14px;
}
#GNR_dialog li.remove {
color:#666;
}
#GNR_dialog li:hover {
color          : #ff0;
text-decoration: underline;
overflow       : visible;
}
#GNR_dialog li.remove:hover {
color: #aa0;
}
#GNR_dialog p {
text-align: right;
margin    : 5px 0 0;
}
#GNR_dialog input[type="button"] {
background : transparent;
font-size  : 15px;
border     : 1px solid #ccc;
-moz-border-radius:4px;
color      : #fff;
padding    : 1px 10px;
cursor     : pointer;
margin-left: 10px;
}
#GNR_dialog input[type="button"]:hover {
background: #555;
border    : 1px solid #fff;
}
#GNR_dialog.editMode #GNR_save {display: inline;}
#GNR_dialog.editMode #GNR_title,
#GNR_save {display: none;}


#GNR_open_editor,
.GNR_filter_this_site {
display           : inline-block;
margin            : 0 0 0 5px;
padding           : 4px 6px;
line-height:1em;
text-decoration   : none;
font-size         : 12px;
border            : 1px solid;
-moz-border-radius: 3px;
background        : #fff;
}
#GNR_open_editor {
position: absolute;
top  : 34px;
right   : 16px;
padding : 3px 6px;
margin  : 0;
z-index:9999;}
#GNR_open_editor:link,
#GNR_open_editor:visited,
.GNR_filter_this_site:link,
.GNR_filter_this_site:visited {
color: #adc3ec;
}

#GNR_open_editor:hover,
#GNR_open_editor:active,
.GNR_filter_this_site:hover,
.GNR_filter_this_site:active {
color: #5c87da !important;
text-decoration   : none;
}
]]></>;

var Lexicon = (function(locale){
    var lang = navigator.language.slice(0,2);
    return locale[lang] || locale["en"];
})({
    ja: {
        addToGNR:    "フィルタ",
        closeDialog: "閉じる",
        commandName: "フィルターを閲覧/編集",
        saveEdit:    "保存",
        "View All Filters": "フィルターを見る",
        "Click to remove filter": "削除したい項目をクリックしてください。"
    },
    en: {
        addToGNR:    "filter",
        closeDialog: "close",
        commandName: "View/Edit filters",
        saveEdit:    "save",
        "View All Filters": "View All Filter",
        "Click to remove filter": "Click an item to remove from filter.",
    }
});

/*    Utility
=============================================================================*/
function log(){ if (w.console) w.console.log.apply(null, arguments) }
function warn(){ if (w.console) w.console.warn.apply(null, arguments) }
function info(){ if (w.console) w.console.info.apply(null, arguments) }

function depthOfRepeatingUnit (anchors) { // @param Nodes
    anchors = Array.prototype.slice.call(anchors);
    var first = anchors[0];
    var rest = anchors.filter(function(e){ return e !== first });
    var nodeName = first.nodeName.toLowerCase();
    var parent = first;
    var nestLevel = 0;
    while (parent = parent.parentNode) {
        ++nestLevel;
        var parentSibling = parent.nextSibling;
        if (parentSibling && parentSibling.nodeType === 1) { // Node.ELEMENT_NODE
            var psAnchors = parentSibling.getElementsByTagName(nodeName);
            for (var i=0; i<psAnchors.length; ++i)
                if (rest[0] == psAnchors[i]) return nestLevel;
        }
    }
    return -1;
}
/*    Main
=============================================================================*/
$(document).ready(function(){
    launchGNR(SITEINFO);
});
return;

})(this.unsafeWindow, this.jQuery)