// ==UserScript== // @name B站禁止登录弹窗+自动最高清晰度+无限试看+未登录看全部评论 // @namespace https://www.bilibili.com // @version 2.3.0 // @description 优化版:屏蔽B站登录弹窗;自动最高清晰度(720P/1080P);无限试看绕过大会员试看时长,自动续播;未登录可查看全部评论(含楼中楼/翻页);本地文件自动更新。 // @author 自写脚本 // @match *://*.bilibili.com/* // @match *://*.bilibili.tv/* // @match *://*.bilibili.co/* // @run-at document-start // @grant GM_addStyle // @grant unsafeWindow // @grant GM_xmlhttpRequest // @grant GM_info // @grant GM_getValue // @grant GM_setValue // @license MIT // ==/UserScript== (function () { 'use strict'; var VERSION = '2.3.0'; var QN_LABELS = {16:'360P',32:'480P',64:'720P',74:'720P60',80:'1080P',112:'1080P+',116:'1080P60',120:'4K'}; /* ============================================================ * 0. 配置持久化(优先,document-start 立即执行) * ============================================================ */ var options = { preferQuality: GM_getValue('preferQuality', '1080'), isWaitUntilHighQualityLoaded: GM_getValue('isWaitUntilHighQualityLoaded', false), }; var LS_KEYS = ['bilibili_player_codec_prefer_type','b_miniplayer','recommend_auto_play','bpx_player_profile']; // 把脚本存储的配置同步到页面 localStorage LS_KEYS.forEach(function (key) { var value = GM_getValue(key); if (value) window.localStorage.setItem(key, value); }); // 劫持 setItem,保存页面配置回脚本存储 var originSetItem = Storage.prototype.setItem; Storage.prototype.setItem = function (key, value) { if (key === 'bpx_player_profile') { try { var profile = JSON.parse(value); if (!profile.audioEffect) profile.audioEffect = {}; value = JSON.stringify(profile); } catch (e) {} } originSetItem.call(this, key, value); if (LS_KEYS.indexOf(key) >= 0) { setTimeout(function () { GM_setValue('bilibili_player_codec_prefer_type', window.localStorage.getItem('bilibili_player_codec_prefer_type') || '0'); GM_setValue('b_miniplayer', window.localStorage.getItem('b_miniplayer') || '1'); GM_setValue('recommend_auto_play', window.localStorage.getItem('recommend_auto_play') || 'open'); GM_setValue('bpx_player_profile', window.localStorage.getItem('bpx_player_profile') || '{"lastView":' + (Date.now() - 86400000) + ',"lastUid":0}'); }, 100); } }; /* ============================================================ * 1. CSS 强制隐藏登录弹窗 * ============================================================ */ var CSS_HIDE = [ '.bili-mini-mask','.bili-mini-login','#bili-mini-login','.bili-mini', '.login-panel-ctnr','.login-panel','#login-panel', '.login-card-wrp','.login-card','.login-modal','.login-mask', '.login-dialog','.login-popup','.login-tip','.login-guide','.login-entry', '[class*="login-mask"]','[class*="loginMask"]','[class*="login-modal"]', '[class*="loginModal"]','[class*="login-dialog"]','[class*="loginDialog"]', '[class*="login-popup"]','[class*="loginPopup"]', '[id*="login-mask"]','[id*="loginMask"]','[id*="login-modal"]','[id*="loginModal"]', '.bili-mini-mask ~ .mask','[class*="backdrop"][class*="login"]', '.login-guide-pop','.login-toast','.login-bubble' ].join(',') + '{display:none!important;visibility:hidden!important;opacity:0!important;pointer-events:none!important;z-index:-1!important;}'; CSS_HIDE += 'html,body{overflow:auto!important;overflow-x:hidden!important;position:static!important;width:auto!important;}'; function injectCSS(css) { try { if (typeof GM_addStyle === 'function') { GM_addStyle(css); return; } } catch (e) {} function doInject() { var parent = document.head || document.documentElement; if (!parent) { setTimeout(doInject, 10); return; } var style = document.createElement('style'); style.textContent = css; style.setAttribute('data-script', 'bili-enhance'); parent.appendChild(style); } doInject(); } injectCSS(CSS_HIDE); /* document-start 立即安装数据/网络劫持 */ unlockComments(); forceMaxQuality(); installTrialBypass(); /* ============================================================ * 2. 登录弹窗清理 * ============================================================ */ var LOGIN_KEYWORDS = [ 'bili-mini','login-panel','login-card','login-modal','login-mask', 'login-dialog','login-popup','login-guide','login-tip','login-toast', 'login-bubble','login-entry','mini-login','minilogin','loginmask', 'loginmodal','logindialog','loginpopup' ]; function isLoginNode(node) { if (!node || node.nodeType !== 1) return false; var id = (node.id || '').toLowerCase(); var cls = (typeof node.className === 'string' ? node.className : '').toLowerCase(); for (var i = 0; i < LOGIN_KEYWORDS.length; i++) { if (id.indexOf(LOGIN_KEYWORDS[i]) >= 0 || cls.indexOf(LOGIN_KEYWORDS[i]) >= 0) return true; } return false; } function removeLoginNode(node) { try { if (node && node.parentNode) node.parentNode.removeChild(node); else if (node) node.style.display = 'none'; } catch (e) {} } function unlockScroll() { var body = document.body, html = document.documentElement; if (!body || !html) return; var locked = body.classList.contains('bili-mini-mask-open') || body.classList.contains('lock-screen') || body.classList.contains('overflow-hidden') || body.style.overflow === 'hidden' || html.style.overflow === 'hidden'; if (!locked) return; body.classList.remove('bili-mini-mask-open','lock-screen','overflow-hidden'); html.classList.remove('bili-mini-mask-open','lock-screen'); body.style.overflow = ''; html.style.overflow = ''; body.style.position = ''; html.style.position = ''; } var SWEEP_SELECTORS = [ '.bili-mini-mask','.bili-mini-login','#bili-mini-login','.bili-mini', '.login-panel-ctnr','.login-panel','.login-card-wrp','.login-card', '.login-modal','.login-mask','.login-dialog','.login-popup', '.login-guide','.login-toast','.login-bubble' ]; function sweep(root) { if (!root || !root.querySelectorAll) return; for (var i = 0; i < SWEEP_SELECTORS.length; i++) { var found = root.querySelectorAll(SWEEP_SELECTORS[i]); for (var j = 0; j < found.length; j++) removeLoginNode(found[j]); } unlockScroll(); } /* MutationObserver:250ms 节流 */ var observerTimer = null, observerDirty = false; var observer = new MutationObserver(function () { observerDirty = true; if (observerTimer) return; observerTimer = setTimeout(function () { observerTimer = null; if (!observerDirty) return; observerDirty = false; observer.disconnect(); sweep(document.documentElement); observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['class','id'] }); }, 250); }); function startObserver() { observer.observe(document.documentElement, { childList: true, subtree: true, attributes: true, attributeFilter: ['class','id'] }); } /* ============================================================ * 3. Hook 登录触发函数 + 阻止点击登录 * ============================================================ */ function hookLoginTriggers() { var w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window; var blocked = [ 'openLogin','showLogin','showLoginPanel','openLoginPanel', 'showLoginDialog','openLoginDialog','showMiniLogin','openMiniLogin', 'showLoginModal','openLoginModal','loginPanel','toLogin','goLogin','jumpLogin' ]; blocked.forEach(function (name) { try { if (typeof w[name] === 'function') { w[name] = function () { return false; }; } } catch (e) {} }); try { var origDispatch = w.dispatchEvent; w.dispatchEvent = function (event) { if (event && event.type && /login/i.test(event.type)) return false; return origDispatch.apply(this, arguments); }; } catch (e) {} try { var origAdd = w.addEventListener; w.addEventListener = function (type, listener, options) { if (type && /login/i.test(type)) return; return origAdd.apply(this, arguments); }; } catch (e) {} } function blockClickTriggers() { document.addEventListener('click', function (e) { var el = e.target; while (el && el !== document.body) { var cls = (typeof el.className === 'string' ? el.className : '').toLowerCase(); var id = (el.id || '').toLowerCase(); if (/login|to-login|goto-login/.test(cls) || /login/.test(id)) { if (/登录后|登录以|登录才能/.test(el.textContent || '')) { e.preventDefault(); e.stopPropagation(); e.stopImmediatePropagation(); return false; } } el = el.parentElement; } }, true); } /* ============================================================ * 4. 未登录看全部评论 * ============================================================ */ function unlockComments() { var w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window; function hookBiliUser(bu) { if (!bu || bu.__commentHooked || typeof bu.get !== 'function') return; bu.__commentHooked = true; var orig = bu.get.bind(bu); bu.get = function () { return orig().then(function (r) { if (r && (r.code === -101 || r.code === -102)) { return { code: 0, message: 'OK', data: r.data }; } return r; }); }; } var _bu = null; try { if (w.__BiliUser__) { hookBiliUser(w.__BiliUser__); } else { Object.defineProperty(w, '__BiliUser__', { configurable: true, get: function () { return _bu; }, set: function (v) { _bu = v; hookBiliUser(v); } }); } } catch (e) {} try { var origFetch = w.fetch.bind(w); w.fetch = function (input, init) { var url = typeof input === 'string' ? input : (input && input.url); if (url && /\/x\/v2\/reply\/(wbi\/main|main|reply)(\?|$)/.test(url)) { if (init && init.credentials === 'include') { var newInit = Object.assign({}, init, { credentials: 'omit' }); return origFetch(input, newInit); } } return origFetch.apply(this, arguments); }; } catch (e) {} } /* ============================================================ * 5. 自动最高清晰度(保留 XHR/fetch 兜底 + 新增 defineProperty 优先) * ============================================================ */ function isPlayurl(url) { if (!url) return false; var path = String(url).split('?')[0]; return /\/x\/player\/(wbi\/)?playurl/.test(path); } function rewritePlayurlUrl(url) { try { var u = new URL(url, location.origin); u.searchParams.set('qn', '80'); u.searchParams.set('fnval', '4032'); u.searchParams.set('fourk', '1'); return u.toString(); } catch (e) { return url.replace(/([?&])qn=[^&]*/, '$1qn=80') .replace(/([?&])fnval=[^&]*/, '$1fnval=4032') .replace(/([?&])fourk=[^&]*/, '$1fourk=1'); } } function setLocalStorageQuality() { try { var keys = ['bilibili_player_settings','player_settings','bpx_player_settings','bwp_player_settings']; for (var i = 0; i < keys.length; i++) { try { var raw = localStorage.getItem(keys[i]); if (raw) { var s = JSON.parse(raw); s.video_quality = 80; s.quality = 80; if (s.player) s.player.quality = 80; localStorage.setItem(keys[i], JSON.stringify(s)); } } catch (e) {} } } catch (e) {} } function hijackPlayurlResponse(data) { if (!data || !data.data) return data; var d = data.data; var maxQ = 0; if (d.durl && d.durl.length > 0) maxQ = d.quality || 80; if ((!maxQ) && Array.isArray(d.accept_quality) && d.accept_quality.length > 0) { maxQ = Math.max.apply(null, d.accept_quality); } if (maxQ) d.quality = maxQ; if (Array.isArray(d.accept_quality)) d.accept_quality.sort(function (a, b) { return b - a; }); console.log('[B站增强] 清晰度响应: ' + (QN_LABELS[maxQ] || maxQ) + ' 格式=' + (d.format || '?') + ' 可用=[' + (d.accept_quality || []).map(function(q){return QN_LABELS[q]||q;}).join(',') + ']'); return data; } function hijackPlayinfo() { var _play, _state, _origPlay; function doReplace() { if (!_state || !_origPlay) return; try { var v = _state.videoData; if (!v || !v.bvid || !v.cid) return; var u = 'https://api.bilibili.com/x/player/playurl?bvid=' + v.bvid + '&cid=' + v.cid + '&qn=80&fnval=4032&fourk=1'; var xhr = new XMLHttpRequest(); xhr.open('GET', u, false); xhr.send(null); var hq = JSON.parse(xhr.responseText); if (hq.code === 0 && hq.data && hq.data.durl && hq.data.durl.length) { _play = hq; console.log('[B站增强] 内联播放信息已升级为 ' + (QN_LABELS[hq.data.quality] || hq.data.quality)); } } catch (e) {} } try { Object.defineProperty(window, '__playinfo__', { configurable: true, get: function () { return _play; }, set: function (p) { _origPlay = p; _play = p; doReplace(); } }); } catch (e) {} try { Object.defineProperty(window, '__INITIAL_STATE__', { configurable: true, get: function () { return _state; }, set: function (s) { _state = s; doReplace(); } }); } catch (e) {} } function forceMaxQuality() { setLocalStorageQuality(); hijackPlayinfo(); // Hook XHR try { var origOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function (method, url) { this.__isPlayurl = isPlayurl(url); if (this.__isPlayurl) { try { var newUrl = rewritePlayurlUrl(url); arguments[1] = newUrl; this.__url = newUrl; } catch (e) {} } return origOpen.apply(this, arguments); }; var origSend = XMLHttpRequest.prototype.send; XMLHttpRequest.prototype.send = function () { if (this.__isPlayurl) { var self = this; var doHijack = function () { if (self.readyState === 4 && self.status === 200 && !self.__hijacked) { try { var data = JSON.parse(self.responseText); hijackPlayurlResponse(data); var text = JSON.stringify(data); Object.defineProperty(self, 'responseText', { value: text, configurable: true }); Object.defineProperty(self, 'response', { value: text, configurable: true }); self.__hijacked = true; } catch (e) {} } }; this.addEventListener('readystatechange', doHijack); this.addEventListener('load', doHijack); } return origSend.apply(this, arguments); }; } catch (e) { console.log('[B站增强] XHR hook失败:', e.message); } // Hook fetch try { var origFetch = window.fetch; window.fetch = function (input, init) { var url = typeof input === 'string' ? input : (input && input.url); if (isPlayurl(url)) { try { var newUrl = rewritePlayurlUrl(url); if (typeof input === 'string') input = newUrl; else if (input && input.url) input = new Request(newUrl, init || input); url = newUrl; } catch (e) {} } return origFetch.call(this, input, init).then(function (response) { if (isPlayurl(url) && response && response.ok) { return response.clone().json().then(function (data) { hijackPlayurlResponse(data); return new Response(JSON.stringify(data), { status: response.status, statusText: response.statusText, headers: response.headers }); }).catch(function () { return response; }); } return response; }); }; } catch (e) { console.log('[B站增强] fetch hook失败:', e.message); } } /* ============================================================ * 6. 无限试看(v测试版核心:defineProperty + setTimeout + 自动点击) * ============================================================ */ function installTrialBypass() { if (document.cookie.includes('DedeUserID')) return; // 已登录无需处理 var w = (typeof unsafeWindow !== 'undefined') ? unsafeWindow : window; // ① 劫持 isViewToday / isVideoAble,欺骗播放器"今天已试用过/视频可看" var origDefineProperty = Object.defineProperty; Object.defineProperty = function (obj, prop, descriptor) { if (prop === 'isViewToday' || prop === 'isVideoAble') { descriptor = { get: function () { return true; }, enumerable: false, configurable: true }; } return origDefineProperty.call(this, obj, prop, descriptor); }; // ② 劫持 setTimeout,把 30 秒试用到期弹窗改为 3000 秒(实际上永不触发) var origSetTimeout = w.setTimeout; w.setTimeout = function (func, delay) { if (delay === 30000) delay = 300000000; return origSetTimeout.call(this, func, delay); }; // ③ 自动点击"免费试用"按钮 setInterval(function () { var trialBtn = document.querySelector('.bpx-player-toast-confirm-login'); if (!trialBtn) return; setTimeout(function () { trialBtn.click(); console.log('[B站增强] 已自动点击试用按钮'); // ④ 音画同步:暂停→等待"试用中"→恢复播放 if (options.isWaitUntilHighQualityLoaded && w.player) { var isPlaying = !w.player.mediaElement().paused; if (isPlaying) w.player.mediaElement().pause(); var timer4Toast = setInterval(function () { var toasts = Array.from(document.querySelectorAll('.bpx-player-toast-text')); if (toasts.some(function (toast) { return toast.textContent.endsWith('试用中'); })) { if (isPlaying) w.player.mediaElement().play(); clearInterval(timer4Toast); } }, 100); } // ⑤ 切换到偏好分辨率 var preferQualityNum = ({ '1080': 80, '720': 64, '480': 32, '360': 16 })[options.preferQuality] || 80; setTimeout(function () { if (w.player && w.player.getSupportedQualityList && w.player.getQuality) { if (w.player.getSupportedQualityList().indexOf(preferQualityNum) >= 0 && preferQualityNum < w.player.getQuality().nowQ) { w.player.requestQuality(preferQualityNum); console.log('[B站增强] 已切换至 ' + options.preferQuality + 'P'); } } }, 5000); }, 1000); }, 1500); } /* ============================================================ * 7. 设置面板(移植自 v测试版) * ============================================================ */ function setupSettingPanel() { var style = document.createElement('style'); style.textContent = ` #userscript-467511-setting-panel-container { position: fixed; top: 0; left: 0; z-index: 999999999; width: 100vw; height: 100vh; display: none; flex-direction: column; justify-content: center; align-items: center; background-color: rgba(0,0,0,0.5); } .userscript-467511-setting-panel-wrapper { width: 600px; padding: 16px; display: flex; flex-direction: column; background-color: #FFFFFF; border-radius: 8px; user-select: none; } .userscript-467511-setting-panel-title { margin-top: 0; margin-bottom: 8px; padding-top: 16px; padding-left: 12px; font-size: 28px; } .userscript-467511-setting-panel-option-group { display: flex; flex-direction: column; width: 100%; font-size: 16px; } .userscript-467511-setting-panel-option-item { padding: 16px 16px; display: flex; justify-content: space-between; align-items: center; border-radius: 4px; } .userscript-467511-setting-panel-option-item:hover { background-color: #FAFAFA; } .userscript-467511-setting-panel-option-item-switch { display: flex; align-items: center; width: 40px; height: 20px; padding: 2px; cursor: pointer; border-radius: 4px; } .userscript-467511-setting-panel-option-item-switch[data-status="off"] { justify-content: flex-start; background-color: #CCCCCC; } .userscript-467511-setting-panel-option-item-switch[data-status="on"] { justify-content: flex-end; background-color: #00AEEC; } .userscript-467511-setting-panel-option-item-switch:after { content: ''; width: 20px; height: 20px; background-color: #FFFFFF; border-radius: 4px; } #userscript-467511-setting-panel-close-btn { margin-top: 16px; padding: 2px; width: 20px; height: 20px; display: flex; justify-content: center; align-items: center; font-size: 20px; color: #FFFFFF; border: 2px solid #FFFFFF; border-radius: 100%; cursor: pointer; user-select: none; } `; var container = document.createElement('div'); container.id = 'userscript-467511-setting-panel-container'; container.innerHTML = `
自定义设置