Merge upstream 0.6.3

This commit is contained in:
codebicycle
2021-02-06 10:01:27 +02:00
parent 3975b74d27
commit 86545a6a34
7 changed files with 313 additions and 196 deletions

View File

@@ -9,6 +9,11 @@
opacity: 1 !important;
}
.vsc-controller {
/* In case of pages using `white-space: pre-line` (eg Discord), don't render vsc's whitespace */
white-space: normal;
}
/* Origin specific overrides */
/* YouTube player */
.ytp-hide-info-bar .vsc-controller {

322
inject.js
View File

@@ -8,6 +8,7 @@ var tc = {
displayKeyCode: 86, // default: V
rememberSpeed: false, // default: false
forceLastSavedSpeed: false, //default: false
audioBoolean: false, // default: false
startHidden: false, // default: false
controllerOpacity: 0.3, // default: 0.3
@@ -21,7 +22,10 @@ var tc = {
`.replace(regStrip, ""),
defaultLogLevel: 4,
logLevel: 3
}
},
// Holds a reference to all of the AUDIO/VIDEO DOM elements we've attached to
mediaElements: []
};
/* Log levels (depends on caller specifying the correct level)
@@ -107,6 +111,7 @@ chrome.storage.sync.get(tc.settings, function(storage) {
version: tc.settings.version,
displayKeyCode: tc.settings.displayKeyCode,
rememberSpeed: tc.settings.rememberSpeed,
forceLastSavedSpeed: tc.settings.forceLastSavedSpeed,
audioBoolean: tc.settings.audioBoolean,
startHidden: tc.settings.startHidden,
enabled: tc.settings.enabled,
@@ -117,6 +122,7 @@ chrome.storage.sync.get(tc.settings, function(storage) {
tc.settings.lastSpeed = Number(storage.lastSpeed);
tc.settings.displayKeyCode = Number(storage.displayKeyCode);
tc.settings.rememberSpeed = Boolean(storage.rememberSpeed);
tc.settings.forceLastSavedSpeed = Boolean(storage.forceLastSavedSpeed);
tc.settings.audioBoolean = Boolean(storage.audioBoolean);
tc.settings.enabled = Boolean(storage.enabled);
tc.settings.startHidden = Boolean(storage.startHidden);
@@ -124,7 +130,9 @@ chrome.storage.sync.get(tc.settings, function(storage) {
tc.settings.blacklist = String(storage.blacklist);
// ensure that there is a "display" binding (for upgrades from versions that had it as a separate binding)
if (tc.settings.keyBindings.filter(x => x.action == "display").length == 0) {
if (
tc.settings.keyBindings.filter((x) => x.action == "display").length == 0
) {
tc.settings.keyBindings.push({
action: "display",
key: Number(storage.displayKeyCode) || 86,
@@ -137,32 +145,42 @@ chrome.storage.sync.get(tc.settings, function(storage) {
initializeWhenReady(document);
});
var forEach = Array.prototype.forEach;
function getKeyBindings(action, what = "value") {
try {
return tc.settings.keyBindings.find(item => item.action === action)[what];
return tc.settings.keyBindings.find((item) => item.action === action)[what];
} catch (e) {
return false;
}
}
function setKeyBindings(action, value) {
tc.settings.keyBindings.find(item => item.action === action)["value"] = value;
tc.settings.keyBindings.find((item) => item.action === action)[
"value"
] = value;
}
function defineVideoController() {
// Data structures
// ---------------
// videoController (JS object) instances:
// video = AUDIO/VIDEO DOM element
// parent = A/V DOM element's parentElement OR
// (A/V elements discovered from the Mutation Observer)
// A/V element's parentNode OR the node whose children changed.
// div = Controller's DOM element (which happens to be a DIV)
// speedIndicator = DOM element in the Controller of the speed indicator
// added to AUDIO / VIDEO DOM elements
// vsc = reference to the videoController
tc.videoController = function (target, parent) {
if (target.dataset["vscid"]) {
if (target.vsc) {
return target.vsc;
}
tc.mediaElements.push(target);
this.video = target;
this.parent = target.parentElement || parent;
this.document = target.ownerDocument;
this.id = Math.random()
.toString(36)
.substr(2, 9);
storedSpeed = tc.settings.speeds[target.currentSrc];
if (!tc.settings.rememberSpeed) {
if (!storedSpeed) {
@@ -183,16 +201,11 @@ function defineVideoController() {
this.div = this.initializeControls();
target.addEventListener(
"play",
(this.handlePlay = function(event) {
var mediaEventAction = function (event) {
storedSpeed = tc.settings.speeds[event.target.currentSrc];
if (!tc.settings.rememberSpeed) {
if (!storedSpeed) {
log(
"Overwriting stored speed to 1.0 (rememberSpeed not enabled)",
4
);
log("Overwriting stored speed to 1.0 (rememberSpeed not enabled)", 4);
storedSpeed = 1.0;
}
// resetSpeed isn't really a reset, it's a toggle
@@ -210,21 +223,28 @@ function defineVideoController() {
// override a website's intentional initial speed setting interfering
// with the site's default behavior)
log("Explicitly setting playbackRate to: " + storedSpeed, 4);
event.target.playbackRate = storedSpeed;
}.bind(this))
setSpeed(event.target, storedSpeed);
};
target.addEventListener(
"play",
(this.handlePlay = mediaEventAction.bind(this))
);
var observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
target.addEventListener(
"seeked",
(this.handleSeek = mediaEventAction.bind(this))
);
var observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (
mutation.type === "attributes" &&
(mutation.attributeName === "src" ||
mutation.attributeName === "currentSrc")
) {
var controller = getController(this.id);
if (!controller) {
return;
}
log("mutation of A/V element", 5);
var controller = this.div;
if (!mutation.target.src && !mutation.target.currentSrc) {
controller.classList.add("vsc-nosource");
} else {
@@ -241,22 +261,26 @@ function defineVideoController() {
tc.videoController.prototype.remove = function () {
this.div.remove();
this.video.removeEventListener("play", this.handlePlay);
delete this.video.dataset["vscid"];
this.video.removeEventListener("seek", this.handleSeek);
delete this.video.vsc;
let idx = tc.mediaElements.indexOf(this.video);
if (idx != -1) {
tc.mediaElements.splice(idx, 1);
}
};
tc.videoController.prototype.initializeControls = function () {
log("initializeControls Begin", 5);
var document = this.document;
var speed = this.video.playbackRate.toFixed(2),
top = Math.max(this.video.offsetTop, 0) + "px",
left = Math.max(this.video.offsetLeft, 0) + "px";
const document = this.video.ownerDocument;
const speed = this.video.playbackRate.toFixed(2);
const rect = this.video.getBoundingClientRect();
const top = Math.max(rect.top, 0) + "px";
const left = Math.max(rect.left, 0) + "px";
log("Speed variable set to: " + speed, 5);
var wrapper = document.createElement("div");
wrapper.classList.add("vsc-controller");
wrapper.dataset["vscid"] = this.id;
if (!this.video.currentSrc) {
wrapper.classList.add("vsc-nosource");
@@ -278,35 +302,49 @@ function defineVideoController() {
<span data-action="drag" class="draggable">${speed}</span>
<span id="controls">
<button data-action="rewind" class="rw">«</button>
<button data-action="slower">-</button>
<button data-action="faster">+</button>
<button data-action="slower">&minus;</button>
<button data-action="faster">&plus;</button>
<button data-action="advance" class="rw">»</button>
<button data-action="display" class="hideButton">x</button>
<button data-action="display" class="hideButton">&times;</button>
</span>
</div>
`;
shadow.innerHTML = shadowTemplate;
shadow.querySelector(".draggable").addEventListener("mousedown", e => {
runAction(e.target.dataset["action"], document, false, e);
});
shadow.querySelector(".draggable").addEventListener(
"mousedown",
(e) => {
runAction(e.target.dataset["action"], false, e);
e.stopPropagation();
},
true
);
forEach.call(shadow.querySelectorAll("button"), function(button) {
button.onclick = e => {
shadow.querySelectorAll("button").forEach(function (button) {
button.addEventListener(
"click",
(e) => {
runAction(
e.target.dataset["action"],
document,
getKeyBindings(e.target.dataset["action"]),
e
);
};
e.stopPropagation();
},
true
);
});
shadow
.querySelector("#controller")
.addEventListener("click", (e) => e.stopPropagation(), false);
shadow
.querySelector("#controller")
.addEventListener("mousedown", (e) => e.stopPropagation(), false);
this.speedIndicator = shadow.querySelector("span");
var fragment = document.createDocumentFragment();
fragment.appendChild(wrapper);
this.video.dataset["vscid"] = this.id;
switch (true) {
case location.hostname == "www.amazon.com":
case location.hostname == "www.reddit.com":
@@ -314,13 +352,17 @@ function defineVideoController() {
// insert before parent to bypass overlay
this.parent.parentElement.insertBefore(fragment, this.parent);
break;
case location.hostname == "www.facebook.com":
// this is a monstrosity but new FB design does not have *any*
// semantic handles for us to traverse the tree, and deep nesting
// that we need to bubble up from to get controller to stack correctly
let p = this.parent.parentElement.parentElement.parentElement
.parentElement.parentElement.parentElement.parentElement;
p.insertBefore(fragment, p.firstChild);
break;
case location.hostname == "tv.apple.com":
// insert after parent for correct stacking context
this.parent
.getRootNode()
.querySelector(".scrim")
.prepend(fragment);
this.parent.getRootNode().querySelector(".scrim").prepend(fragment);
default:
// Note: when triggered via a MutationRecord, it's possible that the
// target is not the immediate parent. This appends the controller as
@@ -338,7 +380,7 @@ function escapeStringRegExp(str) {
function isBlacklisted() {
blacklisted = false;
tc.settings.blacklist.split("\n").forEach(match => {
tc.settings.blacklist.split("\n").forEach((match) => {
match = match.replace(regStrip, "");
if (match.length == 0) {
return;
@@ -375,25 +417,26 @@ function refreshCoolDown() {
}
function setupListener() {
document.body.addEventListener(
"ratechange",
function(event) {
if (coolDown) {
log("Speed event propagation blocked", 4);
event.stopImmediatePropagation();
}
var controller = event.target.parentElement.querySelector(
".vsc-controller"
);
var speedIndicator = controller.shadowRoot.querySelector("span");
var video = controller.parentElement.querySelector("video");
/**
* This function is run whenever a video speed rate change occurs.
* It is used to update the speed that shows up in the display as well as save
* that latest speed into the local storage.
*
* @param {*} video The video element to update the speed indicators for.
*/
function updateSpeedFromEvent(video) {
// It's possible to get a rate change on a VIDEO/AUDIO that doesn't have
// a video controller attached to it. If we do, ignore it.
if (!video.vsc)
return;
var speedIndicator = video.vsc.speedIndicator;
var src = video.currentSrc;
var speed = video.playbackRate.toFixed(2);
var speed = Number(video.playbackRate.toFixed(2));
log("Playback rate changed to " + speed, 4);
log("Updating controller with new speed", 5);
speedIndicator.textContent = speed;
speedIndicator.textContent = speed.toFixed(2);
tc.settings.speeds[src] = speed;
log("Storing lastSpeed in settings for the rememberSpeed feature", 5);
tc.settings.lastSpeed = speed;
@@ -402,7 +445,33 @@ function setupListener() {
log("Speed setting saved: " + speed, 5);
});
// show the controller for 1000ms if it's hidden.
runAction("blink", document, null, null);
runAction("blink", null, null);
}
document.addEventListener(
"ratechange",
function (event) {
if (coolDown) {
log("Speed event propagation blocked", 4);
event.stopImmediatePropagation();
}
var video = event.target;
/**
* If the last speed is forced, only update the speed based on events created by
* video speed instead of all video speed change events.
*/
if (tc.settings.forceLastSavedSpeed) {
if (event.detail && event.detail.origin === "videoSpeed") {
video.playbackRate = event.detail.speed;
updateSpeedFromEvent(video);
} else {
video.playbackRate = tc.settings.lastSpeed;
}
event.stopImmediatePropagation();
} else {
updateSpeedFromEvent(video);
}
},
true
);
@@ -436,9 +505,23 @@ function inIframe() {
return true;
}
}
function getController(id) {
return document.querySelector(`div[data-vscid="${id}"]`);
function getShadow(parent) {
let result = [];
function getChild(parent) {
if (parent.firstElementChild) {
var child = parent.firstElementChild;
do {
result.push(child);
getChild(child);
if (child.shadowRoot) {
result.push(getShadow(child.shadowRoot));
}
child = child.nextElementSibling;
} while (child);
}
}
getChild(parent);
return result.flat(Infinity);
}
function initializeNow(document) {
@@ -501,15 +584,13 @@ function initializeNow(document) {
}
// Ignore keydown event if typing in a page without vsc
if (
!document.querySelector(".vsc-controller")
) {
if (!tc.mediaElements.length) {
return false;
}
var item = tc.settings.keyBindings.find(item => item.key === keyCode);
var item = tc.settings.keyBindings.find((item) => item.key === keyCode);
if (item) {
runAction(item.action, document, item.value);
runAction(item.action, item.value);
if (item.force === "true") {
// disable websites key bindings
event.preventDefault();
@@ -535,8 +616,7 @@ function initializeNow(document) {
if (added) {
node.vsc = new tc.videoController(node, parent);
} else {
let id = node.dataset["vscid"];
if (id) {
if (node.vsc) {
node.vsc.remove();
}
}
@@ -551,19 +631,35 @@ function initializeNow(document) {
var observer = new MutationObserver(function (mutations) {
// Process the DOM nodes lazily
requestIdleCallback(
_ => {
(_) => {
mutations.forEach(function (mutation) {
switch (mutation.type) {
case "childList":
forEach.call(mutation.addedNodes, function(node) {
mutation.addedNodes.forEach(function (node) {
if (typeof node === "function") return;
checkForVideo(node, node.parentNode || mutation.target, true);
});
forEach.call(mutation.removedNodes, function(node) {
mutation.removedNodes.forEach(function (node) {
if (typeof node === "function") return;
checkForVideo(node, node.parentNode || mutation.target, false);
});
break;
case "attributes":
if (
mutation.target.attributes["aria-hidden"] &&
mutation.target.attributes["aria-hidden"].value == "false"
) {
var flattenedNodes = getShadow(document.body);
var node = flattenedNodes.filter(
(x) => x.tagName == "VIDEO"
)[0];
if (node) {
if (node.vsc)
node.vsc.remove();
checkForVideo(node, node.parentNode || mutation.target, true);
}
}
break;
}
});
},
@@ -582,12 +678,12 @@ function initializeNow(document) {
var mediaTags = document.querySelectorAll("video");
}
forEach.call(mediaTags, function(video) {
mediaTags.forEach(function (video) {
video.vsc = new tc.videoController(video);
});
var frameTags = document.getElementsByTagName("iframe");
forEach.call(frameTags, function(frame) {
Array.prototype.forEach.call(frameTags, function (frame) {
// Ignore frames we don't have permission to access (different origin).
try {
var childDocument = frame.contentDocument;
@@ -599,23 +695,29 @@ function initializeNow(document) {
log("End initializeNow", 5);
}
function setSpeed(controller, video, speed) {
function setSpeed(video, speed) {
log("setSpeed started: " + speed, 5);
var speedvalue = speed.toFixed(2);
if (tc.settings.forceLastSavedSpeed) {
video.dispatchEvent(
new CustomEvent("ratechange", {
detail: { origin: "videoSpeed", speed: speedvalue }
})
);
} else {
video.playbackRate = Number(speedvalue);
}
var speedIndicator = video.vsc.speedIndicator;
speedIndicator.textContent = speedvalue;
tc.settings.lastSpeed = speed;
refreshCoolDown();
log("setSpeed finished: " + speed, 5);
}
function runAction(action, document, value, e) {
function runAction(action, value, e) {
log("runAction Begin", 5);
if (tc.settings.audioBoolean) {
var mediaTags = document.querySelectorAll("video,audio");
} else {
var mediaTags = document.querySelectorAll("video");
}
mediaTags.forEach = Array.prototype.forEach;
var mediaTags = tc.mediaElements;
// Get the controller that was used if called from a button press event e
if (e) {
@@ -623,17 +725,14 @@ function runAction(action, document, value, e) {
}
mediaTags.forEach(function (v) {
var id = v.dataset["vscid"];
var controller = getController(id);
var controller = v.vsc.div;
// Don't change video speed if the video has a different controller
if (e && !(targetController == controller)) {
return;
}
// Controller may have been (force) removed by the site, guard to prevent crashes but run the command
if (controller) {
showController(controller);
}
if (!v.classList.contains("vsc-cancelled")) {
if (action === "rewind") {
@@ -650,16 +749,16 @@ function runAction(action, document, value, e) {
(v.playbackRate < 0.1 ? 0.0 : v.playbackRate) + value,
16
);
setSpeed(controller, v, s);
setSpeed(v, s);
} else if (action === "slower") {
log("Decrease speed", 5);
// Video min rate is 0.0625:
// https://cs.chromium.org/chromium/src/third_party/blink/renderer/core/html/media/html_media_element.cc?gsn=kMinRate&l=165
var s = Math.max(v.playbackRate - value, 0.07);
setSpeed(controller, v, s);
setSpeed(v, s);
} else if (action === "reset") {
log("Reset speed", 5);
resetSpeed(v, controller, 1.0);
resetSpeed(v, 1.0);
} else if (action === "display") {
log("Showing controller", 5);
controller.classList.add("vsc-manual");
@@ -682,13 +781,13 @@ function runAction(action, document, value, e) {
);
}
} else if (action === "drag") {
handleDrag(v, controller, e);
handleDrag(v, e);
} else if (action === "fast") {
resetSpeed(v, controller, value);
resetSpeed(v, value);
} else if (action === "pause") {
pause(v);
} else if (action === "muted") {
muted(v, value);
muted(v);
} else if (action === "mark") {
setMark(v);
} else if (action === "jump") {
@@ -709,28 +808,28 @@ function pause(v) {
}
}
function resetSpeed(v, controller, target) {
function resetSpeed(v, target) {
if (v.playbackRate === target) {
if (v.playbackRate === getKeyBindings("reset")) {
if (target !== 1.0) {
log("Resetting playback speed to 1.0", 4);
setSpeed(controller, v, 1.0);
setSpeed(v, 1.0);
} else {
log('Toggling playback speed to "fast" speed', 4);
setSpeed(controller, v, getKeyBindings("fast"));
setSpeed(v, getKeyBindings("fast"));
}
} else {
log('Toggling playback speed to "reset" speed', 4);
setSpeed(controller, v, getKeyBindings("reset"));
setSpeed(v, getKeyBindings("reset"));
}
} else {
log('Toggling playback speed to "reset" speed', 4);
setKeyBindings("reset", v.playbackRate);
setSpeed(controller, v, target);
setSpeed(v, target);
}
}
function muted(v, value) {
function muted(v) {
v.muted = v.muted !== true;
}
@@ -746,7 +845,8 @@ function jumpToMark(v) {
}
}
function handleDrag(video, controller, e) {
function handleDrag(video, e) {
const controller = video.vsc.div;
const shadowController = controller.shadowRoot.querySelector("#controller");
// Find nearest parent of same size as video parent.
@@ -768,7 +868,7 @@ function handleDrag(video, controller, e) {
parseInt(shadowController.style.top)
];
const startDragging = e => {
const startDragging = (e) => {
let style = shadowController.style;
let dx = e.clientX - initialMouseXY[0];
let dy = e.clientY - initialMouseXY[1];
@@ -790,18 +890,16 @@ function handleDrag(video, controller, e) {
parentElement.addEventListener("mousemove", startDragging);
}
var timer;
var animation = false;
var timer = null;
function showController(controller) {
log("Showing controller", 4);
controller.classList.add("vcs-show");
if (animation) clearTimeout(timer);
if (timer) clearTimeout(timer);
animation = true;
timer = setTimeout(function () {
controller.classList.remove("vcs-show");
animation = false;
timer = false;
log("Hiding controller", 5);
}, 2000);
}

View File

@@ -1,7 +1,7 @@
{
"name": "Video Speed Controller",
"short_name": "videospeed",
"version": "0.6.1",
"version": "0.6.3",
"manifest_version": 2,
"description": "Speed up, slow down, advance and rewind HTML5 audio/video with shortcuts",
"homepage_url": "https://github.com/codebicycle/videospeed",

View File

@@ -147,6 +147,11 @@
<label for="rememberSpeed">Remember playback speed</label>
<input id="rememberSpeed" type="checkbox" />
</div>
<div class="row">
<label for="forceLastSavedSpeed">Force last saved speed<br />
<em>Useful for video players that override the speeds set by VideoSpeed</em></label>
<input id="forceLastSavedSpeed" type="checkbox" />
</div>
<div class="row">
<label for="audioBoolean">Work on audio</label>
<input id="audioBoolean" type="checkbox" />

View File

@@ -6,6 +6,7 @@ var tcDefaults = {
rememberSpeed: false, // default: false
audioBoolean: false, // default: false
startHidden: false, // default: false
forceLastSavedSpeed: false, //default: false
enabled: true, // default enabled
controllerOpacity: 0.3, // default: 0.3
keyBindings: [
@@ -17,8 +18,7 @@ var tcDefaults = {
{ action: "reset", key: 82, value: 1, force: false, predefined: true }, // R
{ action: "fast", key: 71, value: 1.8, force: false, predefined: true } // G
],
blacklist:
`www.instagram.com
blacklist: `www.instagram.com
twitter.com
imgur.com
teams.microsoft.com
@@ -186,7 +186,7 @@ function validate() {
document
.getElementById("blacklist")
.value.split("\n")
.forEach(match => {
.forEach((match) => {
match = match.replace(regStrip, "");
if (match.startsWith("/")) {
try {
@@ -208,11 +208,12 @@ function save_options() {
return;
}
keyBindings = [];
Array.from(document.querySelectorAll(".customs")).forEach(item =>
Array.from(document.querySelectorAll(".customs")).forEach((item) =>
createKeyBindings(item)
); // Remove added shortcuts
var rememberSpeed = document.getElementById("rememberSpeed").checked;
var forceLastSavedSpeed = document.getElementById("forceLastSavedSpeed").checked;
var audioBoolean = document.getElementById("audioBoolean").checked;
var enabled = document.getElementById("enabled").checked;
var startHidden = document.getElementById("startHidden").checked;
@@ -235,6 +236,7 @@ function save_options() {
chrome.storage.sync.set(
{
rememberSpeed: rememberSpeed,
forceLastSavedSpeed: forceLastSavedSpeed,
audioBoolean: audioBoolean,
enabled: enabled,
startHidden: startHidden,
@@ -257,6 +259,7 @@ function save_options() {
function restore_options() {
chrome.storage.sync.get(tcDefaults, function (storage) {
document.getElementById("rememberSpeed").checked = storage.rememberSpeed;
document.getElementById("forceLastSavedSpeed").checked = storage.forceLastSavedSpeed;
document.getElementById("audioBoolean").checked = storage.audioBoolean;
document.getElementById("enabled").checked = storage.enabled;
document.getElementById("startHidden").checked = storage.startHidden;
@@ -265,7 +268,7 @@ function restore_options() {
document.getElementById("blacklist").value = storage.blacklist;
// ensure that there is a "display" binding for upgrades from versions that had it as a separate binding
if (storage.keyBindings.filter(x => x.action == "display").length == 0) {
if (storage.keyBindings.filter((x) => x.action == "display").length == 0) {
storage.keyBindings.push({
action: "display",
value: 0,
@@ -321,7 +324,7 @@ function restore_defaults() {
restore_options();
document
.querySelectorAll(".removeParent")
.forEach(button => button.click()); // Remove added shortcuts
.forEach((button) => button.click()); // Remove added shortcuts
// Update status to let user know options were saved.
var status = document.getElementById("status");
status.textContent = "Default options restored";
@@ -334,7 +337,7 @@ function restore_defaults() {
function show_experimental() {
document
.querySelectorAll(".customForce")
.forEach(item => (item.style.display = "inline-block"));
.forEach((item) => (item.style.display = "inline-block"));
}
document.addEventListener("DOMContentLoaded", function () {
@@ -356,24 +359,24 @@ document.addEventListener("DOMContentLoaded", function() {
funcName(event);
}
document.addEventListener("keypress", event => {
document.addEventListener("keypress", (event) => {
eventCaller(event, "customValue", inputFilterNumbersOnly);
});
document.addEventListener("focus", event => {
document.addEventListener("focus", (event) => {
eventCaller(event, "customKey", inputFocus);
});
document.addEventListener("blur", event => {
document.addEventListener("blur", (event) => {
eventCaller(event, "customKey", inputBlur);
});
document.addEventListener("keydown", event => {
document.addEventListener("keydown", (event) => {
eventCaller(event, "customKey", recordKeyPress);
});
document.addEventListener("click", event => {
document.addEventListener("click", (event) => {
eventCaller(event, "removeParent", function () {
event.target.parentNode.remove();
});
});
document.addEventListener("change", event => {
document.addEventListener("change", (event) => {
eventCaller(event, "customDo", function () {
if (customActionsNoValues.includes(event.target.value)) {
event.target.nextElementSibling.nextElementSibling.disabled = true;

View File

@@ -3,11 +3,11 @@ document.addEventListener("DOMContentLoaded", function() {
window.open(chrome.runtime.getURL("options.html"));
});
document.querySelector('#about').addEventListener('click', function() {
document.querySelector("#about").addEventListener("click", function () {
window.open("https://github.com/codebicycle/videospeed");
});
document.querySelector('#feedback').addEventListener('click', function() {
document.querySelector("#feedback").addEventListener("click", function () {
window.open("https://github.com/codebicycle/videospeed/issues");
});

View File

@@ -1,6 +1,6 @@
* {
line-height: 1.8em;
font-family: Verdana, Geneva, sans-serif;
font-family: sans-serif;
font-size: 13px;
}
@@ -16,8 +16,8 @@
background: black;
color: white;
border-radius: 5px;
padding: 5px;
border-radius: 30px;
padding: 6px 12px 6px 12px;
margin: 10px 10px 10px 15px;
cursor: default;
@@ -57,17 +57,19 @@
}
button {
opacity: 1;
cursor: pointer;
color: black;
background: white;
font-weight: bold;
border-radius: 5px;
padding: 1px 6px 3px 6px;
font-weight: normal;
border-radius: 20px;
padding: 1px 5px 3px 5px;
font-size: 14px;
line-height: 14px;
border: 1px solid white;
border: 0px solid white;
font-family: "Lucida Console", Monaco, monospace;
margin-bottom: 2px;
margin: 0px 2px 2px 2px;
transition: background 0.2s, color 0.2s;
}
button:focus {
@@ -76,10 +78,14 @@ button:focus {
button:hover {
opacity: 1;
background: #2196f3;
color: #ffffff;
}
button:active {
background: #ccc;
background: #2196f3;
color: #ffffff;
font-weight: bold;
}
button.rw {
@@ -87,6 +93,6 @@ button.rw {
}
button.hideButton {
opacity: 0.65;
margin-right: 2px;
opacity: 0.5;
}