// ==UserScript== // @name Media Player Enhancer // @description Enhances the HTML5 video player with keyboard shortcuts and other features, and provides feedback on key presses. // @match *://*/* // @icon https://raw.githubusercontent.com/WhyWhatHow/powertoys4browser/master/icons/media_enhancer.ico // @grant none // @run-at window-load // @namespace https://whywhathow.github.io/ // @homepage https://github.com/WhyWhatHow/powertoys4browser // @supportURL https://github.com/WhyWhatHow/powertoys4browser/issues // @version 1.9 // @author whywhathow // @updateURL https://raw.githubusercontent.com/WhyWhatHow/powertoys4browser/master/js/media_enhancer.js // @license MIT // ==/UserScript== // 快捷键消息提示框 元素ID. const MSG_BOX_ID = 'reference'; // 避免 body.offsetHeight = 0 的情况. let body_size; // 初始化 function init() { // 初始化消息提示框 initShortCutsBox(); // 初始化 body_size initBodySize(); } // 初始化 body_size function initBodySize() { body_size = { width: document.body.offsetWidth, height: document.body.offsetHeight }; console.log("----------body_size----------") console.log(body_size) } var container_default_size; // 即videoPlayer的 width, height // 初始化快捷键信息提示框 function initShortCutsBox() { const reference = document.createElement('div'); reference.id = MSG_BOX_ID; reference.style.top = '35%'; reference.style.left = '15%'; reference.style.width = 'auto'; reference.style.height = 'auto'; reference.style.fontSize = 'large'; reference.style.margin = '10px'; reference.style.transform = 'translate(-50%, -50%)'; reference.style.background = 'rgba(33,33,33,.9)' reference.style.color = '#fff'; reference.style.padding = '10px'; reference.style.zIndex = '9999'; reference.style.position = 'fixed'; reference.style.display = 'none'; reference.innerHTML = ` <h3>Video Player Shortcuts</h3> <ul style="list-style-type: none; padding-left: 0;"> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">←</code> <span style="color: #999; margin-left: 10px;">Rewind 5 seconds</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">→</code> <span style="color: #999; margin-left: 10px;">Fast forward 5 seconds</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">↑</code> <span style="color: #999; margin-left: 10px;">Increase volume</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">↓</code> <span style="color: #999; margin-left: 10px;">Decrease volume</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">F</code> <span style="color: #999; margin-left: 10px;">Toggle fullscreen</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">M</code> <span style="color: #999; margin-left: 10px;">Toggle mute</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">[</code> <span style="color: #999; margin-left: 10px;">Slow down playback</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">]</code> <span style="color: #999; margin-left: 10px;">Speed up playback</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">R</code> <span style="color: #999; margin-left: 10px;">Reset player settings</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">Q</code> <span style="color: #999; margin-left: 10px;">Show shortcuts reference</span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">P</code> <span style="color: #999; margin-left: 10px;">Play or Pause Video </span></li> <li style="display: flex; align-items: center;"><code style="font-size: 1.2em; font-weight: bold;">Esc</code> <span style="color: #999; margin-left: 10px;">Exit fullscreen</span></li> </ul> <button style="position: absolute; top: 5px; right: 5px; background: none; border: none; font-size: 20px; color: #fff; cursor: pointer;" onclick="this.parentNode.style.display = 'none'">×</button> `; document.body.appendChild(reference); } // 显示快捷键提示框 function showReference() { let ele = document.getElementById(MSG_BOX_ID); if (ele.style.display === 'none') { ele.style.display = 'block'; } else { ele.style.display = 'none'; } } /** * 生成video标签的父标签 * @param videoElement video player tag * @param feedbackElement some Information * @returns videoContainer */ function createVideoParentElement(videoElement, feedbackElement) { var videoContainer; /////// videoContainer = document.createElement('div'); videoContainer.id = 'fun-video-container'; // videoContainer 样式设置 videoContainer.style.position = 'relative'; // 设置父节点 div 的定位方式 // videoContainer.style.position ='inherit'; videoContainer.style.width = videoElement.offsetWidth + 'px'; // 设置父节点 div 的宽度 videoContainer.style.height = videoElement.offsetHeight + 'px'; // 设置父节点 div 的高度 container_default_size = { width: videoElement.offsetWidth, height: videoElement.offsetHeight }; // console.log("----------------------container_default_size--------------------") // console.log(container_default_size) // console.log(videoContainer) if (videoElement.parentElement === document.body) { document.body.appendChild(videoContainer); } else { // hint: 这个函数已经将videoContainer 加入到document 中, 不需要二次加入 videoElement.parentNode.insertBefore(videoContainer, videoElement); // 将父节点 div 插入到 video 的前面 } // console.log(videoContainer) videoContainer.appendChild(videoElement); videoContainer.appendChild(feedbackElement); // videoContainer.appendChild(document.getElementById(MSG_BOX_ID)); // 添加 快捷键消息提示框. // console.log(videoElement.parentElement) return videoContainer; } // 获取<video> 主元素 function initVideoPlayerDefault() { // 获取HTML5视频播放器元素 let videoPlayer = document.querySelector('video'); // 如果没有找到视频播放器则退出 if (!videoPlayer) return; console.log('----------------videoPlayer--------------') console.log(videoPlayer) videoPlayer.setAttribute('controls', true); videoPlayer.constrolsList = 'nofullscreen'; videoPlayer.style.cssText = 'width:100%;height:100%;display:inline-block'; return videoPlayer; } //全屏观看 function enterFullScreen(videoContainer, videoPlayer, showFeedback) { console.log("---------------enterFullScreen----------------------") console.log(container_default_size) videoContainer.style.width = body_size.width + 'px'; videoContainer.style.height = body_size.height + 'px'; addVideo(videoContainer,videoPlayer); videoContainer.requestFullscreen(); console.log(videoContainer) console.log("====================================================") videoPlayer.play(); showFeedback('Fullscreen'); } // 退出全屏 function exitFullScreen(videoContainer) { if (document.fullscreenElement === videoContainer) { console.log("----------------exit-fullScreen----------------------") console.log(container_default_size) videoContainer.style.width = container_default_size.width + 'px'; videoContainer.style.height = container_default_size.height + 'px'; console.log(videoContainer) console.log("------------------------------------------------------") document.exitFullscreen(); } } /** * 将 video player 作为 videoContainer 的第一个子元素存在 * @param videoContainer * @param videoPlayer */ function addVideo(videoContainer, videoPlayer) { if (videoContainer && videoPlayer) { videoContainer.insertBefore(videoPlayer, videoContainer.firstChild); } else { console.log(" video-container | video don't exist ") } } /** * 判断 videoPlayer.display === none , 如果是, 设置为inline-block * @param videoPlayer */ function checkVideoPlayerDisplay(videoPlayer) { if (videoPlayer.style.display === 'none') { videoPlayer.style.display = 'inline-block'; } return videoPlayer; } /** * 静音切换 * @param videoPlayer * @param showFeedback */ function toggleMute(videoPlayer, showFeedback) { if (videoPlayer.muted) { videoPlayer.muted = false; showFeedback('Mute Off') } else { videoPlayer.muted = true; showFeedback('Mute On') } } /** * 视频全屏, 不是 videoContainer 下的全屏 切换到 videoContainer, * @param videoContainer * @param videoPlayer * @param showFeedback */ function toggleFullScreen(videoContainer, videoPlayer, showFeedback) { addVideo(videoContainer, videoPlayer); videoPlayer = checkVideoPlayerDisplay(videoPlayer); if (document.fullscreenElement === videoContainer) { console.log("*********************----------------------exit------------------------") exitFullScreen(videoContainer) } else { console.log('--*************---------------F----not full screen --------------------') if (document.fullscreenElement) { document.exitFullscreen(); } enterFullScreen(videoContainer, videoPlayer, showFeedback); } } /// main function//// function main() { 'use strict'; // 初始化, 创建shortcutsBox & initBodySize console.log("-----------------video Enhancer---------") init() // 创建 video标签 deepCopy // var videoPlayer = initVideoPlayer(); //copy let videoPlayer = initVideoPlayerDefault(); if (!videoPlayer) return; // 创建一个用于显示反馈提示的<div>元素 let feedback = document.createElement('div'); feedback.style.cssText = 'position:fixed !important; z-index:2147483647 !important; isolation:isolate !important;top:10%;right:5%;transform:translate(-50%,-50%);background:#333;color:#fff;padding:10px;border-radius:5px;z-index:2147483647;font-size:16px;visibility:hidden;' // document.body.appendChild(feedback); // 为视频播放器创建父元素 let videoContainer = createVideoParentElement(videoPlayer, feedback); // 全屏 变化 操作 document.addEventListener('fullscreenchange', function () { // toggleFullScreen(videoContainer, videoPlayer, feedback) addVideo(videoContainer, videoPlayer) var fullscreenElement = document.fullscreenElement; if (!fullscreenElement) { // 退出全屏 videoContainer.style.width = container_default_size.width + 'px'; videoContainer.style.height = container_default_size.height + 'px'; } else if (videoContainer === fullscreenElement) { videoContainer.style.width = body_size.width + 'px'; videoContainer.style.height = body_size.height + 'px'; console.log("------------video-container fullscreen ----------------") } else { // 进入全屏 console.log("-------------other div-------------------------------------") videoContainer.style.position = 'static'; // enterFullScreen(videoContainer,videoPlayer,feedback) } }); handleShortCuts(); /////////////////////////////////// end ////////////////////////// function handleShortCuts() { // 设置视频播放器的快捷键 document.addEventListener('keydown', function (event) { // Add keyboard event listeners to the video element const key = event.key; console.log("----------------key: " + key + "-----------------") switch (key) { case 'Space': // // console.log("----------------space---------------") if (videoPlayer.paused) { // 如果视频已经暂停,则播放视频 videoPlayer.play(); } else { // 如果视频正在播放,则暂停视频 videoPlayer.pause(); } break; case 'ArrowLeft': videoPlayer.currentTime -= 5; showFeedback('← 5s'); break; case 'ArrowRight': videoPlayer.currentTime += 5; showFeedback('→ 5s'); break; case 'ArrowUp': if (videoPlayer.volume < 1) { videoPlayer.volume += 0.1; showFeedback('↑ Volume'); } break; case 'ArrowDown': if (videoPlayer.volume > 0) { videoPlayer.volume -= 0.1; showFeedback('↓ Volume'); } break; case 'f': toggleFullScreen(videoContainer, videoPlayer, showFeedback); break; case 'm': toggleMute(videoPlayer, showFeedback); break; case '[': videoPlayer.playbackRate = Math.max(0.1, videoPlayer.playbackRate - 0.1); showFeedback(`- ${videoPlayer.playbackRate.toFixed(1)}x`); break; case ']': videoPlayer.playbackRate += 0.1; showFeedback(`+ ${videoPlayer.playbackRate.toFixed(1)}x`); break; case 'r': // r 键,重置播放器设置 videoPlayer.volume = 1; videoPlayer.playbackRate = 1; showFeedback('Reset'); break; case 'q': // 显示快捷键信息 showReference(); break; case 'p': if (videoPlayer.paused) { // 如果视频已经暂停,则播放视频 videoPlayer.play(); } else { // 如果视频正在播放,则暂停视频 videoPlayer.pause(); } break; default: break; } }); } // 显示按键反馈 function showFeedback(text) { feedback.textContent = text; feedback.style.visibility = 'visible'; setTimeout(function () { feedback.style.visibility = 'hidden'; }, 1000); } } window.addEventListener('load', main);