Created
April 3, 2023 21:03
-
-
Save crustycrabthe3rd/08897651565ef98f43989bf496ab28d2 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript for TamperMonkey== | |
// @name Skip Forwards and Backwards with keyboard shortcuts for Kick.com | |
// @SHORTCUTS: Right Arrow | Left Arrow => Skip Forwards/Backwards 5 seconds | |
// SHIFT + (Right Arrow | Left Arrow) => Skip Backwards 15 seconds | |
// Period | Comma => Skip Forwards/Backwards 1 frame | |
// @namespace http://tampermonkey.net/ | |
// @version 1.0 | |
// @author Gawbly | |
// @match https://kick.com/* | |
// @icon https://www.google.com/s2/favicons?sz=64&domain=kick.com | |
// @grant none | |
// ==/UserScript== | |
(function () { | |
'use strict'; | |
let Module = function () { | |
Module.hook = function () { | |
let video = null; | |
let seekGraphic = Module.Views.SeekGraphic(); | |
document.addEventListener('keydown', event => { | |
if (!window.location.pathname.includes('/video/')) { | |
return | |
} | |
applySeek(); | |
function applySeek() { | |
let keycode = event.code; | |
let keys = { | |
"Period": 1 / 60, "Comma": -1 / 60, "ArrowRight": 5, "ArrowLeft": -5, | |
} | |
let shiftKeys = { | |
"ArrowRight": 15, "ArrowLeft": -15, | |
} | |
let seekAmount = keys[keycode]; | |
event.shiftKey && (seekAmount = shiftKeys[keycode]); | |
if (!seekAmount || Module.Utility.IS_ACTIVE_ELEMENT_AN_INPUT()) return; | |
if (!seekGraphic.isConnected) { | |
document.getElementById('video-holder').firstElementChild.appendChild(seekGraphic.getView()); | |
} | |
if (!video?.isConnected) { | |
video = document.querySelector('video'); | |
} | |
video.currentTime += seekAmount; | |
fireEvent(); /*shows seek bar by firing a mouse up event on it*/ | |
seekGraphic.show(seekAmount, (seekAmount > 0 ? 'right' : 'left')); | |
event.preventDefault(); | |
event.stopPropagation(); | |
} | |
function fireEvent() { | |
let event = new MouseEvent('mouseup', { | |
'view': window, 'bubbles': true, 'cancelable': true, | |
}); | |
let ok = document.querySelector('.vjs-control-bar'); | |
ok.dispatchEvent(event) | |
} | |
}) | |
} | |
Module.Views = { | |
SeekGraphic: function () { | |
let view = Module.Utility.htmlToElement(` | |
<div class="seek-circle"> <div class="inner"> <div class="dot-holder"> <span class="dot"></span> <span class="dot"></span> <span class="dot"></span></div> <span class="title">15S</span> </div> <style> .inner { display: flex; flex-direction: column; gap: 5px; justify-content: center; align-items: center; } .seek-circle.visible { opacity: 1; transition: opacity 250ms ease; } .seek-circle { position: absolute; right: 15px; top: 50%; transform: translateY(-50%); Z-INDEX: 5000; padding: 15px; background: rgb(0 0 0 / 82%); aspect-ratio: 1; display: flex; align-content: center; justify-content: center; align-items: center; border-radius: 100%; border: #646e7c2e solid 1px; opacity: 0; transition: opacity 250ms ease; } .seek-circle[data-direction=left] { right: unset; left: 15px; } .seek-circle[data-direction=left] .dot-holder{ transform: rotate(180deg); } .seek-circle .title { font-size: 14px; font-weight: 600; opacity: 0.75; } .seek-circle .dot { width: 0; height: 0; border: 10px solid transparent; border-top: 7px solid transparent; border-bottom: 7px solid transparent; display: inline-block; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; -webkit-animation-duration: 1.2s; -o-animation-duration: 1.2s; animation-duration: 1.2s; -webkit-animation-iteration-count: infinite; -o-animation-iteration-count: infinite; animation-iteration-count: infinite; border-left: 11px solid #ddd; /* border-right: 0px; */ } .seek-circle .dot:nth-child(1) { animation-name: arrow-fade-out-1; } .seek-circle .dot:nth-child(2) { animation-name: arrow-fade-out-2; } .seek-circle .dot:nth-child(3) { border-right: 0px; animation-name: arrow-fade-out-3; } @keyframes arrow-fade-out-1 { 0% { opacity: 0 } 17% { opacity: .9 } 33% { opacity: .6 } 50% { opacity: .3 } 67% { opacity: .3 } 83% { opacity: .3 } 100% { opacity: 0 } } @keyframes arrow-fade-out-2 { 0% { opacity: 0 } 17% { opacity: .3 } 33% { opacity: .9 } 50% { opacity: .6 } 67% { opacity: .3 } 83% { opacity: .3 } 100% { opacity: 0 } } @keyframes arrow-fade-out-3 { 0% { opacity: 0 } 17% { opacity: .3 } 33% { opacity: .3 } 50% { opacity: .9 } 67% { opacity: .6 } 83% { opacity: .3 } 100% { opacity: 0 } } </style></div> | |
`); | |
let title = view.querySelector('.title') | |
this.getView = function () { | |
return view; | |
} | |
let timer; | |
this.show = function (seekAmount, direction) { | |
view.dataset.direction = direction; | |
seekAmount = Math.abs(seekAmount) | |
let unit = seekAmount >= 5 ? 'Seconds' : 'Frame'; | |
title.innerText = Math.max(1, seekAmount) + unit; | |
view.classList.add('visible'); | |
clearTimeout(timer); | |
timer = setTimeout(() => { | |
view.classList.remove('visible'); | |
}, 1000) | |
} | |
return this; | |
} | |
} | |
Module.Utility = new function () { | |
function htmlToElement(html) { | |
let template = document.createElement('template'); | |
html = html.trim(); | |
template.innerHTML = html; | |
return template.content.firstChild; | |
} | |
function IS_ACTIVE_ELEMENT_AN_INPUT() { | |
return IS_ACTIVE_ELEMENT_OF_TAGS('TEXTAREA', 'INPUT') | |
} | |
function IS_ACTIVE_ELEMENT_OF_TAGS(...tags) { | |
let activeElementTag = document.activeElement.tagName.toLocaleLowerCase(); | |
for (const tag of tags) { | |
if (tag.toLocaleLowerCase() === activeElementTag) { | |
return true; | |
} | |
} | |
return document.activeElement.classList.contains('chat-input'); | |
} | |
this.htmlToElement = htmlToElement; | |
this.IS_ACTIVE_ELEMENT_AN_INPUT = IS_ACTIVE_ELEMENT_AN_INPUT; | |
} | |
Module.hook() | |
} | |
setTimeout(e => { | |
new Module(); | |
}, 2000) | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment