您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
关于我不想要哔哩哔哩自动连播只想在分 P 中跳转但是阿 b 把他们混为一谈这件事。
// ==UserScript== // @name 矫正 b 站自动连播按钮 - 分P、合集、单视频开关分别独立 // @namespace http://maxchang.me // @version 0.2.1 // @description 关于我不想要哔哩哔哩自动连播只想在分 P 中跳转但是阿 b 把他们混为一谈这件事。 // @author MaxChang3 // @match https://www.bilibili.com/video/* // @match https://www.bilibili.com/list/* // @icon https://www.bilibili.com/favicon.ico // @grant GM_setValue // @grant GM_getValue // @grant GM_addStyle // ==/UserScript== // 自定义 logger const logger = { log: (...args) => console.log('[Correct-Next-Button]', ...args), error: (...args) => console.error('[Correct-Next-Button]', ...args), } /** * 给没有自动连播按钮的页面添加一个开关按钮(目前只考虑了播放列表) */ const prepareSwitchButton = () => { const continuousBtn = document.createElement('div') continuousBtn.className = 'continuous-btn' const txt = document.createElement('div') txt.className = 'txt' txt.textContent = '自动连播' const switchBtn = document.createElement('div') switchBtn.className = 'switch-btn' const switchBlock = document.createElement('div') switchBlock.className = 'switch-block' switchBtn.appendChild(switchBlock) continuousBtn.appendChild(txt) continuousBtn.appendChild(switchBtn) const headerLeft = document.querySelector('.header-left') headerLeft?.appendChild(continuousBtn) GM_addStyle( `.switch-btn{--switch-btn-width:30px;--switch-btn-height:20px;--switch-btn-gap:2px;cursor:pointer;position:relative;display:inline-block;box-sizing:border-box;border-radius:calc(var(--switch-btn-height)/ 2);border-radius:calc(var(--switch-btn-height)/ 2);width:var(--switch-btn-width);width:var(--switch-btn-width);height:var(--switch-btn-height);height:var(--switch-btn-height);background-color:var(--graph_bg_thick);background-color:var(--graph_bg_thick);transition:.2s}.switch-btn .switch-block{position:absolute;border-radius:50%;top:var(--switch-btn-gap);top:var(--switch-btn-gap);left:var(--switch-btn-gap);left:var(--switch-btn-gap);width:calc(var(--switch-btn-height) - calc(2 * var(--switch-btn-gap)));width:calc(var(--switch-btn-height) - calc(2 * var(--switch-btn-gap)));height:calc(var(--switch-btn-height) - calc(2 * var(--switch-btn-gap)));height:calc(var(--switch-btn-height) - calc(2 * var(--switch-btn-gap)));background-color:var(--text_white);background-color:var(--text_white);transition:.2s}.switch-btn.on{background:var(--brand_blue);background:var(--brand_blue)}.switch-btn.on .switch-block{left:calc(calc(var(--switch-btn-width) - var(--switch-btn-height)) + var(--switch-btn-gap));left:calc(calc(var(--switch-btn-width) - var(--switch-btn-height)) + var(--switch-btn-gap))}.continuous-btn{cursor:pointer;display:flex;align-items:center}.continuous-btn .txt{color:var(--text3);color:var(--text3);font-size:14px;margin-right:4px}` ) return switchBtn } const type = { VIDEO: 'video', MULTIPART: 'multipart', COLLECTION: 'collection', PLAYLIST: 'playlist', } const correctNextButton = (app) => { const videoData = app.videoData if (!videoData) { logger.error('videoData is not available') return } const { videos: videosCount } = videoData const pageType = videosCount > 1 ? type.MULTIPART : app.isSection ? type.COLLECTION : app.playlist?.type ? type.PLAYLIST : type.VIDEO const pageStatus = app.continuousPlay const userStatus = GM_getValue(pageType) if (userStatus === undefined) { GM_setValue(pageType, pageStatus) } else if (pageStatus !== userStatus) { app.setContinuousPlay(userStatus) } logger.log(pageType, { collection: GM_getValue(type.COLLECTION), multipart: GM_getValue(type.MULTIPART), video: GM_getValue(type.VIDEO), }) let switchButton = document.querySelector('.switch-btn') if (!switchButton) { switchButton = prepareSwitchButton() switchButton.addEventListener('click', (e) => { e.preventDefault() e.stopPropagation() switchButton.classList.toggle('on') app.setContinuousPlay(!app.continuousPlay) GM_setValue(pageType, app.continuousPlay) }) switchButton.classList.toggle('on', app.continuousPlay) } else { switchButton.addEventListener('click', () => { GM_setValue(pageType, !app.continuousPlay) }) } } let lastVueInstance = null const hookVueInstance = (vueInstance) => { if (!vueInstance || vueInstance === lastVueInstance) return lastVueInstance = vueInstance correctNextButton(vueInstance) // hook loadVideoData 保证从推荐视频加载新视频时重新判断视频类型 if (!vueInstance.__correctNextButtonHooked) { const __loadVideoData = vueInstance.loadVideoData vueInstance.loadVideoData = function () { return __loadVideoData.call(this).then( (res) => { correctNextButton(vueInstance) return res }, (error) => Promise.reject(error) ) } vueInstance.__correctNextButtonHooked = true } } const observeVueInstance = () => { const appContainer = document.querySelector('#app') if (!appContainer) return if (appContainer.__vue__) { hookVueInstance(appContainer.__vue__) } const observer = new MutationObserver(() => { const app = document.querySelector('#app') if (app?.__vue__) { hookVueInstance(app.__vue__) } }) observer.observe(appContainer, { childList: true, subtree: true }) } observeVueInstance()