blockunsafe

Block unsafe(uncomfortable) content on web pages by keywords

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==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';}
    }
})();