您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Sync with native YouTube volume & avoid duplicate seeking
// ==UserScript== // @name YouTube Arrow Key Video Control (Improved Sync) // @name:ru Улучшенное управление YouTube через стрелки // @namespace http://tampermonkey.net/ // @version 2.1 // @description Sync with native YouTube volume & avoid duplicate seeking // @description:ru Правильное управление видео YouTube через стрелки на клавиатуре. // @author Boss of this gym // @match *://www.youtube.com/* // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; const VOLUME_STEP = 10; // 10% const SEEK_STEP = 5; // seconds function getVideoElement() { return document.querySelector('video'); } function getVolumePercent(video) { return Math.round(video.volume * 100); } function setVolumeFromPercent(video, percent) { const clamped = Math.min(Math.max(percent, 0), 100); video.volume = clamped / 100; showOverlay(`🔊 ${clamped}%`); } function seekVideo(video, delta) { const newTime = Math.min(Math.max(video.currentTime + delta, 0), video.duration); video.currentTime = newTime; showOverlay(`${delta > 0 ? '⏩' : '⏪'} ${Math.abs(delta)}s`); } function isInputElementFocused() { const active = document.activeElement; return active && (['INPUT', 'TEXTAREA'].includes(active.tagName) || active.isContentEditable); } function createOverlay() { const overlay = document.createElement('div'); overlay.id = 'yt-ctrl-overlay'; overlay.style.cssText = ` position: fixed; top: 20%; left: 50%; transform: translateX(-50%); padding: 12px 24px; background: rgba(0, 0, 0, 0.7); color: #fff; font-size: 20px; border-radius: 8px; z-index: 9999; display: none; `; document.body.appendChild(overlay); return overlay; } const overlay = createOverlay(); let overlayTimeout = null; function showOverlay(text) { overlay.textContent = text; overlay.style.display = 'block'; clearTimeout(overlayTimeout); overlayTimeout = setTimeout(() => { overlay.style.display = 'none'; }, 800); } window.addEventListener('keydown', function(event) { if (isInputElementFocused() || event.altKey) return; const video = getVideoElement(); if (!video) return; if (['ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(event.key)) { event.preventDefault(); event.stopImmediatePropagation(); if (document.activeElement !== video) { video.setAttribute('tabindex', '-1'); video.focus(); } switch (event.key) { case 'ArrowUp': { const vol = Math.floor(video.volume * 100); setVolumeFromPercent(video, vol + VOLUME_STEP); break; } case 'ArrowDown': { const vol = Math.floor(video.volume * 100); setVolumeFromPercent(video, vol - VOLUME_STEP); break; } case 'ArrowRight': seekVideo(video, SEEK_STEP); break; case 'ArrowLeft': seekVideo(video, -SEEK_STEP); break; } } }, true); // Use capture to intercept before YouTube })();