哔哩哔哩(bilibili.com)播放页调整

1.自动定位到播放器(进入播放页,可自动定位到播放器,可设置偏移量及是否在点击主播放器时定位);2.可设置是否自动选择最高画质;3.可设置播放器默认模式;

目前為 2022-10-13 提交的版本,檢視 最新版本

// ==UserScript==
// @name              哔哩哔哩(bilibili.com)播放页调整
// @license           GPL-3.0 License
// @namespace         https://gf.qytechs.cn/zh-CN/scripts/415804-bilibili%E6%92%AD%E6%94%BE%E9%A1%B5%E8%B0%83%E6%95%B4-%E8%87%AA%E7%94%A8
// @version           0.9.6
// @description       1.自动定位到播放器(进入播放页,可自动定位到播放器,可设置偏移量及是否在点击主播放器时定位);2.可设置是否自动选择最高画质;3.可设置播放器默认模式;
// @author            QIAN
// @match             *://*.bilibili.com/video/*
// @match             *://*.bilibili.com/bangumi/play/*
// @require           https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @require           https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.all.min.js
// @resource          swalStyle https://cdn.jsdelivr.net/npm/[email protected]/dist/sweetalert2.min.css
// @grant             GM_setValue
// @grant             GM_getValue
// @grant             GM_registerMenuCommand
// @grant             GM_getResourceText
// @grant             GM.info
// @supportURL        https://github.com/QIUZAIYOU/Bilibili-VideoPage-Adjustment
// @homepageURL       https://github.com/QIUZAIYOU/Bilibili-VideoPage-Adjustment
// @icon              https://www.bilibili.com/favicon.ico?v=1
// ==/UserScript==
$(function() {
	console.time('播放页调整:总用时')
	const utils = {
		getValue(name) {
			return GM_getValue(name)
		},
		setValue(name, value) {
			GM_setValue(name, value)
		},
		sleep(time) {
			return new Promise(resolve => setTimeout(resolve, time))
		},
		addStyle(id, tag, css) {
			tag = tag || 'style'
			const doc = document
			const styleDom = doc.getElementById(id)
			if (styleDom) return
			const style = doc.createElement(tag)
			style.rel = 'stylesheet'
			style.id = id
			tag === 'style' ? style.innerHTML = css : style.href = css
			document.head.appendChild(style)
		},
		waitElement(selector, times, interval, flag = true) {
			var _times = times || -1; var _interval = interval || 500; var _selector = selector; var _iIntervalID; var _flag = flag
			return new Promise(function(resolve, reject) {
				_iIntervalID = setInterval(() => {
					if (!_times) {
						clearInterval(_iIntervalID)
						reject()
					}
					_times <= 0 || _times--
					var _self = $(_selector)
					if (_flag && _self.length || !_flag && !_self.length) {
						clearInterval(_iIntervalID)
						resolve(_iIntervalID)
					}
				}, _interval)
			})
		},
		waitSameValue(selector, attr, value, times, interval, flag = true) {
			var _times = times || -1; var _interval = interval || 500; var _selector = selector; var _iIntervalID; var _flag = flag
			return new Promise(function(resolve, reject) {
				_iIntervalID = setInterval(() => {
					if (!_times) {
						clearInterval(_iIntervalID)
						reject()
					}
					_times <= 0 || _times--
					var _self = $(_selector).attr(attr)
					if (_flag && _self === value || !_flag && _self !== value) {
						clearInterval(_iIntervalID)
						resolve(_iIntervalID)
					}
				}, _interval)
			})
		},
		getClientHeight() {
			var clientHeight = 0
			if (document.body.clientHeight && document.documentElement.clientHeight) {
				var clientHeight = document.body.clientHeight < document.documentElement.clientHeight ? document.body.clientHeight : document.documentElement.clientHeight
			} else {
				var clientHeight = document.body.clientHeight > document.documentElement.clientHeight ? document.body.clientHeight : document.documentElement.clientHeight
			}
			return clientHeight
		},
		historyListener() {
			class Dep {
				constructor(name) {
					this.id = new Date()
					this.subs = []
				}
				defined() {
					Dep.watch.add(this)
				}
				notify() {
					this.subs.forEach((e, i) => {
						if (typeof e.update === 'function') {
							try {
								e.update.apply(e)
							} catch (err) {
								console.warr(err)
							}
						}
					})
				}
			}
			Dep.watch = null
			class Watch {
				constructor(name, fn) {
					this.name = name
					this.id = new Date()
					this.callBack = fn
				}
				add(dep) {
					dep.subs.push(this)
				}
				update() {
					var cb = this.callBack
					cb(this.name)
				}
			}
			var addHistoryMethod = (function() {
				var historyDep = new Dep()
				return function(name) {
					if (name === 'historychange') {
						return function(name, fn) {
							var event = new Watch(name, fn)
							Dep.watch = event
							historyDep.defined()
							Dep.watch = null
						}
					} else if (name === 'pushState' || name === 'replaceState') {
						var method = history[name]
						return function() {
							method.apply(history, arguments)
							historyDep.notify()
						}
					}
				}
			}())
			window.addHistoryListener = addHistoryMethod('historychange')
			history.pushState = addHistoryMethod('pushState')
			history.replaceState = addHistoryMethod('replaceState')
			window.addHistoryListener('history', function() {
				main.autoLocation()
			})
		},
		documentHidden() {
			var hidden = 'hidden'
			if (hidden in document) document.addEventListener('visibilitychange', onchange); else if ((hidden = 'mozHidden') in document) document.addEventListener('mozvisibilitychange', onchange); else if ((hidden = 'webkitHidden') in document) document.addEventListener('webkitvisibilitychange', onchange); else if ((hidden = 'msHidden') in document) document.addEventListener('msvisibilitychange', onchange); else if ('onfocusin' in document) document.onfocusin = document.onfocusout = onchange; else window.onpageshow = window.onpagehide = window.onfocus = window.onblur = onchange
			function onchange(evt) {
				var v = 'visible'; var h = 'hidden'; var evtMap = {
					focus: v,
					focusin: v,
					pageshow: v,
					blur: h,
					focusout: h,
					pagehide: h
				}
				evt = evt || window.event
				if (evt.type in evtMap) {
					return evtMap[evt.type] === 'hidden'
				} else {
					return this[hidden]
				}
			}
			if (document[hidden] !== undefined) return document[hidden]
		}
	}
	const main = {
		initValue() {
			const value = [{
				name: 'player_type',
				value: 'video'
			}, {
				name: 'offset_top',
				value: 7
			}, {
				name: 'player_offset_top',
				value: 160
			}, {
				name: 'is_vip',
				value: false
			}, {
				name: 'click_player_auto_locate',
				value: true
			}, {
				name: 'current_screen_mod',
				value: 'normal'
			}, {
				name: 'selected_screen_mod',
				value: 'wide'
			}, {
				name: 'auto_select_video_highest_quality',
				value: true
			}, {
				name: 'contain_quality_4k',
				value: false
			}, {
				name: 'contain_quality_8k',
				value: false
			}, {
				name: 'webfull_unlock',
				value: false
			}]
			value.forEach(v => {
				if (utils.getValue(v.name) === undefined) {
					utils.setValue(v.name, v.value)
				}
			})
		},
		getCurrentPlayerTypeAndScreenMod() {
			utils.setValue('current_screen_mod', 'normal')
			const currentUrl = window.location.href
			if (currentUrl.includes('www.bilibili.com/video')) {
				utils.setValue('player_type', 'video')
			}
			if (currentUrl.includes('www.bilibili.com/bangumi/play')) {
				utils.setValue('player_type', 'bangumi')
			}
			const playerSelecter = '.bpx-player-container'
			utils.waitElement(playerSelecter, 10, 100).then(() => {
				const playerDataScreen = $('.bpx-player-container').attr('data-screen') || null
				const screenModObserver = new MutationObserver(function(mutations) {
					mutations.forEach(function(mutation) {
						if ([null, 'null', 'normal'].includes(playerDataScreen)) {
							utils.setValue('current_screen_mod', 'normal')
						}
						if (playerDataScreen === 'wide') {
							utils.setValue('current_screen_mod', 'wide')
						}
						if (playerDataScreen === 'web') {
							utils.setValue('current_screen_mod', 'web')
						}
					})
				})
				screenModObserver.observe($(playerSelecter)[0], {
					attributes: true
				})
			}).catch(() => {
				console.log('播放页调整:未找到播放器')
			})
		},
		showInformation() {
			console.group(GM.info.script.name)
			console.log(' author:' + GM.info.script.author, '\n', 'player_type: ' + utils.getValue('player_type'), '\n', 'offset_top: ' + utils.getValue('offset_top'), '\n', 'player_offset_top: ' + utils.getValue('player_offset_top'), '\n', 'is_vip: ' + utils.getValue('is_vip'), '\n', 'click_player_auto_locate: ' + utils.getValue('click_player_auto_locate'), '\n', 'current_screen_mod: ' + utils.getValue('current_screen_mod'), '\n', 'selected_screen_mod: ' + utils.getValue('selected_screen_mod'), '\n', 'auto_select_video_highest_quality: ' + utils.getValue('auto_select_video_highest_quality'), '\n', 'webfull_unlock: ' + utils.getValue('webfull_unlock'))
			console.groupEnd(GM.info.script.name)
		},
		autoSelectScreenMod() {
			const playerSelecter = '.bpx-player-container'
			const player_type = utils.getValue('player_type')
			const selected_screen_mod = utils.getValue('selected_screen_mod')
			const current_screen_mod = utils.getValue('current_screen_mod')
			const checkDocumentHidden = setInterval(async() => {
				if (await !utils.documentHidden()) {
					clearInterval(checkDocumentHidden)
					utils.waitElement(playerSelecter, 10, 100).then(() => {
						const startTime = new Date().getTime()
						console.log('播放页调整:播放器已找到,开始监控')
						const screenModObserver = new MutationObserver(function(mutations) {
							mutations.forEach(async function(mutation) {
								let playerDataScreen = $(playerSelecter).attr('data-screen') || null
								if (player_type === 'video') {
									if (selected_screen_mod === 'normal' && current_screen_mod === 'normal' && playerDataScreen === 'normal') {
										screenModObserver.disconnect()
										console.log('播放页调整:小屏切换成功,停止监控')
										utils.setValue('current_screen_mod', 'normal')
										main.autoLocation()
										main.fixStyle()
										main.insertLocateButton()
									}
									if (selected_screen_mod === 'normal' && current_screen_mod !== 'normal' && playerDataScreen === 'wide') {
										screenModObserver.disconnect()
										console.log('播放页调整:小屏切换成功,停止监控')
										$('.bpx-player-ctrl-wide-leave').click()
										utils.setValue('current_screen_mod', 'normal')
										main.autoLocation()
										main.fixStyle()
										main.insertLocateButton()
									}
									if (selected_screen_mod === 'normal' && current_screen_mod !== 'normal' && playerDataScreen === 'web') {
										screenModObserver.disconnect()
										console.log('播放页调整:小屏切换成功,停止监控')
										$('.bpx-player-ctrl-web-leave').click()
										utils.setValue('current_screen_mod', 'normal')
										main.autoLocation()
										main.fixStyle()
										main.insertLocateButton()
									}
									if (selected_screen_mod === 'wide' && current_screen_mod !== 'wide' && playerDataScreen !== 'wide') {
										$('.bpx-player-ctrl-wide-enter').click()
										utils.waitSameValue(playerSelecter, 'data-screen', 'wide', 100, 10).then(async() => {
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:宽屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'wide')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												await utils.sleep(1e3)
												main.autoLocation()
												main.fixStyle()
												main.insertLocateButton()
											}
										}).catch(async() => {
											console.log('播放页调整:宽屏切换失败,尝试重试')
											$('.bpx-player-ctrl-wide-enter').click()
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:宽屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'wide')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												await utils.sleep(1e3)
												main.autoLocation()
												main.fixStyle()
												main.insertLocateButton()
											} else {
												$('.bpx-player-ctrl-wide-enter').click()
											}
										})
									}
									if (selected_screen_mod === 'web' && current_screen_mod !== 'web' && playerDataScreen !== 'web') {
										$('.bpx-player-ctrl-web-enter').click()
										utils.waitSameValue(playerSelecter, 'data-screen', 'web', 100, 10).then(async() => {
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:网页全屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'web')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												main.insertLocateButton()
												const webfull_unlock = utils.getValue('webfull_unlock')
												if (webfull_unlock) {
													await utils.sleep(2e3)
													const clientHeight = utils.getClientHeight()
													$('body.webscreen-fix').css({
														'padding-top': clientHeight,
														position: 'unset'
													})
													$('#bilibili-player.mode-webscreen').css({
														height: clientHeight,
														position: 'absolute'
													})
													$('#app').prepend($('#bilibili-player.mode-webscreen'))
													$('#playerWrap').css('display', 'none')
													console.log('播放页调整:网页全屏解锁成功')
													// 退出网页全屏
													$('.bpx-player-ctrl-btn-icon.bpx-player-ctrl-web-leave').click(function() {
														$('body').css({
															'padding-top': 0,
															position: 'auto'
														})
														$('#playerWrap').css('display', 'block')
														const playerWrapHeight = $('#playerWrap').height()
														$('#bilibili-player').css({
															height: playerWrapHeight,
															position: 'unset'
														})
														$('#playerWrap').append($('#bilibili-player.mode-webscreen'))
														utils.setValue('selected_screen_mod', 'wide')
														main.autoLocation()
														utils.setValue('selected_screen_mod', 'web')
													})
													// 再次进入网页全屏
													$('.bpx-player-ctrl-btn-icon.bpx-player-ctrl-web-enter').click(function() {
														$('body').css({
															'padding-top': clientHeight,
															position: 'unset'
														})
														$('#bilibili-player').css({
															height: clientHeight,
															position: 'absolute'
														})
														$('#app').prepend($('#bilibili-player'))
														$('#playerWrap').css('display', 'none')
														main.autoLocation()
													})
												}
												// 进入宽屏
												$('.bpx-player-ctrl-btn-icon.bpx-player-ctrl-wide-enter').click(function() {
													$('body').css({
														'padding-top': 0,
														position: 'auto'
													})
													$('#playerWrap').css('display', 'block')
													$('#bilibili-player').css({
														height: 'auto',
														position: 'unset'
													})
													$('#playerWrap').append($('#bilibili-player.mode-webscreen'))
													utils.setValue('selected_screen_mod', 'wide')
													main.autoLocation()
													utils.setValue('selected_screen_mod', 'web')
												})
												// 进入或离开全屏
												$('.bpx-player-ctrl-full .bpx-player-ctrl-btn-icon').click(function() {
													const playerFullStatusText = $('.bpx-player-tooltip-title').text()
													if (playerFullStatusText.includes('进入全屏')) {
														console.log('播放页调整:进入全屏')
													}
													if (playerFullStatusText.includes('退出全屏')) {
														console.log('播放页调整:退出全屏')
														$('body').css({
															'padding-top': 0,
															position: 'auto'
														})
														$('#playerWrap').css('display', 'block')
														$('#bilibili-player').css({
															height: 'auto',
															position: 'unset'
														})
														$('#playerWrap').append($('#bilibili-player.mode-webscreen'))
														utils.setValue('selected_screen_mod', 'wide')
														main.autoLocation()
														utils.setValue('selected_screen_mod', 'web')
													}
												})
											}
										}).catch(() => {
											console.log('播放页调整:网页全屏切换失败,尝试重试')
											$('.bpx-player-ctrl-web-enter').click()
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:网页全屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'web')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												main.insertLocateButton()
											} else {
												$('.bpx-player-ctrl-web-enter').click()
											}
										})
									}
								}
								if (player_type === 'bangumi') {
									if (selected_screen_mod === 'normal' && current_screen_mod === 'normal' && playerDataScreen === 'normal') {
										screenModObserver.disconnect()
										console.log('播放页调整:小屏切换成功,停止监控')
										utils.setValue('current_screen_mod', 'normal')
										main.autoLocation()
										main.fixStyle()
										main.insertLocateButton()
									}
									if (selected_screen_mod === 'normal' && current_screen_mod !== 'normal' && playerDataScreen === 'wide') {
										screenModObserver.disconnect()
										console.log('播放页调整:小屏切换成功,停止监控')
										$('.squirtle-wide-active').click()
										utils.setValue('current_screen_mod', 'normal')
										main.autoLocation()
										main.fixStyle()
										main.insertLocateButton()
									}
									if (selected_screen_mod === 'normal' && current_screen_mod !== 'normal' && playerDataScreen === 'web') {
										screenModObserver.disconnect()
										console.log('播放页调整:小屏切换成功,停止监控')
										$('.squirtle-pagefullscreen-active').click()
										utils.setValue('current_screen_mod', 'normal')
										main.autoLocation()
										main.fixStyle()
										main.insertLocateButton()
									}
									if (selected_screen_mod === 'wide' && current_screen_mod !== 'wide' && playerDataScreen !== 'wide') {
										$('.squirtle-widescreen-inactive').click()
										utils.waitSameValue(playerSelecter, 'data-screen', 'wide', 100, 10).then(async() => {
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:宽屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'wide')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												await utils.sleep(1e3)
												main.autoLocation()
												main.fixStyle()
												main.insertLocateButton()
											}
										}).catch(async() => {
											console.log('播放页调整:宽屏切换失败,尝试重试')
											$('.squirtle-widescreen-inactive').click()
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:宽屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'wide')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												await utils.sleep(1e3)
												main.autoLocation()
												main.fixStyle()
												main.insertLocateButton()
											} else {
												$('.squirtle-widescreen-inactive').click()
											}
										})
									}
									if (selected_screen_mod === 'web' && current_screen_mod !== 'web' && playerDataScreen !== 'web') {
										$('.squirtle-pagefullscreen-inactive').click()
										utils.waitSameValue(playerSelecter, 'data-screen', 'web', 100, 10).then(async() => {
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:网页全屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'web')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												main.insertLocateButton()
											}
										}).catch(() => {
											console.log('播放页调整:网页全屏切换失败,尝试重试')
											$('.squirtle-pagefullscreen-inactive').click()
											playerDataScreen = $(playerSelecter).attr('data-screen')
											if (selected_screen_mod === playerDataScreen) {
												console.log('播放页调整:网页全屏切换成功,停止监控')
												utils.setValue('current_screen_mod', 'web')
												screenModObserver.disconnect()
												main.autoSelectVideoHightestQuality()
												main.autoCancelMute()
												main.insertLocateButton()
											} else {
												$('.squirtle-pagefullscreen-inactive').click()
											}
										})
									}
								}
							})
						})
						screenModObserver.observe($(playerSelecter)[0], {
							attributes: true,
							attributeOldValue: true,
							attributeFilter: ['data-screen']
						})
						$(playerSelecter).attr('data-screen', 'normal')
					}).catch(() => {
						console.log('播放页调整:播放器模式切换失败')
					})
				} else {
					console.log('播放页调整:当前标签未激活,正在重试')
				}
			}, 100)
		},
		autoSelectVideoHightestQuality() {
			const videoPlayerSelecter = '.bpx-player-ctrl-quality'
			const bangumiPlayerSelecter = '.squirtle-quality-wrap'
			const player_type = utils.getValue('player_type')
			const is_vip = utils.getValue('is_vip')
			const contain_quality_4k = utils.getValue('contain_quality_4k')
			const contain_quality_8k = utils.getValue('contain_quality_8k')
			const auto_select_video_highest_quality = utils.getValue('auto_select_video_highest_quality')
			if (auto_select_video_highest_quality) {
				if (is_vip) {
					if (player_type === 'video') {
						utils.waitElement(videoPlayerSelecter, 10, 100).then(() => {
							// 同时不勾选包含4K和包含8K,自动选除这两项之外最高画质
							if (!contain_quality_4k && !contain_quality_8k) {
								const qualityValue = $('.bpx-player-ctrl-quality > ul > li').filter(function() {
									return !$(this).children('span.bpx-player-ctrl-quality-text').text().includes('4K') || $(this).children('.squirtle-quality-text-c').children('.squirtle-quality-text').text().includes('8K')
								})
								qualityValue.eq(0).click()
								console.log('播放页调整:VIP最高画质(不包含4K及8K)切换成功')
								main.fixStyle()
							}
							// 同时勾选包含4K和包含8K,自动选择8K
							if (contain_quality_4k && contain_quality_8k) {
								const qualityValue = $('.bpx-player-ctrl-quality > ul > li').filter(function() {
									return $(this).children('span.bpx-player-ctrl-quality-text').text().includes('8K')
								})
								qualityValue.eq(0).click()
								console.log('播放页调整:VIP最高画质(8K)切换成功')
								main.fixStyle()
							}
							// 仅勾选包含4K,选择4K
							if (contain_quality_4k && !contain_quality_8k) {
								const qualityValue = $('.bpx-player-ctrl-quality > ul > li').filter(function() {
									return $(this).children('span.bpx-player-ctrl-quality-text').text().includes('4K')
								})
								qualityValue.eq(0).click()
								console.log('播放页调整:VIP最高画质(4K)切换成功')
								main.fixStyle()
							}
							// 仅勾选包含8K,选择8K
							if (!contain_quality_4k && contain_quality_8k) {
								const qualityValue = $('.bpx-player-ctrl-quality > ul > li').filter(function() {
									return $(this).children('span.bpx-player-ctrl-quality-text').text().includes('8K')
								})
								qualityValue.eq(0).click()
								console.log('播放页调整:VIP最高画质(8K)切换成功')
								main.fixStyle()
							}
						}).catch(() => {
							console.log('播放页调整:VIP最高画质切换失败')
						})
					}
					if (player_type === 'bangumi') {
						utils.waitElement(bangumiPlayerSelecter, 10, 100).then(() => {
							if (contain_quality_4k) {
								$('.squirtle-quality-wrap >.squirtle-video-quality > ul > li').eq(0).click()
								console.log('播放页调整:VIP最高画质(包含4K)切换成功')
								main.fixStyle()
							} else {
								const qualityValue = $('.squirtle-quality-wrap > .squirtle-video-quality > ul > li').filter(function() {
									return !$(this).children('.squirtle-quality-text-c').children('.squirtle-quality-text').text().includes('4K') && $(this).children('.squirtle-quality-text-c').children('.squirtle-quality-text').text().includes('8K')
								})
								qualityValue.eq(0).click()
								console.log('播放页调整:VIP最高画质(不包含4K)切换成功')
								main.fixStyle()
							}
						}).catch(() => {
							console.log('播放页调整:VIP最高画质切换失败')
						})
					}
				} else {
					if (player_type === 'video') {
						utils.waitElement(videoPlayerSelecter, 10, 100).then(() => {
							const selectVipItemLength = $('.bpx-player-ctrl-quality > ul > li').children('.bpx-player-ctrl-quality-badge-bigvip').length
							$('.bpx-player-ctrl-quality > ul > li').eq(selectVipItemLength).click()
							console.log('播放页调整:非VIP最高画质切换成功')
							main.fixStyle()
						}).catch(() => {
							console.log('播放页调整:非VIP最高画质切换失败')
						})
					}
					if (player_type === 'bangumi') {
						utils.waitElement(bangumiPlayerSelecter, 10, 100).then(() => {
							const selectVipItemLength = $('.squirtle-quality-wrap >.squirtle-video-quality > ul > li').children('.squirtle-bigvip').length
							$('.squirtle-quality-wrap >.squirtle-video-quality > ul > li').eq(selectVipItemLength).click()
							console.log('播放页调整:非VIP最高画质切换成功')
							main.fixStyle()
						}).catch(() => {
							console.log('播放页调整:非VIP最高画质切换失败')
						})
					}
				}
			} else {
				main.fixStyle()
			}
		},
		autoCancelMute() {
			const player_type = utils.getValue('player_type')
			if (player_type === 'video') {
				const cancelMuteButtn = $('.bpx-player-ctrl-muted-icon')
				const cancelMuteButtnDisplay = cancelMuteButtn.css('display')
				if (cancelMuteButtnDisplay === 'block') {
					cancelMuteButtn.click()
					console.log('播放页调整:已自动取消静音')
				}
			}
			if (player_type === 'bangumi') {
				const cancelMuteButtn = $('.squirtle-volume-wrap .squirtle-volume .squirtle-volume-icon')
				const cancelMuteButtnClass = cancelMuteButtn.attr('class')
				if (cancelMuteButtnClass.includes('squirtle-volume-mute-state')) {
					cancelMuteButtn.click()
					console.log('播放页调整:已自动取消静音')
				}
			}
		},
		autoLocation() {
			const selected_screen_mod = utils.getValue('selected_screen_mod')
			const click_player_auto_locate = utils.getValue('click_player_auto_locate')
			if (selected_screen_mod !== 'web') {
				const offset_top = utils.getValue('offset_top')
				const player_type = utils.getValue('player_type')
				let player_offset_top
				if (player_type === 'video') {
					player_offset_top = $('#playerWrap').offset().top
					utils.setValue('player_offset_top', player_offset_top)
				}
				if (player_type === 'bangumi') {
					player_offset_top = $('#player_module').offset().top
					utils.setValue('player_offset_top', player_offset_top)
				}
				$('html,body').scrollTop(player_offset_top - offset_top)
				const checkAutoLocationStatus = setInterval(() => {
					const document_scroll_top = $(document).scrollTop()
					const success = document_scroll_top === player_offset_top - offset_top
					if (success) {
						clearInterval(checkAutoLocationStatus)
						console.log('播放页调整:自动定位成功')
					} else {
						console.log('播放页调整:自动定位失败,继续尝试', '\n', '-----------------', '\n', '当前文档顶部偏移量:' + document_scroll_top, '\n', '期望文档顶部偏移量:' + (player_offset_top - offset_top), '\n', '播放器顶部偏移量:' + player_offset_top, '\n', '设置偏移量:' + offset_top)
						$('html,body').scrollTop(player_offset_top - offset_top)
					}
				}, 100)
				if (click_player_auto_locate) {
					$('#bilibili-player').on('click', function() {
						$('html,body').scrollTop(player_offset_top - offset_top)
					})
				}
			} else {
				$('html,body').scrollTop(0)
				if (click_player_auto_locate) {
					$('#bilibili-player').on('click', function() {
						$('html,body').scrollTop(0)
					})
				}
			}
		},
		fixStyle() {
			$('body').css('overflow', 'unset')
			$('#viewbox_report').attr('style', 'height:106px!important')
			$('.wide-members').attr('style', 'height: 99px; overflow: hidden; padding: 10px; box-sizing: border-box;margin-top: -18px;')
			main.playerApplyedStatus()
		},
		insertLocateButton() {
			const player_type = utils.getValue('player_type')
			const playerDataScreen = $('.bpx-player-container').attr('data-screen')
			if (player_type === 'video') {
				const locateButtonHtml = `<div class="item locate" title="定位至播放器">\n        <svg t="1643419779790" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1775" width="200" height="200" style="width: 50%;height: 100%;fill: currentColor;"><path d="M512 352c-88.008 0-160.002 72-160.002 160 0 88.008 71.994 160 160.002 160 88.01 0 159.998-71.992 159.998-160 0-88-71.988-160-159.998-160z m381.876 117.334c-19.21-177.062-162.148-320-339.21-339.198V64h-85.332v66.134c-177.062 19.198-320 162.136-339.208 339.198H64v85.334h66.124c19.208 177.062 162.144 320 339.208 339.208V960h85.332v-66.124c177.062-19.208 320-162.146 339.21-339.208H960v-85.334h-66.124zM512 810.666c-164.274 0-298.668-134.396-298.668-298.666 0-164.272 134.394-298.666 298.668-298.666 164.27 0 298.664 134.396 298.664 298.666S676.27 810.666 512 810.666z" p-id="1776"></path></svg></div>`
				const floatNav = $('.float-nav-exp .nav-menu')
				const locateButton = $('.float-nav-exp .nav-menu .item.locate')
				const offset_top = utils.getValue('offset_top')
				const player_offset_top = utils.getValue('player_offset_top')
				$('.fixed-nav').css('bottom', '274px')
				floatNav.prepend(locateButtonHtml)
				locateButton.not(':first-child').remove()
				floatNav.on('click', '.locate', function() {
					if (playerDataScreen !== 'web') {
						$('html,body').scrollTop(player_offset_top - offset_top)
					} else {
						$('html,body').scrollTop(0)
					}
				})
			}
			if (player_type === 'bangumi') {
				const locateButtonHtml = `<div class="tool-item locate" title="定位至播放器">\n        <svg t="1643419779790" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1775" width="200" height="200" style="width: 50%;height: 100%;fill: currentColor;"><path d="M512 352c-88.008 0-160.002 72-160.002 160 0 88.008 71.994 160 160.002 160 88.01 0 159.998-71.992 159.998-160 0-88-71.988-160-159.998-160z m381.876 117.334c-19.21-177.062-162.148-320-339.21-339.198V64h-85.332v66.134c-177.062 19.198-320 162.136-339.208 339.198H64v85.334h66.124c19.208 177.062 162.144 320 339.208 339.208V960h85.332v-66.124c177.062-19.208 320-162.146 339.21-339.208H960v-85.334h-66.124zM512 810.666c-164.274 0-298.668-134.396-298.668-298.666 0-164.272 134.394-298.666 298.668-298.666 164.27 0 298.664 134.396 298.664 298.666S676.27 810.666 512 810.666z" p-id="1776"></path></svg></div>`
				const floatNav = $('.nav-tools')
				const locateButton = $('.nav-tools .tool-item.locate')
				const offset_top = utils.getValue('offset_top')
				const player_offset_top = utils.getValue('player_offset_top')
				floatNav.prepend(locateButtonHtml)
				locateButton.not(':first-child').remove()
				floatNav.on('click', '.locate', function() {
					if (playerDataScreen !== 'web') {
						$('html,body').scrollTop(player_offset_top - offset_top)
					} else {
						$('html,body').scrollTop(0)
					}
				})
			}
		},
		playerLoadStateWatcher() {
			const player_type = utils.getValue('player_type')
			if (player_type === 'video') {
				utils.waitElement('#playerWrap #bilibili-player', 10, 100).then(() => {
					const playerLoadStateWatcher = setInterval(() => {
						const playerVideoLength = $('.bpx-player-video-wrap').children().length
						if (playerVideoLength === 0) {
							location.reload(true)
						} else {
							clearInterval(playerLoadStateWatcher)
						}
					}, 100)
				})
			}
			if (player_type === 'bangumi') {
				utils.waitElement('#player_module #bilibili-player', 10, 100).then(() => {
					const playerLoadStateWatcher = setInterval(() => {
						const playerVideoLength = $('.bpx-player-video-wrap').children().length
						if (playerVideoLength === 0) {
							location.reload(true)
						} else {
							clearInterval(playerLoadStateWatcher)
						}
					}, 1500)
				})
			}
		},
		playerApplyedStatus() {
			const checkApplyedStatus = setInterval(() => {
				const selected_screen_mod = utils.getValue('selected_screen_mod')
				const playerDataScreen = $('.bpx-player-container').attr('data-screen')
				if (selected_screen_mod === playerDataScreen) {
					clearInterval(checkApplyedStatus)
					console.timeEnd('播放页调整:总用时')
				} else {
					console.log('播放页调整:配置应用失败,尝试重试')
				}
			}, 100)
		},
		registerMenuCommand() {
			GM_registerMenuCommand('设置', () => {
				const html = `
                <div id="playerAdjustment" style="font-size: 1em;">
                  <label class="player-adjustment-setting-label" style="padding-top:0!important;"> 是否为大会员
                    <input type="checkbox" id="Is-Vip" ${utils.getValue('is_vip') ? 'checked' : ''} class="player-adjustment-setting-checkbox">
                  </label>
                  <span class="player-adjustment-setting-tips"> -> 请如实勾选,否则影响自动选择清晰度</span>
                  <label class="player-adjustment-setting-label" id="player-adjustment-Range-Wrapper">
                    <span>播放器顶部偏移(px)</span>
                    <input id="Top-Offset" value="${utils.getValue('offset_top')}" style="padding:5px;width: 200px;border: 1px solid #cecece;">
                  </label>
                  <span class="player-adjustment-setting-tips"> -> 参考值:顶部导航栏吸顶时为 71 ,否则为 7</span>
                  <label class="player-adjustment-setting-label"> 点击播放器时定位
                    <input type="checkbox" id="Click-Player-Auto-Location" ${utils.getValue('click_player_auto_locate') ? 'checked' : ''} class="player-adjustment-setting-checkbox">
                  </label>
                  <div class="player-adjustment-setting-label screen-mod" style="display: flex;align-items: center;justify-content: space-between;"> 播放器默认模式 <div style="width: 215px;display: flex;align-items: center;justify-content: space-between;">
                      <label class="player-adjustment-setting-label" style="padding-top:0!important;">
                        <input type="radio" name="Screen-Mod" value="normal" ${utils.getValue('selected_screen_mod') === 'normal' ? 'checked' : ''}> 小屏 </label>
                      <label class="player-adjustment-setting-label" style="padding-top:0!important;">
                        <input type="radio" name="Screen-Mod" value="wide" ${utils.getValue('selected_screen_mod') === 'wide' ? 'checked' : ''}>宽屏 </label>
                      <label class="player-adjustment-setting-label" style="padding-top:0!important;">
                        <input type="radio" name="Screen-Mod" value="web" ${utils.getValue('selected_screen_mod') === 'web' ? 'checked' : ''}> 网页全屏 </label>
                    </div>
                  </div>
                  <span class="player-adjustment-setting-tips"> -> 若遇到不能自动选择播放器模式可尝试点击重置</span>
                  <label class="player-adjustment-setting-label"> 网页全屏模式解锁
                    <input type="checkbox" id="Webfull-Unlock" ${utils.getValue('webfull_unlock') ? 'checked' : ''} class="player-adjustment-setting-checkbox">
                  </label>
                  <span class="player-adjustment-setting-tips"> ->*实验性功能(不稳,可能会有这样或那样的问题):勾选后网页全屏模式下可以滑动滚动条查看下方评论等内容,2秒延迟后解锁(番剧播放页不支持)</span>
                  <label class="player-adjustment-setting-label"> 自动选择最高画质
                    <input type="checkbox" id="Auto-Quality" ${utils.getValue('auto_select_video_highest_quality') ? 'checked' : ''} class="player-adjustment-setting-checkbox">
                  </label>
                  <div class="auto-quality-sub-options">
                    <label class="player-adjustment-setting-label fourK"> 是否包含4K画质
                      <input type="checkbox" id="Quality-4K" ${utils.getValue('contain_quality_4k') ? 'checked' : ''} class="player-adjustment-setting-checkbox">
                    </label>
                    <label class="player-adjustment-setting-label eightK"> 是否包含8K画质
                      <input type="checkbox" id="Quality-8K" ${utils.getValue('contain_quality_8k') ? 'checked' : ''} class="player-adjustment-setting-checkbox">
                    </label>
                  </div>
                  <span class="player-adjustment-setting-tips"> -> 网络条件好时可以启用此项,勾哪项选哪项,都勾选8k,否则选择4k及8k外最高画质。</span>
                </div>
                `
				Swal.fire({
					title: '播放页调整设置',
					html: html,
					icon: 'info',
					showCloseButton: true,
					showDenyButton: true,
					confirmButtonText: '保存',
					denyButtonText: '重置',
					footer: '<div style="text-align: center;">如果发现脚本不能用,可能是播放页更新了,请耐心等待适配。</div><hr style="border: none;height: 1px;margin: 12px 0;background: #eaeaea;"><div style="text-align: center;font-size: 1.25em;"><a href="//userstyles.world/style/241/nightmode-for-bilibili-com" target="_blank">夜间哔哩 - </a><a href="//gf.qytechs.cn/zh-CN/scripts/415804-bilibili%E6%92%AD%E6%94%BE%E9%A1%B5%E8%B0%83%E6%95%B4-%E8%87%AA%E7%94%A8" target="_blank">检查更新</a></div>'
				}).then(res => {
					res.isConfirmed && location.reload(true)
					if (res.isConfirmed) {
						location.reload(true)
					} else if (res.isDenied) {
						utils.setValue('current_screen_mod', 'normal')
						location.reload(true)
					}
				})
				$('#Is-Vip').change(e => {
					utils.setValue('is_vip', e.target.checked)
					if (e.target.checked === true) {
						$('.fourK,.eightK').css('display', 'flex!important')
					} else {
						$('.fourK,.eightK').css('display', 'none!important')
					}
				})
				$('#Top-Offset').change(e => {
					utils.setValue('offset_top', e.target.value)
				})
				$('#Click-Player-Auto-Location').change(e => {
					utils.setValue('click_player_auto_locate', e.target.checked)
				})
				$('#Auto-Quality').change(e => {
					utils.setValue('auto_select_video_highest_quality', e.target.checked)
				})
				$('#Quality-4K').change(e => {
					utils.setValue('contain_quality_4k', e.target.checked)
				})
				$('#Quality-8K').change(e => {
					utils.setValue('contain_quality_8k', e.target.checked)
				})
				$('input[name="Screen-Mod"]').click(function() {
					utils.setValue('selected_screen_mod', $(this).val())
				})
				$('#Webfull-Unlock').change(e => {
					utils.setValue('webfull_unlock', e.target.checked)
				})
			})
		},
		addPluginStyle() {
			const style = `.swal2-popup{width:34em!important;padding:1.25em!important}.swal2-html-container{margin:0!important;padding:16px 5px 0!important;width:100%!important;box-sizing:border-box!important}.swal2-footer{flex-direction:column!important}.swal2-close{top:5px!important;right:3px!important}.swal2-actions{margin:7px auto 0!important}.swal2-styled.swal2-confirm{background-color:#23ade5!important}.swal2-icon.swal2-info.swal2-icon-show{display:none!important}.player-adjustment-container,.swal2-container{z-index:999999999!important}.player-adjustment-popup{font-size:14px!important}.player-adjustment-setting-label{display:flex!important;align-items:center!important;justify-content:space-between!important;padding-top:10px!important}.player-adjustment-setting-checkbox{width:16px!important;height:16px!important}.player-adjustment-setting-tips{width:100%!important;display:flex!important;align-items:center!important;padding:5px!important;margin-top:10px!important;background:#f5f5f5!important;box-sizing:border-box!important;font-size:14px;color:#666!important;border-radius:2px!important;text-align:left!important}.player-adjustment-setting-tips svg{margin-right:5px!important}label.player-adjustment-setting-label input{border:1px solid #cecece!important;background:#fff!important}label.player-adjustment-setting-label input[type=checkbox],label.player-adjustment-setting-label input[type=radio]{width:16px!important;height:16px!important}label.player-adjustment-setting-label input:checked{border-color:#1986b3!important;background:#23ade5!important}.auto-quality-sub-options{display:flex;align-items:center;padding-left:15px}.auto-quality-sub-options label.player-adjustment-setting-label.fourK{margin-right:10px}.auto-quality-sub-options .player-adjustment-setting-label input[type="checkbox"]{margin-left:5px!important}.player-adjustment-setting-label.screen-mod input{margin-right:5px!important}`
			if (document.head) {
				utils.addStyle('swal-pub-style', 'style', GM_getResourceText('swalStyle'))
				utils.addStyle('player-adjustment-style', 'style', style)
			}
			const headObserver = new MutationObserver(() => {
				utils.addStyle('swal-pub-style', 'style', GM_getResourceText('swalStyle'))
				utils.addStyle('player-adjustment-style', 'style', style)
			})
			headObserver.observe(document.head, {
				childList: true,
				subtree: true
			})
		},
		isTopWindow() {
			return window.self === window.top
		},
		init() {
			$('body').css('overflow', 'hidden')
			this.initValue()
			this.addPluginStyle()
			this.getCurrentPlayerTypeAndScreenMod()
			this.showInformation()
			this.autoSelectScreenMod()
			this.playerLoadStateWatcher()
			this.isTopWindow() && this.registerMenuCommand()
			utils.historyListener()
		}
	}
	main.init()
})

QingJ © 2025

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