您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为指定视频添加可移动的进度条、音量控制器和重新加载按钮
当前为
// ==UserScript== // @name Video Control with Reload // @namespace http://tampermonkey.net/ // @version 1.0 // @description 为指定视频添加可移动的进度条、音量控制器和重新加载按钮 // @match https://app.kosmi.io/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; let videoElement = null; let controller = null; let isDragging = false; // 是否正在拖动控制器 let initialX = 0, initialY = 0; // 初始点击位置 let lastX = 0, lastY = 0; // 上一次位置 // 创建控制器 function createController() { controller = document.createElement('div'); controller.id = 'video-controller'; controller.style.cssText = ` position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%); background-color: rgba(0, 0, 0, 0.7); color: white; padding: 10px; border-radius: 5px; z-index: 9999; cursor: move; user-select: none; width: 300px; transition: width 0.3s, height 0.3s; display: none; /* 初始隐藏 */ `; controller.innerHTML = ` <div id="progress-container" style="width: 100%; height: 10px; background-color: #444; position: relative; cursor: pointer;"> <div id="progress-indicator" style="width: 0%; height: 100%; background-color: #fff; position: absolute;"></div> </div> <div id="time-display" style="text-align: center; margin-top: 5px;">0:00 / 0:00</div> <div id="volume-container" style="display: flex; align-items: center; margin-top: 10px;"> <span id="volume-icon" style="margin-right: 10px;">🔊</span> <input type="range" id="volume-slider" min="0" max="1" step="0.1" value="1" style="flex-grow: 1;"> </div> <button id="reload-button" style="width: 100%; margin-top: 10px; padding: 5px; background-color: #4CAF50; border: none; color: white; cursor: pointer;">重新加载视频控制</button> `; document.body.appendChild(controller); return controller; } // 创建显示/隐藏按钮 function createToggleButton() { const button = document.createElement('button'); button.textContent = '🎥'; // 修改按钮图标 button.style.cssText = ` position: fixed; left: 10px; top: 50%; transform: translateY(-50%); padding: 5px; font-size: 20px; background-color: rgba(0, 0, 0, 0.5); color: white; border: none; border-radius: 50%; cursor: move; z-index: 9999; `; document.body.appendChild(button); // 使按钮可拖动 let pos1 = 0, pos2 = 0; button.addEventListener('touchstart', touchStart, false); function touchStart(e) { isDragging = true; initialX = e.touches[0].clientX; initialY = e.touches[0].clientY; lastX = initialX; lastY = initialY; document.addEventListener('touchmove', touchMove, false); document.addEventListener('touchend', touchEnd, false); } function touchMove(e) { if (!isDragging) return; e.preventDefault(); let currentX = e.touches[0].clientX; let currentY = e.touches[0].clientY; pos1 = lastX - currentX; pos2 = lastY - currentY; lastX = currentX; lastY = currentY; button.style.top = (button.offsetTop - pos2) + "px"; button.style.left = (button.offsetLeft - pos1) + "px"; } function touchEnd() { isDragging = false; document.removeEventListener('touchmove', touchMove, false); document.removeEventListener('touchend', touchEnd, false); } button.addEventListener('click', function() { if (controller.style.display === 'none') { controller.style.display = 'block'; } else { controller.style.display = 'none'; } }); } // 使控制器可拖动 function makeDraggable(element) { let pos1 = 0, pos2 = 0; element.addEventListener('mousedown', dragMouseDown, false); function dragMouseDown(e) { if (e.target.id === 'progress-container' || e.target.id === 'progress-indicator' || e.target.id === 'volume-slider' || e.target.id === 'reload-button') return; e.preventDefault(); isDragging = true; initialX = e.clientX; initialY = e.clientY; lastX = initialX; lastY = initialY; document.addEventListener('mouseup', closeDragElement, false); document.addEventListener('mousemove', throttle(elementDrag, 16), false); // 节流控制拖动频率 } function elementDrag(e) { if (!isDragging) return; e.preventDefault(); pos1 = initialX - e.clientX; pos2 = initialY - e.clientY; initialX = e.clientX; initialY = e.clientY; requestAnimationFrame(() => { element.style.top = (element.offsetTop - pos2) + "px"; element.style.left = (element.offsetLeft - pos1) + "px"; element.style.bottom = 'auto'; }); } function closeDragElement() { document.removeEventListener('mouseup', closeDragElement, false); document.removeEventListener('mousemove', throttle(elementDrag, 16), false); isDragging = false; } } // 节流函数,用于限制函数调用频率 function throttle(func, limit) { let lastFunc; let lastRan; return function() { const context = this; const args = arguments; if (!lastRan) { func.apply(context, args); lastRan = Date.now(); } else { clearTimeout(lastFunc); lastFunc = setTimeout(function() { if ((Date.now() - lastRan) >= limit) { func.apply(context, args); lastRan = Date.now(); } }, limit - (Date.now() - lastRan)); } }; } // 格式化时间 function formatTime(seconds) { const minutes = Math.floor(seconds / 60); seconds = Math.floor(seconds % 60); return `${minutes}:${seconds.toString().padStart(2, '0')}`; } // 主函数 function main() { // 先移除已存在的控制器元素和按钮 const existingController = document.getElementById('video-controller'); const existingButton = document.getElementById('toggle-button'); if (existingController) { existingController.remove(); } if (existingButton) { existingButton.remove(); } videoElement = document.querySelector('video[src^="blob:https://app.kosmi.io/"]'); if (!videoElement) { console.log('未找到指定视频'); return; } controller = createController(); makeDraggable(controller); createToggleButton(); const progressContainer = document.getElementById('progress-container'); const progressIndicator = document.getElementById('progress-indicator'); const timeDisplay = document.getElementById('time-display'); const volumeSlider = document.getElementById('volume-slider'); const volumeIcon = document.getElementById('volume-icon'); const reloadButton = document.getElementById('reload-button'); // 更新进度 function updateProgress() { const progress = (videoElement.currentTime / videoElement.duration) * 100; progressIndicator.style.width = `${progress}%`; const current = formatTime(videoElement.currentTime); const total = formatTime(videoElement.duration); timeDisplay.textContent = `${current} / ${total}`; } // 点击进度条更新视频位置 progressContainer.addEventListener('click', function(e) { if (isDragging) return; const rect = progressContainer.getBoundingClientRect(); const pos = (e.clientX - rect.left) / rect.width; videoElement.currentTime = pos * videoElement.duration; }); // 更新音量 volumeSlider.addEventListener('input', function() { videoElement.volume = this.value; updateVolumeIcon(this.value); }); // 更新音量图标 function updateVolumeIcon(volume) { if (volume > 0.5) { volumeIcon.textContent = '🔊'; } else if (volume > 0) { volumeIcon.textContent = '🔉'; } else { volumeIcon.textContent = '🔇'; } } // 初始化音量 volumeSlider.value = videoElement.volume; updateVolumeIcon(videoElement.volume); // 重新加载按钮事件 reloadButton.addEventListener('click', function() { // 移除旧的事件监听器 videoElement.removeEventListener('timeupdate', updateProgress); videoElement.removeEventListener('loadedmetadata', updateProgress); // 重新执行主函数 main(); // 重新绑定事件监听器 videoElement.addEventListener('timeupdate', updateProgress); videoElement.addEventListener('loadedmetadata', updateProgress); }); videoElement.addEventListener('timeupdate', updateProgress); videoElement.addEventListener('loadedmetadata', updateProgress); } // 等待视频加载完成 function waitForVideo() { const video = document.querySelector('video[src^="blob:https://app.kosmi.io/"]'); if (video) { main(); } else { setTimeout(waitForVideo, 1000); } } waitForVideo(); })();