b站直播徽章切换增强

展示全部徽章,展示更多信息,更方便切换,可以自动切换徽章

スクリプトをインストール?
作者が勧める他のスクリプト

b站自动续牌も気に入るかもしれません。

スクリプトをインストール
このスクリプトの質問や評価の投稿はこちら通報はこちらへお寄せください。
// ==UserScript==
// @name         b站直播徽章切换增强
// @version      1.2.9
// @description  展示全部徽章,展示更多信息,更方便切换,可以自动切换徽章
// @author       Pronax
// @include      /https:\/\/live\.bilibili\.com\/(blanc\/)?\d+/
// @icon         http://bilibili.com/favicon.ico
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// @require      https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js
// @require      https://greasyfork.org/scripts/439903-blive-room-info-api/code/blive_room_info_api.js?version=1037039
// @namespace http://tampermonkey.net/
// ==/UserScript==

// ! csrf过期后调用原生徽章按钮不会刷新状态
// ! bug: 有一个最近获得的粉丝牌置顶,然后获取了新粉丝牌,且新粉丝牌为当前房间(最新获得被当前房间顶掉)

function main() {
    'use strict';

    // 设置是否支持使用拼音查找粉丝牌/ID
    // 为false时关闭此功能
    let pinyinSwitch = true;



    if (document.querySelector(".medal-section:not(.scripted)")) {
        let controlPanelCtnrBox = document.querySelector(".medal-section:not(.scripted)");
        let template = document.createElement("div");
        template.className = "medal-section scripted";
        template.innerHTML = `<span id="medal-selector" class="dp-i-block medal"><span class="action-item medal get-medal"></span></span>`;
        for (let key in controlPanelCtnrBox.dataset) {
            template.dataset[key] = controlPanelCtnrBox.dataset[key];
        }
        controlPanelCtnrBox.after(template);
        // controlPanelCtnrBox.classList.add("origin"); // 加了没用,这个元素每次聚焦都会消失
        controlPanelCtnrBox.style.display = "none";
    }

    // 活动直播间的CSS调整
    setTimeout(() => {
        let svgIconList = document.querySelectorAll('.svg-icon');
        for (let index = 0; index < svgIconList.length && index < 10; index++) {
            const element = svgIconList[index];
            if (element) {
                let computedStyle = getComputedStyle(element);
                let backgroundImage = computedStyle.getPropertyValue('background-image');
                // 普通页面用base64覆盖了http的,活动页面还是http
                if (backgroundImage && backgroundImage.includes("http")) {
                    GM_addStyle(".des>.svg-icon{background-position:0 -6em !important}.des>.svg-icon.checkbox-selected{background-position:0 -7em !important}");
                }
                break;
            }
        }
    }, 3000);
    // 加载动画
    GM_addStyle(".medal-loading{height:30px;color:#bbb;font-size:13px;display:flex;align-items:center;justify-content:center}.medal-loading>i.icon-link-world{font-size:12px;margin-left:5px;animation:medal-loading-rotate 2s infinite}.medal-loading>i.icon-info{margin-right:5px}@keyframes medal-loading-rotate{from{transform:rotate(45deg)}to{transform:rotate(405deg)}}");
    // body内的条目css
    GM_addStyle(".medal-list-move{transition:transform .5s!important}.medal-wear-body{height:335px;margin-top:5px;padding-right:2px;overflow:auto;scrollbar-width:thin}.medal-wear-body::-webkit-scrollbar{width:6px}.medal-wear-body::-webkit-scrollbar-thumb{background-color:#aaa}.medal-item-content{display:flex;justify-content:space-between}.medal-wear-body .medal-item{padding:5px 5px 3px;background:0;border:1px solid transparent;border-radius:5px;width:calc(100% - 12px);text-align:left;transition:border,background .2s}.medal-wear-body .medal-item:hover{border:1px solid #d7d7d7;background-color:#f5f5f5}.medal-item .face,.medal-item .search-user-avatar{width:auto;height:35px;margin-right:5px;padding:1px;position:relative;transition:filter .3s}.medal-item .face:hover,.medal-item .search-user-avatar:hover{filter:drop-shadow(0px 0 3px #fb7299);cursor:alias}.medal-item .face>img{height:35px;border-radius:50%}.medal-wear-body .medal-item .name{color:#666;position:relative;max-width:calc(100% - 78px);font-size:14px;line-height:18px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:pointer}.medal-wear-body .medal-item .name:hover{color:#00aeec}.medal-wear-body .medal-item .living-gif{background-image:url(//s1.hdslb.com/bfs/static/blive/live-fansmedal-wall/static/img/icon-online.fd4254c1.gif);background-size:cover;width:16px;height:16px;transform:rotateY(180deg)}.medal-item .wear-icon{background-color:#fb7299;padding:0 2px;color:#fff;height:16px;border:1px solid #fb7299;border-radius:4px;line-height:16px;font-size:14px}.medal-item .room-icon{padding:0 2px;color:#fea249;height:16px;border:1px solid #fea249;border-radius:4px;line-height:16px;font-size:14px}.medal-item .content-icon{padding:0 2px;color:#40bf55;height:16px;border:1px solid #40bf55;border-radius:4px;line-height:16px;font-size:14px}.medal-wear-body .medal-item .text{color:#888;position:relative;line-height:18px;font-size:14px}.medal-wear-body .medal-item .left{color:#2cbce7;line-height:18px;font-size:14px;margin-right:5px}.medal-item-content .medal-content-head{height:18px}.medal-item-content .medal-content-footer{height:18px;padding-top:1px;width:100%}.medal-wear-body .medal-item .progress-level-div{margin-top:3px;width:100%;text-align:center;display:flex;justify-content:space-between;font-size:13px}.medal-wear-body .medal-item .progress-level-div .level-span-left{text-align:right!important}.medal-wear-body .medal-item .progress-level-div .level-span{width:33px;color:#999;padding-top:1px}.medal-wear-body .medal-item .progress-level-div .progress-div{line-height:16px;height:14px;width:70%;background-color:#e2e8ec;border-radius:2px;margin:0 2px;position:relative;overflow:hidden}.medal-wear-body .medal-item .progress-level-div .progress-div-cover{position:absolute;left:0;top:0;overflow:hidden;background-color:#23ade5}.medal-wear-body .medal-item .progress-level-div .progress-div .progress-num-span{color:#23ade5}.medal-wear-body .medal-item .progress-level-div .progress-div-cover .progress-num-span-cover{width:174px;position:relative;z-index:1000;color:#fff}.medal-item.outdated{opacity:.5;filter:grayscale(0.5);}");
    // 面板css
    GM_addStyle(".chat-input-ctnr .medal-section{position:static;display:flex;align-items:center;justify-content:center;flex-shrink:0;padding:0 12px;min-width:70px;height:56px;border-right:1px solid #e9eaec;box-sizing:border-box}.medal-section .action-item.medal.get-medal,.medal-section .action-item.medal.wear-medal{width:41px;height:24px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFYAAAAyCAMAAADx7dyJAAAA51BMVEUAAACampqZmZmampqZmZmampqampqZmZmdnZ2oqKiamprU1NSZmZmZmZmZmZmvr6+ampqampqamprIyMiZmZmampqampqZmZmZmZmampqenp6cnJyfn5+ampqbm5uampqenp7Q0NDOzs6ampqamprPz8/Ozs6ampqbm5vMzMyZmZmZmZnNzc2bm5ubm5uZmZmampqcnJyampqampqampqampqamprNzc2amprU1NTU1NTU1NSamprV1dXS0tLR0dHT09PU1NTT09PW1tbS0tLMzMzt7e2ZmZnj4+PPz8/V1dXo6OjZ2dk1f/nUAAAARXRSTlMA49Zr8zV1SzkGgKukj4UL+q5iA97uw1mpiSAbDupeQRX6eLPNPBnIT+bm0rI9JsFlLdmWm41G+buqn35xMBHr2r5WRCgCpQL/AAADqUlEQVRYw7TS226qQBiG4Q8cUAg7hbHIRo1Y0epCa2vbA0/Jf/93tBhApYqJK3G9yT+QQJ4ME/D/et2s8qe12rxW6ix/crNyr/n3bIGntZh952K/G6E/s1m+AbDKF3hqi3wFIM9xlariqoGCOx19iEK/i8kUIiG2spKE32lxmhmNXiBy7aKExKplpE75PPo3tkudHnnyKbIgGtO5TkA6vpzEbWOVXlUc9+o0lBnOtEd/cIpVbDAumpNYM8Giw5Q2ltF1AUQ2S3DLupqoT+UloFGxhprbwh7VKs7Vuqj+2hfBGm9lcs0a1JL1+NnaHimC3ZnmnJumVbOTTjNKy4vyOKtTxQIw5cbZhvq5CLyPqkfZgDntrELG4SDJh0NCIfZDYGJMb9mweyqOz7ch4DujitUZc4ix9MIugyDtB8GuYIcyoFMLu6OWdrBJfanYkXfcxsdEvrCMc8fhnBWsz4GfNW7ZbFA1lzmX54OqDLBcwU5IGQ3FIagNVgG2BrCkUOzUZeb9s+1SV5KWjoJLgl1ScMt6+z1j+71EoXhnQsu7bMC3kCRs1/ZvtkP2NRtNJuu0Gg3vNPh0pvdYLXXeBZuxxP3F6gxnlluof1xvXYxc/q6xwfu4x5o0gGCxpE+3yX54F1YaQWR5nsOq6QCGQ1932MigT1QsLErsBttPL6xnoouyYVKOaEweEGotrOKR4Z5YjGgeXFjJr1ldxvojIgWR7/uxVMxbcRNhRx+A7rnXrKs64smZhUVsd2LfaVyysS79YNvPKELUbxQFjGIbvoxr1qS/tdZvS8JQFMfxHy2SFNxqJJUau6ggCdnSxDacf093d/P9v56Gd7Gcyx2ofZ8Jh88D72Ecy8BPFk+XspmyV9I5sFa/NcN0NOzqR+sPk0d+dwBnZBnWg/08PWHdvotjFm6rnbLjPmB2kj9B/764Aczbluw9wja6l3XnTRqoy7mccT81mr2vIyllMZdDoG31Dgg6zTt38gpgIsf2GbZWw1EvhoOOXutrHGojycF3JnR6ETL2fyOq6Pyo6Fiq6LSr5hCt8GzOWgiKPnOFRA3kahCF+bmIxAI6tvoXNyhWPwC2G+C0Dalilesq2hRthiIVFqhMN1SkCvd0sCSK4rzKc+OIaDlAYbYv0tnstRiunhW+jd8K1sksS9VuNrsOcC6fVJypPDdW5KOkFe0zlefuaYWydoriTOW4MakdSvNIaZXrKvJQnilIq1yXhAlGW6E8sPOU2IKXjeL4w19GXEgqF0Zf/gAAAABJRU5ErkJggg==)}.medal-section .action-item.medal{background-size:cover;border:0}.medal-section .action-item{display:inline-block;margin:0 2px;font-size:12px;color:#fff;line-height:14px;text-align:center;border-radius:2px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.dialog-ctnr.medal{z-index:999;padding:10px 14px 10px 16px;position:absolute}.medal-ctnr{width:268px}.medal-wear-component>.title{font-weight:400;font-size:18px;margin:0;color:#23ade5;line-height:20px}.medal-search{width:160px;margin-left:10px;position:relative;line-height:20px;top:-1px;font-size:14px;font-weight:100;border:0;padding:0;color:var(--Pi4)}.medal-search::placeholder{color:#dcdcdc}.des{cursor:pointer;color:#666;height:20px;display:flex;align-items:center}.des>.svg-icon{width:14px;height:14px;font-size:14px;background-position:0-8em;margin-right:5px}.des>span.pointer{line-height:14px}.des>.svg-icon.checkbox-selected{background-position:0-9em}.qs-icon{width:14px;height:14px;background-size:100%;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAYAAAByDd+UAAAAAXNSR0IArs4c6QAAA79JREFUSA29lk1IVFEYhpsZf0AwDDc5RlJBYepK+rHQFhUutaCdiyL8w5JWkijlIjNISBrTUYha2MZAjBZRmEERGa1CSwqysrSVCw2DGNGe93LP5TreOzOL8MC55zvf+37fe/7uuTewJYXS0NBQvLa2Vk0th54fCATCCqM/TzNH/xV1NBqNTsmfqAQSgfX19VUk7YRTRMIp7KfYs9gSkqCEd9KvxC7G/oDdNjAw8Ei4V/EUrKurU5IhkhwmaIDaMzg4+MUrgfERswf7ErWe2Alia4iZNbhpNwiyfEchj1CnIZ1PJmQSmdYWvotoIfU0y/zaYGrXCdpiz/HfQ7AZsZib3NLSkr24uKhZl5Asd3V19XMoFJro7+//5OYhmk4/Aucs9bhb1BG0l/EdxBH2oNGdQDb7WcEgHmDuoC6T6Df97bSr9O9kZ2e3dnd3L2M7hZxR8FPwDpjlDRoUYAj7o2ZmfKZtbGw8gX8cznwwGCwJh8NbGVReVlbWNjg3qU1LS0u3Dd/VXiRu2s5tua0Z2qfxIZ7C+D0bHh4OjY2NvRc7MzOzNBKJ/LUiXQ9mEqF7IS0t7WBfX59WySlgOkwSPaPTa82QUXTiiMaLKWp8fFzvXhEz6/ISE4cyqAd7ekituyincktD/iAjKKFVwh430dgkKZJNO2F88W1OTs43+Ui6Kx5T385dpAskiHoVvklO2owXmVMo/w327bsXLh8nd59aBD05yo2OLo7qNB7ldHSDeBbITwBUfQs52gBjGRkZj/1IcKRRrj3Mp264EfwC4/0cuOv4qhl0d29v79d43PTBNft8LWmYat2NBky1Zf+7GHkr8RFebs3St0hDWs576Mv0ARC7CnSZ2slxbybZmg91nVt7qNlZn5t1SIIOy1gGfIXYWxz79gRUB4IblpZmOIdR4CCpGbXELEFNSUwpbY057aE+npWp6TisI1hvmN0fx5PEkIa0JDiKejH35e4kMW74J523bkciW7mlIS2Lx55MUr0u30R5UsaUWxoKMKe0nRE02Bdt0kRwA0lJNkE5lZvrzXptnEBG8BJA37aT7E3ML2FTU9PeWCz2AnyG6+5YR0eHYjwLYuks4zPAEK9OhUhmhjpFNYD6LUi4tCsrK6XE6TUqW1hYyFUSv2Ln2q/chuPMUA7ziwHhPt2LXjO1R10L/oNRe96dNkcDP4eo9y8GoFU29SfKiDLCzftNNKJqOUj6Vl5jifUOWT/CtLr1fwmn5IEV4LN+hMXB165fCQv1eKzbQw/cculLTeL/8qv/D4FH4W+V11VGAAAAAElFTkSuQmCC);cursor:pointer;position:relative;top:1px}.link-radio-button-ctnr{display:inline-block;cursor:default;vertical-align:middle;font-size:0}.footer-line{position:relative;left:-16px;width:300px;border-top:1px solid #f0f0f0;margin-top:3px}.medal-wear-footer{margin-top:10px;font-size:14px;color:#23ade5;justify-content:space-between}.medal-wear-footer>*{cursor:pointer}.medal-wear-footer a{color:#23ade5}.medal-wear-footer .right-span{float:right}.medal-wear-footer .arrow-box{width:10px;height:10px;font-size:10px;position:relative;top:2px}");
    // 直播中 头像动画
    GM_addStyle(".search-user-avatar.avatar-small .avatar-wrap{transform:scale(.8)}.search-user-avatar .avatar-wrap{width:100%;height:35px}.medal-item .bili-avatar{display:block;position:relative;background-image:url(data:image/gif;base64,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);background-size:cover;border-radius:50%;margin:0;padding:0;width:35px;height:35px}.medal-item .bili-avatar .bili-avatar-img{border:1px solid var(--line_light)}.medal-item .bili-avatar-img-radius{border-radius:50%}.medal-item .bili-avatar-img{border:0;display:block;-o-object-fit:cover;object-fit:cover;image-rendering:-webkit-optimize-contrast}.medal-item .bili-avatar-face{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);-moz-transform:translate(-50%,-50%);-ms-transform:translate(-50%,-50%);-o-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:100%;height:100%}.medal-item .bili-avatar *{margin:0;padding:0}.medal-item .bili-avatar-right-icon{width:27.5%;height:27.5%;position:absolute;z-index:2;right:0;bottom:-1px;background-size:cover;image-rendering:-webkit-optimize-contrast;background-image:url(data:image/png;base64,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)}.search-user-avatar .avatar-wrap.live-ani .a-cycle{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:35px;height:35px;border:1px solid #f69;border-radius:50%;z-index:1;opacity:0;animation:scaleUpCircle 1.5s linear;animation-iteration-count:infinite}.search-user-avatar .avatar-wrap.live-ani .a-cycle-1{animation-delay:0s}.search-user-avatar .avatar-wrap.live-ani .a-cycle-2{animation-delay:.5s}.search-user-avatar .avatar-wrap.live-ani .a-cycle-3{animation-delay:1s}@keyframes scaleUpCircle{0%{transform:translate(-50%,-50%) scale(1);opacity:1}100%{transform:translate(-50%,-50%) scale(1.5);opacity:0}}");
    // 旧的粉丝牌样式
    GM_addStyle(".old-style.fans-medal-item{border:1px solid #fff;border-radius:2px;padding:0;height:16px}.old-style .fans-medal-label{height:100%;border-radius:0;padding:0 3px}.old-style .fans-medal-label .fans-medal-content{transform:none}.old-style .fans-medal-level{width:17px;height:14px;border-radius:0}");
    // 调用原始按钮更新粉丝牌,暂时隐藏弹窗的css
    GM_addStyle(".panel-hide .medalAb{display:none}");

    // 公用对象
    let pinyinPro = undefined;
    let my_id = document.cookie.match(/DedeUserID=(\d*); /)[1];
    let originMedalSelectorDebounce = null;
    let pinyin = pinyinSwitch;
    // 默认粉丝牌UID   如果拥有该用户的粉丝牌会在退出直播间时切换到这个粉丝牌
    // 废弃功能,不要用
    let defaultMedalUid = false;

    new Vue({
        el: '#medel_switch_box',
        async created() {
            let json = await this.getFansMedalInfo();
            let assignMedal = true;
            if (this.autoSwitch && json.has_fans_medal) {
                assignMedal = false;
                this.switchBadge(json.my_fans_medal.medal_id);
            }
            this.refreshMedalList(1, assignMedal);
            if (pinyin) {
                fetch("https://unpkg.com/pinyin-pro@3.13.0/dist/index.js")
                    .then(res => res.text(), err => { })
                    .then(js => {
                        if (!js) { console.warn("徽章切换增强-启动拼音组件失败"); return; }
                        try {
                            js = js.replace("pinyinPro", "biliSwitchBoostPinyinPro");
                            eval(js);
                            pinyinPro = window.biliSwitchBoostPinyinPro;
                            Reflect.deleteProperty(window, 'biliSwitchBoostPinyinPro');
                            this.backUpMedalWall.forEach(item => {
                                // 用户名
                                item.anchor_info.nick_pinyin = pinyinPro.pinyin(item.anchor_info.nick_name, { toneType: 'none', nonZh: 'consecutive', v: true }).replaceAll(" ", "").toLowerCase();
                                // 粉丝牌
                                item.medal.medal_pinyin = pinyinPro.pinyin(item.medal.medal_name, { toneType: 'none', nonZh: 'consecutive', v: true }).replaceAll(" ", "").toLowerCase();
                            });
                        } catch (error) {
                            console.warn("徽章切换增强-启动拼音组件错误", error);
                        }
                    });
            }
        },
        mounted: function () {
            document.querySelector("#medal-selector").onclick = () => {
                this.togglePanel();
            };
            // 如果有默认粉丝牌,则退出直播间时换上默认粉丝牌
            if (defaultMedalUid) {
                this.getFansMedalInfo(defaultMedalUid, (json, context) => {
                    if (json.has_fans_medal == false) { return; }
                    let index = this.medalWallIndex.indexOf(json.my_fans_medal.medal_id);
                    window.addEventListener('beforeunload', () => {
                        context.switchBadge(json.my_fans_medal.medal_id, index);
                    });
                });
            }
            window.addEventListener('click', e => {
                if (e.target.closest(".medal") == null && this.panelStatus) {
                    this.panelStatus = false;
                    document.querySelector(".medal-wear-body").scrollTop = 0;
                }
            });
            window.addEventListener('blur', () => { this.isTabBlur = true; });
            window.addEventListener('focus', this.refreshScriptInfo);
            // // 鼠标移动到礼物栏、弹幕输入区域时进行自动切换
            // let initMouseEventDeadLine = Date.now() + 15000;
            // (function initMouseEvent(vueInstance) {
            //     let giftDom = document.querySelector("#gift-control-vm .gift-panel");
            //     let inputDom = document.querySelector("#control-panel-ctnr-box");
            //     if (giftDom && inputDom) {
            //         giftDom.onmouseenter = inputDom.onmouseenter = () => {
            //             // console.log("徽章更换检测1", vueInstance.isTabBlur);
            //             if (vueInstance.isTabBlur) {
            //                 vueInstance.refreshScriptInfo();
            //             }
            //             // console.log("徽章更换检测2", vueInstance.isTabBlur);
            //             let cRoomMedal = vueInstance.fansMedalInfo.my_fans_medal.medal_id;
            //             if (vueInstance.autoSwitch && vueInstance.needSwitch && cRoomMedal != 0) {
            //                 // console.log("徽章触发更换");
            //                 vueInstance.switchBadge(cRoomMedal, vueInstance.medalWallIndex.indexOf(cRoomMedal));
            //                 vueInstance.needSwitch = false;
            //             }
            //         };
            //     } else if (Date.now() < initMouseEventDeadLine) {
            //         requestIdleCallback(() => {
            //             initMouseEvent();
            //         }, { timeout: 3000 });
            //     } else {
            //         console.log("切换模块初始化失败");
            //     }
            // })(this);
            this.$refs.medalList.$el.addEventListener('scroll', () => {
                let medalList = this.$refs.medalList.$el;
                let baseline = medalList.scrollHeight - medalList.offsetHeight;
                // 滚动条到最后10%的时候开始加载下一页
                if (this.pageInfo.isLastPage == false && this.pageInfo.loading == false && medalList.scrollTop > baseline - baseline * .1) {
                    this.pageInfo.loading = true;
                    this.refreshMedalList(this.pageInfo.cPage + 1);
                }
            }, false);
        },
        computed: {
            medalWallIndex: function () {
                let indexList = [];
                this.medalWall.forEach(item => {
                    indexList.push(item.medal.medal_id);
                });
                return indexList;
            },
            backUpMedalWallIndex: function () {
                let indexList = [];
                this.backUpMedalWall.forEach(item => {
                    indexList.push(item.medal.medal_id);
                });
                return indexList;
            }
        },
        data() {
            return {
                name: Date.now().toString(16) + "-" + btoa(location.host),
                fansMedalInfo: {
                    "has_fans_medal": false,
                    "my_fans_medal": {
                        "target_id": 0,
                        "medal_id": 0
                    }
                },
                currentlyWearing: {
                    medal: {
                        medal_id: 0
                    }
                },
                recentAward: {
                    medal: {
                        medal_id: 0
                    }
                },
                autoSwitch: false,
                // b站自己做了自动切换功能,所以我就不做了,这里改一下默认值防止有些人开着然后永远关不了了
                // autoSwitch: GM_getValue(`autoSwitch-${my_id}`, false),
                needSwitch: false,
                panelStatus: false,
                pageInfo: {
                    loading: false,
                    cPage: 1,
                    isLastPage: true
                },
                /* 
                    本来是用于展示的,但是牌子多加载需要翻页的情况显示的全是脏数据 
                    现在仅用于缓存存在的牌子提速自动换牌的速度
                */
                backUpMedalWall: GM_getValue(`medalWall-${my_id}`, []),
                medalWall: [],
                debounce: {},
                search: "",
                label: "",
                isTabBlur: false,   // 标识网页是否失焦
            }
        },
        watch: {
            currentlyWearing: {
                handler(val, oldVal) {
                    // 持久化用于从其他tab取出信息
                    GM_setValue(`currentlyWearing-${my_id}`, val);
                    clearTimeout(originMedalSelectorDebounce);
                    this.refreshMedal();
                    /* 
                        新旧ID相同的情况下也刷新牌子显示,因为牌子的数据可能会有变化
                        但是牌子相同的情况下不需要调用网页刷新
                    */
                    if (oldVal && val.medal.medal_id == oldVal.medal.medal_id) {
                        return;
                    }
                    // 借用原始徽章按钮来刷新当前页面上的徽章缓存
                    // 用于其他原版消息发送时展示最新的牌子(比如发表情弹幕)
                    originMedalSelectorDebounce = setTimeout(() => {
                        let originMedelBtn = document.querySelector(".medal-section:not(.scripted)>span");
                        let medelPanelParent = document.querySelector(".control-panel-ctnr-new");
                        if (!originMedelBtn || !medelPanelParent) {
                            console.log("徽章刷新失败-找不到原版按钮");
                            return;
                        }
                        originMedelBtn.click();
                        medelPanelParent.classList.add("panel-hide");
                        // 检测窗口
                        let deadLine = Date.now() + 1000;
                        let interval = setInterval(() => {
                            if (Date.now() > deadLine) {
                                clearInterval(interval);
                                medelPanelParent.classList.remove("panel-hide");
                                console.log("徽章刷新失败-无法抓取到原版徽章页面");
                            }
                            // 弹出后,点击展示设置
                            let originMedelBox = document.querySelector(".medalAb");
                            if (originMedelBox) {
                                clearInterval(interval);
                                originMedelBox.dispatchEvent(new Event('mouseleave'));
                                // 立刻执行会闪一下,观感很不好
                                setTimeout(() => { medelPanelParent.classList.remove("panel-hide"); }, 500);
                            }
                        }, 100);
                    }, 1000);
                },
                immediate: false
            },
            autoSwitch(val) {
                GM_setValue(`autoSwitch-${my_id}`, val);
                if (val) {
                    let cRoomMedal = this.fansMedalInfo.my_fans_medal.medal_id;
                    if (cRoomMedal != 0) {
                        this.switchBadge(cRoomMedal, this.medalWallIndex.indexOf(cRoomMedal));
                        this.needSwitch = false;
                    }
                }
            },
            search(val) {
                clearTimeout(this.debounce["search"]);
                let vm = this;
                this.debounce["search"] = setTimeout(function () {
                    if (val) {
                        val = val.toLowerCase().trim();
                        vm.medalWall = vm.backUpMedalWall.filter((item) => {
                            if (item.medal.medal_name.toLowerCase().includes(val) || item.anchor_info.nick_name.toLowerCase().includes(val)) {
                                item.score = 2;
                                return true;
                            }
                            if (!pinyinPro) { return false; }
                            if (item.medal.medal_pinyin.includes(val) || item.anchor_info.nick_pinyin.includes(val)) {
                                item.score = 1;
                                return true;
                            }
                            return false;
                        });
                        vm.medalWall.sort(vm.sort);
                        vm.pageInfo.isLastPage = true;
                    } else {
                        vm.medalWall = vm.backUpMedalWall.slice(0, 50);
                        vm.pageInfo.isLastPage = vm.backUpMedalWall.length < 50;
                    }
                }, 200);
            }
        },
        methods: {
            /* 将10进制数字转为16进制字符串,不足6位时自动补充 */
            padToHex(str) {
                return str.toString(16).padStart(6, 0);
            },
            async sleep(ms) {
                return new Promise(r => {
                    setTimeout(() => {
                        r(true);
                    }, ms);
                });
            },
            async getCurrentWear() {    // 获取当前佩戴粉丝牌
                let res = await fetch(`https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/panel?page=1&page_size=1`, { credentials: 'include', });
                let json = await res.json();
                if (json.code == json.message) {
                    for (const item of json.data.special_list) {
                        if (item.superscript == null) {
                            this.currentlyWearing = item;
                            break;
                        }
                    }
                    return;
                }
                warn("获取当前佩戴失败:", json.message);
            },
            async getFansMedalInfo(uid, callback) {  // 用来获取是否拥有指定用户的粉丝牌
                let muid = undefined;
                if (!uid) {
                    muid = uid = await ROOM_INFO_API.getUid();
                }
                let res = await fetch(`https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/fans_medal_info?target_id=${uid}`, { credentials: 'include', });
                let json = await res.json();
                if (json.code == json.message) {
                    // 仅在获取当前房间信息时赋值
                    if (muid == uid) {
                        this.fansMedalInfo = json.data;
                    }
                    if (callback) {
                        // 存在回调的情况下异步执行
                        (async () => {
                            callback(json.data, this);
                        })();
                    }
                    return json.data;
                }
                alert("徽章初始化失败:", json.message);
            },
            async refreshMedalList(page = 1, assignMedal = true) {
                let uid = await ROOM_INFO_API.getUid();
                return new Promise((resolve, reject) => {
                    fetch(`https://api.live.bilibili.com/xlive/app-ucenter/v1/fansMedal/panel?page=${page}&page_size=50&target_id=${uid}`, { credentials: 'include', })
                        .then(res => res.json())
                        .then(json => {
                            if (json.code == json.message) {
                                /* 
                                    刷新当前佩戴的徽章
                                    special_list的内容不会超过3条,所以两次循环无所谓
                                */
                                if (page == 1 && assignMedal) {     // 只有第一页special_list才会有值
                                    // 防止在其他地方取消牌子后插件无反应
                                    this.currentlyWearing = { medal: { medal_id: 0 } };
                                }
                                for (let item of json.data.special_list) {
                                    // 抓取当前佩戴
                                    // 2023年7月26日 item.medal.wearing_status不总是准确的
                                    if (assignMedal && item.medal.wearing_status) {
                                        this.currentlyWearing = item;
                                        continue;
                                    }
                                    // 抓取最近获取
                                    if (item.superscript && item.superscript.type == 2) {
                                        this.recentAward = item;
                                        continue;
                                    }
                                }

                                if (page == 1) {
                                    this.label = Math.floor(Math.random() * 2 ** 32);
                                }
                                // 合并列表并排序
                                let list = [].concat(json.data.list, json.data.special_list);
                                list.forEach((item) => {
                                    // 添加标识
                                    item.label = this.label;
                                    // 解析拼音
                                    if (pinyinPro) {
                                        // 用户名
                                        item.anchor_info.nick_pinyin = pinyinPro.pinyin(item.anchor_info.nick_name, { toneType: 'none', nonZh: 'consecutive', v: true }).replaceAll(" ", "").toLowerCase();
                                        // 粉丝牌
                                        item.medal.medal_pinyin = pinyinPro.pinyin(item.medal.medal_name, { toneType: 'none', nonZh: 'consecutive', v: true }).replaceAll(" ", "").toLowerCase();
                                    }
                                    let index = this.medalWallIndex.indexOf(item.medal.medal_id);
                                    if (index >= 0) {
                                        this.$set(this.medalWall, index, item);
                                    } else {
                                        this.medalWall.push(item);
                                    }
                                    // backUpMedalWall
                                    index = this.backUpMedalWallIndex.indexOf(item.medal.medal_id);
                                    item.superscript = null;    // 防止搜索出现脏数据
                                    if (index >= 0) {
                                        this.$set(this.backUpMedalWall, index, item);
                                    } else {
                                        this.backUpMedalWall.push(item);
                                    }
                                });
                                this.medalWall.sort(this.sort);
                                this.backUpMedalWall.sort(this.sort);
                                // 保存页面数据
                                this.pageInfo.loading = false;
                                this.pageInfo.cPage = +json.data.page_info.current_page;
                                this.pageInfo.isLastPage = page >= json.data.page_info.total_page;
                                // 获取完整列表后替换旧列表
                                if (this.pageInfo.isLastPage) {
                                    this.backUpMedalWall = this.medalWall;
                                }
                                GM_setValue(`medalWall-${my_id}`, this.backUpMedalWall);
                                // 返回是否有下一页
                                resolve(json.data.page_info.has_more && page < json.data.page_info.total_page);
                            } else {
                                reject(false);
                            }
                        })
                        .catch(err => {
                            reject();
                        });
                });
            },
            async switchBadge(badgeId, index) {
                let jct = document.cookie.match(/bili_jct=(\w*); /)[1]
                let params = new URLSearchParams();
                params.set("medal_id", badgeId);
                params.set("csrf_token", jct);
                params.set("csrf", jct);
                fetch("https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/wear", {
                    credentials: 'include',
                    method: 'POST',
                    body: params
                });
                // .then(res => res.json())
                // .then(json => {
                //     if (json.code == 0) {
                //     }
                // });
                if (index >= 0) {
                    this.currentlyWearing = this.medalWall[index];
                } else {
                    let result = this.backUpMedalWall.find(item => {
                        return badgeId == item.medal.medal_id;
                    });
                    if (result) {
                        this.currentlyWearing = result;
                    } else {
                        console.warn("徽章列表内找不到对应的徽章");
                        await this.getCurrentWear();
                    }
                }
                // 佩戴时更新为最新状态
                // todo 现有接口不能更新 头像、直播状态
                // if (this.currentlyWearing.label != this.label) {
                //     this.getFansMedalInfo(this.currentlyWearing.medal.target_id, (data) => {
                //         this.medalWall[index].label = this.label;
                //         this.$set(this.medalWall[index], "medal", data.my_fans_medal);
                //     });
                // }
                // 仅主动切换才保存操作人
                GM_setValue(`operator-${my_id}`, this.name);
            },
            takeOff() {
                this.currentlyWearing = { medal: { medal_id: 0 } };
                let jct = document.cookie.match(/bili_jct=(\w*); /)[1]
                let params = new URLSearchParams();
                params.set("visit_id", '');
                params.set("csrf_token", jct);
                params.set("csrf", jct);
                fetch("https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/take_off", {
                    "method": "POST",
                    "credentials": "include",
                    "body": params,
                });
                // 仅主动切换才保存操作人
                GM_setValue(`operator-${my_id}`, this.name);
            },
            openConfig() {
                // 点击原版
                let originMedelBtn = document.querySelector(".medal-section:not(.scripted)>span");
                if (!originMedelBtn) {
                    console.log("展示设置打开失败-找不到原版按钮");
                    return;
                }
                originMedelBtn.click();
                // 检测窗口
                let deadLine = Date.now() + 1000;
                let interval = setInterval(() => {
                    if (Date.now() > deadLine) {
                        clearInterval(interval);
                        console.log("展示设置打开失败-无法抓取到原版徽章页面");
                    }
                    // 弹出后,点击展示设置
                    let originMedelBox = document.querySelector(".medalAb");
                    if (originMedelBox) {
                        clearInterval(interval);
                        let configBtn = document.querySelector(".medalAb .cancel-wear");
                        if (configBtn) {
                            configBtn.click();
                        } else {
                            console.log("展示设置打开失败-找不到设置按钮");
                        }
                    }
                }, 100);
            },
            openSpace: (uid) => {
                window.open(`//space.bilibili.com/${uid}`);
            },
            openRoom: (rid) => {
                window.open(`//live.bilibili.com/${rid}`);
            },
            togglePanel() {
                clearTimeout(this.debounce["panel"]);
                this.panelStatus = !this.panelStatus;
                if (!this.panelStatus) {
                    this.debounce["panel"] = setTimeout(() => {
                        this.debounce["panel"] = null;
                        // 临时处理,防止第二次打开后未翻页脏数据
                        this.medalWall = this.backUpMedalWall.slice(0, 50);
                        this.search = "";
                    }, 2000);
                } else {
                    if (this.debounce["panel"]) { return; }
                    // 刷新本房间粉丝牌状态
                    if (this.fansMedalInfo.has_fans_medal == false) {
                        this.getFansMedalInfo();
                    }
                    this.$nextTick(() => {
                        // 只能在nexttick里面不然元素处于display:none时无法起作用
                        document.querySelector(".medal-wear-body").scrollTop = 0;
                        this.refreshMedalList();
                    });
                }
            },
            refreshMedal() {
                let selector = document.querySelector("#medal-selector");
                if (this.currentlyWearing.medal.medal_id != 0) {
                    selector.innerHTML = `
                        <div class="v-middle fans-medal-item none-select old-style medal-item-margin"
                            style="border-color:#${this.padToHex(this.currentlyWearing.medal.medal_color_border)}">
                            <div class="fans-medal-label"
                                style="background-image:linear-gradient(45deg,#${this.padToHex(this.currentlyWearing.medal.medal_color_start)},#${this.padToHex(this.currentlyWearing.medal.medal_color_end)})">
                                <span class="fans-medal-content">${this.currentlyWearing.medal.medal_name}</span>
                            </div>
                            <div class="fans-medal-level" style="color:#${this.padToHex(this.currentlyWearing.medal.medal_color_start)}">${this.currentlyWearing.medal.level}</div>
                        </div>
                    `;
                } else {
                    selector.innerHTML = `<span class="action-item medal get-medal"></span>`;
                }
            },
            sort(a, b) {
                // 搜索匹配度
                // if (this.search && (a.score || b.score) && a.score != b.score) {
                //     return a.score > b.score ? -1 : 1;
                // }
                // 当前房间
                if (a.medal.target_id == this.fansMedalInfo.my_fans_medal.target_id) {
                    return -1;
                } else if (b.medal.target_id == this.fansMedalInfo.my_fans_medal.target_id) {
                    return 1;
                }
                // 当前佩戴 
                if (a.medal.medal_id == this.currentlyWearing.medal.medal_id) {
                    return -1;
                } else if (b.medal.medal_id == this.currentlyWearing.medal.medal_id) {
                    return 1;
                }
                // 最近获得、其他特殊情况
                if (a.medal.medal_id == this.recentAward.medal.medal_id) {
                    return -1;
                } else if (b.medal.medal_id == this.recentAward.medal.medal_id) {
                    return 1;
                }
                // 如果不是此次获取的牌子,向后靠
                if (a.label != this.label) {
                    return 1;
                } else if (b.label != this.label) {
                    return -1;
                }
                // 灰色牌子
                if (a.medal.is_lighted == 0) {
                    return 1;
                } else if (b.medal.is_lighted == 0) {
                    return -1;
                }
                // 等级排序
                if (a.medal.level != b.medal.level) {
                    return b.medal.level - a.medal.level;
                }
                // 经验排序
                return b.medal.intimacy - a.medal.intimacy;
            },
            refreshScriptInfo(event) {
                // console.log("插件状态更新", this.isTabBlur);
                this.isTabBlur = false;
                // 获取最新状态
                // this.autoSwitch = GM_getValue(`autoSwitch-${my_id}`, false);
                // 如果当前页面展示的粉丝牌不是实际佩戴的粉丝牌,那么更新显示
                let wearing = GM_getValue(`currentlyWearing-${my_id}`);
                if (wearing && this.currentlyWearing.medal.medal_id != wearing.medal.medal_id) {
                    this.currentlyWearing = wearing;
                }
                if (wearing && this.name != GM_getValue(`operator-${my_id}`) && this.fansMedalInfo.my_fans_medal.medal_id != wearing.medal.medal_id) {
                    this.needSwitch = true;
                } else {
                    this.needSwitch = false;
                }
            }
        },
        template: `
            <div class="border-box dialog-ctnr common-popup-wrap medal a-scale-in" v-show="panelStatus" @mouseleave="togglePanel">
                <div class="medal-ctnr none-select">
                    <div class="medal-wear-component">
                        <h1 class="dp-i-block title">
                            粉丝牌
                        </h1>
                        <a href="http://link.bilibili.com/p/help/index#/audience-fans-medal" target="_blank"
                            class="dp-i-block qs-icon"></a>
                        <input class="medal-search" placeholder="搜索粉丝牌" v-model="search">
                        <div class="dp-i-block des f-right" @click="autoSwitch = !autoSwitch" style="display:none">
                            <span class="cb-icon svg-icon v-middle" :class="{'checkbox-selected':autoSwitch}"></span>
                            <span class="pointer v-middle">自动更换</span>
                        </div>
                        <transition-group name="medal-list" tag="div" class="medal-wear-body" ref="medalList">
                            <div class="medal-item" v-for="(item,index) in medalWall" :class="{ outdated: item.label != label }"
                                :key="item.medal.medal_id" :data-uid="item.medal.target_id" :data-rid="item.room_info.room_id" 
                                :data-uname="item.anchor_info.nick_name.toLowerCase()" :data-mname="item.medal.medal_name.toLowerCase()"
                                @click="currentlyWearing.medal.medal_id == item.medal.medal_id ? takeOff() : switchBadge(item.medal.medal_id,index)">
                                <div class="medal-item-content">
                                    <template v-if="item.room_info.living_status == 1">
                                        <a :href="'//live.bilibili.com/' + item.room_info.room_id" target="blank" @click.stop="" class="search-user-avatar p_relative avatar-small mr_md cs_pointer">
                                            <div class="avatar-wrap p_relative live-ani">
                                                <div class="avatar-inner">
                                                    <div class="bili-avatar" style="width: 35px;height:35px;">
                                                        <img class="bili-avatar-img bili-avatar-face bili-avatar-img-radius"
                                                            :src="item.anchor_info.avatar">
                                                        <span class="bili-avatar-right-icon"
                                                            v-if="item.anchor_info.verify == 0"></span>
                                                    </div>
                                                </div>
                                                <div class="a-cycle a-cycle-1"></div>
                                                <div class="a-cycle a-cycle-2"></div>
                                                <div class="a-cycle a-cycle-3"></div>
                                            </div>
                                        </a>
                                    </template>
                                    <template v-else>
                                        <a :href="'//live.bilibili.com/' + item.room_info.room_id" target="blank" class="face" @click.stop="">
                                            <img :src="item.anchor_info.avatar">
                                            <span class="bili-avatar-right-icon" v-if="item.anchor_info.verify == 0"></span>
                                        </a>
                                    </template>
                                    <div class="dp-i-block v-bottom w-100 p-relative">
                                        <div class="medal-content-head">
                                            <div class="fans-medal-item none-select old-style f-right"
                                                :style="'border-color:#'+(padToHex(item.medal.medal_color_border))">
                                                <div class="fans-medal-label"
                                                    :style="'background-image:linear-gradient(45deg,#'+(padToHex(item.medal.medal_color_start))+',#'+(padToHex(item.medal.medal_color_end))+')'">
                                                    <span class="fans-medal-content">{{item.medal.medal_name}}</span>
                                                </div>
                                                <div class="fans-medal-level"
                                                    :style="'color:#'+(padToHex(item.medal.medal_color_start))">
                                                    {{item.medal.level}}
                                                </div>
                                            </div>
                                            <a :href="'//space.bilibili.com/' + item.medal.target_id" target="blank" @click.stop="" class="name dp-i-block">{{item.anchor_info.nick_name}}</a>
                                        </div>
                                        <div class="medal-content-footer">
                                            <transition enter-active-class="a-scale-in" leave-active-class="a-scale-out"
                                                mode="out-in">
                                                <div class="wear-icon dp-i-block" :key="'wear'"
                                                    v-if="item.medal.medal_id == currentlyWearing.medal.medal_id">
                                                    佩戴中
                                                </div>
                                                <div class="room-icon dp-i-block" :key="'room'"
                                                    v-else-if="item.medal.medal_id == fansMedalInfo.my_fans_medal.medal_id">
                                                    当前房间
                                                </div>
                                                <div class="content-icon dp-i-block" :key="'content'"
                                                    v-else-if="item.medal.medal_id == recentAward.medal.medal_id">
                                                    最近获得
                                                    <!-- {{item.superscript.content}} -->
                                                </div>
                                            </transition>
                                            <span class="text f-right dp-i-block">{{item.medal.today_feed}}/{{item.medal.day_limit}}</span>
                                            <span v-if="false" class="left f-right dp-i-block">{{item.medal.next_intimacy - item.medal.intimacy}}</span>
                                        </div>
                                    </div>
                                </div>
                                <div class="progress-level-div">
                                    <span class="dp-i-block level-span">Lv.{{item.medal.level}}</span>
                                    <div class="dp-i-block progress-div">
                                        <span
                                            class="dp-i-block progress-num-span">{{item.medal.intimacy}}/{{item.medal.next_intimacy}}</span>
                                        <div class="dp-i-block progress-div-cover"
                                            :style="'width:'+(item.medal.intimacy / item.medal.next_intimacy * 100) + '%'">
                                            <span class="dp-i-block progress-num-span-cover">
                                                {{item.medal.intimacy}}/{{item.medal.next_intimacy}}
                                            </span>
                                        </div>
                                    </div>
                                    <span class="dp-i-block level-span">Lv.{{item.medal.level + 1}}</span>
                                </div>
                            </div>
                            <div class="medal-loading" key="medal-loading">
                                <template v-if="!pageInfo.isLastPage">
                                    正在加载<i class="v-middle icon-font icon-link-world"></i>
                                </template>
                                <template v-else>
                                    <i class="v-middle icon-font icon-info"></i>没有了
                                </template>
                            </div>
                        </transition-group>
                        <div class="footer-line"></div>
                        <div class="dp-flex medal-wear-footer">
                            <span class="dp-i-block cancel-wear" @click="takeOff">
                                不佩戴勋章
                            </span>
                            <span class="dp-i-block display-config" @click="openConfig">
                                展示设置
                            </span>
                            <a href="https://link.bilibili.com/p/center/index#/user-center/wearing-center/my-medal" target="_blank"
                                class="dp-i-block right-span">
                                装扮中心
                                <span class="dp-i-block icon-font icon-arrow-right arrow-box"></span>
                            </a>
                        </div>
                    </div>
                </div>
            </div>
        `,
    });

}

function spinInit(loadHook, timeout) {
    return new Promise((resolve, reject) => {
        let startTime = Date.now();
        let checkInterval = setInterval(() => {
            if (Date.now() - startTime >= timeout) {
                clearInterval(checkInterval);
                reject("徽章切换增强-无法找到加载点");
            }
            // console.log(`徽章切换增强-正在寻找加载点`);
            let hooked = false;
            for (const prop in loadHook) {
                // console.log(`徽章切换增强-加载点[${prop}]`);
                if (typeof loadHook[prop] === 'function') {
                    hooked = loadHook[prop]();
                    if (hooked) {
                        console.log(`徽章切换增强-加载成功[${prop}]`);
                        clearInterval(checkInterval);
                        resolve();
                        break;
                    }
                }
            }
        }, 300);
    });
}

if (!document.cookie.match(/bili_jct=(\w*); /)) { return; } // 未登录就撤

spinInit({
    ">0.0.1": function () {  // 旧版锚点
        let bottomBox = document.querySelector(".bottom-actions");
        if (bottomBox) {
            // 列表元素
            let tempElement = document.createElement("div");
            tempElement.id = "medel_switch_box";
            bottomBox.after(tempElement);
            // 旧版适用的插件粉丝牌框框CSS
            GM_addStyle(".dialog-ctnr.medal{bottom:100px;left:-1px}");
            return true;
        }
        return false;
    },
    ">1.2.8": function () {  // B站新版前端(SC和点赞独立大按钮)锚点
        let bottomBox = document.querySelector(".icon-left-part-new");
        if (bottomBox) {
            // 列表元素
            let tempElement = document.createElement("div");
            tempElement.id = "medel_switch_box";
            bottomBox.after(tempElement);
            // 原版的按钮CSS调整
            GM_addStyle(".medalAb .close{display:none}.medal-section:not(.scripted){display:none !important;}.chat-input-ctnr-new .medal-section{padding: 5px !important;}.chat-input-focus .medal-section{display:none !important}");
            GM_addStyle(".dialog-ctnr.medal{bottom:-20px;left:-8px}");  // 插件粉丝牌框框CSS
            return true;
        }
        return false;
    }
}, 7000)
    .then((result) => main());