// ==UserScript==
// @name BiliBili Tags Blocker BiliBili标签屏蔽助手
// @namespace https://gf.qytechs.cn/zh-CN/users/924205-xiao-xi
// @version 0.10.3
// @description 眼不见为净,耳不听为清,心不想则静
// @author xiaoxi
// @license MIT
// @include *://www.bilibili.com/*
// @include *://t.bilibili.com/*
// @include *://search.bilibili.com/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=bilibili.com
// @require https://cdn.bootcdn.net/ajax/libs/jquery/2.2.4/jquery.min.js
// @require https://unpkg.com/[email protected]/dist/ajaxhook.min.js
// @require https://cdn.jsdelivr.net/npm/[email protected]/minified/arrive.min.js
// @require https://gf.qytechs.cn/scripts/407543-block-obj/code/Block_Obj.js?version=963893
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @grant GM_getValue
// @grant GM.getValue
// @grant GM_setValue
// @grant GM.setValue
// @grant GM_setClipboard
// @grant GM.setClipboard
// @grant GM_registerMenuCommand
// @grant GM_addValueChangeListener
// @run-at document-start
// ==/UserScript==
var tagsBlocker = {
functionEnable: true,
onlyChangeColorEnable: false,
printLog: false,
blurMode: false,
hiddenMode: false,
tagsArray: [],
titlesArray: [],
};
var href = location.href;
var matchSearch = href.match(/search.bilibili/);
var matchPopular = href.match(/popular/);
var matchRank = href.match(/\/popular\/rank/);
var matchPost = href.match(/t.bilibili/);
var matchVideo = href.match(/video/);
var matchHome = href.match(/bilibili.com/);
var blockObj = new Block_Obj('Tags_Blocker');
const BASIC_STYLE = `
.block_obj_checkbox_label {
padding-left: 13px;
}
`;
const tagsApi = 'https://api.bilibili.com/x/web-interface/view/detail/tag?bvid=';
//加载选项
document.arrive("body", { fireOnAttributesModification: true, onceOnly: true, existing: true }, function() {
initSettingUI()
});
function initSettingUI(){
blockObj.init({
id: 'tagsBlocker',
menu: '屏蔽设置',
style: BASIC_STYLE,
field: [
{
id: 'version',
label: 'v0.10.3',
type: 's',
},
{
id: 'functionEnable',
label: '启用屏蔽功能',
title: '总开关',
type: 'c',
default: true,
},
{
id: 'onlyChangeColorEnable',
label: '看看屏蔽了什么',
title: '更改屏蔽视频的背景色',
type: 'c',
default: false,
},
{
id: 'printLog',
label: '在控制台输出匹配的视频信息',
title: '。。',
type: 'c',
default: false,
},
{
label: '屏蔽模式',
type: 's',
},
{
id: 'blurMode',
label: '模糊模式',
type: 'c',
default: false,
},
{
id: 'hiddenMode',
label: '隐藏模式',
type: 'c',
default: false,
},
{
label: '标签关键字',
type: 's',
},
{
id: 'tagInput',
label: '',
placeholder: ' 同时输入多个时以英文逗号分隔 ',
type: 'i',
list_id: 'tagsArray',
},
{
id: 'tagsArray',
type: 'l',
default: [],
},
{
label: '标题关键字 (例如‘原 神’标题,请输入‘原神’)',
type: 's',
},
{
id: 'titleInput',
label: '',
placeholder: ' 同时输入多个时以英文逗号分隔 ',
type: 'i',
list_id: 'titlesArray',
},
{
id: 'titlesArray',
type: 'l',
default: [],
},
],
events: {
save: config => {
tagsBlocker = config;
},
change: config => {
tagsBlocker = config;
},
},
})
}
class VideoCard{
constructor(card,title,bv) {
this.card = card;
this.title = replaceAllSymbol(title);
this.bv = bv;
this.tags = null;
this.typeName = null;
this.match = null;
this.where = null;
}
}
class Listener{
constructor(targetNode, nth, options = {}) {
this.targetNode = targetNode;
this.nth = nth;
this.options = options;
}
init(initMethod,callMethod){
let targetNode = $(this.targetNode)[this.nth];
let options = this.options;
function callback(mutationsList, observer) {
if(mutationsList.length >= 1 && mutationsList[0].addedNodes.length != 0){
callFunc(callMethod,mutationsList)
}
}
let mutationObserver = new MutationObserver(callback);
let checkTarget = setInterval(function () {
if(targetNode != undefined && targetNode != null && targetNode.length != 0){
mutationObserver.observe(targetNode, options);
callFunc(initMethod,targetNode)
clearInterval(checkTarget);
}
else
{
targetNode = $(this.targetNode)[this.nth];
}
}, 50);
}
}
class Match{
init(url,parameter,callMethod){
return new Promise(function(resolve) {
$.ajax(url + parameter.bv, {
method: 'GET',
headers: {
"content-type": "application/json"
},
async: true,
success: function (result) {
parameter.tags = result.data
resolve(callFunc(callMethod,parameter));
},
error: function (result) {
console.log(result)
},
});
});
}
}
var match = new Match();
//==视频页==//
function videoInit(card){
let info = $(card).children(".card-box").children(".info").children("a")
let href = $(info).attr("href");
let title = $(info).children('span').attr("title");
let videoCard = $(card);
let bv = getBvcountber(href);
let v1 = new VideoCard(videoCard,title,bv);
return v1
}
function videoListenerInit(targetNode){
$.each($(targetNode).children(".video-page-card"), function(i, card){
let v1 = videoInit(card)
match.init(tagsApi,v1,finalMatch)
});
}
function videoListenerCall(targetNode){
$.each(targetNode, function(i, m){
let v1 = videoInit(m.addedNodes[0])
match.init(tagsApi,v1,finalMatch)
});
}
function ad1(){
//.video-page-special-card
//#live_recommand_report
//#activity_vote
document.arrive(".video-page-special-card", { fireOnAttributesModification: true, onceOnly: true, existing: true }, function() {
$(this).css({"display":"none"});
});
document.arrive("#live_recommand_report", { fireOnAttributesModification: true, onceOnly: true, existing: true }, function() {
$(this).css({"display":"none"});
});
document.arrive("#activity_vote", { fireOnAttributesModification: true, onceOnly: true, existing: true }, function() {
$(this).css({"display":"none"});
});
//结束视频
$(document).arrive('.bpx-player-ending-related', {fireOnAttributesModification: true, onceOnly: true, existing: true},function(){
$(this).remove();
$('.bpx-player-ending-functions').animate({
marginTop: 145, opacity: 'show'
}, "slow");
})
$(document).arrive('.bpx-player-popup', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).remove();
})
$(document).arrive('.bpx-player-follow', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).remove();
})
//三连
$(document).arrive('.bpx-player-popup-guide-all', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).remove();
})
//投票
$(document).arrive('.bpx-player-popup-vote', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).remove();
})
//跳转其他视频
$(document).arrive('.bpx-player-link', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).remove();
})
//评分
$(document).arrive('.bpx-player-score', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).remove();
})
//推广视频
$(document).arrive('.video-ad-creative-card', {fireOnAttributesModification: true, onceOnly: true, existing: true},function(){
$(this).css({"display":"none"})
})
//右下角推广
$(document).arrive('#right-bottom-banner', {fireOnAttributesModification: true, onceOnly: true, existing: true},function(){
$(this).css({"display":"none"})
})
}
$(document).arrive('.reply-notice', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).css({"display":"none"})
})
$(document).arrive('.trending', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
$(this).css({"display":"none"})
})
//==动态导航栏==//
function barListenerInit(targetNode){
let navbarListener = new Listener('.video-list', 0, {childList: true})
navbarListener.init(navbarListenerInit,navbarListenerCall)
}
function barListenerCall(targetNode){
targetNode.map(r => {
if(r.addedNodes[0] != null){
let tab = $(r.addedNodes[0])
if(tab.hasClass('video-tab')){
let navbarListener = new Listener('.video-list', 0, {childList: true})
navbarListener.init(navbarListenerInit,navbarListenerCall)
}
}
})
}
function navbarInit(card){
let href = $(card).children(".main-container").children("a").attr("href");
let title = $(card).children(".main-container").children(".center-box").children("a").attr('title')
let videoCard = $(card);
let bv = getBvcountber(href)
let v1 = new VideoCard(videoCard,title,bv);
return v1
}
function navbarListenerInit(targetNode){
let checkTarget = setInterval(function () {
if($(targetNode).children(".list-item").length > 1){
clearInterval(checkTarget);
$.each($(targetNode).children(".list-item"), function(i, card){
let v1 = navbarInit(card)
match.init(tagsApi,v1,finalMatch)
});
}
}, 50);
}
function navbarListenerCall(targetNode){
$.each(targetNode, function(i, m){
let v1 = navbarInit(m.addedNodes[0])
match.init(tagsApi,v1,finalMatch)
});
}
//==热门页面==//
function initPopularVideoInfo(url){
let l1 = url.indexOf('pn=');
let num = url.substring(l1+3,url.length)
let checkTarget = setInterval(function () {
let videoCardList = $(".video-card__content");
if(videoCardList != null && videoCardList != undefined){
clearInterval(checkTarget);
if(num != 1){
videoCardList = videoCardList.slice((num-1)*20,videoCardList.length)
}
videoCardList.each(function(i){
let href = $(this).children("a").attr("href");
let videoCard = $(this).parent(".video-card");
let title = $($(videoCard).children(".video-card__info")).children("p").attr("title");
let v1 = new VideoCard(videoCard,title,"BV"+getBvcountber(href));
v1.where = 'popular'
match.init(tagsApi,v1,finalMatch)
});
}
}, 50);
}
//==排行榜==//
function initRankVideoInfo(){
let videoCardList = $(".rank-item");
if(!location.href.match(/\/rank\/bangumi/) || !location.href.match(/\/rank\/guochan/) || !location.href.match(/\/rank\/documentary/) || !location.href.match(/\/rank\/movie/) || !location.href.match(/\/rank\/tv/) || !location.href.match(/\/rank\/variety/)){
let checkTarget = setInterval(function () {
if(videoCardList != null && videoCardList != undefined && videoCardList.length != 0){
clearInterval(checkTarget);
videoCardList.each(function(i){
let info = $(this).children(".content").children(".info").children("a");
let href = $(info).attr("href");
let title = $(info).text();
let videoCard = $(this);
let v1 = new VideoCard(videoCard,title,"BV"+getBvcountber(href));
match.init(tagsApi,v1,finalMatch)
});
}
else{
videoCardList = $(".rank-item");
}
}, 50);
}
}
//==搜索页==//
function initSearchVideoInfo(responses){
let checkTarget = setInterval(function () {
if(responses.length >= 1){
let r = []
let checkTarget1 = setInterval(function () {
if(r.length > 1 ){
setVideoInfo(r[0])
clearInterval(checkTarget1);
}
else
{
$.each(responses,function(i,t){
if(t.result_type == 'video'){
r.push(t)
}
})
}
}, 50);
clearInterval(checkTarget);
}
}, 50);
}
function setVideoInfo(tagList){
let videoList = $('.video-list.clearfix').children('.video-item.matrix')
videoList.each(function(i,v){
let tags = tagList.data[i].tag.split(',');
let typeName = tagList.data[i].typename;
let title = $($($(v).children('.info')).children('.headline')).children('a').attr('title')
let v1 = new VideoCard($(v),title,-1);
let newTags = [];
tags.map(function(item) {
let t = {tag_name : item}
newTags.push(t)
});
v1.tags = newTags;
v1.typeName = typeName;
finalMatch(v1)
})
}
function reSetOption(){
$(document).arrive('.filter-type.clearfix.order', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
let op1 = '<li id="filter-item-week" class="filter-item"><a>一周之内</a><li>'
let op2 = '<li id="filter-item-month" class="filter-item"><a>一月之内</a><li>'
let op3 = '<li id="filter-item-year" class="filter-item"><a>一年之内</a><li>'
$(this).append(op1);
$(this).append(op2);
$(this).append(op3);
let week = $('#filter-item-week');
let month = $('#filter-item-month');
let year = $('#filter-item-year');
week.click(function(){
week.addClass('active')
month.removeClass('active')
year.removeClass('active')
});
month.click(function(){
month.addClass('active')
week.removeClass('active')
year.removeClass('active')
});
year.click(function(){
year.addClass('active')
week.removeClass('active')
month.removeClass('active')
});
})
}
//==动态==//
function initPostVideoInfo(){
let postCardList = $(".bili-dyn-list__items").children(".bili-dyn-list__item");
$(postCardList).each(function(i){
let info = $(this).children(".bili-dyn-item").children(".bili-dyn-item__main").children(".bili-dyn-item__body").children(".bili-dyn-content").children(".bili-dyn-content__orig").children(".bili-dyn-content__orig__major").children("a");
let bv = getBvcountber($(info).attr("href"));
let title = $(info).children('.bili-dyn-card-video__body');
if (title.length == 1){
title = title.children('.bili-dyn-card-video__title').text();
}
else{
title = '';
}
let videoCard = $(this).children(".bili-dyn-item").children(".bili-dyn-item__main");
let v1 = new VideoCard($(this),title,bv);
v1.where = 'post'
match.init(tagsApi,v1,finalMatch)
});
}
function matchTopic(){
$(document).arrive('.relevant-topic__title', {fireOnAttributesModification: true, onceOnly: true, existing: true},function(){
let parent = $($(this).parents('.relevant-topic'));
let title = $(this).text();
let successed = false;
$.each(tagsBlocker.tagsArray,function(i,tag){
if(title.indexOf(tag) != -1 && !successed)
{
if(tagsBlocker.onlyChangeColorEnable){
parent.css({"background":"blue"})
}else{
if(tagsBlocker.blurMode){
parent.css({"filter":"blur(1rem)"});
}
if(tagsBlocker.hiddenMode){
parent.css({"display":"none"});
}
}
successed = true;
}
})
$.each(tagsBlocker.titlesArray,function(i,mtitle){
if(title.indexOf(mtitle) != -1 && !successed)
{
if(tagsBlocker.onlyChangeColorEnable){
parent.css({"background":"blue"})
}else{
if(tagsBlocker.blurMode){
parent.css({"filter":"blur(1rem)"});
}
if(tagsBlocker.hiddenMode){
parent.css({"display":"none"});
}
}
successed = true;
}
})
})
}
//==首页==//
function homeInit(card){
let href = $(card).children(".info-box").children("a").attr("href");
let title = $(card).children(".info-box").children("a").children(".info").children(".title").attr('title')
let videoCard = $(card);
let bv = getBvcountber(href)
let v1 = new VideoCard(videoCard,title,bv);
return v1
}
function homeListenerInit(){
$.each($('.video-card-reco'), function(i, card){
let v1 = homeInit(card)
match.init(tagsApi,v1,finalMatch).then(result =>{
if(result instanceof VideoCard){
$('.rcmd-box').append(result.card)
}
})
});
}
function finalMatch(parameter){
let successed = false;
$.each(parameter.tags,function(i,tag){
$.each(tagsBlocker.tagsArray,function(i,mtag){
//匹配到
if((tag.tag_name.indexOf(mtag) != -1 || tag.tag_name.indexOf(parameter.typeName) != -1) && !successed)
{
match1(parameter)
if(tagsBlocker.printLog){
parameter.match = mtag
console.log(parameter)
}
successed = true
}
})
$.each(tagsBlocker.titlesArray,function(i,mtitle){
//匹配到
if(parameter.title.indexOf(mtitle) != -1 && !successed)
{
match1(parameter)
if(tagsBlocker.printLog){
parameter.match = mtitle
console.log(parameter)
}
successed = true
}
})
})
if(successed){
return parameter
}
}
function match1(parameter){
if(tagsBlocker.onlyChangeColorEnable){
if(parameter.where == 'post'){
parameter.card.children(".bili-dyn-item").children(".bili-dyn-item__main").css({"background":"blue"});
}else{
parameter.card.css({"background":"blue"})
}
}else{
if(tagsBlocker.blurMode){
parameter.card.css({"filter":"blur(1rem)"});
}
if(tagsBlocker.hiddenMode){
if(parameter.where == 'popular'){
parameter.card.remove()
}else{
parameter.card.css({"display":"none"});
}
}
}
}
function reSetUI(){
let count = 0;
document.arrive(".block_obj_input_btn", { fireOnAttributesModification: true, onceOnly: false, existing: true }, function() {
if($(this).attr('title') == '展开列表'){
let index = count
let targetNode = $($('.block_obj_list_textarea_div')[index]);
$(this).click(function(){
if(!targetNode.hasClass('expand')){
targetNode.animate({
maxHeight: 300, opacity: 'show'
}, "slow");
targetNode.addClass("expand");
}
else
{
targetNode.animate({
maxHeight: 65, opacity: 'show'
}, "slow");
targetNode.removeClass("expand");
}
});
count ++
}
});
if (window.parent == window) {
// 当前页面不在iframe中
}
else
{
$('#blockObj_tagsBlocker_expandSpan').animate({
opacity: 'hide'
}, 140);
}
}
if (window.parent == window) {
// 当前页面不在iframe中
ajaxHook();
}
else
{
// 当前页面在iframe或者frameset中
}
function ajaxHook() {
ah.proxy(
{
onResponse: (response, handler) => {
//搜索页 例/all?keyword=原神
if (!response.config.url.includes('/web-interface/search/default') && !response.config.url.includes('/web-interface/search/square') && response.config.url.includes('/web-interface/search')){
let responses = [];
let data = JSON.parse(response.response).data
if(data.result.length == 11){
responses.push(data.result[data.result.length-1])
}
if(data.result.length == 20){
let data1 = {
data: data.result,
result_type: 'video'
}
responses.push(data1)
}
initSearchVideoInfo(responses)
}
//热门页面
if (response.config.url.includes('/web-interface/popular')){
initPopularVideoInfo(response.config.url)
}
//排行榜
if (response.config.url.includes('rank')){
initRankVideoInfo()
}
//首页
if (response.config.url.includes('web-interface/index/top/rcmd')){
setTimeout(function(){
homeListenerInit()
},50);
}
//动态
if (response.config.url.includes('web-dynamic/v1/feed/all')){
setTimeout(function(){
initPostVideoInfo()
},50);
}
handler.next(response);
},
},
unsafeWindow
);
}
//移除所有符号
var symbols = [' ','♂','【','】']
function replaceAllSymbol(title) {
$.each(symbols,function(i,k){
if(title.indexOf(k) != -1){
title = title.replaceAll(k,'')
}
})
return title;
}
//通过url获得BV号
function getBvcountber(video_link) {
let bvcount = '';
try {
bvcount = /\/video\/(?:av|bv)(\w+)/i.exec(video_link)[1];
} catch (e) {
bvcount = null;
}
return bvcount;
}
//通过名称调用方法
function callFunc(functionName){
//根据函数名得到函数类型
var func=eval(functionName);
//创建函数对象,并调用
return new func(arguments[1],arguments[2],arguments[3]);
}
//检查jQuery
var checkJQuery = function () {
let jqueryCdns = [
'http://code.jquery.com/jquery-2.1.4.min.js',
'https://ajax.aspnetcdn.com/ajax/jquery/jquery-2.1.4.min.js',
'https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js',
'https://cdn.staticfile.org/jquery/2.1.4/jquery.min.js',
'https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js',
];
function isJQueryValid() {
try {
let wd = unsafeWindow;
if (wd.jQuery && !wd.$) {
wd.$ = wd.jQuery;
}
$();
return true;
} catch (exception) {
return false;
}
}
function insertJQuery(url) {
setTimeout(function(){
let checkJQuery = setInterval(function () {
if(document == undefined && document != null && document.createElement('script') == undefined && document.createElement('script') != null){
let script = document.createElement('script');
script.src = url;
document.head.appendChild(script);
return script;
clearInterval(checkJQuery);
}
}, 100);
},500);
}
function converProtocolIfNeeded(url) {
let isHttps = location.href.indexOf('https://') != -1;
let urlIsHttps = url.indexOf('https://') != -1;
return script;
if (isHttps && !urlIsHttps) {
return url.replace('http://', 'https://');
} else if (!isHttps && urlIsHttps) {
return url.replace('https://', 'http://');
}
return url;
}
function waitAndCheckJQuery(cdnIndex, resolve) {
if (cdnIndex >= jqueryCdns.length) {
iLog.e('无法加载 JQuery,正在退出。');
resolve(false);
return;
}
let url = converProtocolIfNeeded(jqueryCdns[cdnIndex]);
iLog.i('尝试第 ' + (cdnIndex + 1) + ' 个 JQuery CDN:' + url + '。');
let script = insertJQuery(url);
setTimeout(function () {
if (isJQueryValid()) {
iLog.i('已加载 JQuery。');
resolve(true);
} else {
iLog.w('无法访问。');
script.remove();
waitAndCheckJQuery(cdnIndex + 1, resolve);
}
}, 100);
}
return new Promise(function (resolve) {
if (isJQueryValid()) {
iLog.i('已加载 jQuery。');
resolve(true);
} else {
iLog.i('未发现 JQuery,尝试加载。');
waitAndCheckJQuery(0, resolve);
}
});
}
//检查脚本参数
var checkScriptVariate = setInterval(function () {
tagsBlocker = blockObj.getConfig();
if(tagsBlocker.tagsArray != null){
clearInterval(checkScriptVariate);
}
}, 500);
function ILog() {
this.prefix = '';
this.v = function (value) {
if (level <= this.LogLevel.Verbose) {
console.log(this.prefix + value);
}
}
this.i = function (info) {
if (level <= this.LogLevel.Info) {
console.info(this.prefix + info);
}
}
this.w = function (warning) {
if (level <= this.LogLevel.Warning) {
console.warn(this.prefix + warning);
}
}
this.e = function (error) {
if (level <= this.LogLevel.Error) {
console.error(this.prefix + error);
}
}
this.d = function (element) {
if (level <= this.LogLevel.Verbose) {
console.log(element);
}
}
this.setLogLevel = function (logLevel) {
level = logLevel;
}
this.LogLevel = {
Verbose: 0,
Info: 1,
Warning: 2,
Error: 3,
};
let level = this.LogLevel.Verbose;
}
var inChecking = false;
var matchSuccess = false;
var jqItv = setInterval(function () {
if (inChecking) {
return;
}
inChecking = true;
checkJQuery().then(function (isLoad) {
if (isLoad)
{
//动态导航栏
let barListener = new Listener('.container', 0, {childList: true})
barListener.init(barListenerInit,barListenerCall)
//视频页
if (matchVideo && tagsBlocker.functionEnable && !matchSuccess) {
matchSuccess = true;
let videoListener = new Listener('.rec-list', 0, {childList: true})
videoListener.init(videoListenerInit,videoListenerCall)
ad1()
}
//搜索页
if (matchSearch && tagsBlocker.functionEnable && !matchSuccess) {
matchSuccess = true;
$('div.search-button').click()
reSetOption();
}
//动态
if (matchPost && tagsBlocker.functionEnable && !matchSuccess) {
matchSuccess = true;
matchTopic()
}
//排行榜
if (matchRank && tagsBlocker.functionEnable && !matchSuccess) {
matchSuccess = true;
initRankVideoInfo()
}
//首页
if (matchHome && tagsBlocker.functionEnable && !matchSuccess) {
matchSuccess = true;
homeListenerInit()
}
reSetUI()
clearInterval(jqItv);
}
inChecking = false;
});
}, 500);
var iLog = new ILog();