Greasy Fork

Greasy Fork is available in English.

巴哈姆特黑名單、關鍵字過濾文章留言

在巴哈姆將黑名單、關鍵字過濾文章留言,在頂端列可以開關過濾器(一次性)

当前为 2018-04-26 提交的版本,查看 最新版本

// ==UserScript==
// @name         巴哈姆特黑名單、關鍵字過濾文章留言
// @namespace    https://home.gamer.com.tw/moontai0724
// @version      2.3.2
// @description  在巴哈姆將黑名單、關鍵字過濾文章留言,在頂端列可以開關過濾器(一次性)
// @author       moontai0724
// @match        https://forum.gamer.com.tw/B.php*
// @match        https://forum.gamer.com.tw/Bo.php*
// @match        https://forum.gamer.com.tw/C.php*
// @match        https://forum.gamer.com.tw/Co.php*
// @match        https://forum.gamer.com.tw/search.php*
// @grant        GM_xmlhttpRequest
// @connect      home.gamer.com.tw
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
// @supportURL   https://home.gamer.com.tw/moontai0724
// ==/UserScript==

(function () {
    'use strict';
    if (!localStorage.getItem("BLH_Setting")) localStorage.setItem("BLH_Setting", JSON.stringify({
        switch: {
            keywordPostFliter: true,
            keywordCommentFliter: true,
            blacklistPostFliter: true,
            blacklistCommentFliter: true,
            contentLengthPostFliter: false,
            contentLengthCommentFliter: false,
        },
        lengthLimit: {
            contentLengthPostLimit: 2,
            contentLengthCommentLimit: 2
        },
        data: {
            forceShowList: [],
            forceHideList: [],
            blockKeywords: [],
            postBlockKeywords: [],
            commentBlockKeywords: []
        }
    }));
    var setting = JSON.parse(localStorage.getItem("BLH_Setting"));

    // 加入隱藏切換
    jQuery('head').append('<style type="text/css" id="BLH_BlockHideCSS">.BlockHide { display: none !important; }</style>');
    jQuery('.BH-menuE').append('<li><a id="BLH_ShowBlock" href="javascript:;" style="display: block;" onclick="BlockDisplay(true);">關閉過濾器</a></li>');
    jQuery('.BH-menuE').append('<li><a id="BLH_HideBlock" href="javascript:;" style="display: none;" onclick="BlockDisplay(false);">開啟過濾器</a></li>');
    jQuery('.BH-menuE').append('<li><a id="BLH_FliterSetting" href="javascript:;" style="display: block;">過濾器設定</a></li>');
    jQuery('body').append('<script type="text/javascript">' + function BlockDisplay(status) {
        document.getElementById('BLH_HideBlock').style.display = status ? 'block' : 'none';
        document.getElementById('BLH_ShowBlock').style.display = status ? 'none' : 'block';
        status ? document.getElementById('BLH_BlockHideCSS').innerHTML = document.getElementById('BLH_BlockHideCSS').innerHTML.replace('BlockHide', 'noBlockHide') : document.getElementById('BLH_BlockHideCSS').innerHTML = document.getElementById('BLH_BlockHideCSS').innerHTML.replace('noBlockHide', 'BlockHide');
    } + '</script>');
    document.getElementById('BLH_FliterSetting').onclick = () => openSettingWindow();

    // 將 blockKeywords 加入 postBlockKeywords 和 commentBlockKeywords 中
    for (let i = 0; i < setting.data.blockKeywords.length; i++) setting.data.postBlockKeywords[setting.data.postBlockKeywords.length] = setting.data.commentBlockKeywords[setting.data.commentBlockKeywords.length] = setting.data.blockKeywords[i];
    setting.data.postBlockKeywords = setting.data.postBlockKeywords.map(value => value.toLowerCase());
    setting.data.commentBlockKeywords = setting.data.commentBlockKeywords.map(value => value.toLowerCase());

    //BC頁分開
    switch (location.pathname) {
        case '/B.php':
            console.group('Fliter log message');
            setTimeout(() => console.groupEnd(), 250);
            // blacklist post fliter
            setting.switch.blacklistPostFliter ? getBlackList().then(BlackList => jQuery('.b-list__count__user>a').each((index, value) => BlackList.includes(value.innerText.toLowerCase()) ? (jQuery(value).parents('.b-list__row').addClass('BlockHide'), console.log('Hid a post with block user: ' + value.innerText.toLowerCase(), jQuery(value).parents('.b-list__row'))) : void (0))) : void (0);
            // keywords post title fliter
            setting.switch.keywordPostFliter ? jQuery('.b-list__main__title').each((index, value) => setting.data.postBlockKeywords.forEach(data => value.innerText.toLowerCase().includes(data) ? (jQuery(value).parents('.b-list__row').addClass('BlockHide'), console.log('Hid a post includes keyword: ' + data, jQuery(value).parents('.b-list__row'))) : void (0))) : void (0);
            break;
        case '/C.php': case '/Co.php':
            console.group('Fliter log message');
            setTimeout(() => console.groupEnd(), 250);
            // 擷取展開按鈕事件:當展開留言按鈕被點擊,執行原生展開留言指令並處理內容
            jQuery('body').append('<button id="extendCommentListener" style="display: none;"></button>');
            jQuery('.more-reply').each((index, element) => element.setAttribute("onclick", element.getAttribute("onclick") + " [document.getElementById('extendCommentListener').dataset.bsn, document.getElementById('extendCommentListener').dataset.postid] = [" + element.getAttribute('onclick').replace('extendComment(', '').replace(');', '').split(', ') + "]; jQuery('#Commendlist_" + element.getAttribute('onclick').replace('extendComment(', '').replace(');', '').split(', ')[1] + "').append('<div id=\"extendCommentAreaListener\"></div>'); document.getElementById('extendCommentListener').click();"));
            // 當按鈕點擊就執行
            document.getElementById('extendCommentListener').onclick = function () {
                let [bsn, postid] = [document.getElementById('extendCommentListener').dataset.bsn, document.getElementById('extendCommentListener').dataset.postid], times = 0, ms = 0;
                setTimeout(function restartFliter(ms) {
                    setTimeout(function () {
                        if (!document.getElementById('extendCommentAreaListener')) {
                            jQuery('#Commendlist_' + postid).each((index, element) => {
                                setting.switch.blacklistCommentFliter ? getBlackList().then(BlackList => jQuery(element).find('.reply-content__user').each((index, value) => BlackList.includes(value.href.replace('https://home.gamer.com.tw/', '').toLowerCase()) ? (jQuery(value).parents('.c-reply__item').addClass('BlockHide'), console.log('Hid a comment with block user: ' + value.innerText.toLowerCase(), jQuery(value).parents('.c-reply__item'))) : void (0))) : void (0);
                                setting.switch.keywordCommentFliter ? jQuery(element).find('.reply-content__article').each((index, value) => setting.data.commentBlockKeywords.forEach(data => value.innerText.toLowerCase().includes(data) ? (jQuery(value).parents('.c-reply__item').addClass('BlockHide'), console.log('Hid a post includes keyword: ' + data, jQuery(value).parents('.c-reply__item'))) : void (0))) : void (0);
                                if (setting.switch.contentLengthCommentFliter) {
                                    jQuery(element).find('.reply-content__article').each((index, value) => {
                                        let data = value.innerText.replace(/\s/g, '').length;
                                        if (data < setting.lengthLimit.contentLengthCommentLimit) {
                                            jQuery(value).parents('.c-reply__item').addClass('BlockHide');
                                            console.log('Hid a comment less then setting text totalLength limit: ' + setting.lengthLimit.contentLengthCommentLimit, data, jQuery(value).parents('.c-reply__item'));
                                        }
                                    });
                                }
                            });
                        } else if (times++ < 50) restartFliter(100);
                    }, ms);
                });
            };

            // blacklist post fliter
            setting.switch.blacklistPostFliter ? getBlackList().then(BlackList => jQuery('.c-post__header__author>.userid').each((index, value) => BlackList.includes(value.innerText.toLowerCase()) ? (jQuery(value).parents('.c-section').addClass('BlockHide'), console.log('Hid a post with block user: ' + value.innerText.toLowerCase(), jQuery(value).parents('.c-section'))) : void (0))) : void (0);
            // blacklist comment fliter
            setting.switch.blacklistCommentFliter ? getBlackList().then(BlackList => jQuery('.reply-content__user').each((index, value) => BlackList.includes(value.href.replace('https://home.gamer.com.tw/', '').toLowerCase()) ? (jQuery(value).parents('.c-reply__item').addClass('BlockHide'), console.log('Hid a comment with block user: ' + value.innerText.toLowerCase(), jQuery(value).parents('.c-reply__item'))) : void (0))) : void (0);
            // keywords post fliter
            setting.switch.keywordPostFliter ? jQuery('.c-article__content').each((index, value) => setting.data.postBlockKeywords.forEach(data => value.innerText.toLowerCase().includes(data) ? (jQuery(value).parents('.c-section').addClass('BlockHide'), console.log('Hid a post includes keyword: ' + data, jQuery(value).parents('.c-section'))) : void (0))) : void (0);
            // keywords comment fliter
            setting.switch.keywordCommentFliter ? jQuery('.reply-content__article').each((index, value) => setting.data.commentBlockKeywords.forEach(data => value.innerText.toLowerCase().includes(data) ? (jQuery(value).parents('.c-reply__item').addClass('BlockHide'), console.log('Hid a comment includes keyword: ' + data, jQuery(value).parents('.c-reply__item'))) : void (0))) : void (0);
            // post content length fliter
            if (setting.switch.contentLengthPostFliter) {
                jQuery('.c-article__content').each((index, value) => {
                    let data = value.innerText.replace(/\s/g, '').length;
                    if (data < setting.lengthLimit.contentLengthPostLimit) {
                        jQuery(value).parents('.c-section').addClass('BlockHide');
                        console.log('Hid a post less then setting text totalLength limit: ' + setting.lengthLimit.contentLengthPostLimit, data, jQuery(value).parents('.c-section'));
                    }
                });
            }
            // comment content length fliter
            if (setting.switch.contentLengthCommentFliter) {
                jQuery('.reply-content__article').each((index, value) => {
                    let data = value.innerText.replace(/\s/g, '').length;
                    if (data < setting.lengthLimit.contentLengthCommentLimit) {
                        jQuery(value).parents('.c-reply__item').addClass('BlockHide');
                        console.log('Hid a comment less then setting text totalLength limit: ' + setting.lengthLimit.contentLengthCommentLimit, data, jQuery(value).parents('.c-reply__item'));
                    }
                });
            }
            break;
        case '/Bo.php':
            console.group('Fliter log message');
            setTimeout(() => console.groupEnd(), 250);
            setting.switch.blacklistPostFliter ? getBlackList().then(BlackList => jQuery('.FM-blist6>a[href*="home.gamer.com.tw"]').each((index, value) => BlackList.includes(value.innerText.toLowerCase()) ? (jQuery(value).parents('tr').addClass('BlockHide'), console.log('Hid a post with block user: ' + value.innerText.toLowerCase(), jQuery(value).parents('tr'))) : void (0))) : void (0);
            setting.switch.keywordPostFliter ? jQuery('.FM-blist3').each((index, value) => setting.data.postBlockKeywords.forEach(data => value.innerText.toLowerCase().includes(data) ? (jQuery(value).parents('tr').addClass('BlockHide'), console.log('Hid a comment includes keyword: ' + data, jQuery(value).parents('tr'))) : void (0))) : void (0);
            break;
        case '/search.php':
            setTimeout(function restartFliter(ms) {
                setTimeout(() => jQuery('.gsc-table-cell-snippet-close').length > 0 ? (console.group('Fliter log message'), setTimeout(() => console.groupEnd(), 100), setting.switch.keywordPostFliter ? jQuery('.gsc-table-cell-snippet-close').each((index, value) => setting.data.postBlockKeywords.forEach(data => value.innerText.toLowerCase().includes(data) ? (jQuery(value).parents('.gsc-result').addClass('BlockHide'), console.log('Hid a comment includes keyword: ' + data, jQuery(value).parents('.gsc-result'))) : void (0))) : void (0)) : restartFliter(100), ms);
            });
            break;
    }

    function BlackListHandle(BlackList) {
        let removeNum = [];
        setting.data.forceHideList.forEach(value => BlackList.includes(value.replace(/\s/g, '').toLowerCase()) ? void (0) : BlackList[BlackList.length] = value.replace(/\s/g, '').toLowerCase());
        BlackList.forEach((value, index) => setting.data.forceShowList.includes(value.toLowerCase()) ? removeNum[removeNum.length] = index : void (0));
        for (let i = removeNum.length - 1; i >= 0; i--) BlackList.splice(removeNum[i], 1);
        localStorage.setItem('BHBlackList', JSON.stringify({ time: new Date().getTime(), BlackList: BlackList }));
        console.log('Blacklist handle process over, returned blacklist: ', BlackList);
        return BlackList;
    }

    function getBlackList(forceReload) {
        return new Promise(resolve => {
            if (localStorage.getItem('BHBlackList') && !forceReload) {
                let BHBlackList = JSON.parse(localStorage.getItem('BHBlackList')), today = new Date((new Date()).getFullYear(), (new Date()).getMonth(), (new Date()).getDate(), 0, 0, 0, 0);
                today.getTime() < BHBlackList.time && BHBlackList.time < today.getTime() + 86400000 ? (console.log('Already requested blacklist today, resolve.'), resolve(BlackListHandle(BHBlackList.BlackList))) : (console.log('Today not requested blacklist yet, start request.'), getBlackList(true).then(data => resolve(BlackListHandle(data))));
            } else GM_xmlhttpRequest({
                method: "GET",
                url: "https://home.gamer.com.tw/ajax/friend_getData.php?here=0",
                onload: data => (console.log('Get blacklist data from Bahamut server.'), resolve(BlackListHandle(data.response.includes('<div id="BMW_nlist" style="display:none;">') ? data.response.split('<div id="BMW_nlist" style="display:none;">')[1].replace('</div>', '').split(',') : [])))
            });
        });
    }

    function openSettingWindow() {
        // black background
        let BLH_SW_Background = document.createElement("div");
        BLH_SW_Background.id = "BLH_SW_Background";
        BLH_SW_Background.setAttribute("onmousedown", "javascript:if(!jQuery(this).hasClass('mouseenter')) jQuery('#BLH_SW_Background').remove();");
        BLH_SW_Background.style = "background-color: rgba(0, 0, 0, 0.5); z-index: 95; position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px; width: 100%; height: 100%; padding-top: 35px;" +
            " border: 1px solid #a7c7c8;" +
            " display: flex; align-items: center; justify-content: center;" +
            " -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;";
        document.body.appendChild(BLH_SW_Background);

        // window case
        let BLH_SW_Case = document.createElement("div");
        BLH_SW_Case.id = "BLH_SW_Case";
        BLH_SW_Case.setAttribute("onmouseenter", "javascipt:jQuery('#BLH_SW_Background').addClass('mouseenter');");
        BLH_SW_Case.setAttribute("onmouseleave", "javascipt:jQuery('#BLH_SW_Background').removeClass('mouseenter');");
        BLH_SW_Case.style = "position: absolute; height: 80%; width: 90%; overflow: hidden;" +
            " display: flex; align-item: stretch; flex-direction: column;" +
            " background-color: #FFFFFF; border: 1px solid #a7c7c8;";
        document.getElementById("BLH_SW_Background").appendChild(BLH_SW_Case);

        // title
        let BLH_SW_Title = document.createElement("div");
        BLH_SW_Title.setAttribute("style", "display: flex; align-items: center; justify-content: center; width: 100%; min-height: 35px;" +
            " background-color: #E5F7F8; color: #484b4b;" +
            " font-size: 22px; font-weight: bold; font-family: '微軟正黑體', 'Microsoft JhengHei', '黑體-繁', '蘋果儷中黑', 'sans-serif';");
        BLH_SW_Title.innerHTML = "過濾器設定";
        document.getElementById("BLH_SW_Case").appendChild(BLH_SW_Title);

        // content
        let BLH_SW_Content = document.createElement("div");
        BLH_SW_Content.id = "BLH_SW_Content";
        BLH_SW_Content.setAttribute("style", "display: flex; align-items: center; justify-content: center; flex-flow: row wrap; flex-grow: 1; overflow: auto; padding: 10px;" +
            " background-color: #FFFFFF;" +
            " word-break: break-all; font-size: 16px; line-height: 150%; text-align: center; font-family: 微軟正黑體, Microsoft JhengHei, 黑體-繁, 蘋果儷中黑, sans-serif;" +
            " -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;");
        document.getElementById("BLH_SW_Case").appendChild(BLH_SW_Content);

        // bottom element
        let BLH_SW_BottomArea = document.createElement("div");
        BLH_SW_BottomArea.id = "BLH_SW_BottomArea";
        BLH_SW_BottomArea.style = "display: flex; align-items: center; justify-content: center;" +
            " background-color: #E5F7F8;" +
            " width: 100%; min-height: 35px;";
        document.getElementById('BLH_SW_Case').appendChild(BLH_SW_BottomArea);

        // close button
        let BLH_SW_CloseButton = document.createElement('button');
        BLH_SW_CloseButton.innerHTML = '完成';
        BLH_SW_CloseButton.setAttribute("onclick", "jQuery('#BLH_SW_Background').remove();");
        document.getElementById('BLH_SW_BottomArea').appendChild(BLH_SW_CloseButton);

        // content
        jQuery('#BLH_SW_Content').append(`
<div style="padding: 10px; border: 1px solid; border-radius: 10px; margin: 10px; background: antiquewhite;">
    切換
    <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; background: beige;">
            黑名單過濾
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                黑名單文章過濾:
                <span id="blacklistPostFliter"></span>
                <button style="margin: 5px;" onclick="BLH_switch('blacklistPostFliter');">切換</button>
            </div>
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                黑名單留言過濾:
                <span id="blacklistCommentFliter"></span>
                <button style="margin: 5px;" onclick="BLH_switch('blacklistCommentFliter');">切換</button>
            </div>
        </div>
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; background: beige;">
            關鍵字過濾
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                關鍵字文章過濾:
                <span id="keywordPostFliter"></span>
                <button style="margin: 5px;" onclick="BLH_switch('keywordPostFliter');">切換</button>
            </div>
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                關鍵字留言過濾:
                <span id="keywordCommentFliter"></span>
                <button style="margin: 5px;" onclick="BLH_switch('keywordCommentFliter');">切換</button>
            </div>
        </div>
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; background: beige;">
            字數過濾
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                文章字數過濾:
                <span id="contentLengthPostFliter"></span>
                <button style="margin: 5px;" onclick="BLH_switch('contentLengthPostFliter');">切換</button>
            </div>
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                留言字數過濾:
                <span id="contentLengthCommentFliter"></span>
                <button style="margin: 5px;" onclick="BLH_switch('contentLengthCommentFliter');">切換</button>
            </div>
        </div>
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; background: beige;">
            字數過濾
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                文章字數下限:
                <span id="contentLengthPostLimit"></span>
                <button style="margin: 5px;" onclick="BLH_lengthLimit('contentLengthPostLimit');">變更</button>
            </div>
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                留言字數下限:
                <span id="contentLengthCommentLimit"></span>
                <button style="margin: 5px;" onclick="BLH_lengthLimit('contentLengthCommentLimit');">變更</button>
            </div>
        </div>
    </div>
</div>
<div style="width: 100%; margin: 10px; padding: 10px; border: 1px solid; border-radius: 10px; background: antiquewhite;">
    關鍵字封鎖(不分大小寫)<br>
    當設定在全域變數中,下方就不需再設定同樣的字詞(系統會體醒已在全域過濾清單中有)。<br>
    當文章與留言都有相同的變數,會自動改到全域變數中。
    <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; width: 90%; background: beige;">
            <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
                全域過濾關鍵字(文章與留言皆會過濾)
                <button style="margin: 5px;" onclick="BLH_addFliter('blockKeywords');">新增</button>
                <button style="margin: 5px;" onclick="BLH_removeFliter('blockKeywords');">移除選取</button>
            </div>
            <div id="blockKeywords" style="display: flex; flex-flow: row wrap; width: 90%; padding: 10px;">
            </div>
        </div>
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; width: 45%; background: beige;">
            <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
                文章過濾關鍵字
                <button style="margin: 5px;" onclick="BLH_addFliter('postBlockKeywords');">新增</button>
                <button style="margin: 5px;" onclick="BLH_removeFliter('postBlockKeywords');">移除選取</button>
            </div>
            <div id="postBlockKeywords" style="display: flex; flex-flow: row wrap; width: 90%; padding: 10px;">
            </div>
        </div>
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; width: 45%; background: beige;">
            <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
                留言過濾關鍵字
                <button style="margin: 5px;" onclick="BLH_addFliter('commentBlockKeywords');">新增</button>
                <button style="margin: 5px;" onclick="BLH_removeFliter('commentBlockKeywords');">移除選取</button>
            </div>
            <div id="commentBlockKeywords" style="display: flex; flex-flow: row wrap; width: 90%; padding: 10px;">
            </div>
        </div>
    </div>
</div>
<div style="width: 100%; margin: 10px; padding: 10px; border: 1px solid; border-radius: 10px; background: antiquewhite;">
    ID封鎖(不分大小寫)<button onclick="localStorage.removeItem('BHBlackList'); location.reload();">強制重獲取黑名單</button><br>
    黑名單會自動獲取已經被黑名單的列表,但若要手動添加,可於上方參數進行添加。<br>
    可以添加強制顯示、強制隱藏,這兩個參數會優先於黑名單列表。<br>
    ID只能在強制顯示與強制隱藏其中一個清單內,不會有重複(輸入時會被提醒)。<br>
    輸入的ID不分大小寫。
    <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; width: 45%; background: beige;">
            <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
                顯示名單
                <button style="margin: 5px;" onclick="BLH_addFliter('forceShowList');">新增</button>
                <button style="margin: 5px;" onclick="BLH_removeFliter('forceShowList');">移除選取</button>
            </div>
            <div id="forceShowList" style="display: flex; flex-flow: row wrap; width: 90%; padding: 10px;">
            </div>
        </div>
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; width: 45%; background: beige;">
            <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
                隱藏名單
                <button style="margin: 5px;" onclick="BLH_addFliter('forceHideList');">新增</button>
                <button style="margin: 5px;" onclick="BLH_removeFliter('forceHideList');">移除選取</button>
            </div>
            <div id="forceHideList" style="display: flex; flex-flow: row wrap; width: 90%; padding: 10px;">
            </div>
        </div>
    </div>
</div>
<div style="margin: 10px; padding: 10px; border: 1px solid; border-radius: 10px; background: antiquewhite;">
    其他設定
    <div style="display: flex; align-items: center; justify-content: center; flex-flow: row wrap;">
        <div style="border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px; background: beige;">
            備份與還原
            <div style="display: flex; align-items: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                備份:
                <input type="text" readonly="" name="BLH_Setting_backupText">
                <button style="margin: 5px;" onclick="document.getElementsByName('BLH_Setting_backupText')[0].value = localStorage.getItem('BLH_Setting');">手動獲取</button>
            </div>
            <div style="display: flex; align-items: center; justify-content: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                還原:
                <button style="margin: 5px;" onclick="localStorage.setItem('BLH_Setting', window.prompt('請貼上設定檔:(將重新整理)')); location.reload();">還原</button>
            </div>
            <div style="display: flex; align-items: center; justify-content: center; border: 1px solid; padding: 5px; margin: 10px; border-radius: 10px;">
                還原初始設定:
                <button style="margin: 5px;" onclick="if(window.confirm('確定要還原初始設定?還原後將重新整理。')) (localStorage.removeItem('BLH_Setting'), location.reload()); ">還原</button>
            </div>
        </div>
    </div>
</div>
`);
        let setting = JSON.parse(localStorage.getItem("BLH_Setting"));
        for (let key in setting.switch) (document.getElementById(key).innerHTML = (setting.switch[key] ? '開' : '關'), document.getElementById(key).parentNode.style.color = setting.switch[key] ? 'olive' : 'crimson');
        for (let key in setting.lengthLimit) document.getElementById(key).innerHTML = setting.lengthLimit[key];
        for (let key in setting.data) {
            for (let i = 0; i < setting.data[key].length; i++) {
                jQuery('#' + key).append(`<div style="margin: 10px;" data-value="` + setting.data[key][i] + `"><input type="checkbox"><span onclick="jQuery(this).parent().find('input').prop('checked', !jQuery(this).parent().find('input').prop('checked'));">` + setting.data[key][i] + `</span></div>`);
            }
        }
    }

    jQuery('body').append('<script type="text/javascript">' + function BLH_switch(key) {
        let setting = JSON.parse(localStorage.getItem("BLH_Setting"));
        setting.switch[key] = !setting.switch[key];
        localStorage.setItem('BLH_Setting', JSON.stringify(setting));
        document.getElementById(key).innerHTML = (setting.switch[key] ? '開' : '關');
        document.getElementById(key).parentNode.style.color = setting.switch[key] ? 'olive' : 'crimson';
        console.log('Switch ' + key + ' to ' + setting.switch[key]);
    } + function BLH_lengthLimit(key) {
        let lengthLimit = window.prompt('請輸入不小於2之過濾字數,若輸入5將過濾4字,5字不過濾。');
        console.log('Input: ' + lengthLimit);
        if (lengthLimit == null) return false; else lengthLimit = parseInt(lengthLimit);
        if (isNaN(lengthLimit)) (window.alert('請輸入半形數字。'), console.log('Input value is not a number'));
        else if (lengthLimit < 2) (window.alert('數值不得小於2'), console.log('Input value less then 2!'));
        else {
            let setting = JSON.parse(localStorage.getItem("BLH_Setting"));
            setting.lengthLimit[key] = lengthLimit;
            localStorage.setItem('BLH_Setting', JSON.stringify(setting));
            document.getElementById(key).innerHTML = lengthLimit;
            console.log('Set ' + key + ' to ' + lengthLimit);
        }
    } + function BLH_addFliter(key) {
        let setting = JSON.parse(localStorage.getItem("BLH_Setting"));
        let response = window.prompt('請輸入欲過濾' + (key.includes('force') ? '使用者ID' : '詞') + '(不分大小寫,空格符號等非英數字或文字會被過濾)');
        console.log('Input: ' + response);
        if (response != null) response = response.replace(/[^\u2E80-\u9FFF\ufee0-\uffdfa-zA-Z0-9]/g, '').toLowerCase();
        else return false;
        if (response != '' && response != null) {
            if (key.includes('force')) {
                if (setting.data.forceShowList.includes(response)) {
                    if (key == 'forceShowList') {
                        window.alert('清單中已經有此ID');
                        console.log('ID "' + response + '" already exist in forceShowList.');
                        return false;
                    } else {
                        if (window.confirm('顯示清單中已經含有此ID,是否從顯示清單中移除並加到隱藏清單?')) {
                            setting.data.forceShowList.splice(setting.data.forceShowList.findIndex(element => element == response), 1);
                            jQuery('#forceShowList [data-value="' + response + '"]').remove();
                            console.log('Removed "' + response + '" from forceShowList because it is ready to add to forceHideList.');
                        } else return false;
                    }
                }
                if (setting.data.forceHideList.includes(response)) {
                    if (key == 'forceHideList') {
                        window.alert('清單中已經有此ID');
                        console.log('ID "' + response + '" already exist in forceHideList.');
                        return false;
                    } else {
                        if (window.confirm('隱藏清單中已經含有此ID,是否從隱藏清單中移除並加到顯示清單?')) {
                            setting.data.forceHideList.splice(setting.data.forceHideList.findIndex(element => element == response), 1);
                            jQuery('#forceHideList [data-value="' + response + '"]').remove();
                            console.log('Removed "' + response + '" from forceHideList because it is ready to add to forceShowList.');
                        } else return false;
                    }
                }
            } else {
                if (setting.data[key].includes(response)) {
                    window.alert('清單中已經有此過濾詞');
                    console.log('Value "' + response + '" already exist.');
                    return false;
                } else if (key == 'blockKeywords') {
                    if (setting.data.postBlockKeywords.includes(response)) {
                        setting.data.postBlockKeywords.splice(setting.data.postBlockKeywords.findIndex(element => element == response), 1);
                        jQuery('#postBlockKeywords [data-value="' + response + '"]').remove();
                        console.log('Removed "' + response + '" from postBlockKeywords because it is ready to add to blockKeywords.');
                    }
                    if (setting.data.commentBlockKeywords.includes(response)) {
                        setting.data.commentBlockKeywords.splice(setting.data.commentBlockKeywords.findIndex(element => element == response), 1);
                        jQuery('#commentBlockKeywords [data-value="' + response + '"]').remove();
                        console.log('Removed "' + response + '" from commentBlockKeywords because it is ready to add to blockKeywords.');
                    }
                } else {
                    if (setting.data.blockKeywords.includes(response)) {
                        window.alert('全域過濾清單中已經有此過濾詞');
                        console.log('Value "' + response + '" already exist in blockKeywords.');
                        return false;
                    }
                    if (key == 'commentBlockKeywords' && setting.data.postBlockKeywords.includes(response)) {
                        setting.data.postBlockKeywords.splice(setting.data.postBlockKeywords.findIndex(element => element == response), 1);
                        jQuery('#postBlockKeywords [data-value="' + response + '"]').remove();
                        key = 'blockKeywords';
                        console.log('Removed "' + response + '" from postBlockKeywords because both post and comment fliter has this value, add to global blockKeywords.');
                    } else if (key == 'postBlockKeywords' && setting.data.commentBlockKeywords.includes(response)) {
                        setting.data.commentBlockKeywords.splice(setting.data.commentBlockKeywords.findIndex(element => element == response), 1);
                        jQuery('#commentBlockKeywords [data-value="' + response + '"]').remove();
                        key = 'blockKeywords';
                        console.log('Removed "' + response + '" from commentBlockKeywords because both post and comment fliter has this value, add to global blockKeywords.');
                    }
                }
            }
            setting.data[key][setting.data[key].length] = response;
            localStorage.setItem('BLH_Setting', JSON.stringify(setting));
            jQuery('#' + key).append(`<div style="margin: 10px;" data-value="` + response + `"><input type="checkbox"><span onclick="jQuery(this).parent().find('input').prop('checked', !jQuery(this).parent().find('input').prop('checked'));">` + response + `</span></div>`);
            console.log('Added ' + response + ' to ' + key + '.');
        } else window.alert('輸入的內容錯誤。');
    } + function BLH_removeFliter(key) {
        let setting = JSON.parse(localStorage.getItem("BLH_Setting"));
        let removeList = [];
        jQuery('#' + key + ' input:checked').each((index, element) => {
            console.log('Removed ' + jQuery(element).parent().find('span')[0].innerText + ' from ' + key);
            setting.data[key].splice(setting.data[key].findIndex(element => element == jQuery(element).parent().find('span')[0].innerText), 1);
            jQuery(element).parent().remove();
        });
        localStorage.setItem('BLH_Setting', JSON.stringify(setting));
    } + '</script>');
})();