mirror of
https://github.com/SoPat712/videospeed.git
synced 2025-08-21 09:58:45 -04:00
Merge upstream 0.6.3
This commit is contained in:
@@ -9,6 +9,11 @@
|
|||||||
opacity: 1 !important;
|
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 */
|
/* Origin specific overrides */
|
||||||
/* YouTube player */
|
/* YouTube player */
|
||||||
.ytp-hide-info-bar .vsc-controller {
|
.ytp-hide-info-bar .vsc-controller {
|
||||||
|
408
inject.js
408
inject.js
@@ -8,6 +8,7 @@ var tc = {
|
|||||||
|
|
||||||
displayKeyCode: 86, // default: V
|
displayKeyCode: 86, // default: V
|
||||||
rememberSpeed: false, // default: false
|
rememberSpeed: false, // default: false
|
||||||
|
forceLastSavedSpeed: false, //default: false
|
||||||
audioBoolean: false, // default: false
|
audioBoolean: false, // default: false
|
||||||
startHidden: false, // default: false
|
startHidden: false, // default: false
|
||||||
controllerOpacity: 0.3, // default: 0.3
|
controllerOpacity: 0.3, // default: 0.3
|
||||||
@@ -21,7 +22,10 @@ var tc = {
|
|||||||
`.replace(regStrip, ""),
|
`.replace(regStrip, ""),
|
||||||
defaultLogLevel: 4,
|
defaultLogLevel: 4,
|
||||||
logLevel: 3
|
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)
|
/* Log levels (depends on caller specifying the correct level)
|
||||||
@@ -53,7 +57,7 @@ function log(message, level) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
chrome.storage.sync.get(tc.settings, function(storage) {
|
chrome.storage.sync.get(tc.settings, function (storage) {
|
||||||
tc.settings.keyBindings = storage.keyBindings; // Array
|
tc.settings.keyBindings = storage.keyBindings; // Array
|
||||||
if (storage.keyBindings.length == 0) {
|
if (storage.keyBindings.length == 0) {
|
||||||
// if first initialization of 0.5.3
|
// if first initialization of 0.5.3
|
||||||
@@ -107,6 +111,7 @@ chrome.storage.sync.get(tc.settings, function(storage) {
|
|||||||
version: tc.settings.version,
|
version: tc.settings.version,
|
||||||
displayKeyCode: tc.settings.displayKeyCode,
|
displayKeyCode: tc.settings.displayKeyCode,
|
||||||
rememberSpeed: tc.settings.rememberSpeed,
|
rememberSpeed: tc.settings.rememberSpeed,
|
||||||
|
forceLastSavedSpeed: tc.settings.forceLastSavedSpeed,
|
||||||
audioBoolean: tc.settings.audioBoolean,
|
audioBoolean: tc.settings.audioBoolean,
|
||||||
startHidden: tc.settings.startHidden,
|
startHidden: tc.settings.startHidden,
|
||||||
enabled: tc.settings.enabled,
|
enabled: tc.settings.enabled,
|
||||||
@@ -117,6 +122,7 @@ chrome.storage.sync.get(tc.settings, function(storage) {
|
|||||||
tc.settings.lastSpeed = Number(storage.lastSpeed);
|
tc.settings.lastSpeed = Number(storage.lastSpeed);
|
||||||
tc.settings.displayKeyCode = Number(storage.displayKeyCode);
|
tc.settings.displayKeyCode = Number(storage.displayKeyCode);
|
||||||
tc.settings.rememberSpeed = Boolean(storage.rememberSpeed);
|
tc.settings.rememberSpeed = Boolean(storage.rememberSpeed);
|
||||||
|
tc.settings.forceLastSavedSpeed = Boolean(storage.forceLastSavedSpeed);
|
||||||
tc.settings.audioBoolean = Boolean(storage.audioBoolean);
|
tc.settings.audioBoolean = Boolean(storage.audioBoolean);
|
||||||
tc.settings.enabled = Boolean(storage.enabled);
|
tc.settings.enabled = Boolean(storage.enabled);
|
||||||
tc.settings.startHidden = Boolean(storage.startHidden);
|
tc.settings.startHidden = Boolean(storage.startHidden);
|
||||||
@@ -124,7 +130,9 @@ chrome.storage.sync.get(tc.settings, function(storage) {
|
|||||||
tc.settings.blacklist = String(storage.blacklist);
|
tc.settings.blacklist = String(storage.blacklist);
|
||||||
|
|
||||||
// ensure that there is a "display" binding (for upgrades from versions that had it as a separate binding)
|
// 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({
|
tc.settings.keyBindings.push({
|
||||||
action: "display",
|
action: "display",
|
||||||
key: Number(storage.displayKeyCode) || 86,
|
key: Number(storage.displayKeyCode) || 86,
|
||||||
@@ -137,32 +145,42 @@ chrome.storage.sync.get(tc.settings, function(storage) {
|
|||||||
initializeWhenReady(document);
|
initializeWhenReady(document);
|
||||||
});
|
});
|
||||||
|
|
||||||
var forEach = Array.prototype.forEach;
|
|
||||||
|
|
||||||
function getKeyBindings(action, what = "value") {
|
function getKeyBindings(action, what = "value") {
|
||||||
try {
|
try {
|
||||||
return tc.settings.keyBindings.find(item => item.action === action)[what];
|
return tc.settings.keyBindings.find((item) => item.action === action)[what];
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setKeyBindings(action, value) {
|
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() {
|
function defineVideoController() {
|
||||||
tc.videoController = function(target, parent) {
|
// Data structures
|
||||||
if (target.dataset["vscid"]) {
|
// ---------------
|
||||||
|
// 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.vsc) {
|
||||||
return target.vsc;
|
return target.vsc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tc.mediaElements.push(target);
|
||||||
|
|
||||||
this.video = target;
|
this.video = target;
|
||||||
this.parent = target.parentElement || parent;
|
this.parent = target.parentElement || parent;
|
||||||
this.document = target.ownerDocument;
|
|
||||||
this.id = Math.random()
|
|
||||||
.toString(36)
|
|
||||||
.substr(2, 9);
|
|
||||||
storedSpeed = tc.settings.speeds[target.currentSrc];
|
storedSpeed = tc.settings.speeds[target.currentSrc];
|
||||||
if (!tc.settings.rememberSpeed) {
|
if (!tc.settings.rememberSpeed) {
|
||||||
if (!storedSpeed) {
|
if (!storedSpeed) {
|
||||||
@@ -183,48 +201,50 @@ function defineVideoController() {
|
|||||||
|
|
||||||
this.div = this.initializeControls();
|
this.div = this.initializeControls();
|
||||||
|
|
||||||
|
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);
|
||||||
|
storedSpeed = 1.0;
|
||||||
|
}
|
||||||
|
// resetSpeed isn't really a reset, it's a toggle
|
||||||
|
log("Setting reset keybinding to fast", 5);
|
||||||
|
setKeyBindings("reset", getKeyBindings("fast")); // resetSpeed = fastSpeed
|
||||||
|
} else {
|
||||||
|
log(
|
||||||
|
"Storing lastSpeed into tc.settings.speeds (rememberSpeed enabled)",
|
||||||
|
5
|
||||||
|
);
|
||||||
|
storedSpeed = tc.settings.lastSpeed;
|
||||||
|
}
|
||||||
|
// TODO: Check if explicitly setting the playback rate to 1.0 is
|
||||||
|
// necessary when rememberSpeed is disabled (this may accidentally
|
||||||
|
// override a website's intentional initial speed setting interfering
|
||||||
|
// with the site's default behavior)
|
||||||
|
log("Explicitly setting playbackRate to: " + storedSpeed, 4);
|
||||||
|
setSpeed(event.target, storedSpeed);
|
||||||
|
};
|
||||||
|
|
||||||
target.addEventListener(
|
target.addEventListener(
|
||||||
"play",
|
"play",
|
||||||
(this.handlePlay = function(event) {
|
(this.handlePlay = mediaEventAction.bind(this))
|
||||||
storedSpeed = tc.settings.speeds[event.target.currentSrc];
|
|
||||||
if (!tc.settings.rememberSpeed) {
|
|
||||||
if (!storedSpeed) {
|
|
||||||
log(
|
|
||||||
"Overwriting stored speed to 1.0 (rememberSpeed not enabled)",
|
|
||||||
4
|
|
||||||
);
|
|
||||||
storedSpeed = 1.0;
|
|
||||||
}
|
|
||||||
// resetSpeed isn't really a reset, it's a toggle
|
|
||||||
log("Setting reset keybinding to fast", 5);
|
|
||||||
setKeyBindings("reset", getKeyBindings("fast")); // resetSpeed = fastSpeed
|
|
||||||
} else {
|
|
||||||
log(
|
|
||||||
"Storing lastSpeed into tc.settings.speeds (rememberSpeed enabled)",
|
|
||||||
5
|
|
||||||
);
|
|
||||||
storedSpeed = tc.settings.lastSpeed;
|
|
||||||
}
|
|
||||||
// TODO: Check if explicitly setting the playback rate to 1.0 is
|
|
||||||
// necessary when rememberSpeed is disabled (this may accidentally
|
|
||||||
// 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))
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var observer = new MutationObserver(mutations => {
|
target.addEventListener(
|
||||||
mutations.forEach(mutation => {
|
"seeked",
|
||||||
|
(this.handleSeek = mediaEventAction.bind(this))
|
||||||
|
);
|
||||||
|
|
||||||
|
var observer = new MutationObserver((mutations) => {
|
||||||
|
mutations.forEach((mutation) => {
|
||||||
if (
|
if (
|
||||||
mutation.type === "attributes" &&
|
mutation.type === "attributes" &&
|
||||||
(mutation.attributeName === "src" ||
|
(mutation.attributeName === "src" ||
|
||||||
mutation.attributeName === "currentSrc")
|
mutation.attributeName === "currentSrc")
|
||||||
) {
|
) {
|
||||||
var controller = getController(this.id);
|
log("mutation of A/V element", 5);
|
||||||
if (!controller) {
|
var controller = this.div;
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!mutation.target.src && !mutation.target.currentSrc) {
|
if (!mutation.target.src && !mutation.target.currentSrc) {
|
||||||
controller.classList.add("vsc-nosource");
|
controller.classList.add("vsc-nosource");
|
||||||
} else {
|
} else {
|
||||||
@@ -238,25 +258,29 @@ function defineVideoController() {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
tc.videoController.prototype.remove = function() {
|
tc.videoController.prototype.remove = function () {
|
||||||
this.div.remove();
|
this.div.remove();
|
||||||
this.video.removeEventListener("play", this.handlePlay);
|
this.video.removeEventListener("play", this.handlePlay);
|
||||||
delete this.video.dataset["vscid"];
|
this.video.removeEventListener("seek", this.handleSeek);
|
||||||
delete this.video.vsc;
|
delete this.video.vsc;
|
||||||
|
let idx = tc.mediaElements.indexOf(this.video);
|
||||||
|
if (idx != -1) {
|
||||||
|
tc.mediaElements.splice(idx, 1);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
tc.videoController.prototype.initializeControls = function() {
|
tc.videoController.prototype.initializeControls = function () {
|
||||||
log("initializeControls Begin", 5);
|
log("initializeControls Begin", 5);
|
||||||
var document = this.document;
|
const document = this.video.ownerDocument;
|
||||||
var speed = this.video.playbackRate.toFixed(2),
|
const speed = this.video.playbackRate.toFixed(2);
|
||||||
top = Math.max(this.video.offsetTop, 0) + "px",
|
const rect = this.video.getBoundingClientRect();
|
||||||
left = Math.max(this.video.offsetLeft, 0) + "px";
|
const top = Math.max(rect.top, 0) + "px";
|
||||||
|
const left = Math.max(rect.left, 0) + "px";
|
||||||
|
|
||||||
log("Speed variable set to: " + speed, 5);
|
log("Speed variable set to: " + speed, 5);
|
||||||
|
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement("div");
|
||||||
wrapper.classList.add("vsc-controller");
|
wrapper.classList.add("vsc-controller");
|
||||||
wrapper.dataset["vscid"] = this.id;
|
|
||||||
|
|
||||||
if (!this.video.currentSrc) {
|
if (!this.video.currentSrc) {
|
||||||
wrapper.classList.add("vsc-nosource");
|
wrapper.classList.add("vsc-nosource");
|
||||||
@@ -278,35 +302,49 @@ function defineVideoController() {
|
|||||||
<span data-action="drag" class="draggable">${speed}</span>
|
<span data-action="drag" class="draggable">${speed}</span>
|
||||||
<span id="controls">
|
<span id="controls">
|
||||||
<button data-action="rewind" class="rw">«</button>
|
<button data-action="rewind" class="rw">«</button>
|
||||||
<button data-action="slower">-</button>
|
<button data-action="slower">−</button>
|
||||||
<button data-action="faster">+</button>
|
<button data-action="faster">+</button>
|
||||||
<button data-action="advance" class="rw">»</button>
|
<button data-action="advance" class="rw">»</button>
|
||||||
<button data-action="display" class="hideButton">x</button>
|
<button data-action="display" class="hideButton">×</button>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
shadow.innerHTML = shadowTemplate;
|
shadow.innerHTML = shadowTemplate;
|
||||||
shadow.querySelector(".draggable").addEventListener("mousedown", e => {
|
shadow.querySelector(".draggable").addEventListener(
|
||||||
runAction(e.target.dataset["action"], document, false, e);
|
"mousedown",
|
||||||
|
(e) => {
|
||||||
|
runAction(e.target.dataset["action"], false, e);
|
||||||
|
e.stopPropagation();
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
|
|
||||||
|
shadow.querySelectorAll("button").forEach(function (button) {
|
||||||
|
button.addEventListener(
|
||||||
|
"click",
|
||||||
|
(e) => {
|
||||||
|
runAction(
|
||||||
|
e.target.dataset["action"],
|
||||||
|
getKeyBindings(e.target.dataset["action"]),
|
||||||
|
e
|
||||||
|
);
|
||||||
|
e.stopPropagation();
|
||||||
|
},
|
||||||
|
true
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
forEach.call(shadow.querySelectorAll("button"), function(button) {
|
shadow
|
||||||
button.onclick = e => {
|
.querySelector("#controller")
|
||||||
runAction(
|
.addEventListener("click", (e) => e.stopPropagation(), false);
|
||||||
e.target.dataset["action"],
|
shadow
|
||||||
document,
|
.querySelector("#controller")
|
||||||
getKeyBindings(e.target.dataset["action"]),
|
.addEventListener("mousedown", (e) => e.stopPropagation(), false);
|
||||||
e
|
|
||||||
);
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
this.speedIndicator = shadow.querySelector("span");
|
this.speedIndicator = shadow.querySelector("span");
|
||||||
var fragment = document.createDocumentFragment();
|
var fragment = document.createDocumentFragment();
|
||||||
fragment.appendChild(wrapper);
|
fragment.appendChild(wrapper);
|
||||||
|
|
||||||
this.video.dataset["vscid"] = this.id;
|
|
||||||
|
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case location.hostname == "www.amazon.com":
|
case location.hostname == "www.amazon.com":
|
||||||
case location.hostname == "www.reddit.com":
|
case location.hostname == "www.reddit.com":
|
||||||
@@ -314,13 +352,17 @@ function defineVideoController() {
|
|||||||
// insert before parent to bypass overlay
|
// insert before parent to bypass overlay
|
||||||
this.parent.parentElement.insertBefore(fragment, this.parent);
|
this.parent.parentElement.insertBefore(fragment, this.parent);
|
||||||
break;
|
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":
|
case location.hostname == "tv.apple.com":
|
||||||
// insert after parent for correct stacking context
|
// insert after parent for correct stacking context
|
||||||
this.parent
|
this.parent.getRootNode().querySelector(".scrim").prepend(fragment);
|
||||||
.getRootNode()
|
|
||||||
.querySelector(".scrim")
|
|
||||||
.prepend(fragment);
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Note: when triggered via a MutationRecord, it's possible that the
|
// Note: when triggered via a MutationRecord, it's possible that the
|
||||||
// target is not the immediate parent. This appends the controller as
|
// target is not the immediate parent. This appends the controller as
|
||||||
@@ -338,7 +380,7 @@ function escapeStringRegExp(str) {
|
|||||||
|
|
||||||
function isBlacklisted() {
|
function isBlacklisted() {
|
||||||
blacklisted = false;
|
blacklisted = false;
|
||||||
tc.settings.blacklist.split("\n").forEach(match => {
|
tc.settings.blacklist.split("\n").forEach((match) => {
|
||||||
match = match.replace(regStrip, "");
|
match = match.replace(regStrip, "");
|
||||||
if (match.length == 0) {
|
if (match.length == 0) {
|
||||||
return;
|
return;
|
||||||
@@ -368,41 +410,68 @@ function refreshCoolDown() {
|
|||||||
if (coolDown) {
|
if (coolDown) {
|
||||||
clearTimeout(coolDown);
|
clearTimeout(coolDown);
|
||||||
}
|
}
|
||||||
coolDown = setTimeout(function() {
|
coolDown = setTimeout(function () {
|
||||||
coolDown = false;
|
coolDown = false;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
log("End refreshCoolDown", 5);
|
log("End refreshCoolDown", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupListener() {
|
function setupListener() {
|
||||||
document.body.addEventListener(
|
/**
|
||||||
|
* 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 = Number(video.playbackRate.toFixed(2));
|
||||||
|
|
||||||
|
log("Playback rate changed to " + speed, 4);
|
||||||
|
|
||||||
|
log("Updating controller with new speed", 5);
|
||||||
|
speedIndicator.textContent = speed.toFixed(2);
|
||||||
|
tc.settings.speeds[src] = speed;
|
||||||
|
log("Storing lastSpeed in settings for the rememberSpeed feature", 5);
|
||||||
|
tc.settings.lastSpeed = speed;
|
||||||
|
log("Syncing chrome settings for lastSpeed", 5);
|
||||||
|
chrome.storage.sync.set({ lastSpeed: speed }, function () {
|
||||||
|
log("Speed setting saved: " + speed, 5);
|
||||||
|
});
|
||||||
|
// show the controller for 1000ms if it's hidden.
|
||||||
|
runAction("blink", null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
"ratechange",
|
"ratechange",
|
||||||
function(event) {
|
function (event) {
|
||||||
if (coolDown) {
|
if (coolDown) {
|
||||||
log("Speed event propagation blocked", 4);
|
log("Speed event propagation blocked", 4);
|
||||||
event.stopImmediatePropagation();
|
event.stopImmediatePropagation();
|
||||||
}
|
}
|
||||||
var controller = event.target.parentElement.querySelector(
|
var video = event.target;
|
||||||
".vsc-controller"
|
|
||||||
);
|
|
||||||
var speedIndicator = controller.shadowRoot.querySelector("span");
|
|
||||||
var video = controller.parentElement.querySelector("video");
|
|
||||||
var src = video.currentSrc;
|
|
||||||
var speed = video.playbackRate.toFixed(2);
|
|
||||||
|
|
||||||
log("Playback rate changed to " + speed, 4);
|
/**
|
||||||
|
* If the last speed is forced, only update the speed based on events created by
|
||||||
log("Updating controller with new speed", 5);
|
* video speed instead of all video speed change events.
|
||||||
speedIndicator.textContent = speed;
|
*/
|
||||||
tc.settings.speeds[src] = speed;
|
if (tc.settings.forceLastSavedSpeed) {
|
||||||
log("Storing lastSpeed in settings for the rememberSpeed feature", 5);
|
if (event.detail && event.detail.origin === "videoSpeed") {
|
||||||
tc.settings.lastSpeed = speed;
|
video.playbackRate = event.detail.speed;
|
||||||
log("Syncing chrome settings for lastSpeed", 5);
|
updateSpeedFromEvent(video);
|
||||||
chrome.storage.sync.set({ lastSpeed: speed }, function() {
|
} else {
|
||||||
log("Speed setting saved: " + speed, 5);
|
video.playbackRate = tc.settings.lastSpeed;
|
||||||
});
|
}
|
||||||
// show the controller for 1000ms if it's hidden.
|
event.stopImmediatePropagation();
|
||||||
runAction("blink", document, null, null);
|
} else {
|
||||||
|
updateSpeedFromEvent(video);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
@@ -436,9 +505,23 @@ function inIframe() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function getShadow(parent) {
|
||||||
function getController(id) {
|
let result = [];
|
||||||
return document.querySelector(`div[data-vscid="${id}"]`);
|
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) {
|
function initializeNow(document) {
|
||||||
@@ -470,10 +553,10 @@ function initializeNow(document) {
|
|||||||
if (inIframe()) docs.push(window.top.document);
|
if (inIframe()) docs.push(window.top.document);
|
||||||
} catch (e) {}
|
} catch (e) {}
|
||||||
|
|
||||||
docs.forEach(function(doc) {
|
docs.forEach(function (doc) {
|
||||||
doc.addEventListener(
|
doc.addEventListener(
|
||||||
"keydown",
|
"keydown",
|
||||||
function(event) {
|
function (event) {
|
||||||
var keyCode = event.keyCode;
|
var keyCode = event.keyCode;
|
||||||
log("Processing keydown event: " + keyCode, 6);
|
log("Processing keydown event: " + keyCode, 6);
|
||||||
|
|
||||||
@@ -501,15 +584,13 @@ function initializeNow(document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ignore keydown event if typing in a page without vsc
|
// Ignore keydown event if typing in a page without vsc
|
||||||
if (
|
if (!tc.mediaElements.length) {
|
||||||
!document.querySelector(".vsc-controller")
|
|
||||||
) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var item = tc.settings.keyBindings.find(item => item.key === keyCode);
|
var item = tc.settings.keyBindings.find((item) => item.key === keyCode);
|
||||||
if (item) {
|
if (item) {
|
||||||
runAction(item.action, document, item.value);
|
runAction(item.action, item.value);
|
||||||
if (item.force === "true") {
|
if (item.force === "true") {
|
||||||
// disable websites key bindings
|
// disable websites key bindings
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -535,8 +616,7 @@ function initializeNow(document) {
|
|||||||
if (added) {
|
if (added) {
|
||||||
node.vsc = new tc.videoController(node, parent);
|
node.vsc = new tc.videoController(node, parent);
|
||||||
} else {
|
} else {
|
||||||
let id = node.dataset["vscid"];
|
if (node.vsc) {
|
||||||
if (id) {
|
|
||||||
node.vsc.remove();
|
node.vsc.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -548,22 +628,38 @@ function initializeNow(document) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var observer = new MutationObserver(function(mutations) {
|
var observer = new MutationObserver(function (mutations) {
|
||||||
// Process the DOM nodes lazily
|
// Process the DOM nodes lazily
|
||||||
requestIdleCallback(
|
requestIdleCallback(
|
||||||
_ => {
|
(_) => {
|
||||||
mutations.forEach(function(mutation) {
|
mutations.forEach(function (mutation) {
|
||||||
switch (mutation.type) {
|
switch (mutation.type) {
|
||||||
case "childList":
|
case "childList":
|
||||||
forEach.call(mutation.addedNodes, function(node) {
|
mutation.addedNodes.forEach(function (node) {
|
||||||
if (typeof node === "function") return;
|
if (typeof node === "function") return;
|
||||||
checkForVideo(node, node.parentNode || mutation.target, true);
|
checkForVideo(node, node.parentNode || mutation.target, true);
|
||||||
});
|
});
|
||||||
forEach.call(mutation.removedNodes, function(node) {
|
mutation.removedNodes.forEach(function (node) {
|
||||||
if (typeof node === "function") return;
|
if (typeof node === "function") return;
|
||||||
checkForVideo(node, node.parentNode || mutation.target, false);
|
checkForVideo(node, node.parentNode || mutation.target, false);
|
||||||
});
|
});
|
||||||
break;
|
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");
|
var mediaTags = document.querySelectorAll("video");
|
||||||
}
|
}
|
||||||
|
|
||||||
forEach.call(mediaTags, function(video) {
|
mediaTags.forEach(function (video) {
|
||||||
video.vsc = new tc.videoController(video);
|
video.vsc = new tc.videoController(video);
|
||||||
});
|
});
|
||||||
|
|
||||||
var frameTags = document.getElementsByTagName("iframe");
|
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).
|
// Ignore frames we don't have permission to access (different origin).
|
||||||
try {
|
try {
|
||||||
var childDocument = frame.contentDocument;
|
var childDocument = frame.contentDocument;
|
||||||
@@ -599,41 +695,44 @@ function initializeNow(document) {
|
|||||||
log("End initializeNow", 5);
|
log("End initializeNow", 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSpeed(controller, video, speed) {
|
function setSpeed(video, speed) {
|
||||||
log("setSpeed started: " + speed, 5);
|
log("setSpeed started: " + speed, 5);
|
||||||
var speedvalue = speed.toFixed(2);
|
var speedvalue = speed.toFixed(2);
|
||||||
video.playbackRate = Number(speedvalue);
|
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();
|
refreshCoolDown();
|
||||||
log("setSpeed finished: " + speed, 5);
|
log("setSpeed finished: " + speed, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
function runAction(action, document, value, e) {
|
function runAction(action, value, e) {
|
||||||
log("runAction Begin", 5);
|
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
|
// Get the controller that was used if called from a button press event e
|
||||||
if (e) {
|
if (e) {
|
||||||
var targetController = e.target.getRootNode().host;
|
var targetController = e.target.getRootNode().host;
|
||||||
}
|
}
|
||||||
|
|
||||||
mediaTags.forEach(function(v) {
|
mediaTags.forEach(function (v) {
|
||||||
var id = v.dataset["vscid"];
|
var controller = v.vsc.div;
|
||||||
var controller = getController(id);
|
|
||||||
// Don't change video speed if the video has a different controller
|
// Don't change video speed if the video has a different controller
|
||||||
if (e && !(targetController == controller)) {
|
if (e && !(targetController == controller)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Controller may have been (force) removed by the site, guard to prevent crashes but run the command
|
showController(controller);
|
||||||
if (controller) {
|
|
||||||
showController(controller);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!v.classList.contains("vsc-cancelled")) {
|
if (!v.classList.contains("vsc-cancelled")) {
|
||||||
if (action === "rewind") {
|
if (action === "rewind") {
|
||||||
@@ -650,16 +749,16 @@ function runAction(action, document, value, e) {
|
|||||||
(v.playbackRate < 0.1 ? 0.0 : v.playbackRate) + value,
|
(v.playbackRate < 0.1 ? 0.0 : v.playbackRate) + value,
|
||||||
16
|
16
|
||||||
);
|
);
|
||||||
setSpeed(controller, v, s);
|
setSpeed(v, s);
|
||||||
} else if (action === "slower") {
|
} else if (action === "slower") {
|
||||||
log("Decrease speed", 5);
|
log("Decrease speed", 5);
|
||||||
// Video min rate is 0.0625:
|
// 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
|
// 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);
|
var s = Math.max(v.playbackRate - value, 0.07);
|
||||||
setSpeed(controller, v, s);
|
setSpeed(v, s);
|
||||||
} else if (action === "reset") {
|
} else if (action === "reset") {
|
||||||
log("Reset speed", 5);
|
log("Reset speed", 5);
|
||||||
resetSpeed(v, controller, 1.0);
|
resetSpeed(v, 1.0);
|
||||||
} else if (action === "display") {
|
} else if (action === "display") {
|
||||||
log("Showing controller", 5);
|
log("Showing controller", 5);
|
||||||
controller.classList.add("vsc-manual");
|
controller.classList.add("vsc-manual");
|
||||||
@@ -682,13 +781,13 @@ function runAction(action, document, value, e) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else if (action === "drag") {
|
} else if (action === "drag") {
|
||||||
handleDrag(v, controller, e);
|
handleDrag(v, e);
|
||||||
} else if (action === "fast") {
|
} else if (action === "fast") {
|
||||||
resetSpeed(v, controller, value);
|
resetSpeed(v, value);
|
||||||
} else if (action === "pause") {
|
} else if (action === "pause") {
|
||||||
pause(v);
|
pause(v);
|
||||||
} else if (action === "muted") {
|
} else if (action === "muted") {
|
||||||
muted(v, value);
|
muted(v);
|
||||||
} else if (action === "mark") {
|
} else if (action === "mark") {
|
||||||
setMark(v);
|
setMark(v);
|
||||||
} else if (action === "jump") {
|
} 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 === target) {
|
||||||
if (v.playbackRate === getKeyBindings("reset")) {
|
if (v.playbackRate === getKeyBindings("reset")) {
|
||||||
if (target !== 1.0) {
|
if (target !== 1.0) {
|
||||||
log("Resetting playback speed to 1.0", 4);
|
log("Resetting playback speed to 1.0", 4);
|
||||||
setSpeed(controller, v, 1.0);
|
setSpeed(v, 1.0);
|
||||||
} else {
|
} else {
|
||||||
log('Toggling playback speed to "fast" speed', 4);
|
log('Toggling playback speed to "fast" speed', 4);
|
||||||
setSpeed(controller, v, getKeyBindings("fast"));
|
setSpeed(v, getKeyBindings("fast"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log('Toggling playback speed to "reset" speed', 4);
|
log('Toggling playback speed to "reset" speed', 4);
|
||||||
setSpeed(controller, v, getKeyBindings("reset"));
|
setSpeed(v, getKeyBindings("reset"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
log('Toggling playback speed to "reset" speed', 4);
|
log('Toggling playback speed to "reset" speed', 4);
|
||||||
setKeyBindings("reset", v.playbackRate);
|
setKeyBindings("reset", v.playbackRate);
|
||||||
setSpeed(controller, v, target);
|
setSpeed(v, target);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function muted(v, value) {
|
function muted(v) {
|
||||||
v.muted = v.muted !== true;
|
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");
|
const shadowController = controller.shadowRoot.querySelector("#controller");
|
||||||
|
|
||||||
// Find nearest parent of same size as video parent.
|
// Find nearest parent of same size as video parent.
|
||||||
@@ -768,7 +868,7 @@ function handleDrag(video, controller, e) {
|
|||||||
parseInt(shadowController.style.top)
|
parseInt(shadowController.style.top)
|
||||||
];
|
];
|
||||||
|
|
||||||
const startDragging = e => {
|
const startDragging = (e) => {
|
||||||
let style = shadowController.style;
|
let style = shadowController.style;
|
||||||
let dx = e.clientX - initialMouseXY[0];
|
let dx = e.clientX - initialMouseXY[0];
|
||||||
let dy = e.clientY - initialMouseXY[1];
|
let dy = e.clientY - initialMouseXY[1];
|
||||||
@@ -790,18 +890,16 @@ function handleDrag(video, controller, e) {
|
|||||||
parentElement.addEventListener("mousemove", startDragging);
|
parentElement.addEventListener("mousemove", startDragging);
|
||||||
}
|
}
|
||||||
|
|
||||||
var timer;
|
var timer = null;
|
||||||
var animation = false;
|
|
||||||
function showController(controller) {
|
function showController(controller) {
|
||||||
log("Showing controller", 4);
|
log("Showing controller", 4);
|
||||||
controller.classList.add("vcs-show");
|
controller.classList.add("vcs-show");
|
||||||
|
|
||||||
if (animation) clearTimeout(timer);
|
if (timer) clearTimeout(timer);
|
||||||
|
|
||||||
animation = true;
|
timer = setTimeout(function () {
|
||||||
timer = setTimeout(function() {
|
|
||||||
controller.classList.remove("vcs-show");
|
controller.classList.remove("vcs-show");
|
||||||
animation = false;
|
timer = false;
|
||||||
log("Hiding controller", 5);
|
log("Hiding controller", 5);
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Video Speed Controller",
|
"name": "Video Speed Controller",
|
||||||
"short_name": "videospeed",
|
"short_name": "videospeed",
|
||||||
"version": "0.6.1",
|
"version": "0.6.3",
|
||||||
"manifest_version": 2,
|
"manifest_version": 2,
|
||||||
"description": "Speed up, slow down, advance and rewind HTML5 audio/video with shortcuts",
|
"description": "Speed up, slow down, advance and rewind HTML5 audio/video with shortcuts",
|
||||||
"homepage_url": "https://github.com/codebicycle/videospeed",
|
"homepage_url": "https://github.com/codebicycle/videospeed",
|
||||||
|
@@ -147,6 +147,11 @@
|
|||||||
<label for="rememberSpeed">Remember playback speed</label>
|
<label for="rememberSpeed">Remember playback speed</label>
|
||||||
<input id="rememberSpeed" type="checkbox" />
|
<input id="rememberSpeed" type="checkbox" />
|
||||||
</div>
|
</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">
|
<div class="row">
|
||||||
<label for="audioBoolean">Work on audio</label>
|
<label for="audioBoolean">Work on audio</label>
|
||||||
<input id="audioBoolean" type="checkbox" />
|
<input id="audioBoolean" type="checkbox" />
|
||||||
|
45
options.js
45
options.js
@@ -6,6 +6,7 @@ var tcDefaults = {
|
|||||||
rememberSpeed: false, // default: false
|
rememberSpeed: false, // default: false
|
||||||
audioBoolean: false, // default: false
|
audioBoolean: false, // default: false
|
||||||
startHidden: false, // default: false
|
startHidden: false, // default: false
|
||||||
|
forceLastSavedSpeed: false, //default: false
|
||||||
enabled: true, // default enabled
|
enabled: true, // default enabled
|
||||||
controllerOpacity: 0.3, // default: 0.3
|
controllerOpacity: 0.3, // default: 0.3
|
||||||
keyBindings: [
|
keyBindings: [
|
||||||
@@ -17,8 +18,7 @@ var tcDefaults = {
|
|||||||
{ action: "reset", key: 82, value: 1, force: false, predefined: true }, // R
|
{ action: "reset", key: 82, value: 1, force: false, predefined: true }, // R
|
||||||
{ action: "fast", key: 71, value: 1.8, force: false, predefined: true } // G
|
{ action: "fast", key: 71, value: 1.8, force: false, predefined: true } // G
|
||||||
],
|
],
|
||||||
blacklist:
|
blacklist: `www.instagram.com
|
||||||
`www.instagram.com
|
|
||||||
twitter.com
|
twitter.com
|
||||||
imgur.com
|
imgur.com
|
||||||
teams.microsoft.com
|
teams.microsoft.com
|
||||||
@@ -186,7 +186,7 @@ function validate() {
|
|||||||
document
|
document
|
||||||
.getElementById("blacklist")
|
.getElementById("blacklist")
|
||||||
.value.split("\n")
|
.value.split("\n")
|
||||||
.forEach(match => {
|
.forEach((match) => {
|
||||||
match = match.replace(regStrip, "");
|
match = match.replace(regStrip, "");
|
||||||
if (match.startsWith("/")) {
|
if (match.startsWith("/")) {
|
||||||
try {
|
try {
|
||||||
@@ -208,11 +208,12 @@ function save_options() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
keyBindings = [];
|
keyBindings = [];
|
||||||
Array.from(document.querySelectorAll(".customs")).forEach(item =>
|
Array.from(document.querySelectorAll(".customs")).forEach((item) =>
|
||||||
createKeyBindings(item)
|
createKeyBindings(item)
|
||||||
); // Remove added shortcuts
|
); // Remove added shortcuts
|
||||||
|
|
||||||
var rememberSpeed = document.getElementById("rememberSpeed").checked;
|
var rememberSpeed = document.getElementById("rememberSpeed").checked;
|
||||||
|
var forceLastSavedSpeed = document.getElementById("forceLastSavedSpeed").checked;
|
||||||
var audioBoolean = document.getElementById("audioBoolean").checked;
|
var audioBoolean = document.getElementById("audioBoolean").checked;
|
||||||
var enabled = document.getElementById("enabled").checked;
|
var enabled = document.getElementById("enabled").checked;
|
||||||
var startHidden = document.getElementById("startHidden").checked;
|
var startHidden = document.getElementById("startHidden").checked;
|
||||||
@@ -235,6 +236,7 @@ function save_options() {
|
|||||||
chrome.storage.sync.set(
|
chrome.storage.sync.set(
|
||||||
{
|
{
|
||||||
rememberSpeed: rememberSpeed,
|
rememberSpeed: rememberSpeed,
|
||||||
|
forceLastSavedSpeed: forceLastSavedSpeed,
|
||||||
audioBoolean: audioBoolean,
|
audioBoolean: audioBoolean,
|
||||||
enabled: enabled,
|
enabled: enabled,
|
||||||
startHidden: startHidden,
|
startHidden: startHidden,
|
||||||
@@ -242,11 +244,11 @@ function save_options() {
|
|||||||
keyBindings: keyBindings,
|
keyBindings: keyBindings,
|
||||||
blacklist: blacklist.replace(regStrip, "")
|
blacklist: blacklist.replace(regStrip, "")
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
// Update status to let user know options were saved.
|
// Update status to let user know options were saved.
|
||||||
var status = document.getElementById("status");
|
var status = document.getElementById("status");
|
||||||
status.textContent = "Options saved";
|
status.textContent = "Options saved";
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
status.textContent = "";
|
status.textContent = "";
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
@@ -255,8 +257,9 @@ function save_options() {
|
|||||||
|
|
||||||
// Restores options from chrome.storage
|
// Restores options from chrome.storage
|
||||||
function restore_options() {
|
function restore_options() {
|
||||||
chrome.storage.sync.get(tcDefaults, function(storage) {
|
chrome.storage.sync.get(tcDefaults, function (storage) {
|
||||||
document.getElementById("rememberSpeed").checked = storage.rememberSpeed;
|
document.getElementById("rememberSpeed").checked = storage.rememberSpeed;
|
||||||
|
document.getElementById("forceLastSavedSpeed").checked = storage.forceLastSavedSpeed;
|
||||||
document.getElementById("audioBoolean").checked = storage.audioBoolean;
|
document.getElementById("audioBoolean").checked = storage.audioBoolean;
|
||||||
document.getElementById("enabled").checked = storage.enabled;
|
document.getElementById("enabled").checked = storage.enabled;
|
||||||
document.getElementById("startHidden").checked = storage.startHidden;
|
document.getElementById("startHidden").checked = storage.startHidden;
|
||||||
@@ -265,7 +268,7 @@ function restore_options() {
|
|||||||
document.getElementById("blacklist").value = storage.blacklist;
|
document.getElementById("blacklist").value = storage.blacklist;
|
||||||
|
|
||||||
// ensure that there is a "display" binding for upgrades from versions that had it as a separate binding
|
// 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({
|
storage.keyBindings.push({
|
||||||
action: "display",
|
action: "display",
|
||||||
value: 0,
|
value: 0,
|
||||||
@@ -317,15 +320,15 @@ function restore_options() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function restore_defaults() {
|
function restore_defaults() {
|
||||||
chrome.storage.sync.set(tcDefaults, function() {
|
chrome.storage.sync.set(tcDefaults, function () {
|
||||||
restore_options();
|
restore_options();
|
||||||
document
|
document
|
||||||
.querySelectorAll(".removeParent")
|
.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.
|
// Update status to let user know options were saved.
|
||||||
var status = document.getElementById("status");
|
var status = document.getElementById("status");
|
||||||
status.textContent = "Default options restored";
|
status.textContent = "Default options restored";
|
||||||
setTimeout(function() {
|
setTimeout(function () {
|
||||||
status.textContent = "";
|
status.textContent = "";
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
@@ -334,10 +337,10 @@ function restore_defaults() {
|
|||||||
function show_experimental() {
|
function show_experimental() {
|
||||||
document
|
document
|
||||||
.querySelectorAll(".customForce")
|
.querySelectorAll(".customForce")
|
||||||
.forEach(item => (item.style.display = "inline-block"));
|
.forEach((item) => (item.style.display = "inline-block"));
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
restore_options();
|
restore_options();
|
||||||
|
|
||||||
document.getElementById("save").addEventListener("click", save_options);
|
document.getElementById("save").addEventListener("click", save_options);
|
||||||
@@ -356,25 +359,25 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
funcName(event);
|
funcName(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
document.addEventListener("keypress", event => {
|
document.addEventListener("keypress", (event) => {
|
||||||
eventCaller(event, "customValue", inputFilterNumbersOnly);
|
eventCaller(event, "customValue", inputFilterNumbersOnly);
|
||||||
});
|
});
|
||||||
document.addEventListener("focus", event => {
|
document.addEventListener("focus", (event) => {
|
||||||
eventCaller(event, "customKey", inputFocus);
|
eventCaller(event, "customKey", inputFocus);
|
||||||
});
|
});
|
||||||
document.addEventListener("blur", event => {
|
document.addEventListener("blur", (event) => {
|
||||||
eventCaller(event, "customKey", inputBlur);
|
eventCaller(event, "customKey", inputBlur);
|
||||||
});
|
});
|
||||||
document.addEventListener("keydown", event => {
|
document.addEventListener("keydown", (event) => {
|
||||||
eventCaller(event, "customKey", recordKeyPress);
|
eventCaller(event, "customKey", recordKeyPress);
|
||||||
});
|
});
|
||||||
document.addEventListener("click", event => {
|
document.addEventListener("click", (event) => {
|
||||||
eventCaller(event, "removeParent", function() {
|
eventCaller(event, "removeParent", function () {
|
||||||
event.target.parentNode.remove();
|
event.target.parentNode.remove();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
document.addEventListener("change", event => {
|
document.addEventListener("change", (event) => {
|
||||||
eventCaller(event, "customDo", function() {
|
eventCaller(event, "customDo", function () {
|
||||||
if (customActionsNoValues.includes(event.target.value)) {
|
if (customActionsNoValues.includes(event.target.value)) {
|
||||||
event.target.nextElementSibling.nextElementSibling.disabled = true;
|
event.target.nextElementSibling.nextElementSibling.disabled = true;
|
||||||
event.target.nextElementSibling.nextElementSibling.value = 0;
|
event.target.nextElementSibling.nextElementSibling.value = 0;
|
||||||
|
18
popup.js
18
popup.js
@@ -1,25 +1,25 @@
|
|||||||
document.addEventListener("DOMContentLoaded", function() {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
document.querySelector("#config").addEventListener("click", function() {
|
document.querySelector("#config").addEventListener("click", function () {
|
||||||
window.open(chrome.runtime.getURL("options.html"));
|
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");
|
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");
|
window.open("https://github.com/codebicycle/videospeed/issues");
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector("#enable").addEventListener("click", function() {
|
document.querySelector("#enable").addEventListener("click", function () {
|
||||||
toggleEnabled(true, settingsSavedReloadMessage);
|
toggleEnabled(true, settingsSavedReloadMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
document.querySelector("#disable").addEventListener("click", function() {
|
document.querySelector("#disable").addEventListener("click", function () {
|
||||||
toggleEnabled(false, settingsSavedReloadMessage);
|
toggleEnabled(false, settingsSavedReloadMessage);
|
||||||
});
|
});
|
||||||
|
|
||||||
chrome.storage.sync.get({ enabled: true }, function(storage) {
|
chrome.storage.sync.get({ enabled: true }, function (storage) {
|
||||||
toggleEnabledUI(storage.enabled);
|
toggleEnabledUI(storage.enabled);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ document.addEventListener("DOMContentLoaded", function() {
|
|||||||
{
|
{
|
||||||
enabled: enabled
|
enabled: enabled
|
||||||
},
|
},
|
||||||
function() {
|
function () {
|
||||||
toggleEnabledUI(enabled);
|
toggleEnabledUI(enabled);
|
||||||
if (callback) callback(enabled);
|
if (callback) callback(enabled);
|
||||||
}
|
}
|
||||||
|
26
shadow.css
26
shadow.css
@@ -1,6 +1,6 @@
|
|||||||
* {
|
* {
|
||||||
line-height: 1.8em;
|
line-height: 1.8em;
|
||||||
font-family: Verdana, Geneva, sans-serif;
|
font-family: sans-serif;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -16,8 +16,8 @@
|
|||||||
background: black;
|
background: black;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
border-radius: 5px;
|
border-radius: 30px;
|
||||||
padding: 5px;
|
padding: 6px 12px 6px 12px;
|
||||||
margin: 10px 10px 10px 15px;
|
margin: 10px 10px 10px 15px;
|
||||||
|
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@@ -57,17 +57,19 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
|
opacity: 1;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: black;
|
color: black;
|
||||||
background: white;
|
background: white;
|
||||||
font-weight: bold;
|
font-weight: normal;
|
||||||
border-radius: 5px;
|
border-radius: 20px;
|
||||||
padding: 1px 6px 3px 6px;
|
padding: 1px 5px 3px 5px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
border: 1px solid white;
|
border: 0px solid white;
|
||||||
font-family: "Lucida Console", Monaco, monospace;
|
font-family: "Lucida Console", Monaco, monospace;
|
||||||
margin-bottom: 2px;
|
margin: 0px 2px 2px 2px;
|
||||||
|
transition: background 0.2s, color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:focus {
|
button:focus {
|
||||||
@@ -76,10 +78,14 @@ button:focus {
|
|||||||
|
|
||||||
button:hover {
|
button:hover {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
|
background: #2196f3;
|
||||||
|
color: #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
button:active {
|
button:active {
|
||||||
background: #ccc;
|
background: #2196f3;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
button.rw {
|
button.rw {
|
||||||
@@ -87,6 +93,6 @@ button.rw {
|
|||||||
}
|
}
|
||||||
|
|
||||||
button.hideButton {
|
button.hideButton {
|
||||||
|
opacity: 0.65;
|
||||||
margin-right: 2px;
|
margin-right: 2px;
|
||||||
opacity: 0.5;
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user