您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
根据Up主名称,在动态页进行筛选,隐藏屏蔽的Up主动态。
// ==UserScript== // @name BiliBili动态隐藏 // @author Yiero // @description 根据Up主名称,在动态页进行筛选,隐藏屏蔽的Up主动态。 // @version 1.4.5 // @namespace https://github.com/AliubYiero/TamperMonkeyScripts // @match https://t.bilibili.com/* // @icon https://t.bilibili.com/favicon.ico // @resource layuiCss https://cdn.staticfile.org/layui/2.8.11/css/layui.min.css // @license GPL // @grant GM_registerMenuCommand // @grant GM_unregisterMenuCommand // @grant GM_addStyle // @grant GM_getResourceText // @run-at document-start // @updateUrl https://raw.githubusercontent.com/AliubYiero/TamperMonkeyScripts/master/dist/HideDynamic.js // @downloadUrl https://raw.githubusercontent.com/AliubYiero/TamperMonkeyScripts/master/dist/HideDynamic.js // ==/UserScript== GM_addStyle( GM_getResourceText( 'layuiCss' ) ) var __defProp = Object.defineProperty; var __defNormalProp = ( obj, key, value ) => key in obj ? __defProp( obj, key, { enumerable: true, configurable: true, writable: true, value } ) : obj[key] = value; var __publicField = ( obj, key, value ) => { __defNormalProp( obj, typeof key !== "symbol" ? key + "" : key, value ); return value; }; function getElement( parent, selector, timeout = 0 ) { return new Promise( ( resolve ) => { let result = parent.querySelector( selector ); if ( result ) { return resolve( result ); } let timer; const mutationObserver = window.MutationObserver || window.WebkitMutationObserver || window.MozMutationObserver; if ( mutationObserver ) { const observer = new mutationObserver( ( mutations ) => { for ( let mutation of mutations ) { for ( let addedNode of mutation.addedNodes ) { if ( addedNode instanceof Element ) { result = addedNode.matches( selector ) ? addedNode : addedNode.querySelector( selector ); if ( result ) { observer.disconnect(); timer && clearTimeout( timer ); return resolve( result ); } } } } } ); observer.observe( parent, { childList: true, subtree: true } ); if ( timeout > 0 ) { timer = setTimeout( () => { observer.disconnect(); return resolve( null ); }, timeout ); } } else { const listener = ( e ) => { if ( e.target instanceof Element ) { result = e.target.matches( selector ) ? e.target : e.target.querySelector( selector ); if ( result ) { parent.removeEventListener( "DOMNodeInserted", listener, true ); timer && clearTimeout( timer ); return resolve( result ); } } }; parent.addEventListener( "DOMNodeInserted", listener, true ); if ( timeout > 0 ) { timer = setTimeout( () => { parent.removeEventListener( "DOMNodeInserted", listener, true ); return resolve( null ); }, timeout ); } } } ); } const registerMenu = ( title, callback ) => { GM_registerMenuCommand( title, function () { callback(); } ); }; const createElement = ( elementConfig ) => { const { tagName, className, id, innerHTML, innerText } = elementConfig; const element = document.createElement( tagName ); if ( className && typeof className === "string" ) { element.classList.add( className ); } else if ( className && Array.isArray( className ) ) { element.classList.add( ...className ); } if ( id ) { element.id = id; } if ( innerHTML ) { element.innerHTML = innerHTML; } if ( innerText ) { element.innerText = innerText; } for ( let elementConfigKey in elementConfig ) { if ( [ "tagName", "className", "id", "innerHTML", "innerText" ].indexOf( elementConfigKey ) !== -1 ) { continue; } element.setAttribute( elementConfigKey, elementConfig[elementConfigKey] ); } return element; }; const addElementToDocument = ( element, cssString, fatherElement = document.body ) => { fatherElement.append( element ); GM_addStyle( cssString ); }; const addStyle = ( cssString ) => { GM_addStyle( cssString ); }; class Info { constructor( projectName ) { // @ts-ignore __publicField( this, "projectName" ); __publicField( this, "header" ); this.projectName = projectName; this.header = `[${ projectName }]`; } log( ...msg ) { /* @__PURE__ */ ( () => { } )( ...this.contentInfo( ...msg ) ); } info( ...msg ) { console.info( ...this.contentInfo( ...msg ) ); } warn( ...msg ) { console.warn( ...this.contentInfo( ...msg ) ); } error( ...msg ) { console.error( ...this.contentInfo( ...msg ) ); } contentInfo( ...msg ) { return [ this.header, ...msg ]; } } function importLayui() { let script = document.createElement( "script" ); script.type = "text/javascript"; script.src = "https://cdn.staticfile.org/layui/2.8.11/layui.min.js"; document.head.appendChild( script ); } class Sleep { /** 延时睡眠等待 */ static time( delay = 1 ) { return new Promise( ( resolve ) => { setTimeout( resolve, delay * 1e3 ); } ); } /** 页面加载等待 */ static windowLoad( delay = 0 ) { return new Promise( ( resolve ) => { window.addEventListener( "load", () => { setTimeout( resolve, delay * 1e3 ); } ); } ); } } class Data { /** @param {array} newData */ constructor( newData ) { /** @type {Map<string, {id: string, isBandLive: boolean, isBandDynamic: boolean, isBandVideo: boolean}>} */ __publicField( this, "data" ); __publicField( this, "originData" ); if ( newData ) { this.setToLocalStorage( this.arrayToMap( newData ) ); } this.getFromLocalStorage(); } /** 防止多余数据提交到data中,进行重新赋值 */ limitValue( obj ) { const { id, isBandLive, isBandDynamic, isBandVideo } = obj; return { id, isBandLive: isBandLive || false, isBandDynamic: isBandDynamic || false, isBandVideo: isBandVideo || false }; } /** 添加一个对象 */ set( newObj ) { if ( this.data.has( newObj.id ) ) { return; } const limitData = this.limitValue( newObj ); this.data.set( newObj.id, limitData ); this.setToLocalStorage(); return limitData; } /** 更新其中一个对象 */ update( newObj ) { const limitData = this.limitValue( newObj ); this.data.set( newObj.id, limitData ); this.setToLocalStorage(); } /** 删除其中一个对象 */ delete( newObjOrId ) { if ( typeof newObjOrId === "string" ) { this.data.delete( newObjOrId ); } else { this.data.delete( newObjOrId.id ); } this.setToLocalStorage(); } /** 改变其中一个对象的键(删除原对象,建立新对象) */ change( newObj, oldObjOrId ) { this.delete( oldObjOrId ); this.set( this.limitValue( newObj ) ); this.setToLocalStorage(); } /** 从localStorage中获取data */ getFromLocalStorage() { this.originData = JSON.parse( localStorage.getItem( "bandList" ) || "[]" ); this.data = this.arrayToMap( this.originData ); } /** 将data设置到localStorage中 */ setToLocalStorage( value = this.data ) { localStorage.setItem( "bandList", JSON.stringify( this.mapToArray( value ) ) ); } /** * 数组转Map * @param {{id: string, [propName: string]: any}[]} array * @return {Map} * */ arrayToMap( array ) { const map = /* @__PURE__ */ new Map(); array.forEach( ( value ) => { value.id = value.id.trim(); map.set( value.id, value ); } ); return map; } /** * Map转数组 * @param {Map} map * @return {any[]} * */ mapToArray( map ) { const array = []; for ( let value of map.values() ) { array.push( value ); } return array; } } class UiEvent { constructor( data ) { __publicField( this, "data" ); __publicField( this, "treeTable" ); __publicField( this, "domList" ); this.data = data; this.treeTable = layui.treeTable; this.domList = { main: void 0 }; this.getMainDom(); } /** 添加数据 */ add( res ) { const addData = ( res2 ) => { res2 = res2.trim(); if ( !res2 ) { return; } const newData = this.data.set( { id: res2 } ); if ( !newData ) { return; } this.treeTable.addNodes( "table-bili-band-config", { index: 0, data: newData } ); this.treeTable.reloadData( "table-bili-band-config" ); }; if ( res ) { addData( res ); return; } layer.prompt( { title: "输入要屏蔽Up主名" }, ( res2, index ) => { layer.close( index ); addData( res2 ); } ); } /** * 删除当前行数据 * @param {Object} e layui数据对象 * */ delete( e ) { this.data.delete( e.data ); e.del(); this.treeTable.reloadData( "table-bili-band-config" ); } /** 更新当前行的数据 * @param {Object} originData * @param {'dynamic' | 'video' | 'live'} type * @param {number} index * */ update( originData, type, index ) { let newData = { ...originData }; switch ( type ) { case "dynamic": newData.isBandDynamic = !originData.isBandDynamic; break; case "video": newData.isBandVideo = !originData.isBandVideo; break; case "live": newData.isBandLive = !originData.isBandLive; break; } this.treeTable.updateNode( "table-bili-band-config", index, newData ); this.data.update( newData ); } /** 改变Up主名称(因为需要改变键值,所以不能直接更新) */ change( e ) { this.data.change( e.data, e.oldValue ); this.treeTable.reloadData( "table-bili-band-config" ); } /** 展示UI界面 */ show() { if ( !this.domList.main ) { this.getMainDom(); } const mainContainer = this.domList.main; if ( mainContainer.style.display === "none" ) { mainContainer.style.display = "block"; } mainContainer.classList.remove( "layui-anim-fadeout", "hide" ); mainContainer.classList.add( "layui-anim-fadein" ); } /** 隐藏UI界面 */ hide() { if ( !this.domList.main ) { this.getMainDom(); } const mainContainer = this.domList.main; mainContainer.classList.remove( "layui-anim-fadein" ); mainContainer.classList.add( "layui-anim-fadeout", "hide" ); } getMainDom() { this.domList.main = document.querySelector( ".bili-band-config-container" ); } submitSearch( input ) { const { value } = input; if ( !value.trim() ) { return false; } input.value = ""; const newData = []; let isMatchValue = false; this.data.mapToArray( this.data.data ).forEach( ( bandData ) => { if ( bandData.id.match( value ) ) { isMatchValue = true; newData.unshift( bandData ); } else { newData.push( bandData ); } } ); if ( !isMatchValue ) { layer.confirm( `没有搜索到UP主 [${ value }] ,是否新建UP主 (2s后自动关闭窗口)`, { time: 2e3, btn: [ "确认", "取消" ] }, ( index ) => { layer.close( index ); this.add( value ); } ); return false; } this.treeTable.reloadData( "table-bili-band-config", { data: newData, page: { // 将当前页面设置到第一页,避免看不到搜索结果 curr: 1 } } ); } } class ConfigUI { constructor() { // @ts-ignore __publicField( this, "data" ); // @ts-ignore __publicField( this, "uiEvent" ); importLayui(); Sleep.windowLoad().then( () => { this.data = new Data(); this.uiEvent = new UiEvent( this.data ); this.createContainer(); this.createElementEvent(); this.show = () => { this.uiEvent.show(); }; this.hide = () => { this.uiEvent.hide(); }; } ); } /** 创建UI界面框架 */ createContainer() { const container = createElement( { tagName: "main", className: [ "bili-band-config-container", "layui-anim", "hide" ], innerHTML: `<table class="layui-anim-fadeout" id="ID-table-bili-band-config" lay-filter="show"></table>` } ); addElementToDocument( container, `.bili-band-config-container {position: fixed; top: 0; left:calc(50% - 355px);background: #ffffff; z-index: 10003; width: 710px;}`, document.body ); } /** * 创建UI内容,创建UI事件 * */ createElementEvent() { layui.use( "table", () => { const { treeTable, form } = layui; treeTable.render( { elem: "#ID-table-bili-band-config", id: "table-bili-band-config", cols: [ [ { field: "index", title: "编号", type: "numbers", width: 60 }, { field: "id", title: "UP主", width: 200, sort: true, align: "center", edit: true }, { field: "dynamic", title: "动态卡片", width: 110, sort: true, align: "center", templet: ( d ) => `<input type="checkbox" lay-skin="switch" lay-filter="toggleDynamicStatus" ${ d.isBandDynamic ? "checked" : "" }/>` }, { field: "video", title: "视频卡片", width: 110, sort: true, align: "center", templet: ( d ) => `<input type="checkbox" lay-skin="switch" lay-filter="toggleVideoStatus" ${ d.isBandVideo ? "checked" : "" }/>` }, { field: "live", title: "直播卡片", width: 110, sort: true, align: "center", templet: ( d ) => `<input type="checkbox" lay-skin="switch" lay-filter="toggleLiveStatus" ${ d.isBandLive ? "checked" : "" }/>` }, { field: "delete", title: "操作", width: 110, sort: false, align: "center", fixed: "right", templet: () => `<button type="button" class="layui-btn layui-btn-sm layui-btn-danger layui-btn-radius" lay-event="delete">Delete</button>` } ] ], data: this.data.originData, size: "lg", skin: "line", page: { layout: [ "prev", "page", "next", "count", "skip" ] }, // 底部工具栏 pagebar: ` <div> <button type="button" class="layui-btn layui-btn-sm" lay-event="add"> Add </button> <button type="button" class="layui-btn layui-btn-sm" lay-event="addFromClipboard"> ReadClipboard </button> <button type="button" class="layui-btn layui-btn-sm layui-btn-warm" lay-event="close"> Close </button> </div> `, // 顶部工具栏 toolbar: ` <div> <form class="form-search" style="display: flex;"> <input type="text" class="layui-input" style="width: 200px;" placeholder="输入需要搜索的UP主"/> <button type="button" lay-submit lay-filter="table-search" class="layui-btn" style="margin-left: 20px;">Search</button> <button type="button" lay-submit lay-filter="table-clear" class="layui-btn" style="margin-left: 20px;">Clear</button> </form> </div> `, width: 710, // 不开启顶部右侧默认工具栏 defaultToolbar: "" } ); treeTable.on( "tool(show)", ( e ) => { this.uiEvent.delete( e ); } ); treeTable.on( "edit(show)", ( e ) => { this.uiEvent.change( e ); } ); class Checkbox { constructor( input ) { __publicField( this, "input" ); __publicField( this, "domList" ); this.input = input; this.domList = { input: this.input, tr: this.getTrDom() }; } getTrDom() { var _a, _b, _c; return ( _c = ( _b = ( _a = this.input ) == null ? void 0 : _a.parentElement ) == null ? void 0 : _b.parentElement ) == null ? void 0 : _c.parentElement; } getTableDataIndex() { return parseInt( this.domList.tr.dataset.index ); } getTableData( index ) { index || ( index = this.getTableDataIndex() ); return treeTable.getNodeDataByIndex( "table-bili-band-config", index ); } } form.on( "switch(toggleDynamicStatus)", ( e ) => { const input = new Checkbox( e.elem ); const index = input.getTableDataIndex(); const data = input.getTableData( index ); this.uiEvent.update( data, "dynamic", index ); } ); form.on( "switch(toggleVideoStatus)", ( e ) => { const input = new Checkbox( e.elem ); const index = input.getTableDataIndex(); const data = input.getTableData( index ); this.uiEvent.update( data, "video", index ); } ); form.on( "switch(toggleLiveStatus)", ( e ) => { const input = new Checkbox( e.elem ); const index = input.getTableDataIndex(); const data = input.getTableData( index ); this.uiEvent.update( data, "live", index ); } ); treeTable.on( "pagebar(show)", ( e ) => { const { event } = e; if ( ![ "add", "close", "addFromClipboard" ].includes( event ) ) { return; } if ( event === "add" ) { this.uiEvent.add(); return; } if ( event === "addFromClipboard" ) { navigator.clipboard.readText().then( ( res ) => { this.uiEvent.add( res ); }, ( err ) => { layer.msg( err ); } ); return; } if ( event === "close" ) { this.uiEvent.hide(); return; } } ); form.on( "submit(table-search)", ( res ) => { const input = res.form.querySelector( "input" ); this.uiEvent.submitSearch( input ); return false; } ); form.on( "submit(table-clear)", ( res ) => { res.form.querySelector( "input" ).value = ""; return false; } ); const domList = { form: document.querySelector( ".form-search" ), input: document.querySelector( ".form-search > input" ) }; domList.form.addEventListener( "submit", ( e ) => { e.preventDefault(); this.uiEvent.submitSearch( domList.input ); } ); } ); } // 向外暴露出show事件 // 初始化声明show函数,具体内容会在构造函数定义 show() { } // 向外暴露出hide事件 // 初始化声明hide函数,具体内容会在构造函数定义 hide() { } } ( async () => { const print = new Info( "BiliBiliHideDynamic" ); addStyle( `.hide {display: none !important}` ); print.info( "引入UI" ); const configUI = new ConfigUI(); await Sleep.windowLoad(); class Observer { constructor() { } async observe( observerSelectorList, callback ) { await getElement( document.body, observerSelectorList.waitLoadElementSelector ); const observer2 = new MutationObserver( ( e ) => { e.forEach( ( record ) => { var _a; const item = record.addedNodes[0]; if ( !item || !( ( _a = item == null ? void 0 : item.classList ) == null ? void 0 : _a.contains( observerSelectorList.filterToken || "" ) ) ) { return; } callback( item ); } ); } ); /* @__PURE__ */ ( () => { } )( observerSelectorList.observeElementSelector ); observer2.observe( document.querySelector( observerSelectorList.observeElementSelector ), { childList: true } ); } } class BandEvent { constructor( bandList ) { __publicField( this, "bandList" ); __publicField( this, "bandTypeList", [ "dynamic", "video" ] ); this.bandList = bandList; } /** 判断当前动态的Up主是否在屏蔽列表中,如果是则隐藏 */ band( item, upNameSelector, bandType ) { var _a; const upName = ( _a = item.querySelector( upNameSelector ) ) == null ? void 0 : _a.innerText.trim(); let bandTypeKey; bandTypeKey = { dynamic: "isBandDynamic", video: "isBandVideo", live: "isBandLive" }; if ( this.bandList.has( upName ) && this.bandList.get( upName )[bandTypeKey[bandType]] ) { item.classList.add( "hide" ); } else { item.classList.remove( "hide" ); } } /** * 获取当前所处的动态卡片编号,并根据动态卡片编号,返回不同的BandType * */ judgeBandType( tabsItemListSelector ) { let tabsItemIndex = 0; const tabsItemList = document.querySelectorAll( tabsItemListSelector ); for ( let i = 0; i < tabsItemList.length; i++ ) { const tabsItem = tabsItemList[i]; if ( tabsItem.classList.contains( "active" ) ) { tabsItemIndex = i; break; } } return this.bandTypeList[tabsItemIndex]; } /** 刷新页面数据 */ fresh( observerSelectorList, bandType ) { const { aimElementSelector, upNameSelector } = observerSelectorList; const upNameNodeList = document.querySelectorAll( aimElementSelector ); upNameNodeList.forEach( ( aimElement ) => { this.band( aimElement, upNameSelector, bandType ); } ); } // 刷新动态卡片 / 视频卡片数据 freshDynamic( dynamicSelectorList ) { const bandType = this.judgeBandType( dynamicSelectorList.tabsItemListSelector ); bandEvent.fresh( dynamicSelectorList, bandType ); } // 刷新直播数据 freshLive( liveSelectorList ) { bandEvent.fresh( liveSelectorList, "live" ); } } let domSelector = { dynamic: { waitLoadElementSelector: ".bili-dyn-list", observeElementSelector: ".bili-dyn-list__items", upNameSelector: ".bili-dyn-title__text", tabsItemListSelector: ".bili-dyn-list-tabs__item", filterToken: "bili-dyn-list__item", aimElementSelector: ".bili-dyn-list__item" }, // Bilibili-Evolved直播侧边栏 live: { waitLoadElementSelector: ".be-live-list-content", observeElementSelector: ".be-live-list-content", upNameSelector: ".be-live-list-item-user", filterToken: "be-live-list-item", aimElementSelector: ".be-live-list-item" }, // 旧版直播侧边栏 oldLive: { waitLoadElementSelector: ".bili-dyn-live-users__body", observeElementSelector: ".bili-dyn-live-users__body", upNameSelector: ".bili-dyn-live-users__item__uname", filterToken: "bili-dyn-live-users__item", aimElementSelector: ".bili-dyn-live-users__item" }, // 新版直播侧边栏 newLive: { waitLoadElementSelector: ".bili-dyn-live-users__body", observeElementSelector: ".bili-dyn-live-users__body", upNameSelector: ".bili-dyn-live-users__item__uname", filterToken: "bili-dyn-live-users__container", aimElementSelector: ".bili-dyn-live-users__container" } }; ( function judgeBiliUiVersion() { if ( document.querySelector( "#bili-header-container" ) && document.querySelector( ".bili-header.fixed-header" ) ) { domSelector.live = domSelector.newLive; } else if ( document.querySelector( "#bili-header-container" ) ) { ; } else { domSelector.live = domSelector.oldLive; } } )(); const observer = new Observer(); const bandEvent = new BandEvent( configUI.data.data ); await observer.observe( domSelector.dynamic, ( item ) => { const bandType = bandEvent.judgeBandType( domSelector.dynamic.tabsItemListSelector ); bandEvent.band( item, domSelector.dynamic.upNameSelector, bandType ); } ); bandEvent.freshDynamic( domSelector.dynamic ); await observer.observe( domSelector.live, ( item ) => { bandEvent.band( item, domSelector.live.upNameSelector, "live" ); } ); bandEvent.freshLive( domSelector.live ); registerMenu( "添加屏蔽", () => { configUI.show(); } ); class DragEvent { constructor() { // Dom集合 __publicField( this, "domList" ); // 坐标集合 __publicField( this, "position" ); this.domList = { main: document.querySelector( ".bili-band-config-container" ) }; this.domList.tool = this.domList.main.querySelector( ".layui-table-tool" ); this.position = { start: { x: 0, y: 0 }, end: { x: 0, y: 0 }, relative: { x: 0, y: 0 } }; this.bindDragEvent( this.domList.tool ); } /** 绑定拖拽事件 */ bindDragEvent( willDraggableElement ) { willDraggableElement.draggable = true; willDraggableElement.addEventListener( "dragstart", ( e ) => { this.getStartPosition( e ); } ); willDraggableElement.addEventListener( "dragend", ( e ) => { e.preventDefault(); this.getEndPosition( e ); this.getRelativePosition(); this.changeDomPosition(); } ); } /** 获取开始坐标 */ getStartPosition( e ) { const { pageX, pageY } = e; this.position.start = { x: pageX, y: pageY }; } /** 获取结束坐标 */ getEndPosition( e ) { const { pageX, pageY } = e; this.position.end = { x: pageX, y: pageY }; } /** 获取相对坐标 */ getRelativePosition() { this.position.relative = { x: this.position.relative.x + this.position.end.x - this.position.start.x, y: this.position.relative.y + this.position.end.y - this.position.start.y }; } /** 改变main容器的坐标位置 */ changeDomPosition() { this.domList.main.style.transform = `translate(${ this.position.relative.x }px, ${ this.position.relative.y }px)`; } } ( () => { const domList = { closeBtn: document.querySelector( "[lay-event=close]" ) }; domList.closeBtn.addEventListener( "click", () => { bandEvent.freshDynamic( domSelector.dynamic ); bandEvent.freshLive( domSelector.live ); } ); new DragEvent(); } )(); } )();