Bangumi Autoshow Tags

在条目收藏列表显示条目的常用标签,双击标签栏可以修改。在右边显示标签统计,点击标签可在列表上方显示相应的条目

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Bangumi Autoshow Tags
// @namespace    https://github.com/bangumi/scripts/liaune
// @version      0.4.1
// @description  在条目收藏列表显示条目的常用标签,双击标签栏可以修改。在右边显示标签统计,点击标签可在列表上方显示相应的条目
// @author       Liaune
// @include      /^https?://(bangumi\.tv|bgm\.tv|chii\.in)\/\S+\/list\/.*
// @grant        GM_addStyle
// ==/UserScript==

(function() {
    GM_addStyle(`
.tag_del{
padding: 4px 0;
color: #aaa;
font-size: 10px;
width: 16px;
height: 16px;
line-height: 16px;
float: right;
text-align: center;
}
`);
    let itemsList,TagsAll=[],JsonTags = {},AllTags=[],count=0,update=0;
    const Display_Tag_Num = 15;  //每个条目下展示的标签数量
    const Tag_Bar_Num = 50;   //标签统计栏默认显示的标签数量
    const showBtn0 = document.createElement('a');
    showBtn0.addEventListener('click', ShowProcess);
    showBtn0.className = 'chiiBtn';
    showBtn0.href='javascript:;';
    showBtn0.textContent = 'Show Tags';
    document.querySelector('#browserTools').append(showBtn0);

    //更新缓存数据
    const showBtn4 = document.createElement('a');
    showBtn4.addEventListener('click', Update);
    showBtn4.className = 'chiiBtn';
    showBtn4.href='javascript:;';
    showBtn4.textContent = '更新Tags';

    //停止
    const showBtn5 = document.createElement('a');
    showBtn5.addEventListener('click',ShowSidePanel.bind(this,AllTags),false);
    showBtn5.className = 'chiiBtn';
    showBtn5.href='javascript:;';
    showBtn5.textContent = '停止加载';

    const User =window.location.href.match(/\/list\/(\S+)\//)? window.location.href.match(/\/list\/(\S+)\//)[1]: null;

    function Update(){
        update=1;
        count=0;
        itemsList = document.querySelectorAll('#browserItemList li.item');
        itemsList.forEach( (elem, index) => {
            let href = elem.querySelector('a.subjectCover').href;
            let ID = href.split('/subject/')[1];
            FetchStatus(href,elem);
        });
    }

    //Main Program
    function ShowProcess(){
        $(showBtn0).hide();
        $(document.querySelector('#columnSubjectBrowserB .SimpleSidePanel')).hide();
        itemsList = document.querySelectorAll('#browserItemList li.item');
        itemsList.forEach( (elem, index) => {
            let href = elem.querySelector('a.subjectCover').href;
            let ID = href.split('/subject/')[1];
            //为每个条目添加单独刷新
            let showBtn_Re = document.createElement('a');
            showBtn_Re.className = 'l';
            showBtn_Re.href='javascript:;';
            showBtn_Re.textContent = '↺';
            showBtn_Re.addEventListener('click', FetchStatus.bind(this,href,elem),false);
            elem.querySelector('.inner h3').appendChild(showBtn_Re);

            if(localStorage.getItem('Subject'+ID+'Tags')){
                let info = {"Tags": localStorage.getItem('Subject'+ID+'Tags')};
                DisplayStatus(elem,info);
            }
            else
                FetchStatus(href,elem);

        });
        CreateYearSidePannel();
        CreateRateSidePannel();
    }

    function CheckTag(Tag){
        function ParseDate(Datestring){
            let yy=Datestring.match(/(\d{4})/)? Datestring.match(/(\d{4})/)[1].toString():'';
            let year = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[1].toString(): yy;
            let month = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[3].toString(): '';
            let day = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)?Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[5].toString(): '';
            let time = year? (month? (year+'/'+month+'/'+day):year):'';
            return time;
        }
        if(!Tag) return false;
        else if(ParseDate(Tag)!='') return false;
        else return true;
    }

    function FetchStatus(href,elem){
        fetch(href,{credentials: "include"})
            .then(data => {
            return new Promise(function (resovle, reject) {
                let targetStr = data.text();
                resovle(targetStr);
            });
        })
            .then(targetStr => {
            let ID = href.split('/subject/')[1];
            //获取Tag
            let TagMatch = targetStr.match(/<a href="#;" class="btnGray" onclick="chiiLib.subject.addTag(\S+)<\/a>/g);
            if(TagMatch){
                let Tags=[],len=0;
                for(i=0;i<Math.min(Display_Tag_Num,TagMatch.length-15);i++){
                    let thisTag = TagMatch[i].match(/<a href="#;" class="btnGray" onclick="chiiLib.subject.addTag(\S+)">(\S+)<\/a>/)? TagMatch[i].match(/<a href="#;" class="btnGray" onclick="chiiLib.subject.addTag(\S+)">(\S+)<\/a>/)[2]: null;
                    if(CheckTag(thisTag)) {Tags[len]=thisTag; len+=1;}
                }
                localStorage.setItem('Subject'+ID+'Tags',JSON.stringify(Tags));
                let info = {"Tags": JSON.stringify(Tags)};
                DisplayStatus(elem,info);
                if(update){
                    showBtn4.textContent='更新中... (' + count + '/' + itemsList.length +')';
                    if(count==itemsList.length){ showBtn4.textContent='更新完毕!';}
                }
            }

        });
    }

    function addDivTags(elem,Tags){
        let DivTags = document.createElement('div');
        DivTags.id = "DivTags";
        for(i=0;i<Tags.length;i++){
            let Atags = document.createElement('a');
            //Atags.href = "/anime/tag/"+Tags[i];
            //Atags.target="_blank";
            Atags.href ='#';
            Atags.className = 'l';
            if(i==Tags.length-1) Atags.innerHTML=Tags[i];
            else Atags.innerHTML=Tags[i]+"&nbsp;&nbsp;";
            Atags.addEventListener('click', ShowThisTag.bind(this,Tags[i]),false);
            DivTags.appendChild(Atags);
        }
        if(elem.querySelector('#DivTags')) $(elem.querySelector('#DivTags')).remove();
        $(DivTags).insertAfter(elem.querySelector('.inner .collectInfo'));
        DivTags.addEventListener('dblclick', function (){
            DivTags.contentEditable = true;
        });
        DivTags.addEventListener('blur', function (){
            let Tags = DivTags.textContent.split("  ");
            localStorage.setItem('Subject'+ID+'Tags',JSON.stringify(Tags));

        });
    }

    function DisplayStatus(elem,info){
        let href = elem.querySelector('a.subjectCover').href;
        let ID = href.split('/subject/')[1];
        let Tags = JSON.parse(info.Tags);
        TagsAll = TagsAll.concat(Tags);
        addDivTags(elem,Tags);

        count+=1;
        if(!update){
            document.querySelector('#browserTools').append(showBtn5);
            showBtn5.textContent='加载中... (' + count + '/' + itemsList.length +')';
        }
        if(count==itemsList.length){
            document.querySelector('#browserTools').append(showBtn4);
            $(showBtn5).hide();
            for (i = 0; i < TagsAll.length; i++) {
                JsonTags[TagsAll[i]] = (JsonTags[TagsAll[i]] + 1) || 1;
            }
            AllTags = Object.keys(JsonTags)
                .map(function(key){return {TagName:key, Value:JsonTags[key]};})
                .sort(function(x, y){return y.Value - x.Value;});
            /* for (var key in JsonTags){
                let temp_tag = {TagName:key,Value:JsonTags[key]};
                AllTags.push(temp_tag);
            }
            AllTags.sort(function (x,y){return y.Value - x.Value;});*/
            ShowSidePanel(AllTags);
            //console.log(AllTags);
        }

    }

    function ShowSidePanel(AllTags){
        let SimpleSidePanel = document.createElement('div');
        SimpleSidePanel.className = "SimpleSidePanel";
        SimpleSidePanel.style.width = "190px";
        $(SimpleSidePanel).append($("<h2>标签统计</h2>"));
        let tagList = document.createElement('ul');
        tagList.className = "tagList";
        let showmoreTags = document.createElement('a');
        showmoreTags.href='javascript:;';
        showmoreTags.textContent = '/ 展开全部标签';
        function ShowmoreTags(start,end,hide){
            if(hide) $(showmoreTags).hide();
            for(i=start; i<end; i++){
                let tagli = document.createElement('li');
                let taglia = document.createElement('a');
                taglia.href='#';taglia.textContent = AllTags[i].TagName;
                taglia.addEventListener('click', ShowThisTag.bind(this,AllTags[i].TagName),false);
                $(taglia).append(`<small>${AllTags[i].Value}</small>`);
                //添加删除按钮
                let tag_del = document.createElement('a');
                tag_del.href='javascript:;';tag_del.textContent = 'x';tag_del.title = '删除';tag_del.classList.add('tag_del');
                tag_del.addEventListener('click', DelThisTag.bind(this,tagli,AllTags[i].TagName),false);
                tagli.appendChild(tag_del);
                tagli.appendChild(taglia);
                tagList.appendChild(tagli);
            }
        }
        ShowmoreTags(0,Math.min(Tag_Bar_Num,AllTags.length),0);
        $(SimpleSidePanel).append($(tagList));
        showmoreTags.addEventListener('click', ShowmoreTags.bind(this,Math.min(Tag_Bar_Num,AllTags.length),AllTags.length,1),false);
        $(SimpleSidePanel).append($(showmoreTags));

        document.querySelector('#columnSubjectBrowserB').insertBefore(SimpleSidePanel,document.querySelector('#columnSubjectBrowserB .SimpleSidePanel'));
    }

    function ShowThisTag(TagName){
        itemsList = document.querySelectorAll('#browserItemList li.item');
        let count_t = 0;
        itemsList.forEach( (elem, index) => {

            elem.style.border="none";
            let TagsList = elem.querySelector('#DivTags').textContent.split("  ");
            if (TagsList.includes(TagName)) {
                if(count_t %2 == 0) elem.setAttribute('class', 'item odd clearit');
                else elem.setAttribute('class', 'item even clearit');
                elem.style.border="1px solid #5ebee3";
                document.querySelector('#browserItemList').insertBefore(elem,document.querySelector('#browserItemList li.item'));
                count_t+=1;
            }
        });
    }
    function ShowThisRate(Rate){
        itemsList = document.querySelectorAll('#browserItemList li.item');
        let count_t = 0;
        itemsList.forEach( (elem, index) => {
            elem.style.border="none";
            let stars = elem.querySelectorAll('.inner .collectInfo span')[0].className;
            let User_rate= stars ? (stars.match(/sstars(\d+)/) ? stars.match(/sstars(\d+)/)[1]: 0): 0;
            if (User_rate == Rate) {
                if(count_t %2 == 0) elem.setAttribute('class', 'item odd clearit');
                else elem.setAttribute('class', 'item even clearit');
                elem.style.border="1px solid #5ebee3";
                document.querySelector('#browserItemList').insertBefore(elem,document.querySelector('#browserItemList li.item'));
                count_t+=1;
            }
        });
    }

    function ShowThisYear(Year){
        itemsList = document.querySelectorAll('#browserItemList li.item');
        let count_t = 0;
        itemsList.forEach( (elem, index) => {
            elem.style.border="none";
            let date = elem.querySelectorAll('.inner .info')[0].textContent;
            function ParseDate(Datestring){
                let yy=Datestring.match(/(\d{4})/)? Datestring.match(/(\d{4})/)[1].toString():'';
                let year = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[1].toString(): yy;
                let month = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[3].toString(): '';
                let day = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)?Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[5].toString(): '';
                let time = year? (month? (year+'/'+month+'/'+day):year):'';
                return year;
            }
            date = ParseDate(date);
            if (date == Year) {
                if(count_t %2 == 0) elem.setAttribute('class', 'item odd clearit');
                else elem.setAttribute('class', 'item even clearit');
                elem.style.border="1px solid #5ebee3";
                document.querySelector('#browserItemList').insertBefore(elem,document.querySelector('#browserItemList li.item'));
                count_t+=1;
            }
        });
    }

    Array.prototype.remove = function(val) {
        var a = this.indexOf(val);
        if (a >= 0) {
            this.splice(a, 1);
            return true;
        }
        return false;
    };

    function DelThisTag(tagli,TagName){
        itemsList = document.querySelectorAll('#browserItemList li.item');
        //ShowThisTag(TagName);
        if (!confirm(`确认要删除标签“${TagName}”吗?`)) {
            return;
        }
        $(tagli).remove();
        itemsList.forEach( (elem, index) => {
            let href = elem.querySelector('a.subjectCover').href;
            let ID = href.split('/subject/')[1];
            let TagsList = elem.querySelector('#DivTags').textContent.split("  ");
            if (TagsList.includes(TagName)) {
                TagsList.remove(TagName);
                localStorage.setItem('Subject'+ID+'Tags',JSON.stringify(TagsList));
                addDivTags(elem,TagsList);
            }
        });
    }

    function CreateRateSidePannel(elem){
        let AllRates = [], JsonAllRates = {},RatesAll=[];
        itemsList.forEach( (elem, index) => {
            let User_rate=User ? elem.querySelectorAll('.inner .collectInfo span')[0].className: null;
            let Rate = User_rate ? (User_rate.match(/sstars(\d+)/)?User_rate.match(/sstars(\d+)/)[1]: 0): 0;
            AllRates = AllRates.concat(Rate);
        });
        for (i = 0; i < AllRates.length; i++) {
            JsonAllRates[AllRates[i]] = (JsonAllRates[AllRates[i]] + 1) || 1;
        }
        //console.log(JsonAllRates);
        RatesAll = Object.keys(JsonAllRates)
            .map(function(key){return {Rate:key, Value:JsonAllRates[key]};})
            .sort(function(x, y){return y.Rate - x.Rate;});
        //console.log(RatesAll);
        ShowSidePanelRate(RatesAll);
    }
    function ShowSidePanelRate(RatesAll){
        let SimpleSidePanel = document.createElement('div');
        SimpleSidePanel.className = "SimpleSidePanel";
        SimpleSidePanel.style.width = "190px";
        let RateSum = 0, count_t=0;
        let tagList = document.createElement('ul');
        tagList.className = "tagList";
        for(i=0; i<RatesAll.length; i++){
            let tagli = document.createElement('li');
            let taglia = document.createElement('a');
            taglia.href='#';taglia.textContent = RatesAll[i].Rate+"分";
            if(RatesAll[i].Rate=='0') taglia.textContent = "未评分";
            taglia.addEventListener('click', ShowThisRate.bind(this,RatesAll[i].Rate),false);
            $(taglia).append(`<small>${RatesAll[i].Value}</small>`);
            tagli.appendChild(taglia);
            tagList.appendChild(tagli);
            //不计未评分
            if(RatesAll[i].Rate!='0'){
            RateSum += RatesAll[i].Rate * RatesAll[i].Value;
            count_t += RatesAll[i].Value;}
        }
        $(SimpleSidePanel).append($("<h2>打分统计<small style='float:right'>平均:"+ parseFloat(RateSum/count_t).toFixed(2)+"</small></h2>"));
        $(SimpleSidePanel).append($(tagList));

        document.querySelector('#columnSubjectBrowserB').insertBefore(SimpleSidePanel,document.querySelector('#columnSubjectBrowserB .SimpleSidePanel'));
    }

    function CreateYearSidePannel(elem){
        let AllYears = [], JsonAllYears = {},YearsAll=[];
        itemsList.forEach( (elem, index) => {
            let date = elem.querySelectorAll('.inner .info')[0].textContent;
            function ParseDate(Datestring){
                let yy=Datestring.match(/(\d{4})/)? Datestring.match(/(\d{4})/)[1].toString():'';
                let year = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[1].toString(): yy;
                let month = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)? Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[3].toString(): '';
                let day = Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)?Datestring.match(/(\d{4})(年|-)(\d{1,2})(月|-)(\d{1,2})/)[5].toString(): '';
                let time = year? (month? (year+'/'+month+'/'+day):year):'';
                return year;
            }
            date = ParseDate(date);
            AllYears = AllYears.concat(date);
        });
        for (i = 0; i < AllYears.length; i++) {
            JsonAllYears[AllYears[i]] = (JsonAllYears[AllYears[i]] + 1) || 1;
        }
        console.log(JsonAllYears);
        YearsAll = Object.keys(JsonAllYears)
            .map(function(key){return {Year:key, Value:JsonAllYears[key]};})
            .sort(function(x, y){return y.Year - x.Year;});
        console.log(YearsAll);
        ShowSidePanelYear(YearsAll);
    }

    function ShowSidePanelYear(YearsAll){
        let SimpleSidePanel = document.createElement('div');
        SimpleSidePanel.className = "SimpleSidePanel";
        SimpleSidePanel.style.width = "190px";
        let tagList = document.createElement('ul');
        tagList.className = "tagList";
        let showmoreTags = document.createElement('a');
        showmoreTags.href='javascript:;';
        showmoreTags.textContent = '/ 展开全部标签';
        function ShowmoreTags(start,end,hide){
            if(hide) $(showmoreTags).hide();
            for(i=start; i<end; i++){
                let tagli = document.createElement('li');
                let taglia = document.createElement('a');
                taglia.href='#';taglia.textContent = YearsAll[i].Year;
                taglia.addEventListener('click', ShowThisYear.bind(this,YearsAll[i].Year),false);
                $(taglia).append(`<small>${YearsAll[i].Value}</small>`);
                tagli.appendChild(taglia);
                tagList.appendChild(tagli);
            }
        }
        ShowmoreTags(0,Math.min(15,YearsAll.length),0);
        showmoreTags.addEventListener('click', ShowmoreTags.bind(this,Math.min(15,YearsAll.length),YearsAll.length,1),false);
        $(SimpleSidePanel).append($("<h2>时间统计</h2>"));
        $(SimpleSidePanel).append($(tagList));
        $(SimpleSidePanel).append($(showmoreTags));

        document.querySelector('#columnSubjectBrowserB').insertBefore(SimpleSidePanel,document.querySelector('#columnSubjectBrowserB .SimpleSidePanel'));
    }

})();