Greasy Fork is available in English.

BiliBili Tags Blocker BiliBili标签屏蔽助手

眼不见为净,耳不听为清,心不想则静

このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         BiliBili Tags Blocker BiliBili标签屏蔽助手
// @namespace    https://greasyfork.org/zh-CN/users/924205-xiao-xi
// @version      0.11.2.2
// @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
// ==/UserScript==
var tagsBlocker = {
    functionEnable: true,
    onlyChangeColorEnable: false,
    printLog: false,
    blurMode: false,
    hiddenMode: false,
    tagsArray: [],
    titlesArray: [],
    userNameArray: [],
};

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\/BV/);
var matchHome = href.match(/bilibili.com/);

var blockObj = new Block_Obj('Tags_Blocker');

const BASIC_STYLE = `
     .block_obj_checkbox_label {
         padding-left: 13px;
     }
  `;

const bvTagsApi = 'https://api.bilibili.com/x/web-interface/view/detail/tag?bvid=';
const searchAllApi = 'https://api.bilibili.com/x/web-interface/search/all/v2?';
const searchVideoApi = 'https://api.bilibili.com/x/web-interface/search/type?search_type=video&';
const videoInfoApi = 'https://api.bilibili.com/x/web-interface/view?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.11.2.2',
                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: [],
            },
            {
                label: '用户名称 (动态页)',
                type: 's',
            },
            {
                id: 'nameInput',
                label: '',
                placeholder: ' 同时输入多个时以英文逗号分隔 ',
                type: 'i',
                list_id: 'userNameArray',
            },
            {
                id: 'userNameArray',
                type: 'l',
                default: [],
            },

        ],
        events: {
            save: config => {
                tagsBlocker = config;
            },
            change: config => {
                tagsBlocker = config;
            },
        },
    })
}

class VideoCard{
    constructor(card,title,bv) {
        this.card = card; //DOM元素
        this.title = replaceAllSymbol(title); //标题
        this.bv = bv; //bv号
        this.av = null; //av号
        this.tags = null; //标签
        this.arcurl = null; //av号链接
        this.pic = null; //封面
        this.duration = null; //时长
        this.description = null; //简介
        this.play = null; //播放数
        this.danmaku = null; //弹幕数
        this.pubdate = null; //上传时间 , 时间戳
        this.senddate = null; //更新时间 , 时间戳
        this.displaytime = null; //显示时间
        this.mid = null; //up主ID
        this.author = null; //up主
        this.typeName = null; //视频类型
        this.match = null; //匹配的标签
        this.where = null; //来源
    }
}

class Listener{
    constructor(targetNode, nth, parameter, options = {}) {
        this.targetNode = targetNode;
        this.nth = nth;
        this.options = options;
        this.parameter = parameter;
    }
    init(initMethod,callMethod){
        let targetNode = this.targetNode;
        let options = this.options;
        let parameter = this.parameter;
        let nth = this.nth;
        let node = null;

        function callback(mutationsList, observer) {
            if(mutationsList.length >= 1 && mutationsList[0].addedNodes.length != 0){
                callFunc(callMethod,mutationsList)
            }
            if(parameter == 'search')
            {
                callFunc(callMethod,mutationsList)
            }
        }
        let mutationObserver = new MutationObserver(callback);
        let checkTarget = setInterval(function () {
            if(node !=  undefined && node != null && node.length != 0){
                clearInterval(checkTarget);
                mutationObserver.observe(node, options);
                callFunc(initMethod,node)
            }
            else
            {
                node = $(targetNode)[nth];
            }

        }, 50);
    }
}

class Match{
    init(url,parameter,process,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,process));
                },
                error: function (result) {
                    console.log(result)
                },
            });
        });
    }
    id(url,id,callMethod){
        return new Promise(function(resolve) {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url + id,
                headers: {
                    "content-type": "application/json"
                },
                async: true,
                onload: function (result) {
                    console.log(result)

                    //result = JSON.parse(result.responseText).data.result;
                    resolve(callFunc(callMethod,result,id));
                },

            });
        });
    }
    searchInit(url,callMethod){
        return new Promise(function(resolve) {
            GM_xmlhttpRequest({
                method: 'GET',
                url: url,
                headers: {
                    "content-type": "application/json"
                },
                onload: function (result) {

                    result = JSON.parse(result.responseText).data.result;

                    if(result.length== 11){
                        result = result[result.length-1].data
                    }
                    resolve(callFunc(callMethod,result,url));
                },

            });
        });
    }
}
var match = new Match();
//==视频页==//
async 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);
    //if(bv != null){
    // let result = await match.id(videoInfoApi,bv,getUserId);
    // v1.mid = result.data.owner.mid
    // }
    return Promise.resolve(v1)
}
function videoListenerInit(targetNode){
    $.each($(targetNode).children(".video-page-card"), function(i, card){
        let v1 = videoInit(card).then(v1 =>{
            match.init(bvTagsApi,v1,true,finalMatch);
        });
    });
}
function videoListenerCall(targetNode){
    $.each(targetNode, function(i, m){
        let v1 = videoInit(m.addedNodes[0]).then(v1 =>{
            match.init(bvTagsApi,v1,true,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 , 'null', {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, 'null', {childList: true})
                navbarListener.init(navbarListenerInit,navbarListenerCall)
            }
        }
    })
}
async 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 name = $(card).children(".main-container").children(".center-box").children(".name-line").children(".user-name").text()
    let videoCard = $(card);
    let bv = getBvcountber(href)
    let v1 = new VideoCard(videoCard,title,bv);
    v1.author = name;
    v1.where = 'navbar'
    // if(bv != null){
    //let result = await match.id(videoInfoApi,bv,getUserId);
    //   v1.mid = result.data.owner.mid
    // }
    return Promise.resolve(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).then(v1 =>{
                    match.init(bvTagsApi,v1,true,finalMatch);
                });
            });
        }
    }, 50);

}
function navbarListenerCall(targetNode){
    $.each(targetNode, function(i, m){
        let v1 = navbarInit(m.addedNodes[0]).then(v1 =>{
            match.init(bvTagsApi,v1,true,finalMatch);
        });
    });
}

//==热门页面==//
async function initPopularVideoInfo(url){
    let l1 = url.indexOf('pn=');
    let num = url.substring(l1+3,url.length)
    let videoCardList = $(".video-card__content");
    console.log(videoCardList)
    if(videoCardList != null && videoCardList != undefined && videoCardList.length != 0){
        if(num != 1){
            if(tagsBlocker.blurMode){
                videoCardList = videoCardList.slice((num-1)*20,videoCardList.length)
            }
        }

        for(var i = 0 ; i < videoCardList.length ; i++){
            let href = $(videoCardList[i]).children("a").attr("href");
            let videoCard = $(videoCardList[i]).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'
            //  if(v1.bv != null){
            // let result = await match.id(videoInfoApi,v1.bv,getUserId).then(result => {
            //     v1.mid = result.data.owner.mid
            // });
            // }
            match.init(bvTagsApi,v1,true,finalMatch)

        }
    }
}

//==排行榜==//
async 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/)){
        if(videoCardList != null && videoCardList != undefined && videoCardList.length != 0){
            for(var i = 0 ; i < videoCardList.length ; i++){
                let info = $(videoCardList[i]).children(".content").children(".info").children("a");
                let href = $(info).attr("href");
                let title = $(info).text();
                let videoCard = $(videoCardList[i]);
                let v1 = new VideoCard(videoCard,title,"BV"+getBvcountber(href));
                //  if(v1.bv != null){
                //   let result = await match.id(videoInfoApi,v1.bv,getUserId).then(result => {
                //       v1.mid = result.data.owner.mid
                //   });
                // }
                match.init(bvTagsApi,v1,true,finalMatch)
            }
        }
    }
}

//==搜索页==//
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,true)
    })

}

//总页数
var pageCount = 5;
//date 范围
//type api类型
//rank 第一行选项
//duration 第二行选项
//channel 频道
//channel2 子频道
//second 范围秒
//rangeDate 对比时间

var selectedDuration = {date:null,type:null,rank:null,duration:null,channel:null,channel2:null,second:null,rangeDate:null};

//监听URL前进后退变化
window.onpopstate = function() {
    reSetDuration()
};

function switcherListenerInit(result){
    let all = $(result);
    beforeReSetDuration(all)
}

function switcherListenerCall(result){
    let all = $(result[0].target);
    beforeReSetDuration(all)
}

function beforeReSetDuration(all){
    if(all.hasClass('is-active')){
        selectedDuration.type = searchAllApi
        reSetDuration()
    }
    let video = $($('.v-switcher-header-item')[1]);
    if(video.hasClass('is-active')){
        selectedDuration.type = searchVideoApi
        reSetDuration()
    }
}

function reSetDuration(){
    setTimeout(function(){
        if(selectedDuration.date!= null){
            $(selectedDuration.date).addClass('active')
            generateApi(selectedDuration,false)
        }
    },500);
}

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')
            selectedDuration.date = '#filter-item-week';
            selectedDuration.second = 604800;
            generateApi(selectedDuration,false)
        });
        month.click(function(){
            month.addClass('active')
            week.removeClass('active')
            year.removeClass('active')
            selectedDuration.date = '#filter-item-month';
            selectedDuration.second = 2678400;
            generateApi(selectedDuration,false)

        });
        year.click(function(){
            year.addClass('active')
            week.removeClass('active')
            month.removeClass('active')
            selectedDuration.date = '#filter-item-year';
            selectedDuration.second = 31536000;
            generateApi(selectedDuration,false)

        });

    })
    // $(document).arrive('.pages', {fireOnAttributesModification: true, onceOnly: false, existing: true},function(){
    //   let next = '<li id="next_list" class="page-item"><button class="pagination-btn num-btn">下一批</button><li>';
    //  $(this).append(next);
    //  next = $('#next_list')
    // next.click(function(){
    //     let preview = '<li class="page-item prev"><button class="nav-btn iconfont icon-arrowdown2">上一页</button></li>';
    //     $('.pages').prepend(preview);
    //   generateApi(selectedDuration,true)


    // });
    // })
}

function generateApi(date,next){
    selectedDuration.rangeDate = (Math.round(new Date() / 1000)) - date.second;
    let most = $('.filter-item,.order').children().slice(0,5)
    most.each(function(i,v){
        if($(v).hasClass('active')){
            let option = $(v).children('a').text()
            if(option == '综合排序'){
                selectedDuration.rank = '&order=totalrank'
            }
            if(option == '最多点击'){
                selectedDuration.rank = '&order=click'
            }
            if(option == '最新发布'){
                selectedDuration.rank = '&order=pubdate'
            }
            if(option == '最多弹幕'){
                selectedDuration.rank = '&order=dm'
            }
            if(option == '最多收藏'){
                selectedDuration.rank = '&order=stow'
            }
        }
    });
    let duration = $('.filter-item,.duration').children()
    duration.each(function(i,v){
        if($(v).hasClass('active')){
            let option = $(v).children('a').text()
            if(option == '全部时长'){
                selectedDuration.duration = '&duration=0'
            }
            if(option == '10分钟以下'){
                selectedDuration.duration = '&duration=1'
            }
            if(option == '10-30分钟'){
                selectedDuration.duration = '&duration=2'
            }
            if(option == '30-60分钟'){
                selectedDuration.duration = '&duration=3'
            }
            if(option == '60分钟以上'){
                selectedDuration.duration = '&duration=4'
            }
        }
    });
    selectedDuration.channel = '&tids_1=0'
    let keyWord = 'keyword='+$('#search-keyword').val()
    let page = $('.page-item.active').children('button').text().trim();
    if(next){
        page = Number(page+5)
    }
    let currentPage = '&page='+page
    let url = selectedDuration.type+keyWord+currentPage+selectedDuration.rank+selectedDuration.duration+selectedDuration.channel
    getPageData(url)
}

async function getPageData(url){
    //请求并返回全部页面数据
    requsetOtherPage(url).then(list =>{
        //根据时间戳排序
        sortByDate(list).then(result =>{
            //匹配标签
            matchVideoCard(result).then(result =>{
                //陈列排序后的视频
                displayVideoCard(result)
            })
        })
    })
}

//请求并返回全部页面数据
async function requsetOtherPage(url){
    let currentPagePrefix = url.indexOf('&page=');
    let currentPageSuffix = url.indexOf('&order');
    let currentPage = Number(url.substring(currentPagePrefix+6,currentPageSuffix))
    let allVideoCards = []
    for(var i = currentPage ; i < currentPage + pageCount ; i++){
        await match.searchInit(url,initPageData).then(list =>{
            list.map(v => { allVideoCards.push(v) })
        })
        url = url.replace('&page='+ i,'&page='+ Number(i+1))
    }
    return Promise.resolve(allVideoCards)
}
function initPageData(result,url){
    return new Promise(function(resolve) {
        let list = [];
        result.map((v,i) => {
            if(v.pubdate > selectedDuration.rangeDate){
                let v1 = new VideoCard(null,v.title,v.bvid);
                v1.av = v.aid;
                v1.arcurl = v.arcurl;
                v1.pic = v.pic;
                v1.duration = v.duration;
                v1.typename = v.typename;
                v1.description = v.description;
                v1.play = v.play;
                v1.danmaku = v.danmaku;
                v1.pubdate = v.pubdate;
                v1.senddate = v.senddate;
                v1.displaytime = date('Y-m-d',v.pubdate);
                v1.mid = v.mid;
                v1.author = v.author;
                list.push(v1)

            }
            resolve(list)
        })
    });
}

//根据时间戳排序
function sortByDate(allVideoCards){
    return new Promise(function(resolve) {
        if(allVideoCards.length > 0){
            for (var i=0;i<allVideoCards.length;i++)
            {
                for (var j=i;j<allVideoCards.length;j++)
                {
                    if(allVideoCards[i].pubdate < allVideoCards[j].pubdate){
                        let n = allVideoCards[i]
                        allVideoCards[i] = allVideoCards[j]
                        allVideoCards[j] = n;
                    }
                }
            }
        }
        resolve(allVideoCards)
    });
}
//匹配标签
function matchVideoCard(allVideoCards){
    return new Promise(function(resolve) {
        let count = 0
        if(allVideoCards.length > 0){
            allVideoCards.map((result,i) =>{
                match.init(bvTagsApi,result,false,finalMatch).then(v =>{
                    if(v instanceof VideoCard){
                        result = v;
                        count += 1
                        if(allVideoCards.length == count){
                            resolve(allVideoCards)
                        }
                    }
                });
            })
        }
        else{
            resolve(allVideoCards)
        }
    });

}
//陈列排序后的视频
function displayVideoCard(allVideoCards){
    let cardList = $('.video-list.clearfix');
    cardList.empty();
    if(allVideoCards.length > 0){
        allVideoCards.map((v,i) =>{
            if(v.match == null){
                let template = "<li class='video-item matrix'><a href='"+v.arcurl+"' title='"+v.title+"' target='_blank' class='img-anchor'> <div class='img'><div class='lazy-img'>    <img alt='' src='"+v.pic+"' width='720' data-resolution-width='1620'></div><span class='so-imgTag_rb'>"+v.duration+"</span><div class='watch-later-trigger watch-later'></div><span class='mask-video'></span></div></a><div class='info'><div class='headline clearfix'><span class='type hide'>"+v.typename+"</span><a title='"+v.title+"' href='"+v.arcurl+"' target='_blank' class='title'>"+v.title+"</a></div><div class='des hide'>"+v.description+"</div><div class='tags'><span title='观看' class='so-icon watch-num'><i class='icon-playtime'></i>"+v.play+" </span><span title='弹幕' class='so-icon hide'><i class='icon-subtitle'></i>"+v.danmaku+" </span><span title='上传时间' class='so-icon time'><i class='icon-date'></i>"+v.displaytime+" </span><span title='up主' class='so-icon'><i class='icon-uper'></i><a href='https://space.bilibili.com/"+v.mid+"?from=search' target='_blank' class='up-name'>"+v.author+" </a></span></div></div></li>"
                cardList.append(template);
            }
        });
    }
}

//==动态==//
async function initPostVideoInfo(){
    let postCardList = $(".bili-dyn-list__items").children(".bili-dyn-list__item");


    for(var i = 0 ; i < postCardList.length ; i++){
        let name = $(postCardList[i]).children(".bili-dyn-item").children(".bili-dyn-item__main").children(".bili-dyn-item__header").children(".bili-dyn-title").children(".bili-dyn-title__text").text()
        let info = $(postCardList[i]).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 = $(postCardList[i]).children(".bili-dyn-item").children(".bili-dyn-item__main");
        let v1 = new VideoCard($(postCardList[i]),title,bv);
        v1.author = name.trim()
        //if(bv != null){
        // let result = await match.id(videoInfoApi,bv,getUserId);
        // v1.mid = result.data.owner.mid
        // }
        v1.where = 'post'
        match.init(bvTagsApi,v1,true,finalMatch)

    }

}
function matchTopic(){
    $(document).arrive('.relevant-topic__title', {fireOnAttributesModification: true, onceOnly: false, 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;
            }
        })
    })
}

//==首页==//
//推荐
async 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);
    // if(v1.bv != null){
    //   let result = await match.id(videoInfoApi,v1.bv,getUserId).then(result => {
    //       v1.mid = result.data.owner.mid
    //  });
    // }
    return v1
}
function homeListenerInit(){
    $.each($('.video-card-reco'), function(i, card){
        let v1 = homeInit(card).then(v1 =>{
            match.init(bvTagsApi,v1,true,finalMatch).then(result =>{
                if(result instanceof VideoCard){
                    if(result.match != null){
                        $('.rcmd-box').append(result.card)
                    }
                }
            })
        });
    });
}

async function channelInit(card){

    let title = $($(card).children("a")[0]);
    let href = title.attr("href");
    let bv = getBvcountber(href)
    let videoCard = $(card);
    title = title.text().trim()
    let v1 = new VideoCard(videoCard,title,bv);
    // if(v1.bv != null){
    //   let result = await match.id(videoInfoApi,v1.bv,getUserId).then(result => {
    //       v1.mid = result.data.owner.mid
    //  });
    // }
    return v1
}

function initChannel(channel){
    let target = $(channel).children('.card-list').children('.zone-list-box')
    let checkTarget = setInterval(function () {
        let videoCardList = $(target).children('.video-card-common');
        if(videoCardList.length != 0){
            $.each(videoCardList, function(i, card){
                let v1 = channelInit(card).then(v1 =>{
                    match.init(bvTagsApi,v1,true,finalMatch).then(result =>{
                        if(result instanceof VideoCard){
                            if(result.match != null){
                                $(target).append(result.card)
                            }
                        }
                    })
                });
            });
            clearInterval(checkTarget);
        }
        else{
            videoCardList = $(target).children('.video-card-common');
        }
    }, 50);

}

async function channelRankInit(index,card){
    let v1 = null;
    if(index!=0){
        let href = $($(card).children("a")[0]);
        let title = href.children("p").attr("title");
        href = href.attr("href");
        let bv = getBvcountber(href)
        let videoCard = $(card);
        v1 = new VideoCard(videoCard,title,bv);
        // if(v1.bv != null){
        //   let result = await match.id(videoInfoApi,v1.bv,getUserId).then(result => {
        //       v1.mid = result.data.owner.mid
        //  });
        // }
    }
    else{
        let href = $(card).children(".preview").children(".pic").children("a").attr('href');
        let title = $(card).children(".preview").children(".txt").children("a").children("p").text().trim();
        let bv = getBvcountber(href)
        let videoCard = $(card);
        v1 = new VideoCard(videoCard,title,bv);
    }
    return v1
}

function initChannelRank(rank){
    let target = $(rank).children('.rank-list')
    let checkTarget = setInterval(function () {
        let videoCardList = $(target).children('.rank-wrap');
        if(videoCardList.length != 0){
            $.each(videoCardList, function(i, card){
                let v1 = channelRankInit(i,card).then(v1 =>{
                    match.init(bvTagsApi,v1,true,finalMatch).then(result =>{
                        if(result instanceof VideoCard){
                            if(result.match != null){
                                $(target).append(result.card)
                            }
                        }
                    })
                });
            });
            clearInterval(checkTarget);
        }
        else{
            videoCardList = $(target).children('.rank-wrap');
        }
    }, 50);
}

function finalMatch(parameter,process){
    let successed = false;
    $.each(parameter.tags,function(i,tag){
        $.each(tagsBlocker.tagsArray,function(i,mtag){
            //匹配到
            if((tag.tag_name.indexOf(mtag) != -1 || parameter.typeName.indexOf(mtag) != -1) && !successed)
            {
                if(tag.tag_name.indexOf(mtag) != -1){
                    parameter.match = mtag
                }
                if(tag.tag_name.indexOf(parameter.typeName) != -1){
                    parameter.match = parameter.typeName
                }
                if(process){
                    match1(parameter)
                }
                if(tagsBlocker.printLog){
                    console.log(parameter)
                }
                successed = true
            }
        })

    })
    if(!successed){
        //匹配到
        if(parameter.where == 'post' || parameter.where == 'navbar'){
            if(tagsBlocker.userNameArray.includes(parameter.author)  && !successed)
            {
                parameter.match = parameter.author
                if(process){
                    match1(parameter)
                }
                if(tagsBlocker.printLog){
                    console.log(parameter)
                }
                successed = true
            }
        }
        $.each(tagsBlocker.titlesArray,function(i,mtitle){
            //匹配到
            if(parameter.title.indexOf(mtitle) != -1 && !successed)
            {
                parameter.match = mtitle
                if(process){
                    match1(parameter)
                }
                if(tagsBlocker.printLog){
                    console.log(parameter)
                }
                successed = true
            }
        })
    }
    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 getUserId(result,id){
    return result
}

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中
    //动态导航栏
    let barListener = new Listener('.container', 0, 'null', {childList: true})
    barListener.init(barListenerInit,barListenerCall)
}

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)
                    }
                    if(selectedDuration.date != null){
                        setTimeout(function(){
                            generateApi(selectedDuration,false)
                        },51);
                    }
                    else{
                        initSearchVideoInfo(responses)
                    }
                }
                //热门页面
                if (response.config.url.includes('/web-interface/popular')){
                    setTimeout(function(){
                        initPopularVideoInfo(response.config.url)
                    },51);
                }
                //排行榜
                if (response.config.url.includes('rank')){
                    setTimeout(function(){
                        initRankVideoInfo()
                    },50);
                }
                //首页
                if (response.config.url.includes('web-interface/index/top/rcmd')){
                    setTimeout(function(){
                        homeListenerInit()
                    },50);
                }
                //首页分区
                if (response.config.url.includes('web-interface/dynamic/region')){
                    //游戏区
                    if (response.config.url.includes('rid=4')){
                        setTimeout(function(){
                            initChannel('#bili_report_game')
                            initChannelRank('#bili_report_game')
                        },50);
                    }
                    //汽车区
                    if (response.config.url.includes('rid=223')){
                        setTimeout(function(){
                            initChannel('#bili_report_car')
                            initChannelRank('#bili_report_car')
                        },50);
                    }
                    //科技区
                    if (response.config.url.includes('rid=188')){
                        setTimeout(function(){
                            initChannel('#bili_report_tech')
                            initChannelRank('#bili_report_tech')
                        },50);
                    }
                    //知识区
                    if (response.config.url.includes('rid=36')){
                        setTimeout(function(){
                            initChannel('#bili_report_knowledge')
                            initChannelRank('#bili_report_knowledge')
                        },50);
                    }
                    //电影区
                    if (response.config.url.includes('rid=23')){
                        setTimeout(function(){
                            initChannel('#bili_report_movie')
                            //initChannelRank('#bili_report_movie')
                        },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]);
}

/**
 * 和PHP一样的时间戳格式化函数
 * @param {string} format 格式
 * @param {int} timestamp 要格式化的时间 默认为当前时间
 * @return {string}   格式化的时间字符串
 */
function date(format, timestamp){
    var a, jsdate=((timestamp) ? new Date(timestamp*1000) : new Date());
    var pad = function(n, c){
        if((n = n + "").length < c){
            return new Array(++c - n.length).join("0") + n;
        } else {
            return n;
        }
    };
    var txt_weekdays = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    var txt_ordin = {1:"st", 2:"nd", 3:"rd", 21:"st", 22:"nd", 23:"rd", 31:"st"};
    var txt_months = ["", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
    var f = {
        // Day
        d: function(){return pad(f.j(), 2)},
        D: function(){return f.l().substr(0,3)},
        j: function(){return jsdate.getDate()},
        l: function(){return txt_weekdays[f.w()]},
        N: function(){return f.w() + 1},
        S: function(){return txt_ordin[f.j()] ? txt_ordin[f.j()] : 'th'},
        w: function(){return jsdate.getDay()},
        z: function(){return (jsdate - new Date(jsdate.getFullYear() + "/1/1")) / 864e5 >> 0},

        // Week
        W: function(){
            var a = f.z(), b = 364 + f.L() - a;
            var nd2, nd = (new Date(jsdate.getFullYear() + "/1/1").getDay() || 7) - 1;
            if(b <= 2 && ((jsdate.getDay() || 7) - 1) <= 2 - b){
                return 1;
            } else{
                if(a <= 2 && nd >= 4 && a >= (6 - nd)){
                    nd2 = new Date(jsdate.getFullYear() - 1 + "/12/31");
                    return date("W", Math.round(nd2.getTime()/1000));
                } else{
                    return (1 + (nd <= 3 ? ((a + nd) / 7) : (a - (7 - nd)) / 7) >> 0);
                }
            }
        },

        // Month
        F: function(){return txt_months[f.n()]},
        m: function(){return pad(f.n(), 2)},
        M: function(){return f.F().substr(0,3)},
        n: function(){return jsdate.getMonth() + 1},
        t: function(){
            var n;
            if( (n = jsdate.getMonth() + 1) == 2 ){
                return 28 + f.L();
            } else{
                if( n & 1 && n < 8 || !(n & 1) && n > 7 ){
                    return 31;
                } else{
                    return 30;
                }
            }
        },

        // Year
        L: function(){var y = f.Y();return (!(y & 3) && (y % 1e2 || !(y % 4e2))) ? 1 : 0},
        //o not supported yet
        Y: function(){return jsdate.getFullYear()},
        y: function(){return (jsdate.getFullYear() + "").slice(2)},

        // Time
        a: function(){return jsdate.getHours() > 11 ? "pm" : "am"},
        A: function(){return f.a().toUpperCase()},
        B: function(){
            // peter paul koch:
            var off = (jsdate.getTimezoneOffset() + 60)*60;
            var theSeconds = (jsdate.getHours() * 3600) + (jsdate.getMinutes() * 60) + jsdate.getSeconds() + off;
            var beat = Math.floor(theSeconds/86.4);
            if (beat > 1000) beat -= 1000;
            if (beat < 0) beat += 1000;
            if ((String(beat)).length == 1) beat = "00"+beat;
            if ((String(beat)).length == 2) beat = "0"+beat;
            return beat;
        },
        g: function(){return jsdate.getHours() % 12 || 12},
        G: function(){return jsdate.getHours()},
        h: function(){return pad(f.g(), 2)},
        H: function(){return pad(jsdate.getHours(), 2)},
        i: function(){return pad(jsdate.getMinutes(), 2)},
        s: function(){return pad(jsdate.getSeconds(), 2)},
        //u not supported yet

        // Timezone
        //e not supported yet
        //I not supported yet
        O: function(){
            var t = pad(Math.abs(jsdate.getTimezoneOffset()/60*100), 4);
            if (jsdate.getTimezoneOffset() > 0) t = "-" + t; else t = "+" + t;
            return t;
        },
        P: function(){var O = f.O();return (O.substr(0, 3) + ":" + O.substr(3, 2))},
        //T not supported yet
        //Z not supported yet

        // Full Date/Time
        c: function(){return f.Y() + "-" + f.m() + "-" + f.d() + "T" + f.h() + ":" + f.i() + ":" + f.s() + f.P()},
        //r not supported yet
        U: function(){return Math.round(jsdate.getTime()/1000)}
    };

    var exp = /[\\]?([a-zA-Z])/g;
    return format.replace(exp, function(t, s){
        let ret = null;
        if( t!=s ){
            // escaped
            ret = s;
        } else if( f[s] ){
            // a date function exists
            ret = f[s]();
        } else{
            // nothing special
            ret = s;
        }
        return ret;
    });
}

//检查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)
        {

            //视频页
            if (matchVideo && tagsBlocker.functionEnable && !matchSuccess) {
                matchSuccess = true;
                let videoListener = new Listener('.rec-list', 0, 'null', {childList: true})
                videoListener.init(videoListenerInit,videoListenerCall)
                ad1()
            }
            //搜索页
            if (matchSearch && tagsBlocker.functionEnable && !matchSuccess) {
                matchSuccess = true;
                $('div.search-button').click()
                let name = '.v-switcher-header-item';
                let switcher = new Listener(name, 0, 'search', { childList: true , attributes :true })
                switcher.init(switcherListenerInit,switcherListenerCall)
                reSetOption();
            }
            //动态
            if (matchPost && tagsBlocker.functionEnable && !matchSuccess) {
                matchSuccess = true;
                matchTopic()
            }
            //排行榜
            if (matchRank && tagsBlocker.functionEnable && !matchSuccess) {
                matchSuccess = true;
                setTimeout(function(){
                    initRankVideoInfo()
                },50);
            }
            //首页
            if (matchHome && tagsBlocker.functionEnable && !matchSuccess) {
                matchSuccess = true;
                homeListenerInit()

            }
            reSetUI()
            clearInterval(jqItv);
        }
        inChecking = false;
    });
}, 500);
var iLog = new ILog();