// ==UserScript== // @name Media Speed // @namespace ilyachch/userscripts/scripts // @version 0.1.6 // @description Change media speed // @author ilyachch (https://github.com/ilyachch/userscripts) // @homepageURL https://github.com/ilyachch/userscripts // @source https://github.com/ilyachch/userscripts/blob/main/userscripts/media_speed/media_speed.user.js // @supportURL https://github.com/ilyachch/userscripts/issues // @updateURL https://raw.githubusercontent.com/ilyachch/userscripts/main/userscripts/media_speed/media_speed.user.js // @downloadURL https://raw.githubusercontent.com/ilyachch/userscripts/main/userscripts/media_speed/media_speed.user.js // @license MIT // @run-at document-start // @match *://*/* // @grant GM_addStyle // @icon https://cdn-icons-png.flaticon.com/512/4340/4340125.png // ==/UserScript== const localStorageKey = "user_media_speed"; const FONT_BLOCK = ` `; const STYLE = ` :root{ --font-size: 20px; --font-family: 'Roboto Mono', monospace; --size: 40px; --border-radius: 30px; --placement: 25px; --margin: 10px; } .user_media_speed_control{ font-size: var(--font-size); font-family: var(--font-family); line-height: var(--size); display: flex; position: fixed; bottom: var(--placement); left: var(--placement); z-index: 9999; border-radius: var(--border-radius); background-color: #2e2f34; color: #ffffff; user-select: none; overflow: hidden; opacity: 0.1; } .user_media_speed_control:hover{ opacity: 0.7; } .user_media_speed_control_title, .user_media_speed_control_option{ display: flex; margin: var(--margin); width: var(--size); height: var(--size); justify-content: center; align-items: center; } .user_media_speed_control_title{ font-weight: 600; } .user_media_speed_control_option{ font-weight: 400; cursor: pointer; display: none; } .user_media_speed_control:hover .user_media_speed_control_option{ display: flex; } .user_media_speed_control_option.selected{ font-weight: 600; } `; const SPEED_OPTIONS = [1, 1.5, 1.7, 2, 2.5, 3, 5, 10]; const DEFAULT_VIDEO_STEP = 5; const MEDIUM_VIDEO_STEP = 30; const LARGE_VIDEO_STEP = 90; (function () { "use strict"; let currentPlayingElement = null; document.addEventListener( "play", function (event) { currentPlayingElement = event.target; let speed = get_playback_speed(); set_playback_speed(speed, currentPlayingElement); create_speed_control_element(); set_selected_speed_option_active(speed); }, true, ); document.addEventListener("DOMContentLoaded", function (event) { GM_addStyle(STYLE); document.head.insertAdjacentHTML("beforeend", FONT_BLOCK); if (document.querySelectorAll("video, audio").length > 0) { create_speed_control_element(); } }); document.addEventListener( "MediaPlaybackSpeedChanged", function (event) { let speed = event.detail.speed; set_playback_speed(speed); set_selected_speed_option_active(speed); }, true, ); document.addEventListener("keydown", function (event) { const focusedElement = document.querySelector(":focus"); if ( currentPlayingElement && (!focusedElement || (focusedElement.tagName !== "INPUT" && focusedElement.tagName !== "TEXTAREA")) ) { if (event.shiftKey && event.code === "ArrowRight") { currentPlayingElement.currentTime += LARGE_VIDEO_STEP - DEFAULT_VIDEO_STEP; } else if (event.shiftKey && event.code === "ArrowLeft") { currentPlayingElement.currentTime -= LARGE_VIDEO_STEP - DEFAULT_VIDEO_STEP; } else if (event.ctrlKey && event.code === "ArrowRight") { currentPlayingElement.currentTime += MEDIUM_VIDEO_STEP - DEFAULT_VIDEO_STEP; } else if (event.ctrlKey && event.code === "ArrowLeft") { currentPlayingElement.currentTime -= MEDIUM_VIDEO_STEP - DEFAULT_VIDEO_STEP; } } }); })(); function set_selected_speed_option_active(speed) { document .querySelectorAll(".user_media_speed_control_option") .forEach(function (element) { element.classList.remove("selected"); }); document .querySelector( `.user_media_speed_control_option[data-speed="${speed}"]`, ) .classList.add("selected"); document.querySelector(".user_media_speed_control_title").innerText = speed; } function get_playback_speed() { return localStorage.getItem(localStorageKey) || 1; } function set_playback_speed(speed, element) { if (!element) { document.querySelectorAll("video, audio").forEach(function (element) { element.playbackRate = speed; }); } else { element.playbackRate = speed; } save_playback_speed(speed); } function save_playback_speed(speed) { localStorage.setItem(localStorageKey, speed); } function create_speed_control_element() { if (document.querySelectorAll(".user_media_speed_control").length > 0) { return; } let currentSpeed = get_playback_speed(); let speed_control = document.createElement("div"); speed_control.classList.add("user_media_speed_control"); let speed_control_title = document.createElement("div"); speed_control_title.classList.add("user_media_speed_control_title"); speed_control_title.innerText = currentSpeed; speed_control.appendChild(speed_control_title); for (let speed of SPEED_OPTIONS) { let speed_option = document.createElement("div"); speed_option.classList.add("user_media_speed_control_option"); speed_option.setAttribute("data-speed", speed); if (speed == currentSpeed) { speed_option.classList.add("selected"); } speed_option.innerText = speed; speed_option.addEventListener("click", function () { speed_option.dispatchEvent( new CustomEvent("MediaPlaybackSpeedChanged", { detail: { speed: speed, source: speed_option, }, }), ); }); speed_control.appendChild(speed_option); } document.body.appendChild(speed_control); }