Bilibili话题栏

来点真正有用的话题栏,不会真有人看话题排行吧(

// ==UserScript==
// @name         Bilibili话题栏
// @namespace    https://space.bilibili.com/475210
// @version      0.5
// @description  来点真正有用的话题栏,不会真有人看话题排行吧(
// @author       Xinrea
// @match        https://t.bilibili.com/
// @match        https://t.bilibili.com/?*
// @grant        none
// @license      MIT
// ==/UserScript==


function getCookie(cname)
{
  var name = cname + "=";
  var ca = document.cookie.split(';');
  for(var i=0; i<ca.length; i++)
  {
    var c = ca[i].trim();
    if (c.indexOf(name)==0) return c.substring(name.length,c.length);
  }
  return "";
}

function htmlToElements(html) {
    var template = document.createElement('template');
    template.innerHTML = html;
    return template.content.childNodes;
}

async function runWhenReady(readySelector) {
    return new Promise(resolve => {
        var numAttempts = 0;
        var tryNow = function() {
            var elem = document.querySelector(readySelector);
            if (elem) {
                resolve(elem);
            } else {
                numAttempts++;
                if (numAttempts >= 34) {
                    console.warn('Giving up after 34 attempts. Could not find: ' + readySelector);
                } else {
                    setTimeout(tryNow, 250 * Math.pow(1.1, numAttempts));
                }
            }
        };
        tryNow();
    });
}

function createTagItem(tag_name, description, url) {
    const template = `<div class="relevant-topic-container"><div class="relevant-topic-container__item"><div class="relevant-topic"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" class="relevant-topic__prefix"><path fill-rule="evenodd" clip-rule="evenodd" d="M11.4302 2.57458C11.4416 2.51023 11.4439 2.43974 11.4218 2.3528C11.3281 1.98196 10.9517 1.72037 10.5284 1.7527C10.432 1.76018 10.3599 1.78383 10.297 1.81376C10.2347 1.84398 10.1832 1.88155 10.1401 1.92465C10.1195 1.94485 10.1017 1.96692 10.0839 1.98897L10.0808 1.99289L10.0237 2.06277L9.91103 2.2033C9.76177 2.39141 9.61593 2.58191 9.47513 2.77556C9.33433 2.96936 9.19744 3.16585 9.06672 3.36638C9.00275 3.46491 8.93968 3.56401 8.87883 3.66461L8.56966 3.6613C8.00282 3.6574 7.43605 3.65952 6.86935 3.67034C6.80747 3.56778 6.74325 3.46677 6.67818 3.3664C6.54732 3.16585 6.41045 2.96934 6.26968 2.77568C6.12891 2.58186 5.98309 2.39134 5.83387 2.20322L5.72122 2.06268L5.66416 1.99279L5.6622 1.99036C5.64401 1.96783 5.62586 1.94535 5.60483 1.92454C5.56192 1.88144 5.51022 1.84388 5.44797 1.81364C5.38522 1.78386 5.31305 1.76006 5.21665 1.75273C4.80555 1.72085 4.4203 1.97094 4.32341 2.35273C4.30147 2.43968 4.30358 2.51018 4.31512 2.57453C4.32715 2.63859 4.34975 2.69546 4.38112 2.74649C4.39567 2.77075 4.41283 2.79315 4.42999 2.81557C4.43104 2.81694 4.43209 2.81831 4.43314 2.81968L4.48759 2.89122L4.59781 3.03355C4.74589 3.22242 4.89739 3.40905 5.05377 3.59254C5.09243 3.63788 5.13136 3.68306 5.17057 3.72785C4.99083 3.73681 4.81112 3.7467 4.63143 3.75756C4.41278 3.771 4.19397 3.78537 3.97547 3.80206L3.64757 3.82786L3.48362 3.84177L3.39157 3.85181C3.36984 3.8543 3.34834 3.8577 3.32679 3.86111C3.31761 3.86257 3.30843 3.86402 3.29921 3.86541C3.05406 3.90681 2.81526 3.98901 2.59645 4.10752C2.37765 4.22603 2.17867 4.38039 2.00992 4.56302C1.84117 4.74565 1.70247 4.95593 1.60144 5.18337C1.50025 5.4105 1.43687 5.65447 1.41362 5.90153C1.33103 6.77513 1.27663 7.6515 1.25742 8.5302C1.23758 9.40951 1.25835 10.2891 1.3098 11.1655C1.32266 11.3846 1.33738 11.6035 1.35396 11.8223L1.38046 12.1505L1.39472 12.3144L1.39658 12.335L1.39906 12.3583L1.40417 12.4048C1.40671 12.4305 1.41072 12.4558 1.41473 12.4811C1.41561 12.4866 1.41648 12.4922 1.41734 12.4977C1.45717 12.7449 1.53806 12.9859 1.65567 13.2074C1.77314 13.4289 1.92779 13.6304 2.11049 13.8022C2.29319 13.974 2.50441 14.1159 2.73329 14.2197C2.96201 14.3235 3.2084 14.3901 3.45836 14.4135C3.47066 14.415 3.48114 14.4159 3.49135 14.4167C3.49477 14.417 3.49817 14.4173 3.50159 14.4176L3.5425 14.4212L3.62448 14.4283L3.78843 14.4417L4.11633 14.4674C4.33514 14.4831 4.55379 14.4983 4.7726 14.5111C6.52291 14.6145 8.27492 14.6346 10.0263 14.5706C10.4642 14.5547 10.9019 14.5332 11.3396 14.5062C11.5584 14.4923 11.7772 14.4776 11.9959 14.4604L12.3239 14.434L12.4881 14.4196L12.5813 14.4093C12.6035 14.4065 12.6255 14.403 12.6474 14.3995C12.6565 14.3981 12.6655 14.3966 12.6746 14.3952C12.9226 14.3527 13.1635 14.2691 13.3844 14.1486C13.6052 14.0284 13.8059 13.8716 13.9759 13.6868C14.1463 13.5022 14.2861 13.2892 14.3874 13.0593C14.4381 12.9444 14.4793 12.8253 14.5108 12.7037C14.519 12.6734 14.5257 12.6428 14.5322 12.612L14.5421 12.566L14.55 12.5196C14.5556 12.4887 14.5607 12.4578 14.5641 12.4266C14.5681 12.3959 14.5723 12.363 14.5746 12.3373C14.6642 11.4637 14.7237 10.5864 14.7435 9.70617C14.764 8.825 14.7347 7.94337 14.6719 7.06715C14.6561 6.8479 14.6385 6.62896 14.6183 6.41033L14.5867 6.08246L14.5697 5.91853L14.5655 5.87758C14.5641 5.86445 14.5618 5.8473 14.5599 5.83231C14.5588 5.8242 14.5578 5.81609 14.5567 5.80797C14.5538 5.78514 14.5509 5.76229 14.5466 5.7396C14.5064 5.49301 14.4252 5.25275 14.3067 5.03242C14.1886 4.81208 14.0343 4.61153 13.8519 4.44095C13.6695 4.27038 13.4589 4.12993 13.2311 4.02733C13.0033 3.92458 12.7583 3.85907 12.5099 3.83636C12.4974 3.83492 12.4865 3.83394 12.4759 3.833C12.4729 3.83273 12.4698 3.83246 12.4668 3.83219L12.4258 3.82879L12.3438 3.82199L12.1798 3.80886L11.8516 3.78413C11.633 3.76915 11.4143 3.75478 11.1955 3.74288C10.993 3.73147 10.7904 3.72134 10.5878 3.71243L10.6914 3.59236C10.8479 3.40903 10.9992 3.22242 11.1473 3.03341L11.2576 2.89124L11.312 2.81971C11.3136 2.81773 11.3151 2.81575 11.3166 2.81377C11.3333 2.79197 11.3501 2.77013 11.3641 2.74653C11.3954 2.6955 11.418 2.63863 11.4302 2.57458ZM9.33039 5.49268C9.38381 5.16945 9.67705 4.95281 9.98536 5.00882L9.98871 5.00944C10.2991 5.06783 10.5063 5.37802 10.4524 5.70377L10.2398 6.99039L11.3846 6.9904C11.7245 6.9904 12 7.27925 12 7.63557C12 7.99188 11.7245 8.28073 11.3846 8.28073L10.0266 8.28059L9.7707 9.82911L11.0154 9.82913C11.3553 9.82913 11.6308 10.118 11.6308 10.4743C11.6308 10.8306 11.3553 11.1195 11.0154 11.1195L9.55737 11.1195L9.32807 12.5073C9.27465 12.8306 8.98141 13.0472 8.6731 12.9912L8.66975 12.9906C8.35937 12.9322 8.1522 12.622 8.20604 12.2962L8.40041 11.1195H6.89891L6.66961 12.5073C6.61619 12.8306 6.32295 13.0472 6.01464 12.9912L6.01129 12.9906C5.7009 12.9322 5.49374 12.622 5.54758 12.2962L5.74196 11.1195L4.61538 11.1195C4.27552 11.1195 4 10.8306 4 10.4743C4 10.118 4.27552 9.82913 4.61538 9.82913L5.95514 9.82911L6.21103 8.28059L4.98462 8.28073C4.64475 8.28073 4.36923 7.99188 4.36923 7.63557C4.36923 7.27925 4.64475 6.9904 4.98462 6.9904L6.42421 6.99039L6.67193 5.49268C6.72535 5.16945 7.01859 4.95281 7.3269 5.00882L7.33025 5.00944C7.64063 5.06783 7.8478 5.37802 7.79396 5.70377L7.58132 6.99039H9.08281L9.33039 5.49268ZM8.61374 9.82911L8.86963 8.28059H7.36813L7.11225 9.82911H8.61374Z" fill="currentColor"></path></svg> <div class="relevant-topic__title bili-ellipsis">${tag_name}</div> <div class="relevant-topic__exposed"><!----> <span class="bili-ellipsis">${description}</span></div></div></div></div>`;
    let newElement = htmlToElements(template)[0];
    newElement.addEventListener("click", ()=>{
        window.open(url, '_blank').focus();
    })
    return newElement;
}

(function() {
    'use strict';
    const mid = getCookie('DedeUserID');
    if (mid == "") {
        console.log("未登录");
        return;
    }

    async function getSubTopics() {
        let resp = await fetch("https://app.bilibili.com/x/topic/web/fav/list?page_size=100&page_num=1", {
            "referrerPolicy": "strict-origin-when-cross-origin",
            "body": null,
            "method": "GET",
            "mode": "cors",
            "credentials": "include"
        });
        resp = await resp.json();
        if (resp.code === 0) {
            let ret = [];
            let items = resp.data.topic_list.topic_items;
            if (items) {
                for (let i = 0; i < items.length; i++) {
                    let latest = await getTopicLatest(items[i].id);
                    ret.push({
                        name: items[i].name,
                        description: formatTopicDescription(latest),
                        url: items[i].jump_url,
                        timestamp: latest.dynamic_card_item.modules.module_author.pub_ts
                    });
                    await sleep(100);
                }
            }
            return ret;
        }
        return [];
    }

    async function getTopicLatest(topic_id) {
        let resp = await fetch(`https://app.bilibili.com/x/topic/web/details/cards?topic_id=${topic_id}&sort_by=3&offset=&page_size=1&source=Web`, {
            "referrerPolicy": "strict-origin-when-cross-origin",
            "body": null,
            "method": "GET",
            "mode": "cors",
            "credentials": "include"
        });
        resp = await resp.json();
        if (resp.code === 0) {
            return resp.data.topic_card_list.items[0];
        }
        return null;
    }
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    function formatTagDescription(latest) {
        let unit = "秒";
        let n = Math.floor(Date.now()/1000) - latest.desc.timestamp;
        if (n > 60) {
            n = Math.floor(n/60);
            unit = "分钟";
            if (n > 60) {
                n = Math.floor(n/60);
                unit = "小时";
                if (n > 24) {
                    n = Math.floor(n/24);
                    unit = "天";
                }
            }
        }
        return `${latest.desc.user_profile.info.uname} · ${n}${unit}前`;
    }
    function formatTopicDescription(latest) {
        let uname = "";
        let timestamp = null;
        switch(latest.topic_type) {
            case "DYNAMIC":
                uname = latest.dynamic_card_item.modules.module_author.name;
                timestamp =latest.dynamic_card_item.modules.module_author.pub_ts;
                break;
        }
        if (timestamp == null) return "";
        let unit = "秒";
        let n = Math.floor(Date.now()/1000) - timestamp;
        if (n > 60) {
            n = Math.floor(n/60);
            unit = "分钟";
            if (n > 60) {
                n = Math.floor(n/60);
                unit = "小时";
                if (n > 24) {
                    n = Math.floor(n/24);
                    unit = "天";
                }
            }
        }
        return `${uname} · ${n}${unit}前`;
    }
    async function main() {
        let e = await runWhenReady("#app > div.bili-dyn-home--member > aside.right > section.sticky > div > div");
        // Clean original items
        e.innerHTML = '<div class="topic-panel__nav"><span class="topic-panel__nav-title">关注的话题</span></div><div class="relevant-topic"><div class="relevant-topic__title">信息加载中</div></div>';
        let list = await getSubTopics();
        console.log(list);
        list.sort((a,b)=>{return b.timestamp - a.timestamp});
        e.removeChild(e.lastChild);
        for (let i = 0; i < list.length; i++) {
            let item = createTagItem(list[i].name, list[i].description, list[i].url);
            e.appendChild(item);
        }
    }
    main();
})();