bilibili 移动端 Lite

b 站移动端网页推荐视频直接看

安装此脚本?
作者推荐脚本

您可能也喜欢bilibili 移动端

安装此脚本
  1. // ==UserScript==
  2. // @name Bilibili Mobile Lite
  3. // @name:zh-CN bilibili 移动端 Lite
  4. // @namespace https://github.com/jk278/bilibili-mobile-lite
  5. // @version 3.0.1
  6. // @description view bilibili mobile page recommended video directly
  7. // @description:zh-CN b 站移动端网页推荐视频直接看
  8. // @author jk278
  9. // @match https://m.bilibili.com/*
  10. // @grant none
  11. // @run-at document-start
  12. // @icon https://www.bilibili.com/favicon.ico
  13. // ==/UserScript==
  14.  
  15. (function () {
  16. 'use strict'
  17. console.log('Bilibili mobile execute!')
  18.  
  19. removeAdButton()
  20.  
  21. const pathname = window.location.pathname
  22.  
  23. if (pathname.startsWith('/video')) {
  24. customElementStyle()
  25. }
  26.  
  27. waitDOMContentLoaded(() => {
  28. if (pathname.startsWith('/video')) {
  29. autoplay()
  30. preventAutoCallApp()
  31. removeFullscreenAd()
  32. } else if (pathname === '/' || pathname === '') {
  33. runHome()
  34. }
  35. })
  36.  
  37. // DOM 加载完后
  38. function waitDOMContentLoaded(callback) {
  39. document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', callback) : callback()
  40. }
  41.  
  42. // 阻止点击视频区跳转APP
  43. function preventAutoCallApp() {
  44. const autoCallApp = document.querySelector('.mplayer-display-call-app')
  45. autoCallApp.addEventListener('click', (event) => {
  46. event.preventDefault()
  47. event.stopImmediatePropagation()
  48. })
  49.  
  50. const playButton = document.querySelector('.mplayer-pause-call-app')
  51. playButton.addEventListener('click', (event) => {
  52. event.preventDefault()
  53. event.stopImmediatePropagation()
  54. })
  55. }
  56.  
  57. // 全屏后,全屏广告元素样式变为 flex !important
  58. function removeFullscreenAd() {
  59. document.addEventListener('fullscreenchange', function () {
  60. const adBanner = document.querySelector('.mplayer-widescreen-callapp')
  61. const qualityBtn = document.querySelector('.mplayer-control-btn-quality')
  62. const text = document.querySelector('.mplayer-comment-text')
  63.  
  64. adBanner.style.cssText = 'display: none !important;'
  65. qualityBtn.style.cssText = 'display: none !important;'
  66. text.style.cssText = 'display: none !important;'
  67.  
  68. const commentContent = document.querySelector('.mplayer-btn-comment-content')
  69. commentContent.style.cssText = 'position: absolute; left: 11px; width: 24px !important;'
  70. })
  71. }
  72.  
  73. function removeAdButton() {
  74. const adSelector1 = '.home-float-openapp, .open-app, .m-nav-openapp, .m-float-openapp, [class^="m-video2-awaken-btn"]'
  75. const adSelector2 = '.openapp-dialog, .caution-dialog, .v-dialog'
  76. const style = document.createElement('style')
  77. style.textContent = `${adSelector1}, ${adSelector2}{ display: none !important; }`
  78.  
  79. document.head ? document.head.appendChild(style) : waitDOMContentLoaded(() => document.head.appendChild(style))
  80. }
  81.  
  82. function goToVideoById(keyword, callback) {
  83. const callbackName = `jsonp_callback_${Date.now()}_${Math.floor(Math.random() * 100000)}`
  84.  
  85. window[callbackName] = function (responseData) {
  86. if (responseData.data.result[11].data[0]) {
  87. const bvId = responseData.data.result[11].data[0].bvid
  88. callback(bvId, null)
  89. } else {
  90. callback(null, 'BVId not found')
  91. }
  92. delete window[callbackName]
  93. }
  94.  
  95. const script = document.createElement('script')
  96. script.src = `https://api.bilibili.com/x/web-interface/search/all/v2?page=1&keyword=${keyword}&jsonp=jsonp&callback=${callbackName}`
  97. document.body.appendChild(script)
  98. }
  99.  
  100. // 自动播放
  101. function autoplay() {
  102. const play = document.querySelector('.main-cover')
  103.  
  104. const style = document.createElement('style')
  105. style.textContent = '.m-navbar + div { display: block !important }'
  106. document.head.appendChild(style)
  107.  
  108. if (play) {
  109. const video = document.querySelector('video')
  110. if (video) {
  111. video.addEventListener('play', function () {
  112. if (video.muted === true) createUnmuteButton()
  113. }, { once: true })
  114.  
  115. const startPlayPromise = video.play()
  116.  
  117. if (startPlayPromise !== undefined) {
  118. startPlayPromise
  119. .catch((error) => {
  120. if (error.name === 'NotAllowedError') {
  121. video.muted = true
  122. video.play()
  123. }
  124. })
  125. }
  126.  
  127. function createUnmuteButton() {
  128. if (document.getElementById('unmuteButton')) return
  129.  
  130. const button = document.createElement('button')
  131. button.classList.add('unmute')
  132. button.innerHTML = `
  133. <div class="unmute-inner">
  134. <div class="unmute-icon"><svg height="100%" version="1.1" viewBox="0 0 36 36" width="100%">
  135. <use class="svg-shadow" xlink:href="#ytp-id-1"></use>
  136. <path class="ytp-svg-fill"
  137. 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"
  138. id="id-1"></path>
  139. </svg></div>
  140. <div class="unmute-text">点按取消静音</div>
  141. <div class="unmute-box"></div>
  142. </div>
  143. `
  144. button.addEventListener('click', function () {
  145. video.muted = false
  146. button.remove()
  147. })
  148.  
  149. const videoWrapper = document.querySelector('.mplayer-video-wrap')
  150. videoWrapper.insertAdjacentElement('afterend', button)
  151. setTimeout(() => {
  152. button.classList.add('animated')
  153. }, 4500)
  154. }
  155. }
  156. }
  157.  
  158. observeCardBox()
  159. }
  160.  
  161. function observeCardBox() {
  162. const cardBox = document.querySelector('.card-box')
  163. const targetElements = cardBox.children
  164.  
  165. Array.from(targetElements).forEach(addTargetElementListener)
  166.  
  167. const observer = new MutationObserver((mutations) => {
  168. mutations.forEach((mutation) => {
  169. if (mutation.type === 'childList') {
  170. mutation.addedNodes.forEach((addedNode) => {
  171. addTargetElementListener(addedNode)
  172. })
  173. }
  174. })
  175. })
  176.  
  177. const observerConfig = { childList: true }
  178. observer.observe(cardBox, observerConfig)
  179. }
  180.  
  181. function addTargetElementListener(targetElement) {
  182. if (targetElement) {
  183. const anchor = targetElement.firstChild
  184. const h2Element = anchor.lastChild
  185. const keyword = encodeURIComponent(h2Element.innerHTML)
  186.  
  187. anchor.addEventListener('click', event => {
  188. event.preventDefault()
  189. event.stopImmediatePropagation()
  190.  
  191. goToVideoById(keyword, (bvId, error) => {
  192. if (bvId) {
  193. const videoUrl = `https://m.bilibili.com/video/${bvId}`
  194. window.history.pushState({}, '', videoUrl)
  195. window.location.href = videoUrl
  196. } else {
  197. console.error('BVId wrong: ', error)
  198. }
  199. })
  200. }, true)
  201. }
  202. }
  203.  
  204. function runHome() {
  205. const cardBox = document.querySelector('.card-box')
  206. const aTags = cardBox.children
  207.  
  208. Array.from(aTags).forEach(addHomeTargetElementListener)
  209.  
  210. const observer = new MutationObserver((mutations) => {
  211. mutations.forEach((mutation) => {
  212. if (mutation.type === 'childList') {
  213. mutation.addedNodes.forEach((addedNode) => {
  214. addHomeTargetElementListener(addedNode)
  215. })
  216. }
  217. })
  218. })
  219.  
  220. const observerConfig = { childList: true }
  221. observer.observe(cardBox, observerConfig)
  222.  
  223. function addHomeTargetElementListener(tag) {
  224. tag.addEventListener('click', async (event) => {
  225. event.preventDefault()
  226. event.stopImmediatePropagation()
  227.  
  228. await new Promise((resolve) => setTimeout(resolve, 0))
  229. window.location.href = tag.getAttribute('href')
  230. }, true)
  231. }
  232. }
  233.  
  234. function customElementStyle() {
  235. const initialInsertStyle = `
  236. /* 全屏跳App、倍速按钮、播完推荐 */
  237. .mplayer-fullscreen-call-app, .mplayer-control-btn-speed, .mplayer-ending-panel-recommend {
  238. display: none !important;
  239. }
  240.  
  241. /*
  242. * 优化视觉 *
  243. */
  244.  
  245. /* 调整分集高度 */
  246. .m-video-part-panel-content {
  247. height: 81vmin !important;
  248. }
  249. /* 居中重播按钮 */
  250. .mplayer-ending-panel-buttons {
  251. align-self: center !important;
  252.  
  253. img {
  254. margin-left: 3px !important;
  255. }
  256. }
  257. /* 阻止跳转APP */
  258. .launch-app-btn {
  259. pointer-events: none;
  260. }
  261. .card-box a {
  262. pointer-events: auto;
  263. }
  264. /* 重复的初始图形层 */
  265. .natural-module, .m-footer {
  266. display: none !important;
  267. }
  268.  
  269. /*
  270. * 声音按钮 *
  271. */
  272.  
  273. .unmute {
  274. position: absolute;
  275. top: 0;
  276. padding: 12px;
  277. background: none;
  278. border: 0;
  279. font-size: 127%;
  280. text-align: inherit;
  281. }
  282. .unmute-inner {
  283. position: relative;
  284. }
  285. .unmute-icon {
  286. height: 48px;
  287. display: inline-block;
  288. vertical-align: middle;
  289. padding-left: 2px;
  290. position: relative;
  291. z-index: 10;
  292. background-color: rgb(255, 255, 255);
  293. border-radius: 2px;
  294. border-bottom: 1px solid #f1f1f1;
  295. }
  296. .unmute svg {
  297. filter: drop-shadow(0 0 2px rgba(0,0,0,.5));
  298. }
  299. .unmute-text {
  300. position: relative;
  301. z-index: 10;
  302. padding-right: 10px;
  303. vertical-align: middle;
  304. display: inline-block;
  305. transition: opacity .25s cubic-bezier(.4,0,1,1);
  306. }
  307. .animated .unmute-text {
  308. opacity: 0;
  309. }
  310. .unmute-box {
  311. width: 100%;
  312. background-color: rgb(255, 255, 255);
  313. position: absolute;
  314. top: 0;
  315. bottom: 0;
  316. border-radius: 2px;
  317. border-bottom: 1px solid #f1f1f1;
  318. transition: width .5s cubic-bezier(.4,0,1,1);
  319. }
  320. .animated .unmute-box {
  321. width: 0;
  322. }
  323. `
  324.  
  325. const style = document.createElement('style')
  326. style.textContent = initialInsertStyle
  327.  
  328. document.head ? document.head.appendChild(style) : waitDOMContentLoaded(() => document.head.appendChild(style))
  329. }
  330. })()

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址