// ==UserScript== // @name Bilibili Purify // @name:zh-CN Bilibili纯粹化 // @namespace https://github.com/RevenLiu // @version 1.4.7 // @description 一个用于Bilibili平台的篡改猴脚本。以一种直接的方式抵抗商业化平台对人类大脑的利用。包含重定向首页、隐藏广告、隐藏推荐视频、评论区反成瘾/情绪控制锁等功能,削弱平台/媒体对你心理的操控,恢复你对自己注意力和思考的主导权。 // @author RevenLiu // @license MIT // @icon https://raw.githubusercontent.com/RevenLiu/BilibiliPurify/main/Icon.png // @homepage https://github.com/RevenLiu/BilibiliPurify // @supportURL https://github.com/RevenLiu/BilibiliPurify/issues // @match https://www.bilibili.com/ // @match https://www.bilibili.com/?* // @match https://www.bilibili.com/* // @match https://search.bilibili.com/* // @match https://space.bilibili.com/* // @match https://message.bilibili.com/* // @match https://t.bilibili.com/* // @match https://live.bilibili.com/* // @match https://link.bilibili.com/* // @match https://account.bilibili.com/* // @match https://passport.bilibili.com/* // @match https://pay.bilibili.com/* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @connect www.bilibili.com // @connect live.bilibili.com // @run-at document-start // ==/UserScript== (function() { 'use strict'; // 首页重定向逻辑 if (window.location.hostname === 'www.bilibili.com' && window.location.pathname === '/') { window.location.replace('https://search.bilibili.com/'); return; } // 使用 CSS 隐藏元素 const hideSelectors = [ //左上入口栏广告 'li.v-popover-wrap.left-loc-entry', //视频页右侧小广告 'div.video-card-ad-small', //视频页右侧广告 'div.slide-ad-exp', //视频页视频推荐列表 'div.recommend-list-v1', //视频页右侧底部广告 'div.ad-report.ad-floor-exp.right-bottom-banner', //视频页荣誉标识 'a.honor.item', //视频页活动 'div.activity-m-v1.act-end', //视频页左侧条形广告 'div.ad-report.strip-ad.left-banner', //视频页合集列表 (开启会同时导致分p消失) //'div.video-pod.video-pod', //热搜 'div.trending', //搜索页封面播放器 'div.v-inline-player', //右上入口栏大会员 'a.right-entry__outside.right-entry--vip', //右上入口栏头像下拉菜单会员中心 'div.vip-entry-containter', //左上入口栏杂项 'a.default-entry', //左上入口栏下载客户端按钮 'a.download-entry.download-client-trigger', //左上入口栏首页下拉菜单 'div.v-popover.is-bottom-start', //左上入口栏首页箭头图标 'svg.mini-header__arrow', //视频结束推荐 'div.bpx-player-ending-related', //投票弹幕 (视频内) 'div.bili-danmaku-x-vote.bili-danmaku-x-show', //互动引导 (视频内) 'div.bili-danmaku-x-guide-all.bili-danmaku-x-guide.bili-danmaku-x-show', //关联视频 (视频内) 'div.bili-danmaku-x-link.bili-danmaku-x-show', //评分弹幕及小图片 (视频内) 'div.bili-danmaku-x-score.bili-danmaku-x-show', 'div.bili-danmaku-x-cmd-shrink.bili-danmaku-x-show', //动态页面热搜 'div.bili-dyn-search-trendings', //剧播放页推荐列表 'div.recommend_wrap__PccwM', //剧播放页大会员广告 'div.paybar_container__WApBR', //剧播放页右侧大会员购买广告 '#pc-cashier-wrapper-normal', 'div.paybar_container__WApBR', //剧播放页播放器大会员购买广告 '#pc-cashier-wrapper-video', //剧播放页播放器大会员广告弹窗 'div.bpx-player-toast-wrap', //剧播放页播放器试看结束购买引导 'div.paywall_vipRightWrap__U6Tw3', 'div.paywall_btnItemWrap__s351D.paywall_bigBtn__6S6pz', 'div.paywall_rightBox__pFhO_', //直播首页顶部播放器 'div.player-area-ctnr.border-box.p-relative.t-center', //直播首页广告/公告/推荐 'div.grid-col-1.grid-col.v-top.dp-i-block', 'div.grid-col-3,grid-col,v-top,dp-i-block', 'div.flip-view p-relative.over-hidden.w-100', //直播首页推荐直播 'div.recommend-area-ctnr', 'div.area-detail-ctnr.m-auto', //直播页左上入口栏 'div.nav-items-ctnr.dp-i-block.v-middle', //直播页左上入口栏更多按钮 'div.showmore-link.p-relative.f-left', //直播页右上入口栏 'div.shortcuts-ctnr.h-100.f-left', //直播页右上入口栏头像菜单 'div.user-panel.p-relative.border-box.none-select.panel-shadow', //直播页横向礼物栏 'div.gift-panel.base-panel.live-skin-coloration-area.gift-corner-mark-ui', //直播页电池立即充值文字 'div.recharge-ent-info', //直播页大航海立即上船文字 'div.guard-ent-info', //直播页超能理事会图标 'div.left-part-ctnr.vertical-middle.dp-table.section.p-relative.adaptive', //直播页横向活动栏 'div.activity-gather-entry.activity-entry.s-activity-entry', 'div.rank-entry-play.rank-entries.hot-normal-area', 'div.gift-planet-entry', //直播页观众列表排名图标 'div.rank', //直播页观众列表贡献值 'div.score.live-skin-normal-text', //直播页观众列表送礼引导文字' 'div.need.live-skin-normal-text.opacity6', 'div.switch-box', //直播页观众列表排行榜按钮 'div.tab-box', //直播页观众列表粉丝勋章 'div.fans-medal.fans-medal-item', //直播页观众列表等级勋章 'div.wealth-medal.wealth', //直播页观众列表大航海头像框 'div.guard-frame', //直播页观众列表榜前三显示 'div.top3.top3-3', 'i.rank-icon.rank-icon-1.v-middle', 'i.rank-icon.rank-icon-2.v-middle', 'i.rank-icon.rank-icon-3.v-middle', 'i.top1-rank-icon', 'i.top2-rank-icon', 'i.top3-rank-icon', //直播页大航海 'div.item.live-skin-normal-text.dp-i-block.live-skin-separate-border.border-box.t-center.pointer.tab-item.opacity6', //直播页粉丝团\大航海购买页购买引导 'div.right-list.flex.small-right', 'div.subtitle.m-b-30.text-12.font-bold.lh-14', 'div.h-54.w-full.flex.items-center', 'div.right-list.flex', 'div.medal', 'div.fans-equity', 'div.m-b-50.m-t-30.h-22.flex.flex-row.items-center.border-rd-11.p-l-4.p-r-6', 'div.relation-rights-wrapper.relative.m-auto.box-border.max-w-423.border-rd-12.bg-white.p-12.p-t-20.relative.z-2.m-b-10', 'div.guard-bonus-wrapper.m-auto.m-b-12.box-border.max-w-423.border-rd-12.bg-white.p-12.p-t-20', 'div.platform-rights-wrapper.m-auto.box-border.max-w-423.border-rd-12.bg-white.p-12.p-b-0.p-t-20', //直播页粉丝团\大航海购买页粉丝团成员榜大航海勋章 'div.rights', //直播页粉丝团\大航海购买页粉丝团成员榜排名名次 'div.rank-icon', //直播页粉丝团\大航海购买页舰队权益购买引导 'div.m-t-16.flex.items-center.justify-center.text-14', //直播页粉丝团\大航海购买页舰队权益大航海图标 'div.m-r-5.h-26.w-26.bg-cover', //直播页等级勋章 'div.wealth-medal-ctnr.fans-medal-item-target.dp-i-block.p-relative.v-middle', //直播页粉丝勋章 'div.fans-medal-item-ctnr.fans-medal-item-target.dp-i-block.p-relative.v-middle', //直播页聊天框装扮 'div.title-label.dp-i-block.p-relative.v-middle', //直播页聊天框信息提示/互动引导 'div.chat-item.common-danmuku-msg.border-box', 'div.chat-item.convention-msg.border-box', 'div.chat-item.misc-msg.guard-buy', '#combo-card', 'div.super-gift-item animation', 'div.welcome-section-bottom', //直播页聊天框礼物提示 'div.content-ctnr.border-box.p-relative', 'div.base-bubble-wrapper.super-gift-bubbles', 'div.gift-anim-setting', 'div.gift-bubble-setting', 'div.chat-item.gift-item', //直播页聊天框SC 'div.pay-note-setting', 'div.msg-bubble-setting', 'div.chat-item.danmaku-item.superChat-card-detail', 'div.pay-note-panel', //直播页主播头像框 'div.blive-avatar-pendant', //直播页播放器顶部移动式横幅广告 'div.announcement-wrapper.clearfix.no-select', //直播页播放器左上小橙车提示 'div.shop-popover', //直播页抽奖提示 'div.participation-box.bg-100.lottery-start', 'div.participation-box.bg-100.lottery-end', //直播页播放器结束推荐 'div.web-player-ending-panel-recommendList', //直播页播放器上贴纸 'div.sticker-item', //直播页弹幕图标 'img.bili-danmaku-x-icon', //直播页弹幕连击 'div.combo-danmaku', //直播页中心横向广告 'div.flip-view.p-relative.over-hidden.w-100', //直播页主播心愿提示 'div.gift-wish-card-root', //直播页互动指令窗口 '#game-id', //观赛直播页轮播广告 'div._root_bhaoj_2', //直播分区页大型横向广告 'div.banner-ctn', //直播分区页横幅广告 'div.index_flip-view-image-ctnr_ueRWr.index_ts-dot-4_afXVm', 'div.index_flip-view-titles_ILDY7', //直播站点粉丝勋章页面顶部导航栏 'div.mini-vip.van-popover__reference', 'a.link.download-client-trigger.van-popover__reference', '[href="//manga.bilibili.com?from=bill_top_mnav"]', '[href="//www.bilibili.com/match/home/"]', '[href="//show.bilibili.com/platform/home.html?msource=pc_web"]', '[href="//live.bilibili.com"]', '[href="https://game.bilibili.com/platform/"]', '[href="//www.bilibili.com/anime/"]', 'div.channel-menu-mini', 'svg.navbar_pullup' ]; const cssRules = hideSelectors.map(selector => `${selector} { display: none !important; }` ).join('\n'); // 评论区相关样式 const commentStyles = ` /* 评论区容器相对定位 */ #comment-lock-container { position: relative; } /* 遮罩层 - 覆盖在评论区上方 */ #comment-lock-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(255, 255, 255, 0.95); backdrop-filter: blur(10px); z-index: 999; display: flex; flex-direction: column; justify-content: flex-start; padding-top: 40px; align-items: center; min-height: 400px; } /* 解锁按钮 */ #unlock-comment-btn { padding: 16px 32px; background: linear-gradient(135deg, #00aeec 0%, #0098D1 100%); color: white; border: none; border-radius: 12px; font-size: 18px; font-weight: bold; cursor: pointer; box-shadow: 0 8px 20px rgba(0, 152, 209, 0.4); transition: all 0.3s ease; } #unlock-comment-btn:hover { transform: translateY(-3px); box-shadow: 0 12px 30px rgba(0, 152, 209, 0.4); } /* 提示文字 */ #lock-hint { color: #999; font-size: 14px; margin-top: 20px; text-align: center; } /* 对话框遮罩 */ #comment-dialog-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.75); z-index: 10000; display: flex; justify-content: center; align-items: center; backdrop-filter: blur(8px); animation: fadeIn 0.3s ease; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } /* 对话框 */ #comment-dialog { background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%); border-radius: 24px; padding: 50px 45px; max-width: 520px; width: 90%; box-shadow: 0 30px 90px rgba(0, 0, 0, 0.25); text-align: center; position: relative; overflow: hidden; animation: slideUp 0.4s cubic-bezier(0.34, 1.56, 0.64, 1); } @keyframes slideUp { from { transform: translateY(30px); opacity: 0; } to { transform: translateY(0); opacity: 1; } } #comment-dialog h2 { color: #1a1a1a; font-size: 22px; margin-bottom: 30px; font-weight: 600; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; letter-spacing: 0.5px; opacity: 0; animation: fadeInText 0.6s ease 0.2s forwards; } @keyframes fadeInText { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } #comment-dialog p { color: #666; font-size: 15px; line-height: 2; margin: 12px 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; opacity: 0; } #comment-dialog p:nth-of-type(1) { animation: fadeInText 0.6s ease 0.4s forwards; } #comment-dialog p:nth-of-type(2) { animation: fadeInText 0.6s ease 0.6s forwards; } #comment-dialog p:last-of-type { color: #00AEEC; font-weight: 600; margin-top: 25px; font-size: 16px; animation: fadeInText 0.6s ease 0.8s forwards; } /* 倒计时 */ #countdown { font-size: 72px; font-weight: 300; color: #00AEEC; margin: 40px 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; line-height: 1; animation: pulse 1s ease infinite; text-shadow: 0 2px 10px rgba(0, 174, 236, 0.2); } @keyframes pulse { 0%, 100% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.05); opacity: 0.9; } } #countdown.completed { animation: none; color: #52c41a; font-size: 64px; } /* 输入区域 */ #input-area { margin-top: 35px; opacity: 0.3; pointer-events: none; transition: all 0.6s cubic-bezier(0.34, 1.56, 0.64, 1); transform: translateY(10px); } #input-area.unlocked { opacity: 1; pointer-events: auto; transform: translateY(0); } #reflection-input { width: 100%; padding: 14px 18px; border: 2px solid #e8e8e8; border-radius: 12px; font-size: 15px; box-sizing: border-box; transition: all 0.3s ease; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif; background: #fafafa; } #reflection-input:focus { outline: none; border-color: #00AEEC; background: white; box-shadow: 0 0 0 3px rgba(0, 174, 236, 0.1); } #confirm-btn { margin-top: 18px; padding: 14px 36px; background: linear-gradient(135deg, #00AEEC 0%, #0098D1 100%); color: white; border: none; border-radius: 12px; font-size: 16px; font-weight: 600; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(0, 174, 236, 0.3); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif; } #confirm-btn:hover:not(:disabled) { transform: translateY(-2px); box-shadow: 0 6px 20px rgba(0, 174, 236, 0.4); } #confirm-btn:active:not(:disabled) { transform: translateY(0); } #confirm-btn:disabled { opacity: 0.5; cursor: not-allowed; } #error-msg { color: #ff4d4f; font-size: 13px; margin-top: 12px; min-height: 20px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", sans-serif; animation: shake 0.5s ease; } @keyframes shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } /* 搜索页视频封面遮罩层 */ .search-cover__mask { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.01); /* ↓修改这个来调节模糊度↓ */ backdrop-filter: blur(10px); border-radius: 6px; display: flex; align-items: center; justify-content: center; z-index: 2; transition: opacity 0.2s; will-change: transform; } /* 搜索页视频封面显示按钮 */ .search-cover__button { padding: 8px 16px; background: #00aeec; color: white; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; opacity: 0; transition: opacity 0.2s, background 0.2s; pointer-events: auto; } .search-cover__button.visible { opacity: 1; } .search-cover__button.mouse-in { background: #40c5f1; } /* 封面模糊切换按钮样式 */ .blur-toggle-container { display: flex; align-items: center; margin-left: auto; padding: 0 16px; } .blur-toggle-button { display: flex; align-items: center; background: transparent; border: none; cursor: pointer; padding: 6px 12px; border-radius: 20px; transition: background-color 0.2s ease; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; } .blur-toggle-button:hover { background-color: rgba(0, 0, 0, 0.05); } .blur-toggle-inner { display: flex; align-items: center; gap: 8px; } .blur-toggle-label { font-size: 14px; color: #61666d; user-select: none; } .blur-toggle-switch { position: relative; width: 40px; height: 22px; background-color: #c9ccd0; border-radius: 11px; transition: background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1); } .blur-toggle-switch::after { content: ''; position: absolute; top: 2px; left: 2px; width: 18px; height: 18px; background-color: white; border-radius: 50%; transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1); box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); } .blur-toggle-switch.active { background-color: #00aeec; } .blur-toggle-switch.active::after { transform: translateX(18px); } /* 确认对话框样式 */ .blur-toggle-dialog-overlay { position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; background-color: rgba(0, 0, 0, 0); display: flex !important; align-items: center !important; justify-content: center !important; z-index: 10000 !important; transition: background-color 0.3s cubic-bezier(0.4, 0, 0.2, 1); margin: 0 !important; padding: 0 !important; } .blur-toggle-dialog-overlay.show { background-color: rgba(0, 0, 0, 0.6); } .blur-toggle-dialog-overlay.closing { background-color: rgba(0, 0, 0, 0); } .blur-toggle-dialog-overlay.closing .blur-toggle-dialog { transform: scale(0.9); opacity: 0; } .blur-toggle-dialog { background: white; border-radius: 6px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); max-width: 450px; width: 90%; transform: scale(0.9); opacity: 0; transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; } .blur-toggle-dialog-overlay.show .blur-toggle-dialog { transform: scale(1); opacity: 1; } .blur-toggle-dialog-content { padding: 32px 24px 24px; } .blur-toggle-dialog-title { margin: 0 0 12px; font-size: 20px; font-weight: 600; color: #18191c; opacity: 0; animation: fadeInText 0.4s cubic-bezier(0.4, 0, 0.2, 1) 0.1s forwards; } .blur-toggle-dialog-message { margin: 0 0 24px; font-size: 15px; color: #61666d; line-height: 1.6; opacity: 0; animation: fadeInText 0.4s cubic-bezier(0.4, 0, 0.2, 1) 0.2s forwards; } .blur-toggle-dialog-buttons { display: flex; gap: 12px; justify-content: flex-end; opacity: 0; animation: fadeInText 0.4s cubic-bezier(0.4, 0, 0.2, 1) 0.3s forwards; } .blur-toggle-dialog-btn { padding: 10px 24px; border: none; border-radius: 6px; font-size: 14px; font-weight: 500; cursor: pointer; transition: all 0.2s ease; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; } .blur-toggle-dialog-btn-cancel { background-color: #f1f2f3; color: #61666d; } .blur-toggle-dialog-btn-cancel:hover { background-color: #e3e5e7; } .blur-toggle-dialog-btn-confirm { background-color: #00aeec; color: white; } .blur-toggle-dialog-btn-confirm:hover { background-color: #40c5f1; } .blur-toggle-dialog-btn:active { transform: scale(0.96); } @keyframes fadeInText { from { opacity: 0; transform: translateY(-8px); } to { opacity: 1; transform: translateY(0); } } `; // 注入所有 CSS GM_addStyle(cssRules + commentStyles); console.log('[Bilibili纯粹化] 样式已注入'); // 辅助函数 - 获取范围内随机整数 function getRandomInt(min, max) { min = Math.ceil(min); max = Math.floor(max); return Math.floor(Math.random() * (max - min + 1)) + min; } // 辅助函数 - 标准化字符格式 function normalizeText(str) { if (!str) return ''; return str .toLowerCase() .normalize('NFKC') // 统一全角半角 .replace(/[\s\-_]+/g, '') // 去掉空格/下划线/横线等分隔符 } // 评论区净化功能 - 移除超链接、点赞数、UP主点赞标识、用户装饰 function purifyComments() { //console.log('[Bilibili纯粹化-调试] purifyComments 函数被调用'); let processedCount = { searchLinks: 0, likeCounts: 0, upTags: 0, userStyles: 0, userLevels: 0, sailingCards: 0, avatarLayers: 0 }; // 存储所有观察器 const observers = new Set(); // 处理评论中的搜索关键词超链接 function processSearchLinks(richText) { if (!richText || !richText.shadowRoot) return; const contents = richText.shadowRoot.querySelector('#contents'); if (!contents) return; const searchLinks = contents.querySelectorAll('a[data-type="search"]'); searchLinks.forEach(link => { const span = document.createElement('span'); span.textContent = link.textContent; span.className = link.className; link.parentNode.replaceChild(span, link); //processedCount.searchLinks++; const img = span.querySelector('img'); if (img) { img.style.display = 'none'; } }); } // 隐藏点赞数量 function hideLikeCount(actionButtons) { if (!actionButtons || !actionButtons.shadowRoot) return; const likeDiv = actionButtons.shadowRoot.querySelector('#like'); if (!likeDiv) return; const countSpan = likeDiv.querySelector('button #count'); if (countSpan) { countSpan.style.display = 'none'; //processedCount.likeCounts++; } } // 隐藏UP主点赞标识 function hideUpLikeTags(mainDiv) { if (!mainDiv) return; const tagsDiv = mainDiv.querySelector('#tags'); if (tagsDiv) { tagsDiv.style.display = 'none'; //processedCount.upTags++; } } // 净化用户信息(移除用户名样式、隐藏等级) function purifyUserInfo(userInfo) { if (!userInfo || !userInfo.shadowRoot) return; const infoDiv = userInfo.shadowRoot.querySelector('#info'); if (!infoDiv) return; // 移除用户名的 style 属性 const userNameDiv = infoDiv.querySelector('#user-name'); if (userNameDiv) { const userNameLink = userNameDiv.querySelector('a'); if (userNameLink && userNameLink.hasAttribute('style')) { userNameLink.removeAttribute('style'); //processedCount.userStyles++; } } // 隐藏用户等级 const userLevelDiv = infoDiv.querySelector('#user-level'); if (userLevelDiv && userLevelDiv.style.display !== 'none') { userLevelDiv.style.display = 'none'; //processedCount.userLevels++; } // 隐藏用户勋章 const userMedalDiv = infoDiv.querySelector('#user-medal'); if (userMedalDiv && userMedalDiv.style.display !== 'none') { userMedalDiv.style.display = 'none'; } } // 隐藏用户装扮卡片 function removeSailingCard(header) { if (!header) return; const sailingCard = header.querySelector('bili-comment-user-sailing-card'); if (sailingCard) { sailingCard.style.display = 'none'; //processedCount.sailingCards++; } } // 隐藏头像装饰层 function hideAvatarLayers(avatar) { if (!avatar || !avatar.shadowRoot) return; const canvasDiv = avatar.shadowRoot.querySelector('#canvas'); if (!canvasDiv) return; // 隐藏 class="layer" 的 div (大会员标志) const layers = canvasDiv.querySelectorAll('.layer'); layers.forEach(layer => { if(!layer.classList.contains('center')){ if (layer.style.display !== 'none') { layer.style.display = 'none'; //processedCount.avatarLayers++; } } }); // 隐藏 class="layer-res" 且没有 style 属性的 div,并隐藏其他layer-res的style (头像框) const layerRes = canvasDiv.querySelectorAll('.layer-res'); layerRes.forEach(res => { if (!res.hasAttribute('style') && res.style.display !== 'none') { res.style.display = 'none'; //processedCount.avatarLayers++; } }); //另一种头像框 在隐藏头像框的同时统一头像大小 (可能是动态头像框?) const layerCenter = canvasDiv.querySelectorAll('.layer.center'); layerCenter.forEach(layer => { if(layer.style.width == '66px'){ layer.style.display = 'none'; }else if(layer.style.width !== '48px'){ layer.style.width = '48px'; layer.style.height = '48px'; } }) } // 处理用户头像 function processUserAvatar(bodyDiv) { if (!bodyDiv) return; const avatarLink = bodyDiv.querySelector('#user-avatar'); if (!avatarLink) return; const avatar = avatarLink.querySelector('bili-avatar'); if (avatar) { hideAvatarLayers(avatar); // 监听 avatar 的 shadowRoot if (avatar.shadowRoot) { observeShadowRoot(avatar.shadowRoot, () => { hideAvatarLayers(avatar); }); } } } // 为 Shadow Root 设置观察器 function observeShadowRoot(shadowRoot, callback) { if (!shadowRoot) return null; const observer = new MutationObserver(callback); observer.observe(shadowRoot, { childList: true, subtree: true, attributes: true }); observers.add(observer); return observer; } // 处理单个评论 function processComment(commentRenderer) { if (!commentRenderer || !commentRenderer.shadowRoot) return; // 监听 commentRenderer 的 shadowRoot observeShadowRoot(commentRenderer.shadowRoot, () => { const body = commentRenderer.shadowRoot.querySelector('#body'); if (!body) return; const main = body.querySelector('#main'); if (!main) return; // 处理评论内容 const content = main.querySelector('#content'); if (content) { const richText = content.querySelector('bili-rich-text'); processSearchLinks(richText); // 监听 richText 的 shadowRoot if (richText && richText.shadowRoot) { observeShadowRoot(richText.shadowRoot, () => { processSearchLinks(richText); }); } } // 处理用户信息 const header = main.querySelector('#header'); if (header) { const userInfo = header.querySelector('bili-comment-user-info'); if (userInfo) { purifyUserInfo(userInfo); removeSailingCard(header); // 监听 userInfo 的 shadowRoot if (userInfo.shadowRoot) { observeShadowRoot(userInfo.shadowRoot, () => { purifyUserInfo(userInfo); }); } } } // 处理用户头像 processUserAvatar(body); const footer = main.querySelector('#footer'); if (footer) { const actionButtons = footer.querySelector('bili-comment-action-buttons-renderer'); hideLikeCount(actionButtons); // 监听 actionButtons 的 shadowRoot if (actionButtons && actionButtons.shadowRoot) { observeShadowRoot(actionButtons.shadowRoot, () => { hideLikeCount(actionButtons); }); } } hideUpLikeTags(main); }); // 立即执行一次处理 const body = commentRenderer.shadowRoot.querySelector('#body'); if (!body) return; const main = body.querySelector('#main'); if (!main) return; const content = main.querySelector('#content'); if (content) { const richText = content.querySelector('bili-rich-text'); processSearchLinks(richText); if (richText && richText.shadowRoot) { observeShadowRoot(richText.shadowRoot, () => { processSearchLinks(richText); }); } } const header = main.querySelector('#header'); if (header) { const userInfo = header.querySelector('bili-comment-user-info'); if (userInfo) { purifyUserInfo(userInfo); removeSailingCard(header); if (userInfo.shadowRoot) { observeShadowRoot(userInfo.shadowRoot, () => { purifyUserInfo(userInfo); }); } } } processUserAvatar(body); const footer = main.querySelector('#footer'); if (footer) { const actionButtons = footer.querySelector('bili-comment-action-buttons-renderer'); hideLikeCount(actionButtons); if (actionButtons && actionButtons.shadowRoot) { observeShadowRoot(actionButtons.shadowRoot, () => { hideLikeCount(actionButtons); }); } } hideUpLikeTags(main); } // 处理楼中楼回复 function processReplies(repliesRenderer) { if (!repliesRenderer || !repliesRenderer.shadowRoot) return; // 监听 repliesRenderer 的 shadowRoot observeShadowRoot(repliesRenderer.shadowRoot, () => { const expander = repliesRenderer.shadowRoot.querySelector('#expander'); if (!expander) return; const expanderContents = expander.querySelector('#expander-contents'); if (!expanderContents) return; const replyRenderers = expanderContents.querySelectorAll('bili-comment-reply-renderer'); replyRenderers.forEach(replyRenderer => { if (!replyRenderer.shadowRoot) return; // 监听每个 replyRenderer 的 shadowRoot observeShadowRoot(replyRenderer.shadowRoot, () => { const body = replyRenderer.shadowRoot.querySelector('#body'); if (!body) return; const main = body.querySelector('#main'); if (!main) return; const richText = main.querySelector('bili-rich-text'); processSearchLinks(richText); if (richText && richText.shadowRoot) { observeShadowRoot(richText.shadowRoot, () => { processSearchLinks(richText); }); } // 处理楼中楼的用户信息 const userInfo = main.querySelector('bili-comment-user-info'); if (userInfo) { purifyUserInfo(userInfo); if (userInfo.shadowRoot) { observeShadowRoot(userInfo.shadowRoot, () => { purifyUserInfo(userInfo); }); } } const footer = body.querySelector('#footer'); if (footer) { const actionButtons = footer.querySelector('bili-comment-action-buttons-renderer'); hideLikeCount(actionButtons); if (actionButtons && actionButtons.shadowRoot) { observeShadowRoot(actionButtons.shadowRoot, () => { hideLikeCount(actionButtons); }); } } }); // 立即执行一次处理 const body = replyRenderer.shadowRoot.querySelector('#body'); if (!body) return; const main = body.querySelector('#main'); if (!main) return; const richText = main.querySelector('bili-rich-text'); processSearchLinks(richText); if (richText && richText.shadowRoot) { observeShadowRoot(richText.shadowRoot, () => { processSearchLinks(richText); }); } const userInfo = main.querySelector('bili-comment-user-info'); if (userInfo) { purifyUserInfo(userInfo); if (userInfo.shadowRoot) { observeShadowRoot(userInfo.shadowRoot, () => { purifyUserInfo(userInfo); }); } } const footer = body.querySelector('#footer'); if (footer) { const actionButtons = footer.querySelector('bili-comment-action-buttons-renderer'); hideLikeCount(actionButtons); if (actionButtons && actionButtons.shadowRoot) { observeShadowRoot(actionButtons.shadowRoot, () => { hideLikeCount(actionButtons); }); } } }); }); // 立即执行一次处理 const expander = repliesRenderer.shadowRoot.querySelector('#expander'); if (!expander) return; const expanderContents = expander.querySelector('#expander-contents'); if (!expanderContents) return; const replyRenderers = expanderContents.querySelectorAll('bili-comment-reply-renderer'); replyRenderers.forEach(replyRenderer => { if (!replyRenderer.shadowRoot) return; observeShadowRoot(replyRenderer.shadowRoot, () => { const body = replyRenderer.shadowRoot.querySelector('#body'); if (!body) return; const main = body.querySelector('#main'); if (!main) return; const richText = main.querySelector('bili-rich-text'); processSearchLinks(richText); if (richText && richText.shadowRoot) { observeShadowRoot(richText.shadowRoot, () => { processSearchLinks(richText); }); } const userInfo = main.querySelector('bili-comment-user-info'); if (userInfo) { purifyUserInfo(userInfo); if (userInfo.shadowRoot) { observeShadowRoot(userInfo.shadowRoot, () => { purifyUserInfo(userInfo); }); } } const footer = body.querySelector('#footer'); if (footer) { const actionButtons = footer.querySelector('bili-comment-action-buttons-renderer'); hideLikeCount(actionButtons); if (actionButtons && actionButtons.shadowRoot) { observeShadowRoot(actionButtons.shadowRoot, () => { hideLikeCount(actionButtons); }); } } }); const body = replyRenderer.shadowRoot.querySelector('#body'); if (!body) return; const main = body.querySelector('#main'); if (!main) return; const richText = main.querySelector('bili-rich-text'); processSearchLinks(richText); if (richText && richText.shadowRoot) { observeShadowRoot(richText.shadowRoot, () => { processSearchLinks(richText); }); } const userInfo = main.querySelector('bili-comment-user-info'); if (userInfo) { purifyUserInfo(userInfo); if (userInfo.shadowRoot) { observeShadowRoot(userInfo.shadowRoot, () => { purifyUserInfo(userInfo); }); } } const footer = body.querySelector('#footer'); if (footer) { const actionButtons = footer.querySelector('bili-comment-action-buttons-renderer'); hideLikeCount(actionButtons); if (actionButtons && actionButtons.shadowRoot) { observeShadowRoot(actionButtons.shadowRoot, () => { hideLikeCount(actionButtons); }); } } }); } // 处理所有评论线程 function processAllComments() { const biliComments = document.querySelector('bili-comments'); if (!biliComments || !biliComments.shadowRoot) return false; const contents = biliComments.shadowRoot.querySelector('#contents'); if (!contents) return false; const feed = contents.querySelector('#feed'); if (!feed) return false; const threads = feed.querySelectorAll('bili-comment-thread-renderer'); threads.forEach((thread, index) => { if (!thread.shadowRoot) return; // 监听每个 thread 的 shadowRoot observeShadowRoot(thread.shadowRoot, () => { const commentRenderer = thread.shadowRoot.querySelector('bili-comment-renderer'); if (commentRenderer) { processComment(commentRenderer); } const replies = thread.shadowRoot.querySelector('#replies'); if (replies) { const repliesRenderer = replies.querySelector('bili-comment-replies-renderer'); if (repliesRenderer) { processReplies(repliesRenderer); } } }); // 立即执行一次处理 const commentRenderer = thread.shadowRoot.querySelector('bili-comment-renderer'); if (commentRenderer) { processComment(commentRenderer); } const replies = thread.shadowRoot.querySelector('#replies'); if (replies) { const repliesRenderer = replies.querySelector('bili-comment-replies-renderer'); if (repliesRenderer) { processReplies(repliesRenderer); } } }); // if (processedCount.searchLinks > 0 || processedCount.likeCounts > 0 || processedCount.upTags > 0 || // processedCount.userStyles > 0 || processedCount.userLevels > 0 || processedCount.sailingCards > 0 || // processedCount.avatarLayers > 0) { // console.log(`[Bilibili纯粹化-调试] 本次处理完成 - 搜索链接: ${processedCount.searchLinks}, 点赞数: ${processedCount.likeCounts}, UP标识: ${processedCount.upTags}, 用户名样式: ${processedCount.userStyles}, 用户等级: ${processedCount.userLevels}, 装扮卡片: ${processedCount.sailingCards}, 头像装饰: ${processedCount.avatarLayers}`); // } // processedCount = { // searchLinks: 0, // likeCounts: 0, // upTags: 0, // userStyles: 0, // userLevels: 0, // sailingCards: 0, // avatarLayers: 0 // }; return true; } // 监听评论区变化 function observeComments(retryCount = 0) { const maxRetries = 20; const biliComments = document.querySelector('bili-comments'); if (!biliComments) { if (retryCount < maxRetries) { setTimeout(() => observeComments(retryCount + 1), 500); } return; } if (!biliComments.shadowRoot) { if (retryCount < maxRetries) { setTimeout(() => observeComments(retryCount + 1), 500); } return; } // 监听 biliComments 的 shadowRoot observeShadowRoot(biliComments.shadowRoot, () => { processAllComments(); }); function waitForContents(contentRetryCount = 0) { const maxContentRetries = 20; const contents = biliComments.shadowRoot.querySelector('#contents'); if (!contents) { if (contentRetryCount < maxContentRetries) { setTimeout(() => waitForContents(contentRetryCount + 1), 500); } return; } // 监听 contents observeShadowRoot(contents, () => { processAllComments(); }); function waitForFeed(feedRetryCount = 0) { const maxFeedRetries = 20; const feed = contents.querySelector('#feed'); if (!feed) { if (feedRetryCount < maxFeedRetries) { setTimeout(() => waitForFeed(feedRetryCount + 1), 500); } return; } //console.log('[Bilibili纯粹化-调试] #feed 已找到,开始初始处理和监听'); // 监听 feed observeShadowRoot(feed, () => { processAllComments(); }); // 初始处理 processAllComments(); console.log('[Bilibili纯粹化] 评论区净化功能已启用'); } waitForFeed(); } waitForContents(); } observeComments(); } // 评论区锁定功能 function initCommentLock(pageType) { var commentApp; switch (pageType) { case "video": commentApp = document.querySelector('#commentapp'); break; case "bangumi": commentApp = document.querySelector('#comment-body'); break; default: return; } if (!commentApp || document.querySelector('#comment-lock-container')) { return; } // 创建遮罩容器 const container = document.createElement('div'); container.id = 'comment-lock-container'; // 创建遮罩层 const overlay = document.createElement('div'); overlay.id = 'comment-lock-overlay'; overlay.innerHTML = `
在查看评论前,请先思考一下
`; // 以容器包裹评论区 commentApp.parentNode.insertBefore(container, commentApp); container.appendChild(commentApp); container.appendChild(overlay); // 点击解锁按钮 const unlockBtn = overlay.querySelector('#unlock-comment-btn'); unlockBtn.addEventListener('click', showDialog); console.log('[Bilibili纯粹化] 评论区锁定已启用'); } function showDialog() { // 创建对话框 const dialogOverlay = document.createElement('div'); dialogOverlay.id = 'comment-dialog-overlay'; dialogOverlay.innerHTML = `

请确认你真的想进入这个评论区。

保持清醒,不要被平台/媒体操控。

思考:你现在希望从评论中获得什么?

3
`; document.body.appendChild(dialogOverlay); // 倒计时逻辑 let count = 3; const countdownEl = document.getElementById('countdown'); const inputArea = document.getElementById('input-area'); const confirmBtn = document.getElementById('confirm-btn'); const input = document.getElementById('reflection-input'); const errorMsg = document.getElementById('error-msg'); const timer = setInterval(() => { count--; countdownEl.textContent = count; if (count === 0) { clearInterval(timer); countdownEl.textContent = '✓'; countdownEl.classList.add('completed'); inputArea.classList.add('unlocked'); input.focus(); } }, 1000); // 确认按钮逻辑 confirmBtn.addEventListener('click', () => { if (input.value.trim() === '我保持思考') { // 解锁评论区 - 直接移除遮罩层 const lockOverlay = document.querySelector('#comment-lock-overlay'); if (lockOverlay) { lockOverlay.remove(); } dialogOverlay.remove(); console.log('[Bilibili纯粹化] 评论区已解锁'); } else { errorMsg.textContent = '请输入正确的文字'; input.style.borderColor = '#e74c3c'; setTimeout(() => { errorMsg.textContent = ''; input.style.borderColor = '#ddd'; }, 2000); } }); // 支持回车键确认 input.addEventListener('keypress', (e) => { if (e.key === 'Enter') { confirmBtn.click(); } }); // 点击遮罩关闭 dialogOverlay.addEventListener('click', (e) => { if (e.target === dialogOverlay) { dialogOverlay.remove(); } }); } // 评论区锁定初始化 function waitForComment(pageType) { const observer = new MutationObserver(() => { const biliComments = document.querySelector('bili-comments') if (biliComments && !document.querySelector('#comment-lock-container')) { initCommentLock(pageType); } }); if (document.body) { observer.observe(document.body, { childList: true, subtree: true }); } else { setTimeout(() => waitForComment(pageType), 100); } } //取消自动连播 function autoContinuousOff(){ let hasClicked = false; // 防止重复点击 const observer = new MutationObserver(() => { // 查找自动连播容器 const continuousBtn = document.querySelector('.continuous-btn'); if (continuousBtn) { // 查找开启状态的按钮 const switchBtnOn = continuousBtn.querySelector('.switch-btn.on'); if (switchBtnOn && !hasClicked) { hasClicked = true; switchBtnOn.click(); console.log('[Bilibili纯粹化] 尝试关闭自动连播'); // 等待 500ms 后检查是否真的关闭了 setTimeout(() => { const checkBtn = document.querySelector('.continuous-btn .switch-btn'); if (checkBtn && !checkBtn.classList.contains('on')) { console.log('[Bilibili纯粹化] 自动连播已关闭'); observer.disconnect(); } else { console.log('[Bilibili纯粹化] 自动连播关闭失败,继续尝试'); hasClicked = false; // 允许再次点击 } }, 500); } else { // 检查是否已经是关闭状态 const switchBtn = continuousBtn.querySelector('.switch-btn'); if (switchBtn && !switchBtn.classList.contains('on')) { console.log('[Bilibili纯粹化] 已经是关闭状态'); observer.disconnect(); } } } }); // 开始监听 DOM 变化 observer.observe(document.documentElement, { childList: true, subtree: true }); // 10秒后停止检查 setTimeout(() => observer.disconnect(), 10000); } // 视频页相关功能 if (window.location.pathname.includes('/video/')) { //评论区锁定 waitForComment("video"); //关闭自动连播 autoContinuousOff(); //评论区净化 purifyComments(); } //剧播放页相关功能 if (window.location.pathname.includes('/bangumi/')) { //评论区锁定 waitForComment("bangumi"); //评论区净化 purifyComments(); } // 直播间聊天框彩色背景/彩色名字/彩色名字/特殊弹幕移除功能 function removeChatColors() { // 查找所有带彩色背景的聊天项 const colorfulChats = document.querySelectorAll('.chat-item.danmaku-item.has-bubble'); colorfulChats.forEach(chat => { // 移除 style 属性以去掉背景颜色 if (chat.hasAttribute('style')) { chat.removeAttribute('style'); } }); //移除用户名字颜色 const userNames = document.querySelectorAll('span.user-name.v-middle.pointer.open-menu'); userNames.forEach(name => { if(name.style.color !== '#ffffff'){ name.setAttribute('style', ''); } }) //修改特殊弹幕 const regularDanmakuClassname = 'bili-danmaku-x-dm bili-danmaku-x-roll bili-danmaku-x-show'; // 标准弹幕style const regularDanmakuStyle = `--opacity: 1; --fontSize: 25px; --fontFamily: SimHei, "Microsoft JhengHei", Arial, Helvetica, sans-serif; --fontWeight: bold; --color: #ffffff; --textShadow: 1px 0 1px #000000,0 1px 1px #000000,0 -1px 1px #000000,-1px 0 1px #000000; --display: none; --offset: 1275px; --translateX: -1387px; --duration: 9.5s; --top: 0px;`; const whiteColorHex = '#ffffff'; const MAX_TOP_PIXELS = 200; // 特殊弹幕替换滚动顶部随机距离范围上限 const MIN_TOP_PIXELS = 0; // 特殊弹幕替换滚动顶部随机距离范围下限 // 所有不需要处理(非特殊弹幕)的类名集合 const standardClassnames = new Set([ regularDanmakuClassname, 'bili-danmaku-x-dm bili-danmaku-x-roll', // preparingDanmakuClassname 'bili-danmaku-x-dm', // offScreenDanmakuClassname 'bili-danmaku-x-dm-rotate', // danmakuRotateClassname 'bilibili-combo-danmaku-container' // comboDanmakucontainerClassname ]); const danmakuContainer = document.querySelector('.danmaku-item-container'); if (!danmakuContainer) return; const danmakus = danmakuContainer.childNodes; danmakus.forEach(danmaku => { if (danmaku.nodeType !== 1 || !danmaku.style) return; const currentClassName = danmaku.className; const isStandardClass = standardClassnames.has(currentClassName); const currentColor = danmaku.style.getPropertyValue('--color').trim(); //修改非白色弹幕的颜色 if (isStandardClass && currentColor !== whiteColorHex) { //console.log(`[Bilibili纯粹化-调试] [滚动非白色弹幕] ${danmaku.textContent}, 类名:${currentClassName}, 颜色:${currentColor}`); // 修改颜色 danmaku.style.setProperty('--color', whiteColorHex); } //修改非滚动弹幕的类型 if (!isStandardClass) { //console.log(`[Bilibili纯粹化-调试] [非滚动弹幕] ${danmaku.textContent}, 原始类名:${currentClassName}, 颜色:${currentColor}`); // 修改类名并给予随机顶部距离 danmaku.className = regularDanmakuClassname; danmaku.setAttribute('style',regularDanmakuStyle); const randomTop = getRandomInt(MIN_TOP_PIXELS, MAX_TOP_PIXELS); danmaku.style.setProperty('--top', `${randomTop}px`); } }); } // 监听直播间聊天框的动态变化 function initLiveChatObserver() { // 等待聊天框容器加载 const checkChatContainer = setInterval(() => { const chatContainer = document.querySelector('#chat-items'); if (chatContainer) { clearInterval(checkChatContainer); // 处理已存在的彩色背景/彩色名字/彩色名字/特殊弹幕 removeChatColors(); // 监听新增的聊天消息 const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes.length > 0) { removeChatColors(); } }); }); observer.observe(chatContainer, { childList: true, subtree: true }); console.log('[Bilibili纯粹化] 直播间聊天净化已启用'); } }, 500); // 10秒后停止检查(避免无限循环) setTimeout(() => clearInterval(checkChatContainer), 10000); } // 直播页启用聊天净化 if (window.location.hostname === 'live.bilibili.com') { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initLiveChatObserver); } else { initLiveChatObserver(); } } //直播间首页播放器删除 function removeVideoOnly() { const observer = new MutationObserver(() => { const playerCtnr = document.querySelector('.player-ctnr.p-relative.over-hidden.dp-i-block.v-top.t-left'); if (playerCtnr) { const video = playerCtnr.querySelector('video'); if (video) { video.remove(); console.log('[Bilibili纯粹化] 已删除 video'); observer.disconnect(); // 删除后停止监控 } } }); observer.observe(document.documentElement, { childList: true, subtree: true }); } if (window.location.hostname === 'live.bilibili.com' && window.location.pathname === '/') { removeVideoOnly(); } // 直播分区页横幅样式修改 function modifyBannerClass() { const observer = new MutationObserver(() => { const banners = document.querySelectorAll('div.index_flip-view_R276P.index_banner_bPw9q'); banners.forEach(banner => { // 检查是否已经添加了目标 class if (!banner.classList.contains('index_no_pic_TF1Ph') || !banner.classList.contains('bg-bright-filter')) { banner.className = 'index_flip-view_R276P index_banner_bPw9q index_no_pic_TF1Ph bg-bright-filter'; console.log('[Bilibili纯粹化] 已修改横幅 class'); } }); }); // 开始监听 observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['class'] }); console.log('[Bilibili纯粹化] 直播横幅样式修改已启用'); } // 在直播分区页面启用横幅样式修改 if (window.location.hostname === 'live.bilibili.com' && (window.location.pathname.includes('/p/') || //谁设计的这分区规范??? //英雄联盟分区 window.location.pathname.includes('/lol/') || //吃鸡行动分区 window.location.pathname.includes('/area/'))) { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', modifyBannerClass); } else { modifyBannerClass(); } } // 搜索框推荐关键字修改 function modifySearchInput() { // 配置: const searchConfig = { //包含的div containerClasses: [ 'nav-search-content', 'search-input-wrap.flex_between', 'p-relative.search-bar.over-hidden.border-box.t-nowrap', 'nav-search' ], placeholder: '输入关键字搜索', removeTitle: true }; // 构建选择器字符串 const selectors = searchConfig.containerClasses.map(cls => { const selector = cls.split('.').join('.'); return `.${selector} input`; }).join(', '); const observer = new MutationObserver(() => { const inputs = document.querySelectorAll(selectors); inputs.forEach(input => { // 修改 placeholder if (input.placeholder !== searchConfig.placeholder) { input.placeholder = searchConfig.placeholder; //console.log('[Bilibili纯粹化] 已修改搜索框 placeholder'); } // 删除 title 属性 if (searchConfig.removeTitle && input.hasAttribute('title')) { input.removeAttribute('title'); //console.log('[Bilibili纯粹化] 已删除搜索框 title 属性'); } }); }); // 开始监听 observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['placeholder', 'title'] }); console.log('[Bilibili纯粹化] 搜索框修改功能已启用'); } // 启用搜索框推荐关键字修改功能 if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', modifySearchInput); } else { modifySearchInput(); } // 隐藏搜索页广告视频 + 模糊视频封面功能 function removeSearchPageAdVideo() { const hiddenVideos = new Set(); // 记录已隐藏的视频 const blurredCovers = new Set(); // 记录已添加模糊遮罩的封面 const unblurredCovers = new Set(); // 记录用户已手动显示的封面 let isCoversBLurred = true; // 封面模糊开关,默认开启 const pendingVideos = new Set(); // 可能的算法推荐视频 const allRequestInstances = new Set(); // 发起的网络请求 let currentSearchKeyword = ""; const URL_CHANGE_EVENT = 'bp-url-change'; // 自定义的url更新事件 let lastHref = location.href; // 变更前url存储 // 包裹原生 pushState / replaceState 调用后手动派发事件 function wrapHistoryMethod(type) { const orig = history[type]; return function () { const ret = orig.apply(this, arguments); // 派发事件 window.dispatchEvent(new Event(URL_CHANGE_EVENT)); return ret; }; } history.pushState = wrapHistoryMethod('pushState'); history.replaceState = wrapHistoryMethod('replaceState'); // 监听浏览器前进/后退 window.addEventListener('popstate', function () { window.dispatchEvent(new Event(URL_CHANGE_EVENT)); }); // url变更后行为 function handleUrlChange() { if (location.href === lastHref) return; // 防止重复处理 lastHref = location.href; //console.log("url变啦!") if(allRequestInstances.size>=1){ allRequestInstances.forEach(requestInstance => { requestInstance.abort(); console.log("[Bilibili纯粹化] 已停止之前的网络请求"); }) } pendingVideos.clear(); allRequestInstances.clear(); } // 当视频被添加到 pendingVideos 时,触发 pendingVideoAdded 事件 function addPendingVideo(video) { if (!pendingVideos.has(video)) { pendingVideos.add(video); document.dispatchEvent(new Event('pendingVideoAdded')); // 触发事件 } } //根据视频元素构建视频URL function buildUrlForTags(video){ const videoLinkTag = video.querySelector('a') if(!videoLinkTag) return; let videoUrl = videoLinkTag.href; if(videoUrl.includes("m.bilibili.com")){ videoUrl.replace("m.bilibili.com","www.bilibili.com"); } return videoUrl; } //智能提取关键词 function smartTokenize(keyword) { keyword = keyword.trim(); if (!keyword) return []; // 如果用户自己打了空格,那我们就尊重空格拆法 if (/\s/.test(keyword)) { return keyword.split(/\s+/).filter(Boolean); } const hasChinese = /[\u4e00-\u9fa5]/.test(keyword); const hasLatinDigit = /[a-zA-Z0-9]/.test(keyword); // 只英文/数字:整体作为一个token if (!hasChinese && hasLatinDigit) { return [keyword]; } // 只中文:用整串 + 二字滑窗做token if (hasChinese && !hasLatinDigit) { const s = keyword.replace(/\s+/g, ''); if (s.length <= 2) return [s]; // 太短就不拆 const tokens = [s]; for (let i = 0; i < s.length - 1; i++) { tokens.push(s.slice(i, i + 2)); } return tokens; } // 混合中文 + 英文/数字:按字符类型分段 const tokens = []; let current = ''; let currentType = null; const getType = ch => { if (/[\u4e00-\u9fa5]/.test(ch)) return 'C'; // Chinese if (/[a-zA-Z0-9]/.test(ch)) return 'L'; // Latin/digit return 'O'; // other符号 }; for (const ch of keyword) { const t = getType(ch); if (t === 'O') { // 符号:当作分隔 if (current) { tokens.push(current); current = ''; currentType = null; } continue; } if (!currentType || t === currentType) { current += ch; currentType = t; } else { tokens.push(current); current = ch; currentType = t; } } if (current) tokens.push(current); return tokens.filter(Boolean); } // 隐藏广告视频/推送视频 function hideAdVideos(container) { if (!container) return; const videos = container.querySelectorAll(':scope > *'); videos.forEach(video => { // 隐藏广告视频 if (hiddenVideos.has(video)) return; const adFeedbackEntry = video.querySelector('.ad-feedback-entry'); if (adFeedbackEntry) { video.style.display = 'none'; hiddenVideos.add(video); console.log('[Bilibili纯粹化] 已隐藏一个广告视频'); return; } if(pendingVideos.has(video))return; // 隐藏推送视频 const currentUrl = new URL(window.location.href); const rawKeyword = currentUrl.searchParams.get('keyword'); if (!rawKeyword) return; currentSearchKeyword = rawKeyword; const videoTitle = video.querySelector('.bili-video-card__info--tit'); const videoAuthor = video.querySelector('.bili-video-card__info--author'); if (!videoTitle || !videoAuthor) return; const videoTitleText = videoTitle.textContent || ''; const videoAuthorText = videoAuthor.textContent || ''; const normTitle = normalizeText(videoTitleText); const normAuthor = normalizeText(videoAuthorText); // 智能拆词 let tokens = smartTokenize(rawKeyword); // 把整串原keyword也当作一个token,增加命中机会: if (!tokens.includes(rawKeyword.trim())) { tokens.unshift(rawKeyword.trim()); } // 规范化每个token const normTokens = tokens .map(t => normalizeText(t)) .filter(t => t.length > 0); if (!normTokens.length) return; // 统计命中token的数量 let matchTokenCount = 0; for (const token of normTokens) { if (normTitle.includes(token) || normAuthor.includes(token)) { matchTokenCount++; } } let keepVideo = false; if (normTokens.length === 1) { // 单一关键词(大概率是ID),必须命中才保留 keepVideo = matchTokenCount === 1; } else { // 多token情况:至少命中一个就保留 // 可以改成比例形式: // const ratio = matchTokenCount / normTokens.length; // keepVideo = ratio >= 0.3; // 举例 keepVideo = matchTokenCount >= 1; } if (keepVideo) { return; // 不隐藏 } // 否则视为推荐视频,隐藏 video.style.display = 'none'; hiddenVideos.add(video); addPendingVideo(video); //console.log(`[Bilibili纯粹化-调试] 已隐藏一个可能的分析算法推荐视频:【${video.querySelector('.bili-video-card__info--tit')?.textContent}】,目前的检查视频set大小为:【${pendingVideos.size}】`); console.log('[Bilibili纯粹化] 已隐藏一个可能的分析算法推荐视频'); }); } // 为视频封面添加模糊遮罩 function addBlurMask(container) { if (!container || !isCoversBLurred) return; // 检查开关状态 const imageWraps = container.querySelectorAll('.bili-video-card__image--wrap'); imageWraps.forEach(wrap => { if (blurredCovers.has(wrap) || unblurredCovers.has(wrap)) return; const picture = wrap.querySelector('.v-img.bili-video-card__cover'); if (!picture) return; const searchPageCoverBlurMask = document.createElement('div'); searchPageCoverBlurMask.className = 'search-cover__mask'; const searchPageCoverShowButton = document.createElement('button'); searchPageCoverShowButton.textContent = '显示封面'; searchPageCoverShowButton.className = 'search-cover__button'; searchPageCoverBlurMask.addEventListener('mouseenter', () => { searchPageCoverShowButton.classList.add('visible'); }); searchPageCoverBlurMask.addEventListener('mouseleave', () => { searchPageCoverShowButton.classList.remove('visible'); }); searchPageCoverShowButton.addEventListener('mouseenter', () => { searchPageCoverShowButton.classList.add('mouse-in'); }); searchPageCoverShowButton.addEventListener('mouseleave', () => { searchPageCoverShowButton.classList.remove('mouse-in'); }); searchPageCoverShowButton.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); searchPageCoverBlurMask.remove(); blurredCovers.delete(wrap); unblurredCovers.add(wrap); }); searchPageCoverBlurMask.appendChild(searchPageCoverShowButton); if (getComputedStyle(wrap).position === 'static') { wrap.style.position = 'relative'; } wrap.appendChild(searchPageCoverBlurMask); blurredCovers.add(wrap); }); } // 移除所有模糊遮罩 function removeAllBlurMasks() { const allMasks = document.querySelectorAll('.search-cover__mask'); allMasks.forEach(mask => { const wrap = mask.parentElement; mask.remove(); blurredCovers.delete(wrap); unblurredCovers.add(wrap); }); //console.log('[Bilibili纯粹化] 已移除所有模糊遮罩'); } // 创建确认对话框 function showConfirmDialog(onConfirm, onCancel) { // 创建对话框容器 const dialogOverlay = document.createElement('div'); dialogOverlay.className = 'blur-toggle-dialog-overlay'; // 添加内联样式确保居中显示 dialogOverlay.style.cssText = 'position: fixed !important; top: 0 !important; left: 0 !important; width: 100vw !important; height: 100vh !important; display: flex !important; align-items: center !important; justify-content: center !important; z-index: 10000 !important;'; const dialogBox = document.createElement('div'); dialogBox.className = 'blur-toggle-dialog'; // 对话框内容 const dialogContent = document.createElement('div'); dialogContent.className = 'blur-toggle-dialog-content'; const title = document.createElement('h3'); title.className = 'blur-toggle-dialog-title'; title.textContent = '关闭视觉防护后,你将直接看到所有封面。'; const message = document.createElement('p'); message.className = 'blur-toggle-dialog-message'; message.textContent = '你此刻的观看意图是什么?'; const buttonGroup = document.createElement('div'); buttonGroup.className = 'blur-toggle-dialog-buttons'; const cancelBtn = document.createElement('button'); cancelBtn.className = 'blur-toggle-dialog-btn blur-toggle-dialog-btn-cancel'; cancelBtn.textContent = '返回'; const confirmBtn = document.createElement('button'); confirmBtn.className = 'blur-toggle-dialog-btn blur-toggle-dialog-btn-confirm'; confirmBtn.textContent = '我已确认'; // 关闭对话框的函数 const closeDialog = () => { dialogContent.remove(); dialogOverlay.classList.add('closing'); setTimeout(() => { dialogOverlay.remove(); }, 200); }; // 按钮事件 cancelBtn.addEventListener('click', () => { closeDialog(); if (onCancel) onCancel(); }); confirmBtn.addEventListener('click', () => { closeDialog(); if (onConfirm) onConfirm(); }); // 点击遮罩层关闭 dialogOverlay.addEventListener('click', (e) => { if (e.target === dialogOverlay) { closeDialog(); if (onCancel) onCancel(); } }); // 组装对话框 buttonGroup.appendChild(cancelBtn); buttonGroup.appendChild(confirmBtn); dialogContent.appendChild(title); dialogContent.appendChild(message); dialogContent.appendChild(buttonGroup); dialogBox.appendChild(dialogContent); dialogOverlay.appendChild(dialogBox); // 添加到页面 document.body.appendChild(dialogOverlay); // 触发动画 requestAnimationFrame(() => { dialogOverlay.classList.add('show'); }); } // 创建封面模糊切换按钮 function createBlurToggleButton() { // 查找导航栏 const navBar = document.querySelector('.vui_tabs--nav.vui_tabs--nav-pl0'); if (!navBar) { setTimeout(createBlurToggleButton, 500); return; } // 检查是否已经添加过按钮 if (document.querySelector('.blur-toggle-container')) return; // 创建按钮容器 const toggleContainer = document.createElement('li'); toggleContainer.className = 'blur-toggle-container'; const toggleButton = document.createElement('button'); toggleButton.className = 'blur-toggle-button'; toggleButton.setAttribute('aria-label', '封面模糊开关'); const toggleInner = document.createElement('span'); toggleInner.className = 'blur-toggle-inner'; const toggleLabel = document.createElement('span'); toggleLabel.className = 'blur-toggle-label'; toggleLabel.textContent = '视觉防护'; const toggleSwitch = document.createElement('span'); toggleSwitch.className = 'blur-toggle-switch active'; toggleInner.appendChild(toggleLabel); toggleInner.appendChild(toggleSwitch); toggleButton.appendChild(toggleInner); toggleContainer.appendChild(toggleButton); // 按钮点击事件 toggleButton.addEventListener('click', () => { if (isCoversBLurred) { // 当前是开启状态,点击后显示确认对话框 showConfirmDialog( // 确认回调 () => { isCoversBLurred = false; toggleSwitch.classList.remove('active'); removeAllBlurMasks(); console.log('[Bilibili纯粹化] 视觉防护已关闭'); }, // 取消回调 () => { // 保持开启状态,不做任何操作 console.log('[Bilibili纯粹化] 取消关闭视觉防护'); } ); } else { // 当前是关闭状态,直接开启 isCoversBLurred = true; toggleSwitch.classList.add('active'); // 清空已显示记录,允许重新添加遮罩 unblurredCovers.clear(); // 重新处理所有视频列表 const videoLists = document.querySelectorAll('.video-list'); videoLists.forEach(videoList => { addBlurMask(videoList); }); console.log('[Bilibili纯粹化] 视觉防护已开启'); } }); // 添加到导航栏末尾 navBar.appendChild(toggleContainer); console.log('[Bilibili纯粹化] 封面模糊开关按钮已添加'); } // 监听页面变化 function setupObserver() { const observer = new MutationObserver(() => { const videoLists = document.querySelectorAll('.video-list'); videoLists.forEach(videoList => { hideAdVideos(videoList); addBlurMask(videoList); }); }); observer.observe(document.body, { childList: true, subtree: true }); console.log('[Bilibili纯粹化] 搜索页功能已启用'); } // 监听 pendingVideoAdded 事件,重新检查视频 document.addEventListener('pendingVideoAdded', () => { pendingVideos.forEach(video => { // 如果未被检查过,进行检查流程 if (!video.dataset.checked) { //console.log(`[Bilibili纯粹化-调试] 视频【${video.querySelector('.bili-video-card__info--tit')?.textContent}】成功进入检查流程`) video.dataset.checked = 'true'; // 设置标记已检查 const url = buildUrlForTags(video); const keyword = currentSearchKeyword; //console.log(`[Bilibili纯粹化-调试] 即将开始针对视频【${video.querySelector('.bili-video-card__info--tit')?.textContent}】的网络请求`) const requestInstances = GM_xmlhttpRequest({ method: "GET", url: url, headers: { "Connection": "close", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 Edg/142.0.0.0" }, onload: function(response) { //console.log(`[Bilibili纯粹化-调试] 视频【${video.querySelector('.bili-video-card__info--tit')?.textContent}】的网络请求成功`) if (!video.isConnected) { requestInstances.abort(); //console.log(`[Bilibili纯粹化-调试] 视频【${video.querySelector('.bili-video-card__info--tit')?.textContent}】被判定为废弃节点`) console.log("[Bilibili纯粹化] 检测到废弃节点,已停止对应的请求。"); return; } const html = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(html, "text/html"); const metaKeywords = doc.querySelector('meta[itemprop="keywords"]'); const metaTitle = doc.querySelector('meta[itemprop="name"]'); const descriptionElement = doc.querySelector('span.desc-info-text'); const authorDescriptionElement = doc.querySelector('.up-description.up-detail-bottom'); //console.log(`[Bilibili纯粹化-调试] 视频【${video.querySelector('.bili-video-card__info--tit')?.textContent}】的各项元素为【${metaKeywords}】【${metaTitle}】【${descriptionElement}】【${authorDescriptionElement}】`) const keywordsText = metaKeywords ? normalizeText(metaKeywords.getAttribute("content")) : normalizeText(" "); const titleText = metaTitle ? normalizeText(metaTitle.getAttribute("content")) : normalizeText(" "); const descriptionText = descriptionElement ? normalizeText(descriptionElement.textContent) : normalizeText(" "); const authorDescText = authorDescriptionElement ? normalizeText(authorDescriptionElement.getAttribute('title')) : normalizeText(" "); const rawKeyword = currentSearchKeyword || keyword; let tokens = smartTokenize(rawKeyword); // 把原搜索词整体也作为一个 token if (!tokens.includes(rawKeyword.trim())) { tokens.unshift(rawKeyword.trim()); } // 规范化 tokens const normTokens = tokens .map(t => normalizeText(t)) .filter(t => t.length > 0); let matchTokenCount = 0; //console.log(`[Bilibili纯粹化-调试] 即将检查视频【${video.querySelector('.bili-video-card__info--tit')?.textContent}】中的【${keywordsText}】【${titleText}】【${descriptionText}】【${authorDescText}】中是否含有【${normTokens}】`) for (const token of normTokens) { if ( keywordsText.includes(token) || titleText.includes(token) || descriptionText.includes(token) || authorDescText.includes(token) ) { matchTokenCount++; } } // 判断是否命中 let keepVideo = false; if (normTokens.length === 1) { // 单一关键词: keepVideo = matchTokenCount === 1; } else { // 多词: keepVideo = matchTokenCount >= 1; } //console.log(`[Bilibili纯粹化-调试] 视频【${video.querySelector('.bili-video-card__info--tit')?.textContent}】,关键词命中【${matchTokenCount}】次`) // 恢复视频 if (keepVideo) { video.style.display = ''; const title = video.querySelector('.bili-video-card__info--tit')?.textContent || ''; console.log(`[Bilibili纯粹化] 在视频【${title}】的标签/简介/作者简介中命中关键词,已恢复该视频显示`); } }, onerror: function(error) { console.error('请求视频数据失败:', error); }, onprogress: function(response) { if(!video.isConnected){ requestInstances.abort(); console.log("[Bilibili纯粹化] 检测到废弃节点,已停止对应的请求。"); } }, onreadystatechange: function(respons){ if(!video.isConnected){ requestInstances.abort(); console.log("[Bilibili纯粹化] 检测到废弃节点,已停止对应的请求。"); } } }); allRequestInstances.add(requestInstances); } }); }); // 监听url变动 window.addEventListener(URL_CHANGE_EVENT, handleUrlChange); // 初始化 function init() { const videoLists = document.querySelectorAll('.video-list'); if (videoLists.length > 0) { videoLists.forEach(videoList => { hideAdVideos(videoList); addBlurMask(videoList); }); setupObserver(); createBlurToggleButton(); // 创建开关按钮 } else { setTimeout(init, 500); } } init(); } // 启用搜索页功能 if (window.location.hostname === 'search.bilibili.com') { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', removeSearchPageAdVideo); } else { removeSearchPageAdVideo(); } } })();