您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
为指定视频添加可移动的进度条、音量控制器和重新加载按钮
当前为
// ==UserScript== // @name Video Control with Reload // @namespace http://tampermonkey.net/ // @version 1.2 // @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; // 上一次鼠标位置 let buttonCreated = false; // 标记按钮是否已创建 // 创建控制器 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() { if (!buttonCreated) { 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.onmousedown = function(e) { e.preventDefault(); isDragging = true; initialX = e.clientX; initialY = e.clientY; lastX = initialX; lastY = initialY; document.onmouseup = closeDragElement; document.onmousemove = throttle(buttonDrag, 16); }; function buttonDrag(e) { if (!isDragging) return; e.preventDefault(); pos1 = lastX - e.clientX; pos2 = lastY - e.clientY; lastX = e.clientX; lastY = e.clientY; button.style.top = (button.offsetTop - pos2) + "px"; button.style.left = (button.offsetLeft - pos1) + "px"; } function closeDragElement() { document.onmouseup = null; document.onmousemove = null; isDragging = false; } button.addEventListener('click', function() { if (controller.style.display === 'none') { controller.style.display = 'block'; } else { controller.style.display = 'none'; } }); let initialX = 0, initialY = 0; let isDragging = false; let isClicking = false; // 触摸点击事件 button.addEventListener('touchstart', function(e) { e.preventDefault(); // 检查是否是单击事件(避免与移动事件冲突) if (e.touches.length === 1) { isClicking = true; setTimeout(() => { if (isClicking) { // 显示/隐藏控制界面 if (controller.style.display === 'none' || controller.style.display === '') { controller.style.display = 'block'; } else { controller.style.display = 'none'; } } }, 200); // 设置一个延迟,如果在200毫秒内没有移动,则认定为点击事件 } else { isClicking = false; // 多指触摸,不算点击 } // 拖动按钮 const touch = e.touches[0]; initialX = touch.clientX - button.offsetLeft; initialY = touch.clientY - button.offsetTop; isDragging = true; }); // 触摸移动事件 button.addEventListener('touchmove', function(e) { e.preventDefault(); if (!isDragging) return; isClicking = false; // 拖动时不算点击 const touch = e.touches[0]; const newX = touch.clientX - initialX; const newY = touch.clientY - initialY; button.style.left = newX + 'px'; button.style.top = newY + 'px'; }); // 触摸结束事件 button.addEventListener('touchend', function() { isDragging = false; }); } buttonCreated=true; } // 使控制器可拖动 function makeDraggable(element) { let pos1 = 0, pos2 = 0; element.onmousedown = dragMouseDown; 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.onmouseup = closeDragElement; document.onmousemove = throttle(elementDrag, 16); // 节流控制拖动频率 } 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.onmouseup = null; document.onmousemove = null; 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(); })();