Greasy Fork is available in English.

B站动态按照日期归类

B站动态按照日期归类。仅作为DD调研用(考古也算的话),若有滥用等问题概不负责诶嘿。

// ==UserScript==
// @name         B站动态按照日期归类
// @namespace    http://tampermonkey.net/
// @version      0.2
// @description  B站动态按照日期归类。仅作为DD调研用(考古也算的话),若有滥用等问题概不负责诶嘿。
// @author       太陽闇の力
// @include      /https?:\/\/space\.bilibili\.com/
// @grant        GM_addStyle
// @grant    GM_registerMenuCommand
// @license MIT
// ==/UserScript==

(function() {
    let flag = true;
    let flag2 = true;
    GM_registerMenuCommand("启动归类",async()=>{
        if(!flag)return;
        let cardList={};
        let dateList = [];
        const uid = /\d+/.exec(location.pathname)[0];
        const relation={"DYNAMIC_TYPE_WORD":"文本","DYNAMIC_TYPE_DRAW":"图片","DYNAMIC_TYPE_AV":"视频","DYNAMIC_TYPE_FORWARD":"转发","DYNAMIC_TYPE_LIVE_RCMD":"直播","DYNAMIC_TYPE_ARTICLE":"专栏","DYNAMIC_TYPE_COMMON_VERTICAL":"漫画","DYNAMIC_TYPE_COURSES_SEASON":"课程","DYNAMIC_TYPE_MUSIC":"音乐","DYNAMIC_TYPE_COMMON_SQUARE":"H5页"}
        let offset = "";
        do{
            let url = `https://api.bilibili.com/x/polymer/web-dynamic/v1/feed/space?offset=${offset}&host_mid=${uid}`
            let res =await fetcher(url);
            for (let item of res.data.items){
                const cardType = relation[item.type]||"未知";
                const cardId = item.id_str;
                const cardTime = item.modules.module_author.pub_ts*1000;
                const cardDate = fmtDate(cardTime);
                const content = item.modules.module_dynamic?.desc?.text||item.modules.module_dynamic.major?.archive?.title||item.modules.module_dynamic.major?.article?.title||item.modules.module_dynamic.major?.common?.title||JSON.parse(item.modules.module_dynamic?.major?.live_rcmd?.content||'{}')?.live_play_info?.title||item.modules.module_dynamic.major?.music?.title||item.modules.module_dynamic.major?.courses?.title;
                if(!cardList[cardDate]){
                    cardList[cardDate] = [];
                }
                cardList[cardDate].push([cardId,content,cardType]);
                dateList.push(cardTime);
            }
            offset = res.data.offset;
        }while(offset!="");
        if(dateList.length>1){
            if(dateList[0]<dateList[1]){
                let temp = dateList[0];
                dateList[0] = dateList[1];
                dateList[1] = temp;
            }
        }
        dateList = dateList.map(fmtDate);
        function fmtDate(obj){
            var date = new Date(obj);
            var y = 1900+date.getYear();
            var m = "0"+(date.getMonth()+1);
            var d = "0"+date.getDate();
            return y+"-"+m.substring(m.length-2,m.length)+"-"+d.substring(d.length-2,d.length);
        }
        async function fetcher(url) {
            const res = await fetch(url)
            if (!res.ok) {
                throw new Error(res.statusText)
            }
            const data = await res.json()
            if (data.code != 0) {
                throw new Error("B站API请求错误:" + data.message)
            }
            return data
        }
        GM_addStyle(`
    * {
			margin: 0;
			padding: 0;
		}

		ul {
			list-style: none;
		}

		#schedule-box {
			width: 320px;
			margin-bottom: 10px;
			padding: 10px 20px;
			font-size: 13px;
		}

		.schedule-hd {
			display: flex;
			justify-content: space-between;
			padding: 0 15px;
		}

		.today {
			flex: 1;
			text-align: center;
		}

		.ul-box {
			overflow: hidden;
		}

		.ul-box>li {
			float: left;
			width: 14.28%;
			text-align: center;
			padding: 5px 0;
		}

		.other-month {
			color: #999999;
		}

		.disabled {
			pointer-events: none;
			background-color: #eeeeee;
			color: #999999;
		}

		.current-month {
			color: #333333;
		}

		.today-style {
			border-radius: 50%;
			background: #58d321;
		}

		.arrow {
			cursor: pointer;
		}

		.dayStyle {
			display: inline-block;
			width: 35px;
			height: 35px;
			border-radius: 50%;
			text-align: center;
			line-height: 35px;
			cursor: pointer;
		}

		.current-month>.dayStyle:hover {
			background: #ffba5a;
			color: #ffffff;
		}

		.today-flag {
			background: #00C2B1;
			color: #fff;
		}

		.boxshaw {
			box-shadow:2px -4px 15px 2px #e3e3e3;
		}

		.selected-style {
			background-color: #00BDFF;
			color: #ffffff;
		}
        .active-style {
			background: #ffba5a;
			color: #ffffff;
		}


		.today {
			text-align: center;
			color: #8ac6d1;
			padding: 5px 0 0;
			font-weight: bold;
			cursor: pointer;
			font-size: 15px;
		}
  @font-face {font-family: "iconfont";
}

.iconfont {
  font-family:"iconfont" !important;
  font-size:16px;
  font-style:normal;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.icon-115rightarrowheads:before { content: "▶"; }

.icon-111arrowheadright:before { content: "▷"; }

.icon-116leftarrowheads:before { content: "◀"; }

.icon-112leftarrowhead:before { content: "◁"; }

table {
  font-family: arial, sans-serif;
  border: 1px solid #dddddd80;
  border-radius: 8px;
  border-collapse:separate;
  width: 100%;
}

td{
  border: 0;
  text-align: left;
  padding: 8px;
}
#tdiv::-webkit-scrollbar{
display:none

}

    `
                   )

        var div = document.createElement('div');
        div.style.cssText = 'max-width:360px;position:fixed;top:70px;left:200px;z-index:999;background-color:#ffffffc2;border-bottom-right-radius:8px;border-bottom-left-radius:8px;';

        const closeButton = window.document.createElement('button');
        closeButton.innerText = "ㄨ";
        closeButton.style.cssText = 'float:right;border:none;cursor:pointer;background-color:#ffffffc2;border-radius:1px;color:red;';

        const collapseButton = window.document.createElement('button');
        collapseButton.innerText = "─";
        collapseButton.style.cssText = 'width:13.34px;height:17px;float: right;margin-right:3px;border:none;cursor:pointer;background-color:#ffffffc2;border-radius:1px;';

        var sb = document.createElement('div');
        sb.id = 'schedule-box';
        sb.classList.add('boxshaw');

        var tb = document.createElement('table');
        var tdiv = document.createElement('div');
        tdiv.id = "tdiv";
        tdiv.style.cssText ="max-height:200px;overflow-y:scroll;overflow-x:hidden;"


        tdiv.append(tb)
        div.append(closeButton);
        div.append(collapseButton);
        div.append(sb);
        tdiv.append(tb);
        div.append(tdiv);
        document.body.appendChild(div);

        closeButton.addEventListener("click",()=>{
            div.remove();
            flag = true;
            flag2 = true;
        });


        collapseButton.addEventListener("click",()=>{
            if(flag2){
                sb.style.display = "none";
                tdiv.style.display = "none";
                closeButton.style.display = "none";
                collapseButton.style.height = "20px";
                collapseButton.style.width = "15.7px";
                flag2 = false;
            }else{
                sb.style.display = "block";
                tdiv.style.display = "block";
                closeButton.style.display = "block";
                collapseButton.style.height = "17px";
                collapseButton.style.width = "13.34px";
                flag2 = true;
            }
        });

        var mySchedule = new Schedule({
            el: '#schedule-box',	//容器元素
            disabledBefore: dateList[dateList.length-1],	//禁用此日期之前
            disabledAfter: dateList[0],	//禁用此日期之后
            selectedDate: dateList,	//选中的日期
            showToday: true,	//回到今天
            clickCb: function (date) {
                tb.innerHTML="";
                if(cardList[date]){
                    for(let i of cardList[date]){
                        const cardurl = `https://t.bilibili.com/${i[0]}?tab=2`
                        tb.innerHTML += `<tr><td><a href="${cardurl}" target="_blank">${i[1]}</a></td><td>${i[2]}</td></tr>`;
                    }
                }
            }
        });
        flag = false;
    });



    //工具函数
    //配置合并
    function extend(def, opt, override) {
        for (var k in opt) {
            if (opt.hasOwnProperty(k) && (!def.hasOwnProperty(k) || override)) {
                def[k] = opt[k]
            }
        }
        return def;
    }
    //日期格式化
    function concatDate(y, m, d) {
        var symbol = '-';
        if (m) {
            m = (m.toString())[1] ? m : '0' + m;
        }
        if (d) {
            d = (d.toString())[1] ? d : '0' + d;
        }

        return y + (m ? symbol + m : '') + (d ? symbol + d : '');
    }
    //得到时间戳
    function getTimeStamp(d) {

        var date = new Date(d);

        if (isNaN(date.getTime())) {
            console.error(d + ' is invalid date');
            return '';
        }

        return date.getTime();
    }

    //polyfill
    if (!Array.isArray) {
        Array.isArray = function (arg) {
            return Object.prototype.toString.call(arg) === '[object Array]';
        };
    }
    //过滤非日期,格式化日期
    function filterDate(arr) {

        if(!Array.isArray(arr)) {
            return [];
        }

        arr = arr || [];
        var dateArr = [];

        for (var i = 0; i < arr.length; i++) {

            var item = arr[i];
            var date = new Date(item);

            if (isNaN(date.getTime())) {
                console.error(item + ' is invalid date')
            } else {
                var y = date.getFullYear();
                var m = date.getMonth();
                var d = date.getDate();
                var dateStr = concatDate(y, m + 1, d);
                dateArr.push(dateStr);
            }
        }

        return dateArr;
    }


    function Schedule(opta) {
        var def = {},
            opt = extend(def, opta, true),
            curDate = opt.date ? new Date(opt.date) : new Date(),
            disabledDate = opt.disabledDate ? filterDate(opt.disabledDate) : [],
            selectedDate = opt.selectedDate ? filterDate(opt.selectedDate) : [],
            disabledBefore = opt.disabledBefore ? getTimeStamp(opt.disabledBefore) : '',
            disabledAfter = opt.disabledAfter ? getTimeStamp(opt.disabledAfter) : '',
            showToday = opt.showToday,
            year = curDate.getFullYear(),
            month = curDate.getMonth(),
            currentYear = curDate.getFullYear(),
            currentMonth = curDate.getMonth(),
            currentDay = curDate.getDate(),
            activeDate = '',
            el = document.querySelector(opt.el) || document.querySelector('body'),
            _this = this;
        var bindEvent = function () {
            el.addEventListener('click', function (e) {
                switch (e.target.id) {
                    case 'nextMonth':
                        _this.nextMonthFun();
                        break;
                    case 'nextYear':
                        _this.nextYearFun();
                        break;
                    case 'prevMonth':
                        _this.prevMonthFun();
                        break;
                    case 'prevYear':
                        _this.prevYearFun();
                        break;
                    case 'todayBtn':
                        _this.renderToday();
                        break;
                    default:
                        break;
                };
                if (e.target.className.indexOf('currentDate') > -1) {
                    activeDate = e.target.title;
                    opt.clickCb && opt.clickCb(activeDate);
                    render();
                }
            }, false)
        }
        var init = function () {
            var scheduleHd = '<div class="schedule-hd">' +
                '<div>' +
                '<span class="arrow icon iconfont icon-116leftarrowheads" id="prevYear" ></span>' +
                '<span class="arrow icon iconfont icon-112leftarrowhead" id="prevMonth"></span>' +
                '</div>' +
                '<div class="today"></div>' +
                '<div>' +
                '<span class="arrow icon iconfont icon-111arrowheadright" id="nextMonth"></span>' +
                '<span class="arrow icon iconfont icon-115rightarrowheads" id="nextYear"></span>' +
                '</div>' +
                '</div>'
            var scheduleWeek = '<ul class="week-ul ul-box">' +
                '<li>日</li>' +
                '<li>一</li>' +
                '<li>二</li>' +
                '<li>三</li>' +
                '<li>四</li>' +
                '<li>五</li>' +
                '<li>六</li>' +
                '</ul>'
            var scheduleBd = '<ul class="schedule-bd ul-box" ></ul>';
            var todayBtn = '<div id="todayBtn" class="today">今天</div>'
            el.innerHTML = scheduleHd + scheduleWeek + scheduleBd + (showToday ? todayBtn : '');
            bindEvent();
            render();
        }
        var render = function () {
            var fullDay = new Date(year, month + 1, 0).getDate(), //当月总天数
                startWeek = new Date(year, month, 1).getDay(), //当月第一天是周几
                total = (fullDay + startWeek) % 7 == 0 ? (fullDay + startWeek) : fullDay + startWeek + (7 - (fullDay + startWeek) % 7),//元素总个数
                lastMonthDay = new Date(year, month, 0).getDate(), //上月最后一天
                eleTemp = [];
            for (var i = 0; i < total; i++) {

                var nowDate = concatDate(year, month + 1, (i + 1 - startWeek));
                var nowTimestamp = new Date(nowDate).getTime();
                var isDisbale = disabledDate.indexOf(nowDate) > -1;
                var isSelected = selectedDate.indexOf(nowDate) > -1;

                if (i < startWeek) {

                    eleTemp.push('<li class="other-month"><span class="dayStyle">' + (lastMonthDay - startWeek + 1 + i) + '</span></li>')
                } else if (i < (startWeek + fullDay)) {

                    var addClass = '';
                    if (isDisbale) {
                        addClass = 'disabled'
                    } else {
                        isSelected && (addClass = 'selected-style');
                        activeDate == nowDate && (addClass = 'active-style');
                        concatDate(currentYear, currentMonth + 1, currentDay) == nowDate && (addClass = 'today-flag');
                    }

                    if (disabledBefore && nowTimestamp < disabledBefore) {
                        addClass = 'disabled'
                    }
                    if (disabledAfter && nowTimestamp > disabledAfter) {
                        addClass = 'disabled'
                    }

                    eleTemp.push('<li class="current-month" ><span title=' + nowDate + ' class="currentDate dayStyle ' + addClass + '">' + (i + 1 - startWeek) + '</span></li>')
                } else {

                    eleTemp.push('<li class="other-month"><span class="dayStyle">' + (i + 1 - (startWeek + fullDay)) + '</span></li>')
                }
            }
            el.querySelector('.schedule-bd').innerHTML = eleTemp.join('');
            el.querySelector('.today').innerHTML = concatDate(year, month + 1);
        };
        this.nextMonthFun = function () {
            if (month + 1 > 11) {
                year += 1;
                month = 0;
            } else {
                month += 1;
            }
            render();
            opt.nextMonthCb && opt.nextMonthCb(year, month + 1);
        };
        this.nextYearFun = function () {
            year += 1;
            render();
            opt.nextYeayCb && opt.nextYeayCb(year, month + 1);
        };
        this.prevMonthFun = function () {
            if (month - 1 < 0) {
                year -= 1;
                month = 11;
            } else {
                month -= 1;
            }
            render();
            opt.prevMonthCb && opt.prevMonthCb(year, month + 1);
        };
        this.prevYearFun = function () {
            year -= 1;
            render();
            opt.prevYearCb && opt.prevYearCb(year, month + 1);
        }
        this.renderToday = function () {
            if (year === currentYear && month === currentMonth) {
                return;
            }

            year = currentYear;
            month = currentMonth;
            render();
        }
        init();
    }
})();