您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
优化Bilibili触屏操作体验,支持长按、滑动、缩放等手势操作,支持倍速播放。
// ==UserScript== // @name Bilibili触屏优化 // @namespace http://tampermonkey.net/ // @version 0.0.2 // @description 优化Bilibili触屏操作体验,支持长按、滑动、缩放等手势操作,支持倍速播放。 // @author Blysh // @match *://*.bilibili.com/* // @grant none // @license MIT // @icon https://cdn.jsdelivr.net/gh/the1812/Bilibili-Evolved@preview/images/logo-small.png // ==/UserScript== class VideoGestureHandler { //! ------------------Contructor------------------ constructor(videoElement) { this.biliPlayer = videoElement; this.videoElement = videoElement.querySelector("video"); this.ctrlWrap = videoElement.querySelector(".bpx-player-control-bottom"); this.playerController = videoElement.querySelector(".bpx-player-container"); this.playerJindutiao = videoElement.querySelector(".bpx-player-control-entity"); this.longPressInterval = null; this.touchMoveInterval = null; this.intervals = []; this.longPressThreshold = 400; // 长按阈值,单位为毫秒 this.gestureType = "none"; this.playbackRate = "1x"; this.touchStartX = 0; this.touchStartY = 0; this.touchX = 0; this.touchY = 0; this.lastDistance = 0; this.add_time = 0; this.touchStartTime = 0; this.touchEndTime = 0; this.currenttime = 0; this.textBox = null; this.photoShotStyle = null; this.progressElement = null; this.clickTimeout = null; this.tryGetTargetElement3Times = 0; this.swipeTouchEnd = this.swipeTouchEnd.bind(this); this.longPressTouchEnd = this.longPressTouchEnd.bind(this); this.normolTouchEnd = this.normolTouchEnd.bind(this); this.zoomTouchEnd = this.zoomTouchEnd.bind(this); this.swipeUDTouchEnd = this.swipeUDTouchEnd.bind(this); this.volume = videoElement.volume; this.videoElement.style.filter = 'brightness(1)'; this.brightness = 1; this.ctrlTimeoutID = null; this.addHint(); //* 创建代理对象 this.proxyGestureType = new Proxy({ gestureType: this.gestureType }, this.handler()); this.proxyPlaybackRate = new Proxy({ playbackRate: this.playbackRate }, this.playbackRateHandler()); //* 添加事件监听器 this.videoElement.addEventListener('touchstart', this.handleTouchStart.bind(this)); this.videoElement.addEventListener('touchmove', this.handleTouchMove.bind(this)); this.videoElement.addEventListener('touchend', this.normolTouchEnd); this.ctrlWrap.addEventListener('touchstart', event => { clearTimeout(this.ctrlTimeoutID); this.ctrlTimeoutID = null; }) } //! ------------------Proxy------------------ handler() { return { set: (target, property, value) => { target[property] = value; this.videoElement.removeEventListener('touchend', this.normolTouchEnd); if (property === 'gestureType' && value === 'longpress') { this.videoElement.addEventListener('touchend', this.longPressTouchEnd); } else if (property === 'gestureType' && value === 'swipe') { // 创建并触发 mouseenter 事件 const mouseEnterEvent = new MouseEvent('mouseenter', { view: window, bubbles: true, cancelable: true }); this.progressElement = document.querySelector(".bpx-player-progress"); this.progressElement.dispatchEvent(mouseEnterEvent); // 将photoshot固定显示在屏幕下方 this.photoShot = document.querySelector(".bpx-player-progress-popup"); this.photoShotStyle = document.createElement("style"); this.photoShotStyle.innerHTML = ` .bpx-player-progress-popup{ left: 50%!important; bottom:250px!important; overflow:visible!important; transform: translate(-100%, 100%); }`; this.photoShot.appendChild(this.photoShotStyle); // photoshot放大两倍 this.photoShotSize = document.querySelector(".bpx-player-progress-preview-image"); this.photoShotSize.style.height = "200%"; this.photoShotSize.style.width = "200%"; // 隐藏进度条上的指示器和预览时间 this.indicator = document.querySelector(".bpx-player-progress-move-indicator"); //this.indicator.style.display = "none"; this.previewTime = document.querySelector(".bpx-player-progress-preview-time"); this.previewTime.style.display = "none"; // 添加touchend事件监听器 this.videoElement.addEventListener('touchend', this.swipeTouchEnd); } else if(property === 'gestureType' && value === 'swipeUD'){ this.videoElement.addEventListener('touchend', this.swipeUDTouchEnd); } else if(property === 'gestureType' && value === 'zoom'){ this.createButton(); this.videoElement.addEventListener('touchend', this.zoomTouchEnd); } this.videoElement.addEventListener('touchend', this.normolTouchEnd); return true; } }; } playbackRateHandler() { return { set: (target, property, value) => { target[property] = value; if (property === 'playbackRate' && value === '1x') { this.playbackRateHint.style.display = "none"; } if (property === 'playbackRate' && value === '2x') { this.playbackRateHint.style.display = ''; this.playbackRateHint.innerHTML = this.playbackRateHint.innerHTML.replace(/\d?倍速播放中/, "2倍速播放中"); } else if (property === 'playbackRate' && value === '3x') { this.playbackRateHint.style.display = ''; this.playbackRateHint.innerHTML = this.playbackRateHint.innerHTML.replace(/\d?倍速播放中/, "3倍速播放中"); } return true; } }; } //! ------------------EventListener------------------ handleCtrl(){ this.isCtrlShow = this.playerController.getAttribute("data-ctrl-hidden") if(this.isCtrlShow == 'false' || this.ctrlTimeoutID){ this.hideCtrl(); this.hideCtrlMenus(); clearTimeout(this.ctrlTimeoutID); this.ctrlTimeoutID = null; } else{ this.showCtrl(); this.ctrlTimeoutID = setTimeout(() => { this.hideCtrl(); this.ctrlTimeoutID = null; },3000); } } showCtrl(){ this.playerController.classList.remove("bpx-state-no-cursor") this.playerController.setAttribute("data-ctrl-hidden","false") this.playerJindutiao.setAttribute("data-shadow-show","false") if(this.button)this.button.style.bottom = '10%'; } hideCtrl(){ this.playerController.classList.add("bpx-state-no-cursor") this.playerController.setAttribute("data-ctrl-hidden","true") this.playerJindutiao.setAttribute("data-shadow-show","true") if(this.button)this.button.style.bottom = '-2%'; } hideCtrlMenus(){ this.menus = document.querySelector(".bpx-player-control-bottom-right").childNodes; this.menus.forEach( menu => { menu.classList.remove("bpx-state-show"); }); } //* 单击事件 handleClick(event) { this.handleCtrl(); } //* 双击事件 handleDblClick(event) { // 切换视频的播放/暂停状态 if (this.videoElement.paused) { this.videoElement.play(); } else { this.videoElement.pause(); } } //* 触摸开始 handleTouchStart(event) { event.preventDefault(); event.stopPropagation(); this.currenttime = this.videoElement.currentTime; const touchCount = event.touches.length; const touch = event.touches[0]; this.touchStartX = touch.clientX; this.touchStartY = touch.clientY; this.touchX = touch.clientX; this.touchY = touch.clientY; try{ const touch2 = event.touches[1]; this.touchStartX2 = touch2.clientX; this.touchStartY2 = touch2.clientY; this.touchX2 = touch2.clientX; this.touchY2 = touch2.clientY;} catch(err){} this.lastDistance = 0; this.lastAngle = 0; if(touchCount === 1){ this.touchStartTime = Date.now(); } this.clearAllInterval(); if (touchCount === 1) { this.longPressInterval = setInterval(this.LongPressAction.bind(this), 200); this.intervals.push(this.longPressInterval); this.touchMoveInterval = setInterval(this.LRSwipeAction.bind(this), 50); this.intervals.push(this.touchMoveInterval); } if (touchCount === 2) { this.add_time = 0; this.currenttime = this.videoElement.currentTime; const secondTouchTime = Date.now(); const timeDifference = secondTouchTime - this.touchStartTime; if (timeDifference < 100){ this.zoomInterval = setInterval(this.zoomAction.bind(this),0); this.intervals.push(this.zoomInterval); } } } //* 触摸移动 handleTouchMove(event) { event.preventDefault(); const touch = event.touches[0]; this.touchX = touch.clientX; this.touchY = touch.clientY; try{ const touch2 = event.touches[1]; this.touchX2 = touch2.clientX; this.touchY2 = touch2.clientY;} catch(err){} } //* 放大缩小画面 zoomAction() { let deltaX = this.touchX - this.touchX2; let deltaY = this.touchY - this.touchY2; let distance = Math.abs(Math.sqrt(deltaX * deltaX + deltaY * deltaY)); let angle = this.calculateAngle(this.touchX, this.touchY, this.touchX2, this.touchY2); if(this.lastAngle == 0){this.lastAngle = angle;return;} if (this.lastDistance == 0) { this.lastDistance = distance; return; } let multiple = distance - this.lastDistance; let rotate = angle - this.lastAngle; if (Math.abs(multiple)>0 && this.proxyGestureType.gestureType === 'none' && this.proxyGestureType.gestureType !== 'zoom'){ this.proxyGestureType.gestureType = 'zoom'; this.clearOtherInterval(this.zoomInterval); } if(this.videoZoomMul == null){this.videoZoomMul=1} if(this.videoRotateDeg == null){this.videoRotateDeg=0} if(Math.abs(rotate)>0.5){ this.videoRotateDeg += rotate; } if(Math.abs(multiple)>0){ if(multiple>10){multiple=1} this.videoZoomMul += multiple*0.01; if(this.videoZoomMul<0.8){ this.videoZoomMul = 0.8 } } this.videoElement.style.transform = `scale(${this.videoZoomMul}) rotate(${this.videoRotateDeg}deg)`; this.lastDistance = distance; this.lastAngle = angle; } //* 单指左右移动调整时间 LRSwipeAction() { let deltaX = this.touchX - this.touchStartX; let distance = Math.sign(deltaX) * ( Math.abs(deltaX) - 5 ); if (this.lastDistance == 0) { this.lastDistance = distance; return; } const move = Math.abs(distance - this.lastDistance); //确保手指有移动 if (Math.abs(deltaX) > 5 && this.proxyGestureType.gestureType === 'none' && this.proxyGestureType.gestureType !== 'swipe') { this.proxyGestureType.gestureType = 'swipe'; this.clearOtherInterval(this.touchMoveInterval); } if(this.proxyGestureType.gestureType === 'swipe'){ if (move > 0.5) { this.add_time = distance * 0.1; let totalTime = this.currenttime + this.add_time; if (totalTime < 0) { totalTime = 0; } if (totalTime > this.videoElement.duration) { totalTime = this.videoElement.duration; } let positionRatio = totalTime / this.videoElement.duration; let start_X = this.progressElement.clientWidth * positionRatio; let videoRect = this.videoElement.getBoundingClientRect(); // 模拟鼠标在进度条移动事件 const mouseEvent = new MouseEvent('mousemove', { view: window, bubbles: true, cancelable: true, clientX: videoRect.left + start_X + 14 }); this.videoElement.dispatchEvent(mouseEvent); let add_txt; if(totalTime <= 0){ add_txt = "00:00" + " / " + this.sec2Time(this.videoElement.duration); } else if(totalTime >= this.videoElement.duration){ add_txt = `${this.sec2Time(this.videoElement.duration)} / ${this.sec2Time(this.videoElement.duration)}`; } else{ add_txt = `${this.sec2Time(this.add_time + this.currenttime)} / ${this.sec2Time(this.videoElement.duration)}`; } let display_sec = this.add_time >= 0 ? `+${Math.floor(this.add_time)}s` : `${Math.floor(this.add_time)}s` add_txt = add_txt + '\n' + display_sec this.textBox = this.createTextBox(this.textBox, add_txt); } } this.lastDistance = distance; } //* 单指上下移动调整音量和亮度 UDSwipeAction() { let deltaY = this.touchY - this.touchStartY; if (this.lastDistance == 0) { this.lastDistance = this.touchY; return; } const move = this.touchY - this.lastDistance; //确保手指有移动 if (Math.abs(deltaY) > 5 && this.proxyGestureType.gestureType === 'none' && this.proxyGestureType.gestureType !== 'swipeUD') { this.proxyGestureType.gestureType = 'swipeUD'; this.clearOtherInterval(this.touchMoveUDInterval); } if(this.proxyGestureType.gestureType === 'swipeUD'){ let videoRect = this.videoElement.getBoundingClientRect(); let centerX = videoRect.left + videoRect.width / 2; if(this.touchX > centerX){ if (Math.abs(move) > 5) { this.add_volume = -Math.sign(move)*0.05; this.volume = this.volume + this.add_volume; if (this.volume > 1) {this.volume = 1;} if (this.volume < 0) {this.volume = 0;} this.videoElement.volume = this.volume; this.add_txt = "🔈:" + Math.round(this.volume * 100) + "%"; this.textBox = this.createTextBox(this.textBox, this.add_txt); }} else if(this.touchX < centerX){ if (Math.abs(move) > 5) { this.add_brightness = -Math.sign(move)*0.05; this.brightness = this.brightness + this.add_brightness; if (this.brightness > 1) {this.brightness = 1;} if (this.brightness < 0) {this.brightness = 0;} this.videoElement.style.filter = `brightness(${this.brightness})`; this.add_txt = "☀:" + Math.round((this.brightness) * 100) + "%"; this.textBox = this.createTextBox(this.textBox, this.add_txt); } } } this.lastDistance = this.touchY; } //* 单指长按倍速播放 LongPressAction() { let touchDuration = Date.now() - this.touchStartTime; if (touchDuration >= this.longPressThreshold && this.proxyGestureType.gestureType === 'none' && this.proxyGestureType.gestureType !== 'longpress') { // 添加震动反馈 navigator.vibrate(50); // 短震动表示长按开始 this.proxyGestureType.gestureType = 'longpress'; this.proxyPlaybackRate.playbackRate = '3x'; this.videoElement.playbackRate = 3; this.clearOtherInterval(this.longPressInterval); } let deltaX = this.touchX - this.touchStartX; let deltaY = this.touchY - this.touchStartY; let direction = deltaX; if (deltaY > 5) { direction = "down"; } else if (deltaY < -5) { direction = "up"; } let distance = Math.abs(deltaX); if (this.lastDistance === 0) { this.lastDistance = distance; } if (Math.abs(distance) > 20 && direction === 'down') { if (this.proxyPlaybackRate.playbackRate !== '2x') { this.videoElement.playbackRate = 2; this.proxyPlaybackRate.playbackRate = '2x'; } } if (Math.abs(distance) > 20 && direction === 'up') { if (this.proxyPlaybackRate.playbackRate !== '3x') { this.videoElement.playbackRate = 3; this.proxyPlaybackRate.playbackRate = '3x'; } } this.lastDistance = distance; } //! ------------------TouchEND------------------ longPressTouchEnd(event) { this.videoElement.playbackRate = 1; this.clearAllInterval(); this.proxyGestureType.gestureType = 'none'; this.proxyPlaybackRate.playbackRate = '1x'; this.videoElement.removeEventListener('touchend', this.longPressTouchEnd); } swipeTouchEnd(event) { const mouseEvent3 = new MouseEvent('mouseleave', { view: window, bubbles: true, cancelable: true, }); this.progressElement.dispatchEvent(mouseEvent3); this.clearAllInterval(); this.fadeoutTextBox(this.textBox); this.videoElement.currentTime = this.currenttime + this.add_time; this.add_time = 0; this.lastDistance = 0; this.proxyGestureType.gestureType = 'none'; this.photoShotStyle.remove(); this.photoShotSize.style.height = "100%"; this.videoElement.removeEventListener('touchend', this.swipeTouchEnd); } swipeUDTouchEnd(event) { this.clearAllInterval(); this.fadeoutTextBox(this.textBox); this.lastDistance = 0; this.proxyGestureType.gestureType = 'none'; this.videoElement.removeEventListener('touchend', this.swipeUDTouchEnd); } zoomTouchEnd(event){ this.clearAllInterval(); this.lastDistance = 0; this.proxyGestureType.gestureType = 'none'; this.videoElement.removeEventListener('touchend', this.zoomTouchEnd); } normolTouchEnd(event) { this.clearAllInterval(); this.videoElement.playbackRate = 1; this.proxyGestureType.gestureType = 'none'; this.touchEndTime = Date.now(); const touchDuration = this.touchEndTime - this.touchStartTime; if (touchDuration < 100) { // 判断是否为点击 if (this.clickTimeout) { clearTimeout(this.clickTimeout); this.clickTimeout = null; this.handleDblClick(event); // 处理双击 } else { this.clickTimeout = setTimeout(() => { this.clickTimeout = null; this.handleClick(event); // 处理单击 }, 200); } } } //! ------------------工具函数------------------ clearAllInterval() { for (let i = 0; i < this.intervals.length; i++) { clearInterval(this.intervals[i]); } } clearOtherInterval(except) { for (let i = 0; i < this.intervals.length; i++) { if (this.intervals[i] !== except) { clearInterval(this.intervals[i]); } } } createTextBox(oldtextBox = null, txt) { if (oldtextBox) { oldtextBox.remove(); } if(this.button) this.button.style.opacity = 0; const textBox = document.createElement('div'); textBox.innerText = txt; // 设置文本内容 // 设置文本框的样式 textBox.style.position = 'absolute'; textBox.style.bottom = '7%'; textBox.style.left = '50%'; textBox.style.padding = '5px'; textBox.style.backgroundColor = 'rgba(255, 255, 255, 0.7)'; // 半透明白色背景 textBox.style.border = '1px solid #ccc'; textBox.style.borderRadius = '5px'; textBox.style.zIndex = '1000'; // 确保文本框在视频上方 textBox.style.pointerEvents = 'none'; textBox.style.transform = 'translate(-50%, -50%)'; // textBox.style.fontSize = '20px'; textBox.style.textAlign = 'center' // 将文本框添加到视频元素的父元素中 this.videoElement.parentElement.style.position = 'relative'; // 确保父元素是相对定位 this.videoElement.parentElement.appendChild(textBox); return textBox; } createButton(){ if (this.button) { this.button.remove(); } this.button = document.createElement('button'); this.button.classList.add('bpx-retore-screen-button'); this.button.innerText = '还原屏幕'; this.button.style.position = 'absolute'; this.button.style.bottom = '-2%'; this.button.style.left = '50%'; this.button.style.padding = '5px'; this.button.style.backgroundColor = 'rgba(255, 255, 255, 0.7)'; this.button.style.border = '1px solid #ccc'; this.button.style.borderRadius = '5px'; this.button.style.zIndex = '1000'; this.button.style.pointerEvents = 'auto'; this.button.style.transform = 'translate(-50%, -50%)'; this.button.style.fontSize = '25px'; this.button.addEventListener('click', (event) => { event.preventDefault(); event.stopPropagation(); this.videoZoomMul = 1; this.videoRotateDeg = 0; this.videoElement.style.transform = `scale(1) rotate(0deg)`; this.button.remove(); }); this.videoElement.parentElement.style.position = 'relative'; this.videoElement.parentElement.appendChild(this.button); } fadeoutTextBox(textBox, timeout = 200) { if(this.button) this.button.style.opacity = 1; // 2秒后将文本框从 DOM 中移除 setTimeout(function () { textBox.remove(); }, timeout); } sec2Time(sec) { sec = Math.abs(sec); sec += 1; let h = Math.floor(sec / 3600); let m = Math.floor((sec % 3600) / 60); let s = Math.floor(sec % 60); m = m.toString().length === 1 ? m = "0" + m : m; s = s.toString().length === 1 ? s = "0" + s : s; h = h.toString().length === 1 ? h = "0" + h : h; if (m == 0) { return `00:${s}`; } if (h == 0) { return `${m}:${s}`; } else { return `${h}:${m}:${s}`; } } isFullScreen() { return document.fullscreenElement != null; } calculateAngle(x1, y1, x2, y2) { const deltaX = x2 - x1; const deltaY = y2 - y1; return Math.atan2(deltaY, deltaX) * (180 / Math.PI); } addHint() { this.videoArea = document.querySelector(".bpx-player-video-area"); this.playbackRateHint = document.createElement("div"); this.playbackRateHint.style.display = "none"; this.playbackRateHint.className = "bpx-player-three-playrate-hint"; this.playbackRateHint.innerHTML = `<span class="bpx-player-three-playrate-hint-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 111 66" width="111" height="66" preserveAspectRatio="xMidYMid meet" style="width: 100%; height: 100%; transform: translate3d(0px, 0px, 0px);"><defs><clipPath id="__lottie_element_234"><rect width="111" height="66" x="0" y="0"></rect></clipPath></defs> <g clip-path="url(#__lottie_element_234)"> <g transform="matrix(1,0,0,1,94.5,32.5)" opacity="1" style="display: block;"><g opacity="1" transform="matrix(0,3,-3,0,0,0)"><path class="triangle" id="triangle3" fill="rgb(255,255,255)" fill-opacity="1" d=" M6.138000011444092,3.5460000038146973 C6.4679999351501465,4.105999946594238 6.2779998779296875,4.826000213623047 5.7179999351501465,5.156000137329102 C5.538000106811523,5.265999794006348 5.3379998207092285,5.326000213623047 5.118000030517578,5.326000213623047 C5.118000030517578,5.326000213623047 -5.122000217437744,5.326000213623047 -5.122000217437744,5.326000213623047 C-5.771999835968018,5.326000213623047 -6.302000045776367,4.796000003814697 -6.302000045776367,4.145999908447266 C-6.302000045776367,3.936000108718872 -6.242000102996826,3.7260000705718994 -6.142000198364258,3.5460000038146973 C-6.142000198364258,3.5460000038146973 -1.3519999980926514,-4.553999900817871 -1.3519999980926514,-4.553999900817871 C-0.9120000004768372,-5.294000148773193 0.04800000041723251,-5.544000148773193 0.7979999780654907,-5.104000091552734 C1.027999997138977,-4.973999977111816 1.218000054359436,-4.783999919891357 1.3480000495910645,-4.553999900817871 C1.3480000495910645,-4.553999900817871 6.138000011444092,3.5460000038146973 6.138000011444092,3.5460000038146973z"></path></g></g> <g transform="matrix(1,0,0,1,55.5,32.5)" opacity="1" style="display: block;"><g opacity="1" transform="matrix(0,3,-3,0,0,0)"><path class="triangle" id="triangle2" fill="rgb(255,255,255)" fill-opacity="1" d=" M6.138000011444092,3.5460000038146973 C6.4679999351501465,4.105999946594238 6.2779998779296875,4.826000213623047 5.7179999351501465,5.156000137329102 C5.538000106811523,5.265999794006348 5.3379998207092285,5.326000213623047 5.118000030517578,5.326000213623047 C5.118000030517578,5.326000213623047 -5.122000217437744,5.326000213623047 -5.122000217437744,5.326000213623047 C-5.771999835968018,5.326000213623047 -6.302000045776367,4.796000003814697 -6.302000045776367,4.145999908447266 C-6.302000045776367,3.936000108718872 -6.242000102996826,3.7260000705718994 -6.142000198364258,3.5460000038146973 C-6.142000198364258,3.5460000038146973 -1.3519999980926514,-4.553999900817871 -1.3519999980926514,-4.553999900817871 C-0.9120000004768372,-5.294000148773193 0.04800000041723251,-5.544000148773193 0.7979999780654907,-5.104000091552734 C1.027999997138977,-4.973999977111816 1.218000054359436,-4.783999919891357 1.3480000495910645,-4.553999900817871 C1.3480000495910645,-4.553999900817871 6.138000011444092,3.5460000038146973 6.138000011444092,3.5460000038146973z"></path></g></g> <g transform="matrix(1,0,0,1,16.5,32.5)" opacity="1" style="display: block;"><g opacity="1" transform="matrix(0,3,-3,0,0,0)"><path class="triangle" id="triangle1" fill="rgb(255,255,255)" fill-opacity="1" d=" M6.138000011444092,3.5460000038146973 C6.4679999351501465,4.105999946594238 6.2779998779296875,4.826000213623047 5.7179999351501465,5.156000137329102 C5.538000106811523,5.265999794006348 5.3379998207092285,5.326000213623047 5.118000030517578,5.326000213623047 C5.118000030517578,5.326000213623047 -5.122000217437744,5.326000213623047 -5.122000217437744,5.326000213623047 C-5.771999835968018,5.326000213623047 -6.302000045776367,4.796000003814697 -6.302000045776367,4.145999908447266 C-6.302000045776367,3.936000108718872 -6.242000102996826,3.7260000705718994 -6.142000198364258,3.5460000038146973 C-6.142000198364258,3.5460000038146973 -1.3519999980926514,-4.553999900817871 -1.3519999980926514,-4.553999900817871 C-0.9120000004768372,-5.294000148773193 0.04800000041723251,-5.544000148773193 0.7979999780654907,-5.104000091552734 C1.027999997138977,-4.973999977111816 1.218000054359436,-4.783999919891357 1.3480000495910645,-4.553999900817871 C1.3480000495910645,-4.553999900817871 6.138000011444092,3.5460000038146973 6.138000011444092,3.5460000038146973z"></path></g></g> </g></svg></span>倍速播放中` this.videoArea.appendChild(this.playbackRateHint); let hintStyle = document.createElement("style"); hintStyle.innerHTML = ` .triangle { animation: fadeToWhite 1.2s infinite; } #triangle1 { animation-delay: 0s; } #triangle2 { animation-delay: 0.18s; } #triangle3 { animation-delay: 0.35s; } @keyframes fadeToWhite { 0% { opacity: 1; filter: brightness(0.3); } 25% { opacity: 1; filter: brightness(0.6); } 50% { opacity: 1; filter: brightness(1); } 75% { opacity: 1; filter: brightness(0.6); } 100% { opacity: 1; filter: brightness(0.3); } } ` this.playbackRateHint.appendChild(hintStyle); } } class AddRightEntryEventListener { constructor(rightEntry) { this.rightEntry = rightEntry; this.rightEntry.addEventListener('click', this.handleRightEntryClick.bind(this)); } handleRightEntryClick(event) { let target = event.target; let href = target.closest('a').getAttribute('href'); if (href && href.includes('//space')) { event.preventDefault(); return; } if (href && href.includes('/history')) { event.preventDefault(); return; } } } function waitForVideoELement(timeout = 5000) { return new Promise((resolve, reject) => { const intervalID = setInterval(() => { let videoElement = document.querySelector("#bilibili-player"); if (videoElement) { clearInterval(intervalID); clearTimeout(timeoutID); resolve(videoElement); } }, 100); const timeoutID = setTimeout(() => { clearInterval(intervalID); reject(new Error("Timeout: Video element not found")); }, timeout); }); } function waitForRightEntry(timeout = 10000) { return new Promise((resolve, reject) => { const intervalID = setInterval(() => { if (document.querySelector("#nav-searchform") != null) { let header_position; header_position = document.querySelector("#biliMainHeader > div.bili-header.fixed-header > div > ul.right-entry") || document.querySelector(".right-entry"); if (header_position) { clearInterval(intervalID); clearTimeout(timeoutID); resolve(header_position); } } }, 100); const timeoutID = setTimeout(() => { clearInterval(intervalID); reject(new Error("Timeout: Right entry element not found")); }, timeout); }); } let currentUrl = window.location.href; // 打开的网页 const exceptUrl = [ "https://www.bilibili.com/correspond", "https://message.bilibili.com/pages/nav/header_sync" ]; let shouldTerminate = false; for (let url of exceptUrl){ if (currentUrl.includes(url)) { shouldTerminate = true; break; } } if (shouldTerminate) { shouldTerminate = false; return; } Promise.race([waitForVideoELement(), waitForRightEntry()]) .then((result) => { if (result.getAttribute("id") == "bilibili-player") { console.log("Video element found!"); new VideoGestureHandler(result); handleAnotherPromise(waitForRightEntry, AddRightEntryEventListener, "right"); } else{ console.log("Right entry element found!"); new AddRightEntryEventListener(result); handleAnotherPromise(waitForVideoELement, VideoGestureHandler, "video"); } }) .catch((error) => { console.error('Error:', error); }); function handleAnotherPromise(promiseFunc, handler, type) { promiseFunc() .then((result) => { new handler(result); if (type == "video") { console.log("Video element found!"); } else if (type == "right") { console.log("Right entry element found!"); } return }) .catch((error) => { console.error('Error:', error); return }); }