diff --git a/umbra/behaviors.d/default.js b/umbra/behaviors.d/default.js index 4470cab..e3f5665 100644 --- a/umbra/behaviors.d/default.js +++ b/umbra/behaviors.d/default.js @@ -2,19 +2,116 @@ // // Scrolls to the bottom of the page. That's it at the moment. // +var umbraAboveBelowOrOnScreen = function(e) { + var eTop = e.getBoundingClientRect().top; + if (eTop < window.scrollY) { + return -1; // above + } else if (eTop > window.scrollY + window.innerHeight) { + return 1; // below + } else { + return 0; // on screen + } +} +var UMBRA_IFRAME_SOUNDCLOUD_EMBEDDED_SELECTOR = "iframe"; +var UMBRA_THINGS_TO_CLICK_SOUNDCLOUD_EMBEDDED_SELECTOR = "button.sc-button-play, button.playButton"; +var MAX_IFRAME_RECURSE_DEPTH = 1; //0-based var umbraState = {'idleSince':null}; +var umbraAlreadyClicked = {}; var umbraFinished = false; var umbraIntervalFunc = function() { - var needToScroll = (window.scrollY + window.innerHeight < document.documentElement.scrollHeight); - // console.log('intervalFunc umbraState.idleSince=' + umbraState.idleSince + ' needToScroll=' + needToScroll + ' window.scrollY=' + window.scrollY + ' window.innerHeight=' + window.innerHeight + ' document.documentElement.scrollHeight=' + document.documentElement.scrollHeight); - if (needToScroll) { - window.scrollBy(0, 200); - umbraState.idleSince = null; - } else if (umbraState.idleSince == null) { + var umbraSoundCloudEmbeddedElements = []; + + getUmbraSoundCloudEmbeddedElements(umbraSoundCloudEmbeddedElements); + + var clickedSomething = false; + var somethingLeftBelow = false; + var somethingLeftAbove = false; + var missedAbove = 0; + + for (var i = 0; i < umbraSoundCloudEmbeddedElements.length; i++) { + + var targetId = umbraSoundCloudEmbeddedElements[i].id; + var target = umbraSoundCloudEmbeddedElements[i].target; + + if (!(targetId in umbraAlreadyClicked)) { + + var where = umbraAboveBelowOrOnScreen(target); + + if (where == 0) { // on screen + // var pos = target.getBoundingClientRect().top; + // window.scrollTo(0, target.getBoundingClientRect().top - 100); + console.log("clicking at " + target.getBoundingClientRect().top + " on " + target.outerHTML); + if (target.click != undefined) { + target.click(); + } + umbraAlreadyClicked[targetId] = true; + clickedSomething = true; + umbraState.idleSince = null; + break; + } else if (where > 0) { + somethingLeftBelow = true; + } else if (where < 0) { + somethingLeftAbove = true; + } + } + } + + if (!clickedSomething) { + if (somethingLeftAbove) { + console.log("scrolling UP because everything on this screen has been clicked but we missed something above"); + window.scrollBy(0, -500); + umbraState.idleSince = null; + } else if (somethingLeftBelow) { + console.log("scrolling because everything on this screen has been clicked but there's more below document.body.clientHeight=" + document.body.clientHeight); + window.scrollBy(0, 200); + umbraState.idleSince = null; + } else if (window.scrollY + window.innerHeight < document.documentElement.scrollHeight) { + console.log("scrolling because we're not to the bottom yet document.body.clientHeight=" + document.body.clientHeight); + window.scrollBy(0, 200); + umbraState.idleSince = null; + } else if (umbraState.idleSince == null) { umbraState.idleSince = Date.now(); } + } + + if (umbraState.idleSince == null) { + umbraState.idleSince = Date.now(); + } +} + +//try to detect sound cloud "Play" buttons and return them as targets for clicking +var getUmbraSoundCloudEmbeddedElements = function(soundCloudEmbeddedElements, currentIframeDepth, currentDocument, + iframeElement) { + + //set default values for parameters + currentIframeDepth = currentIframeDepth || 0; + currentDocument = currentDocument || document; + + if (currentIframeDepth > MAX_IFRAME_RECURSE_DEPTH) { + return; + } + + //collect all buttons on current document first + var button = []; + + button = currentDocument.querySelectorAll(UMBRA_THINGS_TO_CLICK_SOUNDCLOUD_EMBEDDED_SELECTOR); + + var cssPathIframe = iframeElement ? getElementCssPath(iframeElement) : ""; + + for (var i = 0; i < button.length; i++) { + soundCloudEmbeddedElements.push({"id" : cssPathIframe + getElementCssPath(button.item(i)), "target" : button.item(i)}); + } + + //now get all buttons in embedded iframes + var iframe = []; + + iframe = currentDocument.querySelectorAll(UMBRA_IFRAME_SOUNDCLOUD_EMBEDDED_SELECTOR); + + for (var i = 0; i < iframe.length; i++) { + getUmbraSoundCloudEmbeddedElements(soundCloudEmbeddedElements, currentIframeDepth + 1, iframe[i].contentWindow.document.body, iframe[i]); + } } // If we haven't had anything to do (scrolled, clicked, etc) in this amount of @@ -32,4 +129,30 @@ var umbraBehaviorFinished = function() { return false; } +//copied from http://stackoverflow.com/questions/4588119/get-elements-css-selector-without-element-id +var getElementCssPath = function(element) { + + var names = []; + + while (element.parentNode){ + if (element.id){ + names.unshift('#' + element.id); + break; + } else { + if (element == element.ownerDocument.documentElement) { + names.unshift(element.tagName); + } + else { + for (var c = 1, e = element; e.previousElementSibling; e = e.previousElementSibling, c++); + + names.unshift(element.tagName + ":nth-child(" + c + ")"); + } + + element = element.parentNode; + } + } + + return names.join(" > "); +} + var umbraIntervalId = setInterval(umbraIntervalFunc, 100); diff --git a/umbra/browser.py b/umbra/browser.py index 68fa49a..c72bd3e 100644 --- a/umbra/browser.py +++ b/umbra/browser.py @@ -231,7 +231,7 @@ class Chrome: # returns websocket url to chrome window with about:blank loaded def start(self): - timeout_sec = 60 + timeout_sec = 600 new_env = os.environ.copy() new_env["HOME"] = self.user_home_dir chrome_args = [self.executable, @@ -242,6 +242,7 @@ class Chrome: "--window-size=1100,900", "--no-default-browser-check", "--disable-first-run-ui", "--no-first-run", "--homepage=about:blank", "--disable-direct-npapi-requests", + "--disable-web-security", "about:blank"] self.logger.info("running {}".format(chrome_args)) self.chrome_process = subprocess.Popen(chrome_args, env=new_env, start_new_session=True) @@ -270,7 +271,7 @@ class Chrome: time.sleep(0.5) def stop(self): - timeout_sec = 60 + timeout_sec = 300 self.logger.info("terminating chrome pid {}".format(self.chrome_process.pid)) self.chrome_process.terminate()