mirror of
https://github.com/SoPat712/videospeed.git
synced 2025-08-21 09:58:45 -04:00
Apple tv plus (#541)
* add support for traversing shadowRoot's; enables apple tv support.
This commit is contained in:
95
inject.js
95
inject.js
@@ -180,7 +180,7 @@
|
||||
var observer=new MutationObserver((mutations) => {
|
||||
mutations.forEach((mutation) => {
|
||||
if (mutation.type === 'attributes' && (mutation.attributeName === 'src' || mutation.attributeName === 'currentSrc')){
|
||||
var controller = document.querySelector(`div[data-vscid="${this.id}"]`);
|
||||
var controller = getController(this.id)
|
||||
if(!controller){
|
||||
return;
|
||||
}
|
||||
@@ -268,6 +268,9 @@
|
||||
// insert before parent to bypass overlay
|
||||
this.parent.parentElement.insertBefore(fragment, this.parent);
|
||||
break;
|
||||
case (location.hostname == 'tv.apple.com'):
|
||||
// insert after parent for correct stacking context
|
||||
this.parent.getRootNode().querySelector('.scrim').prepend(fragment);
|
||||
|
||||
default:
|
||||
// Note: when triggered via a MutationRecord, it's possible that the
|
||||
@@ -333,6 +336,32 @@
|
||||
return true;
|
||||
}
|
||||
}
|
||||
function getShadow(parent) {
|
||||
let result = []
|
||||
function getChild(parent) {
|
||||
if (parent.firstElementChild) {
|
||||
var child = parent.firstElementChild
|
||||
do {
|
||||
result = result.concat(child)
|
||||
getChild(child)
|
||||
if (child.shadowRoot) {
|
||||
result = result.concat(getShadow(child.shadowRoot))
|
||||
}
|
||||
child = child.nextElementSibling
|
||||
} while (child)
|
||||
}
|
||||
}
|
||||
getChild(parent)
|
||||
return result
|
||||
}
|
||||
function getController(id){
|
||||
return getShadow(document.body).filter(x => {
|
||||
return x.attributes['data-vscid'] &&
|
||||
x.tagName == 'DIV' &&
|
||||
x.attributes['data-vscid'].value==`${id}`
|
||||
})[0]
|
||||
}
|
||||
|
||||
function initializeNow(document) {
|
||||
if (!tc.settings.enabled) return;
|
||||
// enforce init-once due to redundant callers
|
||||
@@ -380,7 +409,7 @@
|
||||
}
|
||||
|
||||
// Ignore keydown event if typing in a page without vsc
|
||||
if (!document.querySelector(".vsc-controller")) {
|
||||
if (!getShadow(document.body).filter(x => x.tagName == 'vsc-controller')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -424,27 +453,48 @@
|
||||
// Process the DOM nodes lazily
|
||||
requestIdleCallback(_ => {
|
||||
mutations.forEach(function(mutation) {
|
||||
forEach.call(mutation.addedNodes, function(node) {
|
||||
if (typeof node === "function")
|
||||
return;
|
||||
checkForVideo(node, node.parentNode || mutation.target, true);
|
||||
});
|
||||
forEach.call(mutation.removedNodes, function(node) {
|
||||
if (typeof node === "function")
|
||||
return;
|
||||
checkForVideo(node, node.parentNode || mutation.target, false);
|
||||
});
|
||||
switch (mutation.type) {
|
||||
case 'childList':
|
||||
forEach.call(mutation.addedNodes, function(node) {
|
||||
if (typeof node === "function")
|
||||
return;
|
||||
checkForVideo(node, node.parentNode || mutation.target, true);
|
||||
});
|
||||
forEach.call(mutation.removedNodes, function(node) {
|
||||
if (typeof node === "function")
|
||||
return;
|
||||
checkForVideo(node, node.parentNode || mutation.target, false);
|
||||
});
|
||||
break;
|
||||
case 'attributes':
|
||||
if (mutation.target.attributes['aria-hidden'].value == "false") {
|
||||
var flattenedNodes = getShadow(document.body)
|
||||
var node = flattenedNodes.filter(x => x.tagName == 'VIDEO')[0]
|
||||
if (node) {
|
||||
var oldController = flattenedNodes.filter(x => x.classList.contains('vsc-controller'))[0]
|
||||
if (oldController) {
|
||||
oldController.remove()
|
||||
}
|
||||
checkForVideo(node, node.parentNode || mutation.target, true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
});
|
||||
}, {timeout: 1000});
|
||||
});
|
||||
observer.observe(document, { childList: true, subtree: true });
|
||||
observer.observe(document, {
|
||||
attributeFilter: ['aria-hidden'],
|
||||
childList: true,
|
||||
subtree: true
|
||||
});
|
||||
|
||||
if (tc.settings.audioBoolean) {
|
||||
var mediaTags = document.querySelectorAll('video,audio');
|
||||
} else {
|
||||
var mediaTags = document.querySelectorAll('video');
|
||||
}
|
||||
|
||||
|
||||
forEach.call(mediaTags, function(video) {
|
||||
video.vsc = new tc.videoController(video);
|
||||
});
|
||||
@@ -459,9 +509,11 @@
|
||||
|
||||
function runAction(action, document, value, e) {
|
||||
if (tc.settings.audioBoolean) {
|
||||
var mediaTags = document.querySelectorAll('video,audio');
|
||||
var mediaTags = getShadow(document.body).filter(x => {
|
||||
return x.tagName == 'AUDIO' || x.tagName == 'VIDEO'
|
||||
});
|
||||
} else {
|
||||
var mediaTags = document.querySelectorAll('video');
|
||||
var mediaTags = getShadow(document.body).filter(x => x.tagName == 'VIDEO');
|
||||
}
|
||||
|
||||
mediaTags.forEach = Array.prototype.forEach;
|
||||
@@ -469,13 +521,12 @@
|
||||
// Get the controller that was used if called from a button press event e
|
||||
if (e) {
|
||||
var targetController = e.target.getRootNode().host;
|
||||
}
|
||||
}
|
||||
|
||||
mediaTags.forEach(function(v) {
|
||||
var id = v.dataset['vscid'];
|
||||
var controller = document.querySelector(`div[data-vscid="${id}"]`);
|
||||
|
||||
// Don't change video speed if the video has a different controller
|
||||
var controller = getController(id)
|
||||
// Don't change video speed if the video has a different controller
|
||||
if (e && !(targetController == controller)) {
|
||||
return;
|
||||
}
|
||||
@@ -564,13 +615,13 @@
|
||||
function setMark(v) {
|
||||
v.vsc.mark = v.currentTime;
|
||||
}
|
||||
|
||||
|
||||
function jumpToMark(v) {
|
||||
if (v.vsc.mark && typeof v.vsc.mark === "number") {
|
||||
v.currentTime = v.vsc.mark;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleDrag(video, controller, e) {
|
||||
const shadowController = controller.shadowRoot.querySelector('#controller');
|
||||
|
||||
|
Reference in New Issue
Block a user