Apple tv plus (#541)

* add support for traversing shadowRoot's; enables apple tv support.
This commit is contained in:
jedawson
2020-02-06 16:07:33 -06:00
committed by GitHub
parent 0389c61db7
commit 4ac2e458f5

View File

@@ -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');