qb-fix-bilibili

inQ_Beta wants to fix some of bilibili problem

目前為 2022-03-21 提交的版本,檢視 最新版本

// ==UserScript==
// @name        qb-fix-bilibili
// @description inQ_Beta wants to fix some of bilibili problem
// @namespace   no1xsyzy
// @match       https://*.bilibili.com/*
// @license     Apache License, Version 2.0 (Apache-2.0); https://opensource.org/licenses/Apache-2.0
// @version     0.0.6
// @author      inQ_Beta
// @grant       GM_addStyle
// ==/UserScript==
(function () {
    'use strict';

    const $ = (x) => document.querySelector(x);
    const $$ = (x) => Array.from(document.querySelectorAll(x));

    function launchObserver({ parentNode, selector, failCallback = null, successCallback = null, stopWhenSuccess = true, config = {
        childList: true,
        subtree: true,
    }, }) {
        // if parent node does not exist, use body instead
        if (!parentNode) {
            parentNode = document.body;
        }
        const observeFunc = () => {
            const selected = document.querySelector(selector);
            if (!selected) {
                if (failCallback) {
                    failCallback();
                }
                return;
            }
            if (stopWhenSuccess) {
                observer.disconnect();
            }
            if (successCallback) {
                successCallback(selected);
            }
        };
        const observer = new MutationObserver(observeFunc);
        observer.observe(parentNode, config);
    }

    function 关注栏尺寸 () {
      GM_addStyle(`.section-content-cntr{height:calc(100vh - 250px)!important;}`);

      launchObserver({
        selector: `.side-bar-popup-cntr.ts-dot-4`,
        successCallback: () => {
          const g = $`.side-bar-popup-cntr.ts-dot-4`;
          if (g.style.height !== '0px') {
            g.style.bottom = '75px';
            g.style.height = 'calc(100vh - 150px)';
            // g.style.height = "600px"
          }
          if ($(`.side-bar-popup-cntr.ts-dot-4 .ps`)) {
            setTimeout(() => $(`.side-bar-popup-cntr.ts-dot-4 .ps`).dispatchEvent(new Event('scroll')), 1000);
          }
        },
        stopWhenSuccess: false,
        config: {
          childList: true,
          subtree: true,
          attributes: true,
        },
      });
    }

    const makeTitle$1 = () =>
      `${($`#area-tags header img+div` || $`#area-tags header h2`).innerText} - 分区列表 - 哔哩哔哩直播`;
    const parentNode$3 = $`#area-tags`;
    const selector$3 = `header`;
    function 分区标题 () {
      launchObserver({
        parentNode: parentNode$3,
        selector: selector$3,
        successCallback: () => {
          document.title = makeTitle$1();
        },
        stopWhenSuccess: false,
      });

      document.title = makeTitle$1();
    }

    const TTL = 10 * 60 * 1000;
    function timedLRU1(func) {
        const cache = new Map();
        let time = [];
        let timeout = null;
        const cleanup = () => {
            if (timeout !== null) {
                clearTimeout(timeout);
            }
            const ts = new Date().getTime();
            const idx = time.findIndex(([a, t]) => t + TTL > ts);
            const drop = time.splice(idx);
            for (const [a] of drop) {
                cache.delete(a);
            }
            timeout = setTimeout(cleanup, 60 * 1000);
        };
        return (a1) => {
            const got = cache.get(a1);
            if (got !== undefined) {
                const ts = new Date().getTime();
                time = [[a1, ts], ...time.filter(([a, t]) => a !== a1)];
                cleanup();
                return got;
            }
            const val = func(a1);
            const ts = new Date().getTime();
            time = [[a1, ts], ...time];
            cache.set(a1, val);
            return val;
        };
    }

    const getCard = timedLRU1(async (uid) => {
        const json = await (await fetch(`https://api.bilibili.com/x/web-interface/card?mid=${uid}`, {
            // credentials: 'include',
            headers: {
                Accept: 'application/json',
            },
            method: 'GET',
            mode: 'cors',
        })).json();
        if (json.code === 0) {
            return json.data;
        }
        else {
            throw json.message;
        }
    });
    const getFansCount = async (uid) => {
        return (await getCard(uid)).card.fans;
    };
    const getSexTag = async (uid) => {
        const sex = (await getCard(uid)).card.sex;
        switch (sex) {
            case '男':
                return '♂';
            case '女':
                return '♀';
            default:
                return '〼';
        }
    };
    const getInfoByRoom = timedLRU1(async (roomid) => {
        const json = await (await fetch(`https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=${roomid}`, {
            // credentials: 'include',
            headers: {
                Accept: 'application/json',
            },
            method: 'GET',
            mode: 'cors',
        })).json();
        if (json.code === 0) {
            return json.data;
        }
        else {
            throw json.message;
        }
    });
    const getRoomFollowers = async (roomid) => {
        return (await getInfoByRoom(roomid)).anchor_info.relation_info.attention;
    };
    const followersTextClass = (followers) => {
        if (followers > 1e6) {
            return [`${Math.round(followers / 1e5) / 10}m★`, 'followers-m'];
        }
        else if (followers > 1e3) {
            return [`${Math.round(followers / 1e2) / 10}k★`, 'followers-k'];
        }
        else {
            return [`${followers}★`, ''];
        }
    };

    const parentNode$2 = $(`#area-tag-list`);
    const selector$2 = `a.Item_1EohdhbR`;
    GM_addStyle(`
.processed::after {
  content: attr(data-followers);
  color: white;
}
.processed.followers-m::before{
  color: purple;
}
.processed.followers-k::before{
  color: red;
}
`);
    function 分区添加粉丝数 () {
        launchObserver({
            parentNode: parentNode$2,
            selector: selector$2,
            successCallback: () => {
                for (const a of $$(`a.Item_1EohdhbR`)) {
                    (async () => {
                        const nametag = a.querySelector(`.Item_QAOnosoB`);
                        if (nametag.classList.contains('processed')) {
                            return;
                        }
                        const followers = await getRoomFollowers(a.pathname.slice(1));
                        let [txt, cls] = followersTextClass(followers);
                        nametag.dataset.followers = txt;
                        nametag.classList.add('processed');
                        nametag.classList.add(cls);
                    })();
                }
            },
            stopWhenSuccess: false,
        });
    }

    function 分区 () {
      关注栏尺寸();
      分区标题();
      分区添加粉丝数();
    }

    function liveStatus() {
      switch ($`.live-status`.innerText) {
        case '直播':
          return '▶️'
        case '闲置':
          return '⏹️'
        case '轮播':
          return '🔁'
        default:
          return `【${$`.live-status`.innerText}】`
      }
    }

    const liveTitle = () => $`.live-title`.innerText;
    const liveHost = () => $`.room-owner-username`.innerText;
    const makeTitle = () => `${liveStatus()} ${liveTitle()} - ${liveHost()} - 哔哩哔哩直播`;
    const parentNode$1 = $`#head-info-vm .left-header-area`;
    const selector$1 = `.live-title`;

    function 直播间标题 () {
      launchObserver({
        parentNode: parentNode$1,
        selector: selector$1,
        successCallback: () => {
          document.title = makeTitle();
        },
        stopWhenSuccess: false,
      });

      document.title = makeTitle();
    }

    function 通用表情框尺寸修复 () {
      GM_addStyle(`
#control-panel-ctnr-box > .border-box.top-left[style^="transform-origin: 249px "],
#control-panel-ctnr-box > .border-box.top-left[style^="transform-origin: 251px "]
{
  height: 700px
}
`);
    }

    const parentNode = $(`#chat-items`);
    const selector = `.user-name`;
    GM_addStyle(`.infoline::before{
  content: attr(data-infoline);
  color: white;
}
.infoline.followers-m::before{
  color: purple;
}
.infoline.followers-k::before{
  color: red;
}
`);
    const append = async (un) => {
        un.classList.add('infoline');
        const uid = un.parentNode.dataset.uid;
        const fans = await getFansCount(uid);
        const [txt, cls] = followersTextClass(fans);
        const sextag = await getSexTag(uid);
        un.dataset.infoline = `${sextag} ${txt} `;
        un.classList.add(cls);
    };
    function 直播间留言者显示粉丝数 () {
        launchObserver({
            parentNode,
            selector,
            successCallback: () => {
                for (const un of $$(`#chat-items .user-name`)) {
                    if (un.classList.contains('infoline')) {
                        continue;
                    }
                    append(un);
                }
            },
            stopWhenSuccess: false,
        });
    }

    function 动态井号标签 () {
        launchObserver({
            parentNode: document.body,
            selector: `a.dynamic-link-hover-bg`,
            successCallback: () => {
                for (let link of $$(`a.dynamic-link-hover-bg`)) {
                    // link: HTMLAnchorElement
                    if (/#.+#/.exec(link.innerHTML) && /https?:\/\/search.bilibili.com\/all\?.+/.exec(link.href)) {
                        link.href = `https://t.bilibili.com/topic/name/${/#(.+)#/.exec(link.innerHTML)[1]}/feed`;
                    }
                }
            },
            stopWhenSuccess: false,
        });
    }

    function 直播间 () {
      关注栏尺寸();
      直播间标题();
      直播间留言者显示粉丝数();
      通用表情框尺寸修复();
      动态井号标签();
    }

    function 直播主页 () {
      关注栏尺寸();
    }

    function 其他页面 () {
      动态井号标签();
    }

    if (location.pathname === '/') {
      直播主页();
    } else if (location.pathname === '/p/eden/area-tags') {
      分区();
    } else if (/^\/\d+$/.exec(location.pathname)) {
      直播间();
    } else {
      其他页面();
    }

})();