blockunsafe

Block unsafe(uncomfortable) content on web pages by keywords

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         blockunsafe
// @namespace    http://blockunsafe.com/
// @version      1.0
// @description  Block unsafe(uncomfortable) content on web pages by keywords
// @author       gonetoorion
// @match        http*://*/*
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_deleteValue
// @run-at       document-start
// @noframes
// @license      GPLv3
// ==/UserScript==

(function() {
    'use strict';
    // Your code here...
    let test_value = 40;
    let is_first = true;
    let setting_btn;
    let config_domain = "blockunsafe.com";
    let pattern_url = window.location.pathname;
    let pattern_key = location.hostname + 'urlpattern';
    let max_class_key = location.hostname + 'classkeyx';
    let dom_nouse = ['SCRIPT','STYLE','TEXTAREA','svg','LINK','IFRAME','EM','I','IMG','FIELDSET','LEGEND','BR','OPTION','SELECT','INPUT','BUTTON','FORM','STRONG','TEXTAREA','FOOTER','META'];
    let no_check_tag = ['LI','TR'];
    let dom_dict = {};
    let no_target_class = [];
    let max_key = '';
    let class_set = GM_getValue(max_class_key);
    let pattern_set = GM_getValue(pattern_key);
    let top_widths = [];
    let class_setx = class_set?class_set:[];
    let warn_words = [];
    let filter_words_area = 'show_filter_keyword';
    let config_url = "https://www.blockunsafe.com/config.html";
    let config_url_marks = ["z", "e", "t"];
    for(let i=0,len=config_url_marks.length; i<len; i++){
        let www_config_url = "https://www.blockunsafe.com/"+config_url_marks[i]+"config.html";
        let no_www_config_url = "https://blockunsafe.com/"+config_url_marks[i]+"config.html";
        if(window.location.href.indexOf(www_config_url)==0||window.location.href.indexOf(no_www_config_url)==0){
            window.addEventListener("load", init_config_page);
            return;
        }
    }
    let all_ok = class_set&&check_url_pattern(pattern_url);
    let f_key = get_f_key();
    if(!f_key){
        return;
    }
    if(f_key==config_domain){
        return;
    }
    let orignal_f_key = f_key;
    f_key += '_fbkssousousous';
    let filter_keywords = GM_getValue(f_key);
    if(document.body){
        if(all_ok){
            document.body.style.display = 'none';
        }
        setTimeout(show_page, 2000);
    }
    function reset_rule(lhn){
        let pattern_key = lhn + 'urlpattern';
        let max_class_key = lhn + 'classkeyx';
        GM_deleteValue(max_class_key);
        GM_deleteValue(pattern_key);
    }
    function init_config_page(){
        let f_key = "";
        let arg = window.location.search;
        arg = arg.replace("?", "");
        if(arg.indexOf("f_key=")!=0){
            config_error();
            return;
        }
        if(arg.indexOf("&")==-1){
            f_key = arg.slice(arg.indexOf("f_key=")+6);
        }else{
            f_key = arg.slice(arg.indexOf("f_key=")+6, arg.indexOf("&"));
        }
        if(!f_key){
            config_error();
            return;
        }
        let lhn = arg.slice(arg.indexOf("lhn=")+4, arg.indexOf("&cltp"));
        if(!lhn){
            config_error();
            return;
        }
        document.getElementById("reset_filter_rule_btn").addEventListener('click', function(e){
            if(confirm("Are you sure you want to reset the filter rules ? ")){
                reset_rule(lhn);
                document.getElementById("add_sign").innerHTML = "Reset successfully";
                document.getElementById("add_sign").style.display = "block";
                setTimeout(function(){
                    document.getElementById("add_sign").style.display = "none";
                }, 1500);
            }
        });
        document.getElementById("domain_eff_page").innerHTML = f_key;
        f_key += "_fbkssousousous";
        let filter_keywords = GM_getValue(f_key);
        if(filter_keywords!=undefined&&filter_keywords.length!=0){
            for(let i=0,len=filter_keywords.length;i<len;i++){
                add_keyword_span(filter_keywords[i], f_key);
            }
        }
        document.getElementById('add_kw_btn').addEventListener('click', function(e){
            let keyword = document.getElementById('add_kw_v').value;
            let values = GM_getValue(f_key);
            keyword = keyword.trim();
            if(keyword==''||keyword.replace(/\s*/g,"")==''){
                alert('Please add blocked keywords');
                return;
            }
            if(values==undefined||values.length==0){
                values = [keyword];
            }else{
                if(values.indexOf(keyword)==-1){
                    values.push(keyword);
                }else{
                    alert("The keywords already exists,don't  add it again~");
                    return;
                }
            }
            GM_setValue(f_key, values);
            add_keyword_span(keyword, f_key);
        });
    }
    function config_error(){
        document.body.innerHTML = "CONFIG ERROR!";
    }
    function get_f_key(){
        let host_info = location.hostname.split('.');
        let temp_f_key = "";
        for(let i=host_info.length-1,stop_i=host_info.length-3;i>stop_i;i--){
            if(temp_f_key){
                temp_f_key = host_info[i] + '.' + temp_f_key;
            }else{
                temp_f_key = host_info[i];
            }
        }
        return temp_f_key;
    }
    function check_dom(dom_node){
        dom_node.style.display = 'none';
    }
    function check_url_pattern(url){
        if(!pattern_set){
            return false;
        }
        if(url=='/'&&pattern_set.indexOf(url)!=-1){
            return true;
        }
        let is_in = false;
        let url_param = url.split('/');
        url_param.shift();
        for(let i=0,len=pattern_set.length; i<len; i++){
            let test_url_param = pattern_set[i].split('/');
            test_url_param.shift();
            if(test_url_param.length!=url_param.length){
                continue;
            }
            let diff_count = 0;
            for(let ix=0,lenx=test_url_param.length; ix<lenx; ix++){
                if(isNaN(test_url_param[ix])!=isNaN(url_param[ix])){
                    break;
                }
                if(test_url_param[ix]!=url_param[ix]&&isNaN(url_param[ix])){
                    diff_count += 1;
                }
                if(diff_count>1){
                    break;
                }
                if(ix==lenx-1){
                    is_in = true;
                }
            }
            if(is_in){
                break;
            }
        }
        return is_in;
    }
    function save_pattern(pattern_url){
        if(pattern_set){
            if(pattern_set.indexOf(pattern_url)!=-1){
                return;
            }else{
                pattern_set.push(pattern_url);
            }
        }else{
            pattern_set = [pattern_url];
        }
        GM_setValue(pattern_key, pattern_set);
    }
    function parse_dom_nodes(dom_nodes){
        let filter_dom_childs = [];
        for(let i=0,len=dom_nodes.length; i<len; i++){
            if(dom_nodes[i].nodeType!=1||dom_nouse.indexOf(dom_nodes[i].nodeName)!=-1){
                continue;
            }
            if(no_check_tag.indexOf(dom_nodes[i].nodeName)!=-1&&all_ok){
                check_update(dom_nodes[i]);
                continue;
            }
            let class_tag = dom_nodes[i].getAttribute('class');
            if(class_tag&&!all_ok){
                class_tag = class_tag.replace(/(^\s*)|(\s*$)/g, "");
                if(dom_dict[class_tag]==undefined){
                    dom_dict[class_tag] = 0;
                }else{
                    dom_dict[class_tag] = dom_dict[class_tag] + 1;
                }
            }
            if(dom_nodes[i].childNodes.length){
                filter_dom_childs.push(...dom_nodes[i].childNodes);
            }
        }
        if(filter_dom_childs.length){
            parse_dom_nodes(filter_dom_childs);
        }
    }
    function get_max_node(){
        let max_key = '';
        for(let key in dom_dict){
            if(max_key==''||dom_dict[max_key]<dom_dict[key]){
                max_key = key;
            }
        }
        return max_key;
    }
    function check_update(mut_node){
        if(no_target_class.indexOf(mut_node.className)!=-1){
            return;
        }
        for(let i=0,len=warn_words.length;i<len;i++){
            if(mut_node.innerText.toLowerCase().indexOf(warn_words[i])!=-1){
                check_dom(mut_node);
                break;
            }
        }
    }
    function analy_page(mut_nodes){
        if(!filter_keywords||!filter_keywords.length){
            return;
        }
        if(all_ok){
            if(!mut_nodes.innerText||!mut_nodes.innerText.replace(/\s+/g, '')){
                return;
            }
            for(let i=0,len=filter_keywords.length;i<len;i++){
                if(mut_nodes.parentNode&&mut_nodes.parentNode.getAttribute('id')==filter_words_area){
                    return;
                }
                if(mut_nodes.innerText.toLowerCase().indexOf(filter_keywords[i].toLowerCase())!=-1){
                    warn_words.push(filter_keywords[i].toLowerCase());
                }
            }
            if(!warn_words.length){
                return;
            }
            if(no_check_tag.indexOf(mut_nodes.nodeName)!=-1){
                check_dom(mut_nodes);
                return;
            }
            parse_dom_nodes(mut_nodes.childNodes);
            if(class_set.indexOf(mut_nodes.className)!=-1){
                check_dom(mut_nodes);
            }else{
                for(let i=0,len=class_set.length; i<len; i++){
                    let childs = mut_nodes.getElementsByClassName(class_set[i]);
                    if(!childs){
                        continue;
                    }
                    for(let j=0,lenx=childs.length; j<lenx; j++){
                        check_update(childs[j]);
                    }
                }
            }
        }else{
            let class_tag = mut_nodes.getAttribute('class');
            if(class_tag){
                class_tag = class_tag.replace(/(^\s*)|(\s*$)/g, "");
                if(dom_dict[class_tag]==undefined){
                    dom_dict[class_tag] = 0;
                }else{
                    dom_dict[class_tag] = dom_dict[class_tag] + 1;
                }
            }
            parse_dom_nodes(mut_nodes.childNodes);
        }
    }
    var dom_observer = new MutationObserver(function(mutations){
        if(is_first&&document.body&&document.readyState=='complete'){
            document.body.style.display = 'block';
            add_filter_btn(setting_btn);
            is_first = false;
        }
        for(let mut of mutations){
            let mut_add_nodes = mut.addedNodes;
            for(let mut_node of mut_add_nodes){
                if(!(dom_nouse.indexOf(mut_node.nodeName)==-1&&mut_node.nodeType==1)){
                    continue;
                }
                warn_words = [];
                analy_page(mut_node);
            }
        }
        if(all_ok){
            return;
        }
        for(let key in dom_dict){
            if(document.body.style.display=='none'||document.body.style.display==''){
                return;
            }
            let class_nodes = document.getElementsByClassName(key);
            if(class_nodes.length>1){
                let test_node = class_nodes[0];
                let count = 0;
                if(!test_node.offsetWidth){
                    no_target_class.push(key);
                    continue
                }
                for(let i=1,len=class_nodes.length;i<len;i++){
                    if((class_nodes[i].innerText==test_node.innerText&&class_nodes[i].parentNode==test_node.parentNode)||(!class_nodes[i].offsetWidth&&!class_nodes[i].innerText)||class_nodes[i].offsetWidth!=test_node.offsetWidth){
                        no_target_class.push(key);
                        break;
                    }
                    if(class_nodes[i].parentNode==test_node.parentNode){
                        count++;
                    }
                    if(count>2){
                        break;
                    }
                }
                if(count==0){
                    no_target_class.push(key);
                }
            }else{
                no_target_class.push(key);
            }
        }
        for(let i=0,len=no_target_class.length;i<len;i++){
            if(no_target_class[i] in dom_dict){
                delete dom_dict[no_target_class[i]];
            }
        }
        max_key = get_max_node();
        if(max_key){
            let max_nodes = document.getElementsByClassName(max_key);
            if(!max_nodes){
                delete dom_dict[max_key];
                return;
            }
            let max_node_width = max_nodes[0].offsetWidth;
            if(max_node_width/document.body.clientWidth>0.9){
                delete dom_dict[max_key];
                return;
            }
            if(top_widths.indexOf(max_node_width)==-1){
                top_widths.push(max_node_width);
            }
            if(Math.max.apply(null, top_widths)>max_node_width){
                if(dom_dict[max_key]>5){
                    dom_dict[max_key] -= 5;
                }
            }
            if(class_set&&max_key==class_set[class_set.length-1]){
                save_pattern(pattern_url);
                all_ok = true;
                return;
            }
            if(dom_dict[max_key]>test_value){
                let s_top = document.documentElement.scrollTop || document.body.scrollTop;
                if(s_top<4000){
                    return;
                }
                for(let class_key in dom_dict){
                    if(class_key==max_key){
                        continue;
                    }
                    if(class_setx.indexOf(class_key)==-1){
                        class_setx.push(class_key);
                    }
                }
                if(class_setx.indexOf(max_key)==-1){
                    class_setx.push(max_key);
                }
                GM_setValue(max_class_key, class_setx);
                save_pattern(pattern_url);
                location.reload();
                class_set = class_setx;
                all_ok = true;
            }
        }
    });
    dom_observer.observe(document, {childList: true, subtree: true, attributes: true});
    function add_filter_btn(setting_btn){
        setting_btn = document.createElement('a');
        let color = 'rgb(198, 94, 36)';
        let text_dec = '';
        if(!all_ok){
            color = '#F8C471';
            text_dec = 'text-decoration:line-through;'
        }
        let lan = navigator.language || navigator.userLanguage;
        lan = lan.toLowerCase();
        let lan_prefix = "";
        if(lan=="zh-cn"){
            lan_prefix = "z";
        }else if(lan=="zh-hk"||lan=="zh-tw"){
            lan_prefix = "t";
        }else{
            lan_prefix = "e";
        }
        let last_hostname = location.hostname;
        let url = config_url.replace("config", lan_prefix+"config")+"?f_key="+orignal_f_key+"&lhn="+last_hostname+"&cltp=1";
        setting_btn.setAttribute("href", url);
        setting_btn.setAttribute("target", "_blank");
        setting_btn.innerHTML = '<div style="position:fixed;top:400px;right:0px;background-color:rgb(244, 234, 194);color:'+color+';'+text_dec+'padding-left:15px;padding-right:15px;padding-top:10px;padding-bottom:10px;font-size:15px;border-radius:5px 0 0 5px;cursor:pointer;z-index:10000;">Add</div>';
        document.body.appendChild(setting_btn);
    }
    function add_keyword_span(keyword, f_key){
        let span_dom = document.createElement('span');
        let span_id = 'span_dom_xt_' + keyword;
        span_dom.style = "background-color:rgb(244, 234, 194);color:rgb(198, 94, 36);font-size:12px;padding:3px 12px 3px 15px;border-radius:3px 3px 3px 3px;margin-right:5px;margin-top:5px;";
        span_dom.innerHTML = keyword+'&nbsp;&nbsp;<span style="color:#666;text-decoration:none;cursor:pointer;" id="'+span_id+'">x</span>';
        document.getElementById('show_filter_keyword').appendChild(span_dom);
        document.getElementById(span_id).addEventListener('click', function(){
            this.parentNode.remove();
            let values = GM_getValue(f_key);
            values.splice(values.indexOf(keyword), 1);
            GM_setValue(f_key, values);
        });
    }
    function show_page(){
        if(is_first){document.body.style.display = 'block';}
    }
})();