// ==UserScript== // @name BiliBili Tags Blocker BiliBili标签屏蔽助手 // @namespace https://greasyfork.org/zh-CN/users/924205-xiao-xi // @version 0.10.0 // @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/ajax-hook@2.1.3/dist/ajaxhook.min.js // @require https://cdn.jsdelivr.net/npm/arrive@2.4.1/minified/arrive.min.js // @require https://greasyfork.org/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 // @downloadURL none // ==/UserScript== var tagsBlocker = { functionEnable: true, onlyChangeColorEnable: 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.8.2', type: 's', }, { id: 'functionEnable', label: '启用屏蔽功能', title: '总开关', type: 'c', default: true, }, { id: 'onlyChangeColorEnable', label: '看看屏蔽了什么', title: '更改屏蔽视频的背景色', type: 'c', default: false, }, { label: '屏蔽模式', type: 's', }, { id: 'blurMode', label: '模糊模式', type: 'c', default: false, }, { id: 'hiddenMode', label: '隐藏模式', type: 'c', default: false, }, { 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; } } 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){ mutationObserver.observe(targetNode, options); callFunc(initMethod,targetNode) clearInterval(checkTarget); } else { targetNode = $(this.targetNode)[this.nth]; } }, 50); } } class Match{ init(url,parameter,callMethod){ $.ajax(url + parameter.bv, { method: 'GET', headers: { "content-type": "application/json" }, async: true, success: function (result) { parameter.tags = result.data callFunc(callMethod,parameter) }, }); } } 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"}) }) //==动态导航栏==// 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){ $.each($(targetNode).children(".list-item"), function(i, card){ let v1 = navbarInit(card) match.init(tagsApi,v1,finalMatch) }); } 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){ if(num != 1){ if(BiliBiliTagsBlocker.blurMode){ 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)); 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 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); 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 || title.indexOf(tagsBlocker.titlesArray[i]) != -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) }); } 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 || parameter.title.indexOf(tagsBlocker.titlesArray[i]) != -1 || tag.tag_name.indexOf(parameter.typeName) != -1) && !successed) { if(tagsBlocker.onlyChangeColorEnable){ parameter.card.css({"background":"blue"}) }else{ if(tagsBlocker.blurMode){ parameter.card.css({"filter":"blur(1rem)"}); } if(tagsBlocker.hiddenMode){ parameter.card.css({"display":"none"}); } } successed = true } }) }) } 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); //创建函数对象,并调用 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 navbarListener = new Listener('.video-list', 0, {childList: true}) navbarListener.init(navbarListenerInit,navbarListenerCall) //视频页 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() } //动态 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();