提供同传弹幕过滤,快速切换牌子,自动切换直播清晰度等功能
// ==UserScript== // @name Bilibili直播间助手 // @namespace http://tampermonkey.net/ // @version 1.0.9.3 // @description 提供同传弹幕过滤,快速切换牌子,自动切换直播清晰度等功能 // @author QingMu_ // @match *://live.bilibili.com/* // @require https://greasyfork.org/scripts/417560-bliveproxy/code/bliveproxy.js?version=984333 // @require https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js // @grant none // @license GPL License // ==/UserScript== (function () { 'use strict'; function main() { initCss(); waitDoucment(MedalComponent); waitDoucment(FilterSettingComponent); waitDoucment(FilterBoxComponent) // 防休眠 setInterval(() => { setTimeout(() => { document.body.dispatchEvent( new Event("mousemove", { bubbles: true }) ); }, Math.random() * 2000); }, 10000); } const toast = { line: 0, withConsole: false, init(msg) { let box = document.createElement("div"); box.innerText = msg; box.style.setProperty("position", "fixed"); box.style.setProperty("padding", "12px 24px"); box.style.setProperty("font-size", "14px"); box.style.setProperty("border-radius", "10px"); box.style.setProperty("color", "#fff"); box.style.setProperty("z-index", "999999"); box.style.setProperty("max-width", "70%"); box.style.setProperty("word-wrap", "break-word"); setTimeout(function () { let num = document.querySelectorAll(".animate-toast").length; if (num <= 1) { toast.line = 0; } document.body.removeChild(box); }, 3000); document.body.appendChild(box); return box; }, success(msg, x, y) { let box = this.init(msg); let px = x ? x + "px" : (document.body.clientWidth - box.clientWidth - 10) + "px"; let py = y ? y + "px" : this.line + 10 + "px"; this.line += box.clientHeight + 5; box.className = "animate-toast"; box.style.setProperty("background-color", "#47D279"); box.style.setProperty( "box-shadow", "0.1em 0.1em .1em rgba(71, 210, 121, .2)" ); box.style.setProperty("left", px); box.style.setProperty("top", py); if (toast.withConsole) console.log(msg); }, error(msg, x, y) { let box = this.init(msg); let px = x ? x + "px" : (document.body.clientWidth - box.clientWidth - 10) + "px"; let py = y ? y + "px" : this.line + 10 + "px"; this.line += box.clientHeight + 5; box.className = "animate-toast"; box.style.setProperty("background-color", "#F04742"); box.style.setProperty( "box-shadow", "0.1em 0.1em .1em rgba(240, 71, 66, .2)" ); box.style.setProperty("left", px); box.style.setProperty("top", py); if (toast.withConsole) console.error(msg); }, warning(msg, x, y) { let box = this.init(msg); let px = x ? x + "px" : (document.body.clientWidth - box.clientWidth - 10) + "px"; let py = y ? y + "px" : this.line + 10 + "px"; this.line += box.clientHeight + 5; box.className = "animate-toast"; box.style.setProperty("background-color", "#EFA957"); box.style.setProperty( "box-shadow", "0.1em 0.1em .1em rgba(239, 169, 87, .2)" ); box.style.setProperty("left", px); box.style.setProperty("top", py); if (toast.withConsole) console.warn(msg); }, info(msg, x, y) { let box = this.init(msg); let px = x ? x + "px" : (document.body.clientWidth - box.clientWidth - 10) + "px"; let py = y ? y + "px" : this.line + 10 + "px"; this.line += box.clientHeight + 5; box.className = "animate-toast"; box.style.setProperty("background-color", "#48bbf8"); box.style.setProperty( "box-shadow", "0.1em 0.1em .1em rgba(72, 187, 248, .2)" ); box.style.setProperty("left", px); box.style.setProperty("top", py); if (toast.withConsole) console.log(msg); }, }; function waitDoucment(domOperate, timeout = 1 * 1000) { function wait() { try { domOperate(); } catch (e) { setTimeout(wait, timeout); } } wait(); } function initCss() { let css = ` /* 屏蔽原来的按钮与弹窗 */ .medal-section { display: none !important; } .dialog-ctnr.medal { display: none !important; } #shop-popover-vm { display: none !important; } /* toast 动画 */ .animate-toast { animation: dropIn 0.5s, hidden 3.1s; } @keyframes dropIn { from { transform: translateY(20px); } to { transform: translateY(0px); } } @keyframes hidden { 0%, 75% { opacity: 1; } 100% { opacity: 0; } } @keyframes scale-in-ease { 0% { transform: scale(0); } 50% { transform: scale(1.1); } 100% { transform: scale(1); } } @keyframes scale-out { from { opacity: 1; transform: scale(1); } to { opacity: 0; transform: scale(0.8); } } /* 按钮样式 */ .bilitools-button { position: relative; box-sizing: border-box; line-height: 1; margin: 0; padding: 6px 12px; border: 0; background-color: transparent; cursor: pointer; outline: 0; overflow: hidden; display: inline-flex; justify-content: center; align-items: center; background-color: #23ade5; color: #fff; border-radius: 4px; } .bilitools-button.bleak { background-color: #909399; } .bilitools-button.disable { cursor: not-allowed; background-color: #e9eaec; color: #b4b4b4; } .bilitools-medal-button:hover { background-color: #39b5e7; } .bilitools-medal-button:active { background-color: #21a4d9; } /* 复选框样式 */ .bilitools-switch { -webkit-appearance: none; -moz-appearance: none; appearance: none; text-align: center; position: relative; width: 26px; height: 14px; border: 1px solid #dfdfdf; outline: 0; border-radius: 16px; box-sizing: border-box; background: #cccccc; cursor: pointer; margin: 0 5px; } .bilitools-switch:active, .bilitools-switch:visited { outline: none; } .bilitools-switch:before { content: attr(data-off); position: absolute; top: 0; left: 0; padding-left: 24px; border-radius: 15px; background-color: #cccccc; color: #fff; } .bilitools-switch:after { content: " "; position: absolute; top: -3px; left: -3px; width: 17px; height: 17px; border-radius: 15px; background-color: #ffffff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); transition: transform 0.3s; } .bilitools-switch:checked { border-color: #23ade5; background-color: #23ade5; } .bilitools-switch:checked:before { content: attr(data-on); padding-left: 0px; background-color: #23ade5; color: #fff; width: 31px; } .bilitools-switch:checked::after { transform: translateX(12px); } /* 模态框 */ .bilitools-medal-modal-bg { width: 100%; height: 100%; position: fixed; overflow: hidden; z-index: 9999999; top: 0; left: 0; display: flex; justify-content: center; align-items: center; background-color: rgba(0, 0, 0, 0.06); } .bilitools-medal-modal-box { width: 45%; height: 60%; min-width: 700px; padding: 1rem; background-color: #fff; color: rgb(75, 85, 99); border-radius: 0.25rem; box-shadow: 0 6px 12px 0 rgba(106, 115, 133, 0.22); } .bilitools-medal-modal-box-header { display: flex; justify-content: space-between; } .bilitools-medal-modal-box-header span { font-size: 18px; line-height: 24px; } .bilitools-close { color: #cfcfcf; font-size: 18px; line-height: 24px; cursor: pointer; outline: none; border: none; background-color: #fff; } .bilitools-close:hover { color: #23ade5; } .bilitools-medal-modal-box-body { display: block; height: calc(100% - 24px); } /* 牌子相关 布局 */ .bilitools-medal-setting { display: flex; flex-wrap: wrap; text-align: left; font-size: 12px; } .setting-full { width: 100%; margin: 2px 0; } .setting-half { margin: 2px 0; width: 50%; } #bilitools-havent { background-color: #fff; border: 2px solid #e9ebef; color: #77787c; border-radius: 4px; padding: 4px; font-size: 14px; } #bilitools-search { border: 2px solid #e9ebef; color: #77787c; border-radius: 4px; padding: 5px; font-size: 14px; outline: none; width: 70%; } #bilitools-havent option { color: #000; font-size: 12px; } #bilitools-havent:hover, #bilitools-search:hover { border: 2px solid #c7cbd2; } #bilitools-havent:focus, #bilitools-search:focus { border: 2px solid #87c2ff; } /* 展示区域 */ .bilitools-medal-table { margin-top: 10px; font-size: 14px; } .bilitools-medal-table table { border-collapse: separate; border-spacing: 0px 5px; width: 100%; height: 100%; } .bilitools-medal-table-body { display: block; overflow: hidden auto; height: 100px; } .bilitools-medal-table-row, .bilitools-medal-table-header { display: table; table-layout: fixed; width: 100%; } .bilitools-medal-table-row:hover { background-color: #f5f7fa; } .bilitools-liver-name a { color: #409eff; text-decoration: none; } .bilitools-liver-name, .bilitools-medal-name, .bilitools-medal-level, .bilitools-medal-exp, .bilitools-medal-exp-limit, .bilitools-medal-operate { text-align: left; padding: 10px; user-select: none; } .bilitools-liver-name.sort::after, .bilitools-medal-name.sort::after, .bilitools-medal-level.sort::after, .bilitools-medal-exp.sort::after, .bilitools-medal-exp-limit.sort::after { content: ">"; display: inline-block; color: inherit; margin-left: 5px; font-weight: 900; transform: rotate(90deg); } .active.positive::after, .active.positive::after, .active.positive::after, .active.positive::after, .active.positive::after { content: ">"; display: inline-block; color: #409eff; margin-left: 5px; font-weight: 900; transform: rotate(90deg); } .active.reverse::after, .active.reverse::after, .active.reverse::after, .active.reverse::after, .active.limit.reverse::after { content: ">"; display: inline-block; color: #409eff; margin-left: 5px; font-weight: 900; transform: rotate(-90deg); } .bilitools-medal-operate::after { content: none !important; } .bilitools-medal-status { display: inline-block; border: 1px solid; border-radius: 4px; padding: 4px; color: #fff; } /* 弹幕过滤相关 */ .bilitools-icons { display: inline-block; position: relative; vertical-align: top; fill: #c8c8c8; margin: 0 5px; font-size: 0; color: #c8c8c8; } .bilitools-icons svg { width: 22px; height: 22px; } .bilitools-icons:hover { color: #23ade5; fill: #23ade5; } .bilitools-icons.active { color: #23ade5; fill: #23ade5; } .bilitools-arrow::after { content: ""; position: absolute; display: inline-block; z-index: 9999; width: 0; height: 0; top: 100%; left: 20%; border-left: 4px solid transparent; border-right: 4px solid transparent; border-top: 8px solid #fff; } .bilitools-dialog { position: absolute; z-index: 699; padding: 16px; font-size: 14px; box-sizing: border-box; background: #fff; border: 1px solid #e9eaec; border-radius: 8px; box-shadow: 0 6px 12px 0 rgba(106, 115, 133, 0.22); color: rgb(75, 85, 99); word-break: keep-all; left: -210%; } .animate-scale-in-ease { animation: scale-in-ease cubic-bezier(0.22, 0.58, 0.12, 0.98) 0.4s; } .animate-scale-out { animation: scale-out cubic-bezier(0.22, 0.58, 0.12, 0.98) 0.4s; } .bilitools-dialog-title { font-weight: 400; font-size: 18px; color: #23ade5; } .bilitools-dialog input[type="text"] { border: 2px solid #e9ebef; color: #77787c; border-radius: 4px; padding: 3px; font-size: 14px; outline: none; width: 100px; margin: 0 5px; } .bilitools-dialog input[type="text"]:hover { border: 2px solid #c7cbd2; } .bilitools-dialog input[type="text"]:focus { border: 2px solid #87c2ff; } .bilitools-dialog-row { display: flex; justify-content: space-between; align-items: center; margin-top: 8px; position: relative; flex-wrap: wrap; } .bliltools-scroll { width: 100%; height: 100px; overflow: hidden auto; } .bilitools-dragable { position: absolute; user-select: none; cursor: move; z-index:9999; pointer-events: all; } .bilitools-filterBox { height: 2rem; max-width: 60rem; background-color: rgba(0, 0, 0, 0.6); border-radius: 4px; padding: 10px; overflow: hidden scroll; line-height: 2rem; color: #fff; scrollbar-width: none; word-break: keep-all; } .bilitools-filterBox::-webkit-scrollbar { display: none; } .bilitools-filterBox p { margin: 0 5px; font-size: 18px; } .bilitools-filterBox.multiline { height: 6rem; text-align: left; } /* 修复模态框层级问题 */ #aside-area-vm{ z-index:999; } `; let styleElement = document.createElement("style"); styleElement.innerText = css; document.head.appendChild(styleElement); } function MedalComponent() { window.loadMedalConfig = function () { return { medalConfig: { wore: "", searchText: "", searchList: [], autoWear: { enable: false, remember: 0 }, sortType: { sorted: 0, uname: true, medalName: true, level: true, exp: true, limit: true }, list: [], modalAnimate: false }, medalBox: false, openMedalBox() { this.getWore().then(res => { this.medalConfig.wore = res.length == 0 ? "" : res.medal_name; }) this.updateMedalList(); this.modalAnimate = true; this.medalBox = true; }, closeMedalBox() { this.modalAnimate = false; setTimeout(() => { this.medalConfig.sortType.sorted = 0; this.medalConfig.searchText = ""; this.medalConfig.searchList = []; this.medalConfig.list = []; this.medalBox = false; }, 400) }, initComponent() { this.readSetting().then((config)=>{ if (config.enable){ document.querySelector(".chat-input-ctnr textarea").addEventListener("click",(e)=>{ this.autoWear() }) } }); // 初始化检查牌子 this.getWore().then(res => { this.medalConfig.wore = res.length == 0 ? "" : res.medal_name; }) }, // 太菜了 css解决不了表格溢出 先这么用着 computedHeight() { let bodyBox = this.$refs.bodyBox; let setting = this.$refs.setting; let tableHeader = this.$refs.tableHeader; return bodyBox.offsetHeight - setting.offsetHeight - tableHeader.offsetHeight; }, search() { this.medalConfig.searchList = []; for (let item of this.medalConfig.list) { if ( item.uname .toLocaleLowerCase() .indexOf(this.medalConfig.searchText.trim().toLocaleLowerCase()) !== -1 || item.medal_name .toLocaleLowerCase() .indexOf(this.medalConfig.searchText.trim().toLocaleLowerCase()) !== -1 ) { this.medalConfig.searchList.push(item); } } }, sort(col) { this.medalConfig.sortType.sorted = col; switch (col) { case 1: { if (this.medalConfig.sortType.uname) { this.medalConfig.list.sort(function (a, b) { return a.uname.localeCompare(b.uname, "zh"); }); } else { this.medalConfig.list.reverse(); } this.medalConfig.sortType.medalName = true; this.medalConfig.sortType.level = true; this.medalConfig.sortType.exp = true; this.medalConfig.sortType.limit = true; this.medalConfig.sortType.uname = !this.medalConfig.sortType.uname; break; } case 2: { if (this.medalConfig.sortType.medalName) { this.medalConfig.list.sort(function (a, b) { return a.medalName.localeCompare(b.medalName, "zh"); }); } else { this.medalConfig.list.reverse(); } this.medalConfig.sortType.uname = true; this.medalConfig.sortType.level = true; this.medalConfig.sortType.exp = true; this.medalConfig.sortType.limit = true; this.medalConfig.sortType.medalName = !this.medalConfig.sortType.medalName; break; } case 3: { if (this.medalConfig.sortType.level) { this.medalConfig.list.sort(function (a, b) { return a.level - b.level; }); } else { this.medalConfig.list.reverse(); } this.medalConfig.sortType.uname = true; this.medalConfig.sortType.medalName = true; this.medalConfig.sortType.exp = true; this.medalConfig.sortType.limit = true; this.medalConfig.sortType.level = !this.medalConfig.sortType.level; break; } case 4: { if (this.medalConfig.sortType.exp) { this.medalConfig.list.sort(function (a, b) { return a.intimacy - b.intimacy; }); } else { this.medalConfig.list.reverse(); } this.medalConfig.sortType.uname = true; this.medalConfig.sortType.medalName = true; this.medalConfig.sortType.level = true; this.medalConfig.sortType.limit = true; this.medalConfig.sortType.exp = !this.medalConfig.sortType.exp; break; } case 5: { if (this.medalConfig.sortType.limit) { this.medalConfig.list.sort(function (a, b) { return a.today_intimacy - b.today_intimacy; }); } else { this.medalConfig.list.reverse(); } this.medalConfig.sortType.uname = true; this.medalConfig.sortType.medalName = true; this.medalConfig.sortType.level = true; this.medalConfig.sortType.exp = true; this.medalConfig.sortType.limit = !this.medalConfig.sortType.limit; break; } } }, topping(arrays) { let wore = []; let room_medal = []; let medals = []; for (let item of arrays) { if (item.medal_name == this.medalConfig.wore) { wore.push(item) } else if (item.roomid == window.BilibiliLive.SHORT_ROOMID || item.roomid == window.BilibiliLive.ROOMID) { room_medal.push(item) } else { medals.push(item); } } medals.sort((a, b) => b.level - a.level); medals.sort((a, b) => b.is_lighted - a.is_lighted); return [...wore, ...room_medal, ...medals]; }, sortedStyle(col) { let isActive = this.medalConfig.sortType.sorted == col ? 'active ' : ' '; let sortType = ""; switch (col) { case 1: { sortType = this.medalConfig.sortType.uname ? 'positive' : 'reverse'; break; } case 2: { sortType = this.medalConfig.sortType.medalName ? 'positive' : 'reverse'; break; } case 3: { sortType = this.medalConfig.sortType.level ? 'positive' : 'reverse'; break; } case 4: { sortType = this.medalConfig.sortType.exp ? 'positive' : 'reverse'; break; } case 5: { sortType = this.medalConfig.sortType.limit ? 'positive' : 'reverse'; break; } } return (isActive + sortType).trim(); }, updateMedalList() { let tasks = []; let tmp_array = []; if (this.medalConfig.list.length == 0) { this.getMedalPage(1).then(res => { tmp_array = res.data.items; console.log(res.data) for (let page = 2; page <= res.data.page_info.total_page; page++) { tasks.push(this.getMedalPage(page)) } Promise.all(tasks).then(res => { for (const item of res) { Array.prototype.push.apply(tmp_array, item.data.items); } }).then(() => { this.medalConfig.list = this.topping(tmp_array); }) }) } }, saveSetting() { window.localStorage.setItem("bilitools-autowear", JSON.stringify(this.medalConfig.autoWear)) }, async readSetting() { let config = await window.localStorage.getItem("bilitools-autowear"); if (!(config === "undefined" || config == null)) { this.medalConfig.autoWear = JSON.parse(config); } return this.medalConfig.autoWear; }, getToken() { return document.cookie.match(/bili_jct=(.+?);/)[1]; }, autoWear() { this.getWore().then(res => { this.medalConfig.wore = res.length == 0 ? "" : res.medal_name; }).then(() => { if (window.__NEPTUNE_IS_MY_WAIFU__ && this.medalConfig.autoWear.enable) { let medalInfo = window.__NEPTUNE_IS_MY_WAIFU__.roomInfoRes.data.anchor_info.medal_info; if (medalInfo && medalInfo.medal_name !== this.medalConfig.wore) { this.wear(medalInfo.medal_id).catch(e => { setTimeout(() => { if (this.medalConfig.autoWear.remember !== 0) { this.wear(this.medalConfig.autoWear.remember).catch(e => { }); } else { this.takeOff(); } }, 1500); }); }else if (this.checkContained(medalInfo.medal_name)) { if (this.medalConfig.autoWear.remember !== 0) { this.wear(this.medalConfig.autoWear.remember).catch(e => { }); } else { this.takeOff(); } } } }) }, checkContained(name){ for(let item of this.medalConfig.list){ if(item.medal_name === name) return true; } return false; }, refreshMedalCache() { let originalMedalButton = document.querySelector('.dp-i-block.medal-item-margin') if (originalMedalButton === null) { return } originalMedalButton.click() setTimeout(() => originalMedalButton.click(), 0) }, async getMedalPage(page) { const res = await fetch("https://api.live.bilibili.com/xlive/app-ucenter/v1/user/GetMyMedals?page_size=10&page=" + page, { method: "GET", credentials: "include" }); const res_1 = await res.json(); if (res_1.code !== 0) { toast.error(`获取第 ${page} 页粉丝牌失败 ${res_1.message}`); return []; } else { return res_1; } }, async getWore() { const res = await fetch("https://api.live.bilibili.com/live_user/v1/UserInfo/get_weared_medal", { method: "GET", credentials: "include" }); const res_1 = await res.json(); if (res_1.code !== 0) { toast.error(`获取当前粉丝牌失败 ${res_1.message}`); return ""; } else { return res_1.data; } }, async takeOff() { let token = this.getToken(); let formdate = new FormData(); formdate.append("csrf_token", token); formdate.append("csrf", token); const res = await fetch("https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/take_off", { method: "POST", credentials: "include", body: formdate }); const res_1 = await res.json(); if (res_1.code !== 0) { toast.error(`取消佩戴失败 ${res_1.message}`); } else { toast.success(`取消佩戴成功`); this.medalConfig.wore = ""; } }, async wear(medal_id) { let token = this.getToken(); let formdate = new FormData(); formdate.append("csrf_token", token); formdate.append("csrf", token); formdate.append("medal_id", medal_id); const res = await fetch("https://api.live.bilibili.com/xlive/web-room/v1/fansMedal/wear", { method: "POST", credentials: "include", body: formdate }); const res_1 = await res.json(); if (res_1.code !== 0) { throw res_1.message; } else { this.getWore().then(res => { this.medalConfig.wore = res.medal_name; toast.success(`你现在是 ${res.medal_name}`) }).then(() => { this.refreshMedalCache() }) } } } } let myMedal = document.createElement("div"); myMedal.setAttribute("x-data", "loadMedalConfig()"); myMedal.setAttribute("x-init", "initComponent()"); myMedal.innerHTML = ` <button class="bilitools-button" x-text="medalConfig.wore == ''?'未佩戴':medalConfig.wore" @click="openMedalBox" ></button> <template x-if="medalBox" x-transport="body"> <div class="bilitools-medal-modal-bg" @click.self="closeMedalBox"> <div class="bilitools-medal-modal-box" :class="modalAnimate?'animate-scale-in-ease':'animate-scale-out'"> <div class="bilitools-medal-modal-box-header"> <span>我持有的粉丝牌</span> <button class="bilitools-close" @click="closeMedalBox">×</button> </div> <div class="bilitools-medal-modal-box-body" x-ref="bodyBox"> <div class="bilitools-medal-setting" x-ref="setting"> <div class="setting-full"> <label for="bilitools-autoMeadl"> 发言时自动佩戴对应粉丝牌(刷新后生效) <input type="checkbox" class="bilitools-switch" id="bilitools-autoMeadl" name="autoMeadl" @change="saveSetting" x-model="medalConfig.autoWear.enable" /> </label> </div> <div class="setting-half"> <label> 未持有牌子的直播间佩戴 <select id="bilitools-havent" @change="saveSetting" x-model = "medalConfig.autoWear.remember"> <option value="0">不佩戴</option> <template x-for="(item,index) in medalConfig.list" :key="index" > <option x-text="item.target_name + '/' + item.medal_name" :value="item.medal_id" :selected="item.medal_id == medalConfig.autoWear.remember ? true : false" ></option> </template> </select> </label> </div> <div class="setting-half"> <input type="text" id="bilitools-search" placeholder="搜索" x-model="medalConfig.searchText" @input.debounce="search" /> </div> </div> <div class="bilitools-medal-table"> <table> <thead class="bilitools-medal-table-header" x-ref="tableHeader" > <th class="bilitools-liver-name sort" style="cursor: pointer" :class="sortedStyle(1)" @click="sort(1)" > 主播 </th> <th class="bilitools-medal-name sort" style="cursor: pointer" :class="sortedStyle(2)" @click="sort(2)" > 粉丝牌 </th> <th class="bilitools-medal-level sort" style="cursor: pointer" :class="sortedStyle(3)" @click="sort(3)" > 等级 </th> <th class="bilitools-medal-exp sort" style="cursor: pointer" :class="sortedStyle(4)" @click="sort(4)" > 粉丝牌经验 </th> <th class="bilitools-medal-exp-limit sort" style="cursor: pointer" :class="sortedStyle(5)" @click="sort(5)" > 今日经验 </th> <th class="bilitools-medal-operate">操作</th> </thead> <tbody class="bilitools-medal-table-body" :style="'height: ' + (computedHeight() - 16)+ 'px;'" > <template x-for="(item,index) in (medalConfig.searchText == ''?medalConfig.list:medalConfig.searchList)" :key="item.medal_id" > <tr class="bilitools-medal-table-row"> <td class="bilitools-liver-name"> <a :href="'https://live.bilibili.com/'+item.roomid" target="_blank" x-text="item.target_name" ></a> </td> <td class="bilitools-medal-name"> <span class="bilitools-medal-status" x-text="item.medal_name" :style="'border-color: #' + item.medal_color_border.toString(16) + ';background-image: linear-gradient(45deg,#' + item.medal_color_start.toString(16) + ',#'+ item.medal_color_end.toString(16)+')'" > </span> </td> <td class="bilitools-medal-level" x-text="item.level" ></td> <td class="bilitools-medal-exp" x-text="item.intimacy + '/' + item.next_intimacy" ></td> <td class="bilitools-medal-exp-limit" x-text="item.today_feed + '/' + item.day_limit" ></td> <td class="bilitools-medal-operate"> <button class="bilitools-button" x-text="item.medal_name == medalConfig.wore? '取消佩戴': '佩戴'" :class="item.medal_name == medalConfig.wore?'bleak':''" @click="item.medal_name == medalConfig.wore?takeOff():wear(item.medal_id)" ></button> </td> </tr> </template> </tbody> </table> </div> </div> </div> </div> </template> `; document.querySelector("#control-panel-ctnr-box").appendChild(myMedal); } function FilterSettingComponent() { window.loadDanmuConfig = function () { return { danmuConfig: { regexp: "(?<who>[^〈{『〖[〔「【]*)[〈{『〖[〔「【](?<text>[^〉}『〗]〕」】]*)[$〉}『〗]〕」】]?", liveRoomSwitch: [], translatorList: [], autoHigh: true, filteBoxStyle: false, }, filterEnable: false, settingBox: false, translatorText: "", dialogAnimate: false, roomid: 0, dialog: { ["@click.stop"]() { this.openSettingBox(); }, ["@click.document"]() { this.closeSettingBox(); }, [":class"]() { return this.dialogAnimate ? "active" : ""; }, }, initComponent() { this.readSetting(); if (this.danmuConfig.autoHigh) { this.autoHigh(); } }, saveSetting() { window.localStorage.setItem( "bilitools-danmuFilter", JSON.stringify(this.danmuConfig) ); }, readSetting() { let config = window.localStorage.getItem("bilitools-danmuFilter"); let room = window.BilibiliLive; if (!(config === "undefined" || config == null)) { this.danmuConfig = JSON.parse(config); } if (typeof room === "object") { this.roomid = room.SHORT_ROOMID || room.ROOMID; this.filterEnable = this.danmuConfig.liveRoomSwitch.includes( this.roomid ); } }, openSettingBox() { this.dialogAnimate = true; this.settingBox = true; }, closeSettingBox() { this.dialogAnimate = false; setTimeout(() => { this.settingBox = false; }, 400); }, computedDialogHeight() { let height = 0; height += this.$refs.dialog.offsetHeight; return -height - 8 + "px"; }, saveRegexp($dispatch) { this.danmuConfig.regexp = this.danmuConfig.regexp.trim(); this.saveSetting(); $dispatch("regexp-update",{regexp:this.danmuConfig.regexp}) toast.success("保存成功"); }, saveTranselator($dispatch) { this.danmuConfig.translatorList.push(this.translatorText.trim()); this.saveSetting(); $dispatch("translator-update",{regexp:this.danmuConfig.translatorList}) toast.success("保存成功"); }, removeTranselator(index,$dispatch) { this.danmuConfig.translatorList.splice(index, 1); this.saveSetting(); $dispatch("translator-update",{list:this.danmuConfig.translatorList}) }, changeFilterStatus($dispatch) { this.filterEnable = !this.filterEnable; if (this.filterEnable) { this.danmuConfig.liveRoomSwitch.push(this.roomid); } else { let index = this.danmuConfig.liveRoomSwitch.indexOf(this.roomid); if (index >= 0) { this.danmuConfig.liveRoomSwitch.splice(index, 1); } } $dispatch("filter-update",{ mode: this.filterEnable }) this.saveSetting(); }, changeFilteBoxStyle($dispatch) { this.danmuConfig.filteBoxStyle = !this.danmuConfig.filteBoxStyle; $dispatch("style-update", { mode: this.danmuConfig.filteBoxStyle }); this.saveSetting(); }, saveAutoHigh() { this.danmuConfig.autoHigh = !this.danmuConfig.autoHigh; this.saveSetting(); }, autoHigh() { let time1 = setInterval(function() { try { let videoDom = document.querySelector("#live-player"); videoDom.dispatchEvent(new Event("mousemove")); let quality = document.querySelector(".quality-wrap"); quality.dispatchEvent(new Event("mouseenter")); if (document.querySelector(".list-it.selected").innerText != "原画") { let list = document.querySelectorAll(".list-it"); for(let item of list){ if(item.innerText == "原画") { console.log(item) item.click() // item.dispatchEvent(new Event("click")); break; } } quality.dispatchEvent(new Event("mouseleave")); } clearInterval(time1) } catch {} }, 1000); }, }; }; let myFilterSetting = document.createElement("span"); myFilterSetting.setAttribute("x-data", "loadDanmuConfig()"); myFilterSetting.setAttribute("x-init", "initComponent()"); myFilterSetting.setAttribute("x-bind", "dialog"); myFilterSetting.className = "bilitools-icons live-skin-main-text" myFilterSetting.innerHTML = ` <svg id="图层_1" data-name="图层 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 40 40" > <title>过滤设置</title> <path id="Combined-Shape" d="M6.73,35.66a6.74,6.74,0,0,1-6.5-7V11.32a6.76,6.76,0,0,1,6.5-7h22.8a6.74,6.74,0,0,1,6.5,7v.85a2,2,0,0,1-4,0h0v-.54A3.22,3.22,0,0,0,29,8.26H7.3a3.24,3.24,0,0,0-3.09,3.37V28.37A3.23,3.23,0,0,0,7.3,31.74h8.84a2,2,0,1,1,0,3.92H6.73Z" ></path> <path id="形状结合" d="M15.16,24.86a1.87,1.87,0,0,1,0,3.73h-4a1.87,1.87,0,0,1,0-3.73Zm-1.57-6.72a1.86,1.86,0,1,1,0,3.72h-4a1.86,1.86,0,0,1,0-3.72Zm6.09-6.73a1.87,1.87,0,0,1,0,3.73H13.44a1.87,1.87,0,0,1,0-3.73Z" style="fill-rule: evenodd" ></path> <path id="图标1" d="m29.026,22.86956c-1.36082,0 -2.46349,1.19207 -2.46349,2.66323c0,1.47048 1.10267,2.66323 2.46349,2.66323c0.3118,0 0.60719,-0.0696 0.88176,-0.18424l0.52767,0.87683l0.85777,-0.60388l-0.52451,-0.87069c0.44498,-0.48174 0.72081,-1.14704 0.72081,-1.88125c0,-1.47116 -1.10267,-2.66323 -2.46349,-2.66323zm-0.00947,-7.2084c-5.06647,0 -9.17355,4.44009 -9.17355,9.91735c0,5.47727 4.10708,9.91735 9.17355,9.91735c5.06647,0 9.17355,-4.44009 9.17355,-9.91735c0,-5.47727 -4.10708,-9.91735 -9.17355,-9.91735zm6.42161,13.1988c-0.15211,0.34391 -0.32379,0.67553 -0.52135,0.98942l-1.99326,-0.46332c-0.3036,0.35892 -0.64948,0.67826 -1.03135,0.94506l0.07511,2.1849c-0.32001,0.15694 -0.64885,0.28727 -0.99032,0.38894l-1.23395,-1.71544c-0.2348,0.0348 -0.47338,0.05868 -0.71702,0.05868c-0.2247,0 -0.44561,-0.01979 -0.66337,-0.05049l-1.22764,1.70589c-0.34147,-0.10304 -0.67221,-0.23337 -0.99095,-0.38826l0.07385,-2.14669c-0.40017,-0.27158 -0.76246,-0.60047 -1.08058,-0.97372l-1.94024,0.44899c-0.19756,-0.31115 -0.36798,-0.64414 -0.52135,-0.98805l1.3179,-1.57556c-0.14265,-0.4797 -0.22344,-0.9901 -0.243,-1.51688l-1.7471,-0.99897c0.03471,-0.38417 0.10414,-0.75537 0.18998,-1.12111l1.94656,-0.29137c0.18304,-0.47901 0.42605,-0.92254 0.71639,-1.32513l-0.74605,-1.97951c0.25184,-0.26544 0.52388,-0.50767 0.8098,-0.73012l1.68083,1.1409c0.41027,-0.22995 0.85146,-0.40464 1.31601,-0.51177l0.61098,-2.04775c0.17547,-0.01433 0.3503,-0.02866 0.5283,-0.02866c0.17799,0 0.35346,0.01501 0.5283,0.02866l0.61603,2.06617c0.45445,0.11122 0.88428,0.28386 1.28508,0.51177l1.70671,-1.15796c0.28719,0.22245 0.55986,0.46468 0.81106,0.73012l-0.76751,2.03751c0.27014,0.38485 0.50052,0.80586 0.6741,1.25895l2.0103,0.30092c0.08521,0.36506 0.1559,0.73763 0.19062,1.12111l-1.80959,1.03445c-0.02146,0.49539 -0.09468,0.97577 -0.22407,1.43295l1.36082,1.62537z" style="fill-rule: evenodd" /> </svg> <template x-if="settingBox"> <div class="bilitools-dialog bilitools-arrow" :class="dialogAnimate?'animate-scale-in-ease':'animate-scale-out'" x-ref="dialog" :style="'top: ' + computedDialogHeight()" @mouseleave="closeSettingBox" > <div class="bilitools-dialog-title">当前房间设置</div> <div class="bilitools-dialog-body"> <div class="bilitools-dialog-row" style="justify-content: left"> <label for="bilitools-filter-switch"> 过滤开关 </label> <input type="checkbox" class="bilitools-switch" name="filterSwitch" id="bilitools-filter-switch" x-model="filterEnable" @click="changeFilterStatus($dispatch)" /> </div> <div class="bilitools-dialog-row" style="justify-content: left"> <label for="bilitools-filter-switch"> 过滤框 单行/多行 </label> <input type="checkbox" class="bilitools-switch" name="filterSwitch" id="bilitools-filter-switch" x-model="danmuConfig.filteBoxStyle" @click="changeFilteBoxStyle($dispatch)" /> </div> <div class="bilitools-dialog-row" style="justify-content: left"> <label for="bilitools-video-switch"> 自动选择最高画质 </label> <input type="checkbox" class="bilitools-switch" name="videoSwitch" id="bilitools-video-switch" x-model="danmuConfig.autoHigh" @click="saveAutoHigh" /> </div> <div class="bilitools-dialog-row" style="flex-wrap: nowrap"> <label for="bilitools-filter-regexp"> 过滤正则 </label> <input type="text" name="filterRegexp" id="bilitools-filter-regexp" x-model="danmuConfig.regexp" /> <button class="bilitools-button" :disabled="danmuConfig.regexp == '' ? true : false" :class="danmuConfig.regexp == '' ? 'disable' : ''" @click="saveRegexp($dispatch)" > 确定 </button> </div> <div class="bilitools-dialog-row" style="flex-wrap: nowrap"> <label for="bilitools-filter-translator"> 添加译者 </label> <input type="text" name="translator" id="bilitools-filter-translator" x-model="translatorText" /> <button class="bilitools-button" :disabled="translatorText == '' ? true : false" :class="translatorText == '' ? 'disable' : ''" @click="saveTranselator($dispatch)" > 确定 </button> </div> <div class="bilitools-dialog-row"> <span style=" display: block; width: 100%; flex-shrink: 0; font-weight: 600; " >译者列表</span > <div class="bliltools-scroll"> <template x-for="(item,index) in danmuConfig.translatorList" :key="index" > <div class="bilitools-dialog-row" style="margin: 0 4px"> <span x-text="item"></span> <button class="bilitools-close" @click="removeTranselator(index,$dispatch)" > × </button> </div> </template> </div> </div> </div> </div> </template> `; document.querySelector(".icon-left-part").appendChild(myFilterSetting); } function FilterBoxComponent() { window.loadFilterBoxSetting = function () { return { filter: { regexp: null, translatorList: [], }, filteBoxStatus:false, filteBoxStyle: false, filtedList: [], dragData: { moveX: 0, moveY: 0, maxX:0, maxY:0 }, status:{ ["@filter-update.document"]($dispatch){ this.updateStatus($dispatch) }, ["@regexp-update.document"]($dispatch){ this.updateRegexp($dispatch) }, ["@translator-update.document"]($dispatch){ this.updateTranslator($dispatch) } }, initComponent() { this.readSetting(); this.dragData.moveX = this.$el.offsetWidth * 0.45 this.dragData.moveY = this.$el.offsetHeight * 0.8 this.websocketHook(); }, readSetting() { let config = window.localStorage.getItem("bilitools-danmuFilter"); if (config === "undefined" || config == null) { this.filter.regexp = new RegExp( "(?<who>[^〈{『〖[〔「【]*)[〈{『〖[〔「【](?<text>[^〉}『〗]〕」】]*)[$〉}『〗]〕」】]?" ); } else { let setting = JSON.parse(config); this.filter.regexp = new RegExp(setting.regexp); this.filter.translatorList = setting.translatorList; this.filteBoxStyle = setting.filteBoxStyle; try{ this.filteBoxStatus = setting.liveRoomSwitch.includes(window.BilibiliLive.SHORT_ROOMID) || setting.liveRoomSwitch.includes(window.BilibiliLive.ROOMID); }catch {} } }, updateStyle(e) { this.filteBoxStyle = e.detail.mode; }, updateStatus(e) { this.filteBoxStatus = e.detail.mode; }, updateRegexp(e) { this.filter.regexp = new RegExp(e.detail.regexp); }, updateTranslator(e) { this.filter.translatorList = e.detail.list; }, updateSetting(setting) { if (typeof setting === "object") { this.filter.regexp = new RegExp(setting.regexp); this.filter.translatorList = setting.translatorList; } }, websocketHook() { bliveproxy.addCommandHandler("DANMU_MSG", (cmd)=>{ if(this.filteBoxStatus){ if (this.filter.regexp.test(cmd.info[1]) || this.filter.translatorList.includes(cmd.info[2][1])){ this.filtedList.unshift(cmd.info[1]) } } }); }, drag(el) { this.dragData.maxX = el.offsetWidth; this.dragData.maxY = el.offsetHeight; document.onmousemove = (e) => { let x = this.dragData.moveX + e.movementX; let y = this.dragData.moveY + e.movementY; this.dragData.moveX = (x > 0 && x + this.$refs.dragable.offsetWidth < this.dragData.maxX)?x:this.dragData.moveX; this.dragData.moveY = (y > 0 && y + this.$refs.dragable.offsetHeight < this.dragData.maxY)?y:this.dragData.moveY; }; document.onmouseup = (e) => { document.onmousemove = null; document.onmouseup = null; }; }, }; } let myFilterBox = document.createElement("div"); myFilterBox.setAttribute("x-data", "loadFilterBoxSetting()"); myFilterBox.setAttribute("x-init", "initComponent()"); myFilterBox.setAttribute("x-spread","status"); myFilterBox.style="height: 100%;width: 100%;position: absolute;z-index: 100;top: 0;left: 0;pointer-events: none;"; myFilterBox.innerHTML = ` <template x-if="filteBoxStatus && filtedList.length > 0"> <div class="bilitools-filterBox bilitools-dragable" @style-update.window="updateStyle" @mousedown="drag($el)" :style="'top: ' + dragData.moveY + 'px;left: ' + dragData.moveX + 'px'" :class="filteBoxStyle?'multiline':''" x-ref="dragable" > <template x-if="filteBoxStyle" x-for="(item,index) in filtedList"> <p x-text="item"></p> </template> <template x-if="!filteBoxStyle"> <p style="font-weight: 600" x-text="filtedList[0]"></p> </template> </div> </template> ` document.querySelector("#live-player").append(myFilterBox); } main(); })();