Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // ==UserScript==
- // @name Video Speed Buttons
- // @description Add speed buttons to any HTML5 <video> element. Comes with a loader for YouTube and Vimeo
- // @namespace bradenscode
- // @version 1.0.9.2
- // @copyright 2017, Braden Best
- // @run-at document-end
- // @author Braden Best
- // @grant none
- //
- // @match *://*.youtube.com/*
- // @match *://*.vimeo.com/*
- // ==/UserScript==
- // warning: vimeo support is broken. A fix will be added in a future patch
- // To add a new site: add a @match above, and modify loader_data.container_candidates near the bottom
- const speedperchannel = {
- "Blitz": 2,
- "Bryce Edward Brown": 1.75,
- "ExplainingComputers": 2
- }
- function getspeed(){
- var channelname;
- if (location.pathname === "/watch" && (channelname = document.querySelector("#primary #meta #channel-name #text"))){
- channelname = channelname.innerText.trim();
- } else {
- channelname = "";
- }
- if (channelname in speedperchannel) return speedperchannel[channelname];
- if (document.querySelector("#container .badge-style-type-verified-artist")) return 1;
- return 1.5;
- }
- function video_speed_buttons(anchor, video_el){
- if(!anchor || !video_el)
- return null;
- const COLOR_SELECTED = "red",
- COLOR_NORMAL = "#dcdcdc",
- BUTTON_SIZE = "80%",
- LABEL_TEXT = "";
- const BUTTON_TEMPLATES = [
- ["50%", 0.5],
- ["75%", 0.75],
- ["Normal", 1],
- ["1.25x", 1.25],
- ["1.5x", 1.5],
- ["1.75x", 1.75],
- ["2x", 2],
- ["2.5x", 2.5],
- ["3x", 3],
- ["4x", 4]
- ];
- const buttons = {
- head: null,
- selected: null,
- last: null
- };
- const keyboard_controls = [
- ["-", "Speed Down", function(ev){
- if(is_comment_box(ev.target))
- return false;
- (buttons.selected || buttons.head)
- .getprev()
- .el
- .dispatchEvent(new MouseEvent("click"));
- }],
- ["+", "Speed Up", function(ev){
- if(is_comment_box(ev.target))
- return false;
- (buttons.selected || buttons.head)
- .getnext()
- .el
- .dispatchEvent(new MouseEvent("click"));
- }],
- ["*", "Reset Speed", function(ev){
- let selbtn = buttons.head;
- let result = null;
- if(is_comment_box(ev.target))
- return false;
- while(selbtn !== null && result === null)
- if(selbtn.speed === getspeed())
- result = selbtn;
- else
- selbtn = selbtn.next;
- if(result === null)
- result = buttons.head;
- result.el.dispatchEvent(new MouseEvent("click"));
- }],
- ["?", "Show Help", function(ev){
- let infobox;
- if(is_comment_box(ev.target))
- return false;
- (infobox = Infobox(container))
- .log("Keyboard Controls (click to close)<br>");
- keyboard_controls.forEach(function([key, description]){
- infobox.log(` [${key}] ${description}<br>`);
- });
- }]
- ];
- const container = (function(){
- let div = document.createElement("div");
- let prev_node = null;
- div.className = "vsb-container";
- div.style.marginBottom = "0px";
- div.style.paddingBottom = "0px";
- div.style.float = "left";
- div.appendChild(document.createTextNode(LABEL_TEXT));
- BUTTON_TEMPLATES.forEach(function(button){
- let speedButton = SpeedButton(...button, div);
- if(buttons.head === null)
- buttons.head = speedButton;
- if(prev_node !== null){
- speedButton.prev = prev_node;
- prev_node.next = speedButton;
- }
- prev_node = speedButton;
- if(speedButton.speed == getspeed())
- speedButton.select();
- });
- return div;
- })();
- function is_comment_box(el){
- const candidate = [
- ".comment-simplebox-text",
- "textarea"
- ].map(c => document.querySelector(c))
- .find(el => el !== null);
- if(candidate === null){
- logvsb("video_speed_buttons::is_comment_box", "no candidate for comment box. Assuming false.");
- return 0;
- }
- return el === candidate;
- }
- function Infobox(parent){
- let el = document.createElement("pre");
- el.style.font = "1em monospace";
- el.style.borderTop = "1px solid #ccc";
- el.style.marginTop = "10px";
- el.style.paddingTop = "10px";
- el.addEventListener("click", function(){
- parent.removeChild(el);
- });
- parent.appendChild(el);
- function log(msg){
- el.innerHTML += msg;
- }
- return {
- el,
- log
- };
- }
- function setPlaybackRate(el, rate){
- if(el)
- el.playbackRate = rate;
- else
- logvsb("video_speed_buttons::setPlaybackRate", "video element is null or undefined", 1);
- }
- function SpeedButtonLabel(text){
- let el = document.createElement("span");
- el.innerHTML = text;
- el.style.marginRight = "10px";
- el.style.fontWeight = "bold";
- el.style.fontSize = BUTTON_SIZE;
- el.style.color = COLOR_NORMAL;
- return el;
- }
- function SpeedButton(text, speed, parent){
- let el = SpeedButtonLabel(text);
- let self;
- el.style.cursor = "pointer";
- el.addEventListener("click", function(){
- setPlaybackRate(video_el, speed);
- self.select();
- });
- parent.appendChild(el);
- function select(){
- if(buttons.last !== null)
- buttons.last.el.style.color = COLOR_NORMAL;
- buttons.last = self;
- buttons.selected = self;
- el.style.color = COLOR_SELECTED;
- }
- function getprev(){
- if(self.prev === null)
- return self;
- return buttons.selected = self.prev;
- }
- function getnext(){
- if(self.next === null)
- return self;
- return buttons.selected = self.next;
- }
- return self = {
- el,
- text,
- speed,
- prev: null,
- next: null,
- select,
- getprev,
- getnext
- };
- }
- function kill(){
- anchor.removeChild(container);
- document.body.removeEventListener("keydown", ev_keyboard);
- }
- function set_video_el(new_video_el){
- video_el = new_video_el;
- }
- function ev_keyboard(ev){
- let match = keyboard_controls.find(([key, unused, callback]) => key === ev.key);
- let callback = (match || {2: ()=>null})[2];
- callback(ev);
- }
- setPlaybackRate(video_el, getspeed());
- anchor.insertBefore(container, anchor.firstChild);
- document.body.addEventListener("keydown", ev_keyboard);
- return {
- controls: keyboard_controls,
- buttons,
- kill,
- SpeedButton,
- Infobox,
- setPlaybackRate,
- is_comment_box,
- set_video_el,
- ALLOW_EXTERNAL_ACCESS,
- };
- }
- video_speed_buttons.from_query = function(anchor_q, video_q){
- return video_speed_buttons(
- document.querySelector(anchor_q),
- document.querySelector(video_q));
- }
- // Multi-purpose Loader (defaults to floating on top right)
- const loader_data = {
- container_candidates: [
- // YouTube
- //"div.ytp-progress-bar-padding",
- //"ytp-chrome-controls",
- "div.ytp-right-controls",
- //"div#container.ytd-video-primary-info-renderer",
- //"div.ytd-video-primary-info-renderer",
- /*"div#watch-header",
- "div#watch7-headline",
- "div#watch-headline-title",
- "div#ytp-title",*/
- // Vimeo
- ".clip_info-wrapper",
- ],
- css_div: [
- // "position: fixed",
- // "top: 0",
- // "right: 0",
- // "zIndex: 100000",
- // "background: rgba(0, 0, 0, 0.8)",
- "background: rgba(0, 0, 0, 0)",
- "color: #eeeeee"
- // "padding: 10px"
- ].map(rule => rule.split(/: */)),
- css_vsb_container: [
- "borderBottom: none",
- "marginBottom: 0",
- "paddingBottom: 0",
- ].map(rule => rule.split(/: */))
- };
- function logvsb(where, msg, lvl = 0){
- let logf = (["info", "error"])[lvl];
- console[logf](`[vsb::${where}] ${msg}`);
- }
- function loader_loop(){
- let vsbc = () => document.querySelector(".vsb-container");
- let candidate;
- let default_candidate;
- let vsb_handle;
- if(vsbc() !== null)
- return;
- candidate = loader_data
- .container_candidates
- .map(candidate => document.querySelector(candidate))
- .find(candidate => candidate !== null);
- default_candidate = (function(){
- let el = document.createElement("div");
- loader_data.css_div.forEach(function([name, value]){
- el.style[name] = value; });
- return el;
- }());
- vsb_handle = video_speed_buttons(candidate || default_candidate, document.querySelector("video"));
- if(candidate === null){
- logvsb("loader_loop", "no candidates for title section. Defaulting to top of page.");
- document.body.appendChild(default_candidate);
- loader_data.css_vsb_container.forEach(function([name, value]){
- vsbc().style[name] = value;
- });
- }
- if(vsb_handle.ALLOW_EXTERNAL_ACCESS)
- window.vsb = vsb_handle;
- }
- setInterval(function(){
- if(document.readyState === "complete")
- setTimeout(loader_loop, 1000);
- }, 1000); // Blame YouTube for this
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement