禁止访问网页

禁止访问网页列表,做一个自律的人,成为更好的自己。

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name                禁止访问网页
// @name:en             Be A Good Guy | Block Webites
// @name:zh-cn          禁止访问网页
// @description         禁止访问网页列表,做一个自律的人,成为更好的自己。
// @description:en      Block websites, be a disciplined person, and become a better self.
// @description:zh-cn   禁止访问网页列表,做一个自律的人,成为更好的自己。
// @namespace           https://github.com/BasilGuo/
// @license             MIT
// @version             0.1.3
// @author              Basil Guo
// @match               http*://*/*
// @grant               GM_addStyle
// @grant               GM_deleteValue
// @grant               GM_getValue
// @grant               GM_listValues
// @grant               GM_setValue
// @grant               GM_registerMenuCommand
// @icon                https://images2.imgbox.com/01/e3/5as6gVyM_o.png
// @homepageURL         https://gist.github.com/BasilGuo/64c0730f2cdee29d2abf057577b86b39
// @run-at              document-start
// ==/UserScript==

(function () {
    'use strict';

    // Your code here...
    var g_one_rule_window = false;
    const G_LANGUAGE_INDEX = ('en' === navigator.language || 'en' === navigator.userLanguage) ? 0 : 1;

    // https://stackoverflow.com/questions/55935641/how-to-get-language-of-user-navigator-languages-not-working
    // console.log(navigator.language, navigator.userLanguage);
    // console.log(navigator.languages ? navigator.languages[0] : (navigator.language || navigator.userLanguage));

    const G_RULE_PROMPT = {
        'title': {
            'addRule': ["Add A Rule For Current Site", '为本站添加规则'],
            'listRule': ["List Rules of All Sites", '列出所有网站规则'],
            'clearRule': ["Clear All Rules of All Sites", "清空所有网站规则"],
            'customURL': ["Custom the Redirect Webite", "自定义重定向网站"]
        },
        'common': {
            'btnCancelText': [`Cancel`, `取消`],
            'btnOKText': [`OK`, `确认`],
            'btnDeleteText': [`Delete`, `删除`],
            'noRuleText': [`There is no access rules now.`, `当前没有受限访问网站`],
            'alertText': [`There is a rule window opened. Please close it first~`, `已经有一个规则窗口了,请先关闭吧~`],
            'redirectURLText': [`Input the URL you would finally accessed when browsing blocked websites`, `输入访问被禁止网站时,最终重定向到的网址`]
        },
        'add': {
            'titleText': [`Add access time limit rule for<br/>${location.host}`, `给${location.host}<br/>添加访问限制时间规则`],
            'siteURLText': [`Set the site path. Default is the current hostname so you could let it alone. Not support for wildcards now.`, `设置本网站屏蔽规则,暂不支持通配符,默认为当前网站域名,非必填项`],
            'limitDayLongText': [`Limit for all day`, `全天限制`],
            'limitStartTimeText': [`Limit start time: `, `限制开始时间`],
            'limitEndTimeText': [`Limit  end  time: `, `限制结束时间`],
            'failedTimeText': [`Add rule failed for limit start time should be less than end time`, `添加规则失败:限制开始时间应该先于限制结束时间`],
            'failedHostText': [`Add rule failed because URL of current site is wrong, please correct it.<br/>Take the following www.example.com/path/subpath as an example. No protocols is needed.`, `添加规则失败:网站URL规则设置错误,参考例子不带协议`],
            'successText': [`Add rule success, effect after refress site.`, `规则添加成功,刷新页面以生效规则`]
        },
        'list': {
            'titleText': [`Limit access rules for all websites`, `当前所有网站限制访问规则`],
            'ruleHostText': [`Limit Website`, `限制网站`],
            'ruleTimeStartText': [`Limit Start Time`, `限制开始时间`],
            'ruleTimeEndText': [`Limit End Time`, `限制结束时间`],
            'deleteActionText': [`Actions`, `操作`],
            'deleteRuleConfirmText1': [`Are you sure to delete?`, `真的要删除限制规则吗?`],
            'deleteRuleConfirmText2': [`Buddy, being the best self?`, `你不打算成为更好的自己了吗?`],
            'deleteRuleConfirmText3': [`OK, the last time to confirm.`, `好吧,最后一次确认了。`],
            'deleteRuleCancelText': [`OK, I have known you are the best.`, `我就知道你是最棒的!`],
        }
    };

    function cancelRuleWindow() {
        let rule_window = document.getElementById('bs-rule');
        rule_window.parentNode.removeChild(rule_window);
        g_one_rule_window = false;
    }

    function addRuleLimitTimeDaylongOnChange() {
        let limit_time_daylong_cbx = document.getElementById('rule-time-day-long');
        let limit_time_start_input = document.getElementById('rule-time-start');
        let limit_time_end_input = document.getElementById('rule-time-end');

        if (limit_time_daylong_cbx.checked) {
            limit_time_start_input.disabled = "disabled";
            limit_time_end_input.disabled = "disabled";
        }
        else {
            limit_time_start_input.disabled = "";
            limit_time_end_input.disabled = "";
        }
    }

    function addRuleOKButtonClick() {
        let time_arr, hour, minute;
        let limit_start_secs, limit_end_secs;
        let limit_time_daylong_cbx = document.getElementById('rule-time-day-long');
        let limit_time_start = document.getElementById('rule-time-start').value;
        let limit_time_end = document.getElementById('rule-time-end').value;
        let rule_url_input = document.getElementById('rule-url');

        if (limit_time_daylong_cbx.checked) {
            limit_time_start = '00:00';
            limit_time_end = '23:59';
        }

        time_arr = limit_time_start.split(':');
        hour = time_arr[0];
        minute = time_arr[1];
        limit_start_secs = hour * 3600 + minute * 60;
        time_arr = limit_time_end.split(':');
        hour = time_arr[0];
        minute = time_arr[1];
        limit_end_secs = hour * 3600 + minute * 60;

        if (limit_start_secs > limit_end_secs) {
            alert(G_RULE_PROMPT.add.failedTimeText[G_LANGUAGE_INDEX]);
            return;
        } else {
            let rule_url = rule_url_input.value;
            let all_hosts = GM_getValue('BlockWebsitesRules');
            let all_hosts_set;

            if (rule_url === '') {
                rule_url = document.location.host;
            } else if (rule_url.indexOf("://") !== -1) {
                rule_url = rule_url.split("://")[1];
            }
            rule_url = rule_url.replace(/\/$/g, ''); // remove the last '/'

            if (all_hosts === undefined || all_hosts === '') {
                all_hosts_set = new Set();
            } else {
                all_hosts_set = new Set(JSON.parse(all_hosts)['BlockWebsitesRules'].split(' '));
            }

            if (document.location.href.indexOf(rule_url) === -1 || rule_url.indexOf(document.location.host) === -1) {
                alert(G_RULE_PROMPT.add.failedHostText[G_LANGUAGE_INDEX]);
                return;
            }

            console.log("all_hosts: ", all_hosts);
            all_hosts_set.add(rule_url);
            all_hosts = { 'BlockWebsitesRules': Array.from(all_hosts_set).join(' ') };
            console.log('BlockWebsitesRules: ', all_hosts);
            GM_setValue(rule_url, JSON.stringify({ 'start': limit_start_secs, 'end': limit_end_secs }));
            GM_setValue("BlockWebsitesRules", JSON.stringify(all_hosts));
            cancelRuleWindow();
            alert(G_RULE_PROMPT.add.successText[G_LANGUAGE_INDEX]);
            location.reload();
        }
    }

    function addRuleActions() {
        let limit_time_daylong_cbx = document.getElementById('rule-time-day-long');
        let ok_add_btn = document.getElementById("ok-add-btn");
        let cancel_add_btn = document.getElementById("cancel-add-btn");

        limit_time_daylong_cbx.onchange = addRuleLimitTimeDaylongOnChange;
        ok_add_btn.onclick = addRuleOKButtonClick;
        cancel_add_btn.onclick = cancelRuleWindow;
        g_one_rule_window = true;
    }

    function addRuleWindow() {
        let add_rule_div = `<div class="bs-rule-content" id="bs-rule">
            <div class="bs-rule-header" id="bs-rule-header">
              <!-- <span class="close">×</span> -->
              <h2>${G_RULE_PROMPT.add.titleText[G_LANGUAGE_INDEX]}</h2>
            </div>
            <div class="bs-rule-body" id="bs-rule-body">
              <form>
                <label for="rule-time-day-long">${G_RULE_PROMPT.add.limitDayLongText[G_LANGUAGE_INDEX]}</label>
                <input type="checkbox" id="rule-time-day-long" name="ruleTimeDayLong" />
                <hr/>
                <label for="rule-time-start">${G_RULE_PROMPT.add.limitStartTimeText[G_LANGUAGE_INDEX]}</label>
                <input id="rule-time-start" type="time" name="limitTimeStart", value="00:00" pattern="[0-9]{2}:[0-9]{2}" required />
                <br/>
                <label for="rule-time-end">${G_RULE_PROMPT.add.limitEndTimeText[G_LANGUAGE_INDEX]}</label>
                <input id="rule-time-end" type="time" name="limitTimeEnd", value="18:00" pattern="[0-9]{2}:[0-9]{2}" required />
                <hr/>
                <label for="rule-url">${G_RULE_PROMPT.add.siteURLText[G_LANGUAGE_INDEX]}</label>
                <br/>
                <input type="text" id="rule-url" name="ruleURL" placeholder="www.example.com/path/subpath" style="width:68%" />
              </form>
            </div>
            <div class="bs-rule-footer" id="bs-rule-footer">
              <button id="cancel-add-btn" class="bs-btn bs-cancel-btn">${G_RULE_PROMPT.common.btnCancelText[G_LANGUAGE_INDEX]}</button>
              <button id="ok-add-btn" class="bs-btn bs-ok-btn">${G_RULE_PROMPT.common.btnOKText[G_LANGUAGE_INDEX]}</button>
            </div>
        </div>`
        let body = document.getElementsByTagName("body")[0];
        let rule_div = document.createElement("div");
        rule_div.setAttribute("id", "bs-rule");
        rule_div.setAttribute("class", "bs-rule");
        rule_div.innerHTML = add_rule_div;
        body.prepend(rule_div);
        g_one_rule_window = true;
    }

    function addRule(event) {
        if (g_one_rule_window) {
            alert(G_RULE_PROMPT.common.alertText[G_LANGUAGE_INDEX]);
            return;
        }

        addRuleWindow();
        addRuleActions();
    }

    function listRuleWindow() {
        let list_rule_div = `<div class="bs-rule-content" id="bs-rule">
            <div class="bs-rule-header" id="bs-rule-header">
              <!-- <span class="close">×</span> -->
              <h2>${G_RULE_PROMPT.list.titleText[G_LANGUAGE_INDEX]}</h2>
            </div>
            <div class="bs-rule-body" id="bs-rule-body">
                <table id="bs-rule-list-tbl">
                <thead>
                  <tr>
                    <td>${G_RULE_PROMPT.list.ruleHostText[G_LANGUAGE_INDEX]}</td>
                    <td>${G_RULE_PROMPT.list.ruleTimeStartText[G_LANGUAGE_INDEX]}</td>
                    <td>${G_RULE_PROMPT.list.ruleTimeEndText[G_LANGUAGE_INDEX]}</td>
                    <td>${G_RULE_PROMPT.list.deleteActionText[G_LANGUAGE_INDEX]}</td>
                  </tr>
                </thead>
                <tbody id="bs-rule-list-tbl-body">
                </tbody>
                </table>
            </div>
            <div class="bs-rule-footer" id="bs-rule-footer">
              <button id="cancel-add-btn" class="bs-btn bs-cancel-btn">${G_RULE_PROMPT.common.btnCancelText[G_LANGUAGE_INDEX]}</button>
            </div>
        </div>`
        let body = document.getElementsByTagName("body")[0];
        let rule_div = document.createElement("div");
        rule_div.setAttribute("id", "bs-rule");
        rule_div.setAttribute("class", "bs-rule");
        rule_div.innerHTML = list_rule_div;
        body.prepend(rule_div);
        g_one_rule_window = true;
    }

    function listRuleActions() {
        let cancel_btn = document.getElementById("cancel-add-btn");
        let bs_rule_window = document.getElementById('bs-rule');

        cancel_btn.onclick = cancelRuleWindow;
        window.onclick = function (event) {
            if (event.target === bs_rule_window) {
                cancelRuleWindow();
            }
        }
    }

    function deleteRuleConfirm(msg) {
        if (msg && msg.length != 0) {
            msg = "\n" + msg;
        } else {
            msg = '';
        }
        let rs = confirm(G_RULE_PROMPT.list.deleteRuleConfirmText1[G_LANGUAGE_INDEX] + msg);
        if (!rs) {
            alert(G_RULE_PROMPT.list.deleteRuleCancelText[G_LANGUAGE_INDEX]);
        } else {
            rs = confirm(G_RULE_PROMPT.list.deleteRuleConfirmText2[G_LANGUAGE_INDEX] + msg);
            if (!rs) {
                alert(G_RULE_PROMPT.list.deleteRuleCancelText[G_LANGUAGE_INDEX]);
            } else {
                rs = confirm(G_RULE_PROMPT.list.deleteRuleConfirmText3[G_LANGUAGE_INDEX] + msg);
                if (!rs) {
                    alert(G_RULE_PROMPT.list.deleteRuleCancelText[G_LANGUAGE_INDEX]);
                }
            }
        }
        return rs;
    }

    function deleteRule() {
        let mrs = JSON.parse(GM_getValue(this.name));
        let msg = this.name + " : ";
        msg = msg + parseInt(mrs['start'] / 3600).toFixed(0).padStart(2, '0') + ":" + parseInt(mrs['start'] % 3600 / 60).toFixed(0).padStart(2, '0');
        msg += '-';
        msg = msg + parseInt(mrs['end'] / 3600).toFixed(0).padStart(2, '0') + ":" + parseInt(mrs['end'] % 3600 / 60).toFixed(0).padStart(2, '0');
        let rs = deleteRuleConfirm(msg);

        if (!rs) return;

        let all_hosts = GM_getValue('BlockWebsitesRules');
        let all_hosts_set;

        if (all_hosts === undefined || all_hosts === '') {
            all_hosts_set = new Set();
        } else {
            all_hosts_set = new Set(JSON.parse(all_hosts)['BlockWebsitesRules'].split(' '));
        }

        console.log("all_hosts: ", all_hosts);
        all_hosts_set.delete(this.name);
        all_hosts = { 'BlockWebsitesRules': Array.from(all_hosts_set).join(' ') };
        console.log('BlockWebsitesRules: ', all_hosts);
        GM_deleteValue(this.name);
        GM_setValue("BlockWebsitesRules", JSON.stringify(all_hosts));
        cancelRuleWindow();
        listRuleFillTable();
    }

    function listRuleFillTable() {
        let blockedSites = JSON.parse(GM_getValue('BlockWebsitesRules'));
        blockedSites = blockedSites['BlockWebsitesRules'].split(' ');
        let rule_tbl_body = document.getElementById("bs-rule-list-tbl-body");
        let is_no_rule = true;

        for (let blocked_site of blockedSites) {
            let site = GM_getValue(blocked_site);
            if (site !== undefined) {
                is_no_rule = false;
                let mrs = JSON.parse(site);
                let tr = document.createElement("tr");
                tr.innerHTML = `<td>${blocked_site}</td>
                <td>${parseInt(mrs['start'] / 3600).toFixed(0).padStart(2, '0')}:${parseInt(mrs['start'] % 3600 / 60).toFixed(0).padStart(2, '0')}</td>
                <td>${parseInt(mrs['end'] / 3600).toFixed(0).padStart(2, '0')}:${parseInt(mrs['end'] % 3600 / 60).toFixed(0).padStart(2, '0')}</td>
                <td><button name="${blocked_site}" class="bs-btn bs-delete-btn">${G_RULE_PROMPT.common.btnDeleteText[G_LANGUAGE_INDEX]}</button></td>`
                rule_tbl_body.append(tr);
            }
        }

        if (is_no_rule) {
            let bs_rule_body = document.getElementById("bs-rule-body");
            let no_rule_txt = document.createElement('h2');
            no_rule_txt.innerHTML = G_RULE_PROMPT.common.noRuleText[G_LANGUAGE_INDEX];
            bs_rule_body.append(no_rule_txt);
        } else {
            let del_btns = document.getElementsByClassName("bs-delete-btn");
            for (let i = 0; i < del_btns.length; ++i) {
                del_btns[i].onclick = deleteRule;
            }
        }
    }

    function listRule(event) {
        if (g_one_rule_window) {
            alert(G_RULE_PROMPT.common.alertText[G_LANGUAGE_INDEX]);
            return;
        }

        listRuleWindow();
        listRuleActions();
        listRuleFillTable();
    }

    function clearRule() {
        let rs = deleteRuleConfirm();
        if (!rs) { return; }

        let all_hosts = GM_getValue('BlockWebsitesRules');
        let all_hosts_set;

        if (all_hosts === undefined || all_hosts === '') {
            all_hosts_set = new Set();
        } else {
            all_hosts_set = new Set(JSON.parse(all_hosts)['BlockWebsitesRules'].split(' '));
        }

        console.log("all_hosts_set", all_hosts_set);

        for (let site of all_hosts_set) {
            console.log(site);
            GM_deleteValue(site);
        }

        all_hosts = { 'BlockWebsitesRules': '' };
        console.log('BlockWebsitesRules: ', all_hosts);
        GM_setValue("BlockWebsitesRules", JSON.stringify(all_hosts));
    }

    function customURL() {
        let url = prompt(G_RULE_PROMPT.common.redirectURLText[G_LANGUAGE_INDEX], "https://www.example.org/");
        GM_setValue("BlockWebsiteRedirectURL", url);
    }

    function setup() {
        let css = `#bs-rule-body>input,.bs-rule{width:100%}.bs-rule{display:block;position:fixed;max-width:unset;z-index:99999;padding-top:100px;left:0;top:0;height:100%;overflow:auto;background-color:rgba(0,0,0,.4)}.bs-rule-content{position:relative;background-color:#fefefe;margin:auto;padding:0;border:1px solid #888;width:35%;box-shadow:0 4px 8px 0 rgba(0,0,0,.2),0 6px 20px 0 rgba(0,0,0,.19);-webkit-animation-name:bs-rule-animatetop;-webkit-animation-duration:.4s;animation-name:bs-rule-animatetop;animation-duration:.4s}.bs-rule-body,.bs-rule-footer,.bs-rule-header{padding:2px 16px}.bs-rule-footer,.bs-rule-header{background-color:#5587a2;color:#fff}@-webkit-keyframes bs-rule-animatetop{from{top:-300px;opacity:0}to{top:0;opacity:1}}@keyframes bs-rule-animatetop{from{top:-300px;opacity:0}to{top:0;opacity:1}}.bs-close{color:#fff;float:right;font-size:28px;font-weight:700}.bs-close:focus,.bs-close:hover{color:#000;text-decoration:none;cursor:pointer}.bs-rule-body{min-height:20%;max-height:100%;min-width:20%;max-width:100%;overflow-x:auto;overflow-y:auto}.bs-rule-footer{text-align:right}.bs-btn{color:#000;border:none;border-radius:5px;font-size:1.2em}.bs-btn:focus,.bs-btn:hover{cursor:pointer;box-shadow:1px 1px 1px rgba(0,0,0,.5);-moz-box-shadow:1px 1px .5em rgba(0,0,0,.5);-webkit-box-shadow:1px 1px .5em rgba(0,0,0,.5);background-color:#5587a2}.bs-ok-btn{background-color:#888}.bs-cancel-btn{background-color:#afafaf}.bs-delete-btn{border-color:none;font-size:1em;background-color:#e5624a}#bs-rule-body>table{border-collapse:collapse}#bs-rule-body>table>thead{background-color:#333;color:#fff;font-size:.875rem;text-transform:title;letter-spacing:2%}#bs-rule-body>table>td,#bs-rule-body>table>tr{border:1px solid #000;color:#000;text-align:left}`;
        GM_addStyle(css);

        let url = GM_getValue("BlockWebsiteRedirectURL");
        if (url === undefined || url === '') {
            GM_setValue("BlockWebsiteRedirectURL", 'chrome-extension://invalid');
        }

    }

    function register_menu() {
        GM_registerMenuCommand(G_RULE_PROMPT.title.addRule[G_LANGUAGE_INDEX], addRule, "a");
        GM_registerMenuCommand(G_RULE_PROMPT.title.listRule[G_LANGUAGE_INDEX], listRule, "l");
        GM_registerMenuCommand(G_RULE_PROMPT.title.clearRule[G_LANGUAGE_INDEX], clearRule, "c");
        GM_registerMenuCommand(G_RULE_PROMPT.title.customURL[G_LANGUAGE_INDEX], customURL, "s");
    }

    function locationReplace(url) {
        console.log(url);
        // location.href = url;
        // location.assign(url);
        location.replace(url);
    }

    function check_to_block() {
        let datetime = new Date();
        let hours = datetime.getHours();
        let minutes = datetime.getMinutes();
        let seconds = hours * 3600 + minutes * 60;
        let paths = document.location.href.split("://")[1].split("/");
        let path = document.location.host;
        let i = 1;

        do {
            let rs = GM_getValue(path);

            if (rs !== undefined) {
                let trs = JSON.parse(rs); // time rs
                if (trs['start'] <= seconds && seconds <= trs['end']) {
                    let url = GM_getValue("BlockWebsiteRedirectURL");
                    locationReplace(url);
                }
            }
            if (i < paths.length) {
                path = path + "/" + paths[i];
            }
        } while (i++ < paths.length)
    }

    function deleteKeysWithConfirm() {
        let keys = GM_listValues();
        console.log(keys);
        for (let i = 0; i < keys.length; ++i) {
            let v = keys[i];
            let rs = confirm("Delete?" + v + ": " + GM_getValue(v));
            if (rs) {
                GM_deleteValue(v);
            }
        }
        console.log(GM_listValues());
    }

    function main() {
        // deleteKeysWithConfirm();
        setup();
        register_menu();
        check_to_block();
    }

    main();
})();