view bilibili mobile page recommended video directly
// ==UserScript== // @name Bilibili Mobile Lite // @name:zh-CN bilibili 移动端 Lite // @namespace https://github.com/jk278/bilibili-mobile-lite // @version 3.0.1 // @description view bilibili mobile page recommended video directly // @description:zh-CN b 站移动端网页推荐视频直接看 // @author jk278 // @match https://m.bilibili.com/* // @grant none // @run-at document-start // @icon https://www.bilibili.com/favicon.ico // ==/UserScript== (function () { 'use strict' console.log('Bilibili mobile execute!') removeAdButton() const pathname = window.location.pathname if (pathname.startsWith('/video')) { customElementStyle() } waitDOMContentLoaded(() => { if (pathname.startsWith('/video')) { autoplay() preventAutoCallApp() removeFullscreenAd() } else if (pathname === '/' || pathname === '') { runHome() } }) // DOM 加载完后 function waitDOMContentLoaded(callback) { document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', callback) : callback() } // 阻止点击视频区跳转APP function preventAutoCallApp() { const autoCallApp = document.querySelector('.mplayer-display-call-app') autoCallApp.addEventListener('click', (event) => { event.preventDefault() event.stopImmediatePropagation() }) const playButton = document.querySelector('.mplayer-pause-call-app') playButton.addEventListener('click', (event) => { event.preventDefault() event.stopImmediatePropagation() }) } // 全屏后,全屏广告元素样式变为 flex !important function removeFullscreenAd() { document.addEventListener('fullscreenchange', function () { const adBanner = document.querySelector('.mplayer-widescreen-callapp') const qualityBtn = document.querySelector('.mplayer-control-btn-quality') const text = document.querySelector('.mplayer-comment-text') adBanner.style.cssText = 'display: none !important;' qualityBtn.style.cssText = 'display: none !important;' text.style.cssText = 'display: none !important;' const commentContent = document.querySelector('.mplayer-btn-comment-content') commentContent.style.cssText = 'position: absolute; left: 11px; width: 24px !important;' }) } function removeAdButton() { const adSelector1 = '.home-float-openapp, .open-app, .m-nav-openapp, .m-float-openapp, [class^="m-video2-awaken-btn"]' const adSelector2 = '.openapp-dialog, .caution-dialog, .v-dialog' const style = document.createElement('style') style.textContent = `${adSelector1}, ${adSelector2}{ display: none !important; }` document.head ? document.head.appendChild(style) : waitDOMContentLoaded(() => document.head.appendChild(style)) } function goToVideoById(keyword, callback) { const callbackName = `jsonp_callback_${Date.now()}_${Math.floor(Math.random() * 100000)}` window[callbackName] = function (responseData) { if (responseData.data.r###lt[11].data[0]) { const bvId = responseData.data.r###lt[11].data[0].bvid callback(bvId, null) } else { callback(null, 'BVId not found') } delete window[callbackName] } const script = document.createElement('script') script.src = `https://api.bilibili.com/x/web-interface/search/all/v2?page=1&keyword=${keyword}&jsonp=jsonp&callback=${callbackName}` document.body.appendChild(script) } // 自动播放 function autoplay() { const play = document.querySelector('.main-cover') const style = document.createElement('style') style.textContent = '.m-navbar + div { display: block !important }' document.head.appendChild(style) if (play) { const video = document.querySelector('video') if (video) { video.addEventListener('play', function () { if (video.muted === true) createUnmuteButton() }, { once: true }) const startPlayPromise = video.play() if (startPlayPromise !== undefined) { startPlayPromise .catch((error) => { if (error.name === 'NotAllowedError') { video.muted = true video.play() } }) } function createUnmuteButton() { if (document.getElementById('unmuteButton')) return const button = document.createElement('button') button.classList.add('unmute') button.innerHTML = ` <div class="unmute-inner"> <div class="unmute-icon"><svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%"> <use class="svg-shadow" xlink:href="#ytp-id-1"></use> <path class="ytp-svg-fill" d="m 21.48,17.98 c 0,-1.77 -1.02,-3.29 -2.5,-4.03 v 2.21 l 2.45,2.45 c .03,-0.2 .05,-0.41 .05,-0.63 z m 2.5,0 c 0,.94 -0.2,1.82 -0.54,2.64 l 1.51,1.51 c .66,-1.24 1.03,-2.65 1.03,-4.15 0,-4.28 -2.99,-7.86 -7,-8.76 v 2.05 c 2.89,.86 5,3.54 5,6.71 z M 9.25,8.98 l -1.27,1.26 4.72,4.73 H 7.98 v 6 H 11.98 l 5,5 v -6.73 l 4.25,4.25 c -0.67,.52 -1.42,.93 -2.25,1.18 v 2.06 c 1.38,-0.31 2.63,-0.95 3.69,-1.81 l 2.04,2.05 1.27,-1.27 -9,-9 -7.72,-7.72 z m 7.72,.99 -2.09,2.08 2.09,2.09 V 9.98 z" id="id-1"></path> </svg></div> <div class="unmute-text">点按取消静音</div> <div class="unmute-box"></div> </div> ` button.addEventListener('click', function () { video.muted = false button.remove() }) const videoWrapper = document.querySelector('.mplayer-video-wrap') videoWrapper.insertAdjacentElement('afterend', button) setTimeout(() => { button.classList.add('animated') }, 4500) } } } observeCardBox() } function observeCardBox() { const cardBox = document.querySelector('.card-box') const targetElements = cardBox.children Array.from(targetElements).forEach(addTargetElementListener) const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { mutation.addedNodes.forEach((addedNode) => { addTargetElementListener(addedNode) }) } }) }) const observerConfig = { childList: true } observer.observe(cardBox, observerConfig) } function addTargetElementListener(targetElement) { if (targetElement) { const anchor = targetElement.firstChild const h2Element = anchor.lastChild const keyword = encodeURIComponent(h2Element.innerHTML) anchor.addEventListener('click', event => { event.preventDefault() event.stopImmediatePropagation() goToVideoById(keyword, (bvId, error) => { if (bvId) { const videoUrl = `https://m.bilibili.com/video/${bvId}` window.history.pushState({}, '', videoUrl) window.location.href = videoUrl } else { console.error('BVId wrong: ', error) } }) }, true) } } function runHome() { const cardBox = document.querySelector('.card-box') const aTags = cardBox.children Array.from(aTags).forEach(addHomeTargetElementListener) const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.type === 'childList') { mutation.addedNodes.forEach((addedNode) => { addHomeTargetElementListener(addedNode) }) } }) }) const observerConfig = { childList: true } observer.observe(cardBox, observerConfig) function addHomeTargetElementListener(tag) { tag.addEventListener('click', async (event) => { event.preventDefault() event.stopImmediatePropagation() await new Promise((resolve) => setTimeout(resolve, 0)) window.location.href = tag.getAttribute('href') }, true) } } function customElementStyle() { const initialInsertStyle = ` /* 全屏跳App、倍速按钮、播完推荐 */ .mplayer-fullscreen-call-app, .mplayer-control-btn-speed, .mplayer-ending-panel-recommend { display: none !important; } /* * 优化视觉 * */ /* 调整分集高度 */ .m-video-part-panel-content { height: 81vmin !important; } /* 居中重播按钮 */ .mplayer-ending-panel-buttons { align-self: center !important; img { margin-left: 3px !important; } } /* 阻止跳转APP */ .launch-app-btn { pointer-events: none; } .card-box a { pointer-events: auto; } /* 重复的初始图形层 */ .natural-module, .m-footer { display: none !important; } /* * 声音按钮 * */ .unmute { position: absolute; top: 0; padding: 12px; background: none; border: 0; font-size: 127%; text-align: inherit; } .unmute-inner { position: relative; } .unmute-icon { height: 48px; display: inline-block; vertical-align: middle; padding-left: 2px; position: relative; z-index: 10; background-color: rgb(255, 255, 255); border-radius: 2px; border-bottom: 1px solid #f1f1f1; } .unmute svg { filter: drop-shadow(0 0 2px rgba(0,0,0,.5)); } .unmute-text { position: relative; z-index: 10; padding-right: 10px; vertical-align: middle; display: inline-block; transition: opacity .25s cubic-bezier(.4,0,1,1); } .animated .unmute-text { opacity: 0; } .unmute-box { width: 100%; background-color: rgb(255, 255, 255); position: absolute; top: 0; bottom: 0; border-radius: 2px; border-bottom: 1px solid #f1f1f1; transition: width .5s cubic-bezier(.4,0,1,1); } .animated .unmute-box { width: 0; } ` const style = document.createElement('style') style.textContent = initialInsertStyle document.head ? document.head.appendChild(style) : waitDOMContentLoaded(() => document.head.appendChild(style)) } })()