// ==UserScript==
// @name 巴哈黑名單、關鍵詞、字數過少隱藏顯示
// @namespace https://home.gamer.com.tw/moontai0724
// @version 2.4.9
// @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
// @license MIT
// @downloadURL https://update.greasyfork.icu/scripts/40867/%E5%B7%B4%E5%93%88%E9%BB%91%E5%90%8D%E5%96%AE%E3%80%81%E9%97%9C%E9%8D%B5%E8%A9%9E%E3%80%81%E5%AD%97%E6%95%B8%E9%81%8E%E5%B0%91%E9%9A%B1%E8%97%8F%E9%A1%AF%E7%A4%BA.user.js
// @updateURL https://update.greasyfork.icu/scripts/40867/%E5%B7%B4%E5%93%88%E9%BB%91%E5%90%8D%E5%96%AE%E3%80%81%E9%97%9C%E9%8D%B5%E8%A9%9E%E3%80%81%E5%AD%97%E6%95%B8%E9%81%8E%E5%B0%91%E9%9A%B1%E8%97%8F%E9%A1%AF%E7%A4%BA.meta.js
// ==/UserScript==
(function () {
'use strict';
console.log('Start, varsion: ' + GM_info.script.version + ', setting: ', localStorage.getItem("BLH_Setting"));
if (!localStorage.getItem("BLH_Setting") || JSON.parse(localStorage.getItem("BLH_Setting")) == null)
(localStorage.setItem("BLH_Setting", JSON.stringify({
switch: {
keywordPostFilter: true,
keywordCommentFilter: true,
blacklistPostFilter: true,
blacklistCommentFilter: true,
contentLengthPostFilter: false,
contentLengthCommentFilter: false,
},
lengthLimit: {
contentLengthPostLimit: 2,
contentLengthCommentLimit: 2
},
data: {
forceShowList: [],
forceHideList: [],
blockKeywordsPC: [],
postBlockKeywordsPC: [],
commentBlockKeywordsPC: [],
blockKeywordsFC: [],
postBlockKeywordsFC: [],
commentBlockKeywordsFC: []
}
})), console.log('New Setting'));
var setting = JSON.parse(localStorage.getItem("BLH_Setting"));
// 加入隱藏切換
jQuery('head').append('');
jQuery('.BH-menuE').append('
關閉過濾器');
jQuery('.BH-menuE').append('開啟過濾器');
jQuery('.BH-menuE').append('過濾器設定');
jQuery('body').append('');
document.getElementById('BLH_FilterSetting').onclick = () => openSettingWindow();
// 將 blockKeywords 加入 postBlockKeywords 和 commentBlockKeywords 中
for (let i = 0; i < setting.data.blockKeywordsPC.length; i++) setting.data.postBlockKeywordsPC[setting.data.postBlockKeywordsPC.length] = setting.data.commentBlockKeywordsPC[setting.data.commentBlockKeywordsPC.length] = setting.data.blockKeywordsPC[i];
for (let i = 0; i < setting.data.blockKeywordsFC.length; i++) setting.data.postBlockKeywordsFC[setting.data.postBlockKeywordsFC.length] = setting.data.commentBlockKeywordsFC[setting.data.commentBlockKeywordsFC.length] = setting.data.blockKeywordsFC[i];
//BC頁分開
switch (location.pathname) {
case '/B.php':
console.group('Filter log message');
setTimeout(() => console.groupEnd(), 200);
// blacklist post filter
if (setting.switch.blacklistPostFilter) startFilter('blacklist', 'post', '.b-list__count__user>a', '.b-list__row');
// keywords post title filter
if (setting.switch.keywordPostFilter) (startFilter('postBlockKeywordsPC', 'post', '.b-list__main__title', '.b-list__row'), startFilter('postBlockKeywordsFC', 'post', '.b-list__main__title', '.b-list__row'));
// popular recommend title filter
if (setting.switch.keywordPostFilter) (startFilter('postBlockKeywordsPC', 'post', '.popular .name', '.popular__item'), startFilter('postBlockKeywordsFC', 'post', '.popular .name', '.popular__item'));
break;
case '/C.php': case '/Co.php':
console.group('Filter log message');
setTimeout(() => console.groupEnd(), 200);
// 擷取展開按鈕事件:當展開留言按鈕被點擊,執行原生展開留言指令並處理內容
jQuery('body').append('');
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(''); 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 restartFilter(ms) {
setTimeout(function () {
if (!document.getElementById('extendCommentAreaListener')) {
jQuery('#Commendlist_' + postid).each((index, element) => {
if (setting.switch.blacklistCommentFilter) {
getBlackList().then(BlackList => jQuery(element).find('.reply-content__user').each((index, value) => {
if (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'));
}
}));
}
if (setting.switch.keywordCommentFilter) {
jQuery(element).find('.reply-content__article').each((index, value) => {
setting.data.commentBlockKeywordsPC.forEach(data => {
if (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'));
}
});
setting.data.commentBlockKeywordsFC.forEach(data => {
if (value.innerText.toLowerCase() == data) {
jQuery(value).parents('.c-reply__item').addClass('BlockHide');
console.log('Hid a post includes keyword: ' + data, jQuery(value).parents('.c-reply__item'));
}
});
});
}
if (setting.switch.contentLengthCommentFilter) {
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) restartFilter(100);
}, ms);
});
};
// blacklist post filter
if (setting.switch.blacklistPostFilter) startFilter('blacklist', 'post', '.c-post__header__author>.userid', '.c-section');
// blacklist comment filter
if (setting.switch.blacklistCommentFilter) startFilter('blacklist', 'comment', '.reply-content__user', '.c-reply__item');
// keywords post filter
if (setting.switch.keywordPostFilter) (startFilter('postBlockKeywordsPC', 'post', '.c-article.FM-P2', '.c-section'), startFilter('postBlockKeywordsFC', 'post', '.c-article.FM-P2', '.c-section'));
// keywords comment filter
if (setting.switch.keywordCommentFilter) (startFilter('commentBlockKeywordsPC', 'post', '.reply-content__article', '.c-reply__item'), startFilter('commentBlockKeywordsFC', 'post', '.reply-content__article', '.c-reply__item'));
// post content length filter
if (setting.switch.contentLengthPostFilter) startFilter('contentLengthPostLimit', 'post', '.c-article.FM-P2', '.c-section');
// comment content length filter
if (setting.switch.contentLengthCommentFilter) startFilter('contentLengthCommentLimit', 'comment', '.reply-content__article', '.c-reply__item');
// popular recommend title filter
if (setting.switch.keywordPostFilter) (startFilter('postBlockKeywordsPC', 'post', '.popular .name', '.popular__item'), startFilter('postBlockKeywordsFC', 'post', '.popular .name', '.popular__item'));
break;
case '/Bo.php':
console.group('Filter log message');
setTimeout(() => console.groupEnd(), 200);
// blacklist post filter
if (setting.switch.blacklistPostFilter) startFilter('blacklist', 'post', '.FM-blist6>a[href*="home.gamer.com.tw"]', 'tr');
// keywords post title filter
if (setting.switch.keywordPostFilter) (startFilter('postBlockKeywordsPC', 'post', '.FM-blist3', 'tr'), startFilter('postBlockKeywordsFC', 'post', '.FM-blist3', 'tr'));
break;
case '/search.php':
setTimeout(function restartFilter(ms) {
setTimeout(() => {
if (jQuery('.gsc-table-cell-snippet-close').length > 0) {
console.group('Filter log message');
setTimeout(() => console.groupEnd(), 100);
if (setting.switch.keywordPostFilter) (startFilter('postBlockKeywordsPC', 'post', '.gsc-table-cell-snippet-close', '.gsc-result'), startFilter('postBlockKeywordsFC', 'post', '.gsc-table-cell-snippet-close', '.gsc-result'));
} else restartFilter(100);
}, ms);
});
break;
}
function startFilter(filterType, elementType, target, hideClass) {
if (filterType.includes('Keyword') && filterType.includes('PC')) {
console.log('Keyword part compare filter start.');
jQuery(target).each((index, element) => setting.data[filterType].forEach(value => {
if (element.innerText.toLowerCase().replace(/\s/g, '').includes(value)) {
jQuery(element).parents(hideClass).addClass('BlockHide');
console.log('Hid a ' + elementType + ' includes keyword: ' + value, jQuery(element).parents(hideClass));
}
}));
} else if (filterType.includes('Keyword') && filterType.includes('FC')) {
console.log('Keyword full compare filter start.');
jQuery(target).each((index, element) => setting.data[filterType].forEach(value => {
if (element.innerText.toLowerCase().replace(/\s/g, '') == value) {
jQuery(element).parents(hideClass).addClass('BlockHide');
console.log('Hid a ' + elementType + ' includes keyword: ' + value, jQuery(element).parents(hideClass));
}
}));
} else if (filterType.includes('blacklist')) {
console.log('Blacklist filter start.');
getBlackList().then(BlackList => jQuery(target).each((index, element) => {
if (BlackList.includes(element.href.replace('https://home.gamer.com.tw/', '').toLowerCase())) {
jQuery(element).parents(hideClass).addClass('BlockHide');
console.log('Hid a ' + elementType + ' with block user: ' + element.href.replace('https://home.gamer.com.tw/', '').toLowerCase(), jQuery(element).parents(hideClass));
}
}));
} else if (filterType.includes('Length')) {
console.log('content length filter start.');
jQuery(target).each((index, element) => {
let value = element.innerText.replace(/\s/g, '').length;
if (value < setting.lengthLimit[filterType]) {
jQuery(element).parents(hideClass).addClass('BlockHide');
console.log('Hid a ' + elementType + ' less then setting text totalLength limit: ' + setting.lengthLimit[filterType], value, jQuery(element).parents(hideClass));
}
});
}
}
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);
console.log('BlackList handle process over, returned blacklist: ', BlackList);
return BlackList;
}
function getBlackList(forceReload) {
return new Promise(resolve => {
console.log('Received get blacklist request!');
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);
if (today.getTime() < BHBlackList.time && BHBlackList.time < today.getTime() + 86400000) {
console.log('Already requested blacklist today, resolve.');
resolve(BlackListHandle(BHBlackList.BlackList));
} else {
console.log('Today not requested blacklist yet, start request.');
getBlackList(true).then(data => resolve(BlackListHandle(data)));
}
} else {
console.log('Start get blacklist from Bahamut server.');
GM_xmlhttpRequest({
method: "GET",
url: "https://home.gamer.com.tw/ajax/friend_getData.php?here=0",
onload: data => {
console.log(data);
let list = data.responseText.match(/data\-gamercard\-userid\=\"[\s\S]*?\"/g);
let BlackList = list != (null || undefined) ? list.map(value => value.replace(/data\-gamercard\-userid\=\"|\"/g, '').toLowerCase()) : [];
console.log('Get blacklist data from Bahamut server.');
localStorage.setItem('BHBlackList', JSON.stringify({ time: new Date().getTime(), BlackList: BlackList }));
resolve(BlackListHandle(BlackList));
},
onerror: err => console.error('Responsed Error: ', err),
ontimeout: err => console.error('Response timeout: ', err)
});
}
});
}
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(`
切換
黑名單過濾
黑名單文章過濾:
黑名單留言過濾:
關鍵詞過濾
關鍵詞文章過濾:
關鍵詞留言過濾:
字數過濾
文章字數過濾:
留言字數過濾:
字數過濾
文章字數下限:
留言字數下限:
部分符合關鍵詞封鎖(不分大小寫)
當設定在此處,文章或留言只要部分符合這個內容就會被過濾。
當設定在全域變數中,下方就不需再設定同樣的字詞(系統會體醒已在全域過濾清單中有)。
當文章與留言都有相同的變數,會自動改到全域變數中。
全域過濾關鍵詞(文章與留言皆會過濾)
完全符合關鍵詞封鎖(不分大小寫)
當設定在此處,文章或留言必須完全符合這個內容才會被過濾。
當設定在全域變數中,下方就不需再設定同樣的字詞(系統會體醒已在全域過濾清單中有)。
當文章與留言都有相同的變數,會自動改到全域變數中。
全域過濾關鍵詞(文章與留言皆會過濾)
ID封鎖(不分大小寫)
黑名單會自動獲取已經被黑名單的列表,但若要手動添加,可於上方參數進行添加。
可以添加強制顯示、強制隱藏,這兩個參數會優先於黑名單列表。
ID只能在強制顯示與強制隱藏其中一個清單內,不會有重複(輸入時會被提醒)。
輸入的ID不分大小寫。
其他設定
備份與還原
備份:
還原:
還原初始設定:
`);
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(`` + setting.data[key][i] + `
`);
}
}
}
jQuery('body').append('');
})();