From 7afdd7b50b525141d84ee7fe99d3f7e03f43bf53 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Tue, 2 Sep 2014 17:02:30 -0700 Subject: [PATCH 1/5] Added behavior for instagram to scroll past two pages, and click to enlarge images. --- umbra/behaviors.d/instagram.js | 78 ++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 umbra/behaviors.d/instagram.js diff --git a/umbra/behaviors.d/instagram.js b/umbra/behaviors.d/instagram.js new file mode 100644 index 0000000..b89685b --- /dev/null +++ b/umbra/behaviors.d/instagram.js @@ -0,0 +1,78 @@ +// {"url_regex":"^https?://(?:www\\.)?instagram\\.com/.*$", "request_idle_timeout_sec":10} +// +// vim:set sw=8 et: +// + +var umbraState = {'idleSince':null,'done':null}; + + +var intervalID = setInterval(scrollInterval,50); +var images; +var imageID=0; +var imageCount=0; +function scrollInterval() { + scroll(); + + //if not at the bottom + if(window.scrollY + window.innerHeight < document.documentElement.scrollHeight) { + umbraState.idleSince=Date.now(); + } + else { + var more = document.querySelectorAll("span.more-photos a.more-photos-enabled"); + if(more.length>0) { + more[0].click(); + umbraState.idleSince=Date.now(); + } + else if(document.querySelectorAll("span.more-photos a.more-photos-disabled").length>0) { //finally done scrolling/loading + clearInterval(intervalID); + umbraState.idleSince=null; + images = document.querySelectorAll("li.photo div.photo-wrapper a.bg[data-reactid]"); + if(images && images !=='undefined' && images.length>0 ) { + images[0].click(); + imageID++; + imageCount=images.length; + } + intervalID = setInterval(clickPhotosInterval,200); + } + } +} + +function clickPhotosInterval() { + rightArrow = document.querySelectorAll("a.mmRightArrow"); + + if(imageID>=imageCount) { + clearInterval(intervalID); + umbraState.done=true; + umbraState.idleSince=(Date.now()-50000);//ready to exit + } + else { + rightArrow[0].click(); + imageID++; + umbraState.idleSince=Date.now(); + } +} + +function scroll() { + window.scrollBy(0,50); +} + + +// If we haven't had anything to do (scrolled, clicked, etc) in this amount of +// time, then we consider ourselves finished with the page. + +var UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC = 10; + +// Called from outside of this script. +var umbraBehaviorFinished = function() { + if(umbraState.done!=null && umbraState.done==true) { + return true; + } + if (umbraState.idleSince != null) { + var idleTimeMs = Date.now() - umbraState.idleSince; + if (idleTimeMs / 1000 > UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC) { + return true; + } + } + return false; +} + From 916f1b990e8df15a61455d8a26f33b8a88ebf05d Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Wed, 17 Sep 2014 16:26:53 -0700 Subject: [PATCH 2/5] Cleanup instagram timeout and state handling --- umbra/behaviors.d/instagram.js | 87 +++++++++++++++------------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/umbra/behaviors.d/instagram.js b/umbra/behaviors.d/instagram.js index b89685b..553d059 100644 --- a/umbra/behaviors.d/instagram.js +++ b/umbra/behaviors.d/instagram.js @@ -2,77 +2,68 @@ // // vim:set sw=8 et: // +var UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC = 10; -var umbraState = {'idleSince':null,'done':null}; +var umbraState = {'idleSince':null,'expectingSomething':null,'done':false}; +var umbraIntervalID = setInterval(umbraScrollInterval,50); +var umbraImages; +var umbraImageID=0; +var umbraImageCount=0; -var intervalID = setInterval(scrollInterval,50); -var images; -var imageID=0; -var imageCount=0; -function scrollInterval() { - scroll(); +function umbraScrollInterval() { - //if not at the bottom - if(window.scrollY + window.innerHeight < document.documentElement.scrollHeight) { - umbraState.idleSince=Date.now(); - } - else { + //if not at the bottom, keep scrolling + if(window.scrollY + window.innerHeight < document.documentElement.scrollHeight) { + window.scrollBy(0,50); + umbraState.expectingSomething=null; + umbraState.idleSince=null; + } + else { var more = document.querySelectorAll("span.more-photos a.more-photos-enabled"); - if(more.length>0) { + if(more.length>0 && umbraState.expectingSomething==null) { more[0].click(); + umbraState.expectingSomething="load more"; umbraState.idleSince=Date.now(); } - else if(document.querySelectorAll("span.more-photos a.more-photos-disabled").length>0) { //finally done scrolling/loading - clearInterval(intervalID); - umbraState.idleSince=null; - images = document.querySelectorAll("li.photo div.photo-wrapper a.bg[data-reactid]"); - if(images && images !=='undefined' && images.length>0 ) { - images[0].click(); - imageID++; - imageCount=images.length; + else if(document.querySelectorAll("span.more-photos a.more-photos-disabled").length>0 || umbraTimeoutExpired() ) { //done scrolling/loading + clearInterval(umbraIntervalID); + umbraImages = document.querySelectorAll("li.photo div.photo-wrapper a.bg[data-reactid]"); + + //click first image + if(umbraImages && umbraImages !=='undefined' && umbraImages.length>0 ) { + umbraImages[0].click(); + umbraImageID++; + umbraImageCount=umbraImages.length; } - intervalID = setInterval(clickPhotosInterval,200); + intervalID = setInterval(umbraClickPhotosInterval,200); } - } + } } -function clickPhotosInterval() { +function umbraClickPhotosInterval() { rightArrow = document.querySelectorAll("a.mmRightArrow"); - if(imageID>=imageCount) { - clearInterval(intervalID); - umbraState.done=true; - umbraState.idleSince=(Date.now()-50000);//ready to exit + if(umbraImageID>=umbraImageCount) { + clearInterval(umbraIntervalID); + umbraState.done=true } else { rightArrow[0].click(); - imageID++; - umbraState.idleSince=Date.now(); + umbraImageID++; } } -function scroll() { - window.scrollBy(0,50); -} - - -// If we haven't had anything to do (scrolled, clicked, etc) in this amount of -// time, then we consider ourselves finished with the page. - -var UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC = 10; - -// Called from outside of this script. -var umbraBehaviorFinished = function() { - if(umbraState.done!=null && umbraState.done==true) { - return true; - } +function umbraTimeoutExpired () { if (umbraState.idleSince != null) { var idleTimeMs = Date.now() - umbraState.idleSince; - if (idleTimeMs / 1000 > UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC) { - return true; - } + return (idleTimeMs/1000 > UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC); } return false; } + +// Called from outside of this script. +var umbraBehaviorFinished = function() { + return umbraState.done; +} From bdf3e73062edbfc3c1ae68b8792962fa95d87148 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Fri, 3 Oct 2014 14:17:07 -0700 Subject: [PATCH 3/5] Wait until big image is loaded before clicking to next image. --- umbra/behaviors.d/instagram.js | 35 +++++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/umbra/behaviors.d/instagram.js b/umbra/behaviors.d/instagram.js index 553d059..b6b7d78 100644 --- a/umbra/behaviors.d/instagram.js +++ b/umbra/behaviors.d/instagram.js @@ -10,6 +10,7 @@ var umbraIntervalID = setInterval(umbraScrollInterval,50); var umbraImages; var umbraImageID=0; var umbraImageCount=0; +var umbraBigImage=undefined; function umbraScrollInterval() { @@ -35,22 +36,42 @@ function umbraScrollInterval() { umbraImages[0].click(); umbraImageID++; umbraImageCount=umbraImages.length; + intervalID = setInterval(umbraClickPhotosInterval,200); } - intervalID = setInterval(umbraClickPhotosInterval,200); + } } } function umbraClickPhotosInterval() { + rightArrow = document.querySelectorAll("a.mmRightArrow"); - - if(umbraImageID>=umbraImageCount) { - clearInterval(umbraIntervalID); - umbraState.done=true + + if(umbraIsBigImageLoaded()) { + if(umbraImageID>=umbraImageCount) { + clearInterval(umbraIntervalID); + umbraState.done=true; + } + else { + umbraBigImage = undefined; + rightArrow[0].click(); + umbraImageID++; + } + } +} + +function umbraIsBigImageLoaded(){ + if(umbraBigImage === undefined) { + var imageFrame = document.querySelectorAll("div.Modal div.Item div.iMedia div.Frame"); + if(imageFrame.length>0) { + umbraBigImage = new Image(); + umbraBigImage.src = imageFrame[0].getAttribute("src"); + } + return false; } else { - rightArrow[0].click(); - umbraImageID++; + return (umbraBigImage.naturalWidth !== 0) + } } From cdcef934e7ceadf28f2d73745f620d8492d7da51 Mon Sep 17 00:00:00 2001 From: Noah Levitt Date: Fri, 16 Jan 2015 13:21:12 -0800 Subject: [PATCH 4/5] rewrite instagram behavior to be more like a state machine; update css selectors for current instagram; refactor as a sort of singleton class for cleaner namespacing --- umbra/behaviors.d/instagram.js | 181 +++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 75 deletions(-) diff --git a/umbra/behaviors.d/instagram.js b/umbra/behaviors.d/instagram.js index b6b7d78..995786f 100644 --- a/umbra/behaviors.d/instagram.js +++ b/umbra/behaviors.d/instagram.js @@ -2,89 +2,120 @@ // // vim:set sw=8 et: // -var UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC = 10; -var umbraState = {'idleSince':null,'expectingSomething':null,'done':false}; +var umbraInstagramBehavior = { + IDLE_TIMEOUT_SEC: 10, + idleSince: null, + state: "loading-thumbs", + imageCount: null, + bigImagesLoaded: 0, + latestBigImage: null, -var umbraIntervalID = setInterval(umbraScrollInterval,50); -var umbraImages; -var umbraImageID=0; -var umbraImageCount=0; -var umbraBigImage=undefined; + intervalFunc: function() { + if (this.state === "loading-thumbs") { + if (window.scrollY + window.innerHeight < document.documentElement.scrollHeight) { + window.scrollBy(0, 200); + this.idleSince = null; + return; + } -function umbraScrollInterval() { + var moreButtons = document.querySelectorAll(".PhotoGridMoreButton:not(.pgmbDisabled)"); + if (moreButtons.length > 0) { + console.log("clicking load more button"); + moreButtons[0].click(); + this.idleSince = null; + return; + } + + if (this.idleSince == null) { + console.log("nothing to do at the moment, might be waiting for something to load, setting this.idleSince=Date.now()"); + this.idleSince = Date.now(); + return; + } else if (Date.now() - this.idleSince > 3000) { + console.log("finished loading-thumbs, it appears we have reached the bottom"); + this.state = "clicking-first-thumb"; + this.idleSince = null; + return; + } else { + // console.log("still might be waiting for something to load..."); + return; + } + } - //if not at the bottom, keep scrolling - if(window.scrollY + window.innerHeight < document.documentElement.scrollHeight) { - window.scrollBy(0,50); - umbraState.expectingSomething=null; - umbraState.idleSince=null; - } - else { - var more = document.querySelectorAll("span.more-photos a.more-photos-enabled"); - if(more.length>0 && umbraState.expectingSomething==null) { - more[0].click(); - umbraState.expectingSomething="load more"; - umbraState.idleSince=Date.now(); - } - else if(document.querySelectorAll("span.more-photos a.more-photos-disabled").length>0 || umbraTimeoutExpired() ) { //done scrolling/loading - clearInterval(umbraIntervalID); - umbraImages = document.querySelectorAll("li.photo div.photo-wrapper a.bg[data-reactid]"); - - //click first image - if(umbraImages && umbraImages !=='undefined' && umbraImages.length>0 ) { - umbraImages[0].click(); - umbraImageID++; - umbraImageCount=umbraImages.length; - intervalID = setInterval(umbraClickPhotosInterval,200); - } - - } - } -} + if (this.state === "clicking-first-thumb") { + var images = document.querySelectorAll("a.pgmiImageLink"); + if (images && images !== "undefined") { + this.imageCount = images.length; + if (images.length > 0) { + console.log("clicking first thumbnail"); + images[0].click(); + this.idleSince = null; + this.state = "waiting-big-image"; + return; + } + } -function umbraClickPhotosInterval() { + console.log("no big images to load?"); + this.idleSince = Date.now(); + return; + } - rightArrow = document.querySelectorAll("a.mmRightArrow"); + if (this.state === "waiting-big-image") { + var imageFrame = document.querySelectorAll("div.Modal div.Item div.iMedia div.Image"); + if (imageFrame.length > 0) { + var bigImage = new Image(); + bigImage.src = imageFrame[0].getAttribute("src"); + // console.log("bigImage.naturalWidth=" + bigImage.naturalWidth + " bigImage.src=" + bigImage.src); + if (bigImage.src !== this.latestBigImage && bigImage.naturalWidth !== 0) { + console.log("next big image appears loaded, will click right arrow next time"); + this.state = "click-next-big-image"; + this.latestBigImage = bigImage.src; + this.bigImagesLoaded++; + this.idleSince = null; + return; + } + } + if (this.bigImagesLoaded >= this.imageCount) { + console.log("looks like we're done, we've loaded all " + this.bigImagesLoaded + " of " + this.imageCount + " big images"); + this.state = "finished"; + this.idleSince = Date.now(); + } + return; + } - if(umbraIsBigImageLoaded()) { - if(umbraImageID>=umbraImageCount) { - clearInterval(umbraIntervalID); - umbraState.done=true; - } - else { - umbraBigImage = undefined; - rightArrow[0].click(); - umbraImageID++; - } - } -} + if (this.state === "click-next-big-image") { + var rightArrow = document.querySelectorAll("a.mmRightArrow"); + if (rightArrow.length > 0) { + // console.log("clicking right arrow"); + rightArrow[0].click(); + this.state = "waiting-big-image"; + this.idleSince = null; + return; + } else { + console.warn("no right arrow to click?? weird"); + this.idleSince = Date.now(); + return; + } + } + }, -function umbraIsBigImageLoaded(){ - if(umbraBigImage === undefined) { - var imageFrame = document.querySelectorAll("div.Modal div.Item div.iMedia div.Frame"); - if(imageFrame.length>0) { - umbraBigImage = new Image(); - umbraBigImage.src = imageFrame[0].getAttribute("src"); - } - return false; - } - else { - return (umbraBigImage.naturalWidth !== 0) + start: function() { + var that = this; + this.intervalId = setInterval(function(){ that.intervalFunc() }, 50); + }, - } -} - -function umbraTimeoutExpired () { - if (umbraState.idleSince != null) { - var idleTimeMs = Date.now() - umbraState.idleSince; - return (idleTimeMs/1000 > UMBRA_USER_ACTION_IDLE_TIMEOUT_SEC); - } - return false; -} + isFinished: function() { + if (this.idleSince != null) { + var idleTimeMs = Date.now() - this.idleSince; + if (idleTimeMs / 1000 > this.IDLE_TIMEOUT_SEC) { + return true; + } + } + return false; + }, +}; // Called from outside of this script. -var umbraBehaviorFinished = function() { - return umbraState.done; -} - +var umbraBehaviorFinished = function() { return umbraInstagramBehavior.isFinished() }; + +umbraInstagramBehavior.start(); From ce474616569aca08a7c75e672dc801c2712a3177 Mon Sep 17 00:00:00 2001 From: Adam Miller Date: Fri, 30 Jan 2015 16:55:53 -0800 Subject: [PATCH 5/5] Making scrolling and image loading more tolerant of slow loading. --- umbra/behaviors.d/instagram.js | 72 +++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 28 deletions(-) diff --git a/umbra/behaviors.d/instagram.js b/umbra/behaviors.d/instagram.js index 995786f..8955fbc 100644 --- a/umbra/behaviors.d/instagram.js +++ b/umbra/behaviors.d/instagram.js @@ -4,12 +4,13 @@ // var umbraInstagramBehavior = { - IDLE_TIMEOUT_SEC: 10, + IDLE_TIMEOUT_SEC: 20, idleSince: null, state: "loading-thumbs", imageCount: null, bigImagesLoaded: 0, - latestBigImage: null, + currentBigImage: null, + previousBigImage: null, intervalFunc: function() { if (this.state === "loading-thumbs") { @@ -31,15 +32,18 @@ var umbraInstagramBehavior = { console.log("nothing to do at the moment, might be waiting for something to load, setting this.idleSince=Date.now()"); this.idleSince = Date.now(); return; - } else if (Date.now() - this.idleSince > 3000) { - console.log("finished loading-thumbs, it appears we have reached the bottom"); - this.state = "clicking-first-thumb"; - this.idleSince = null; - return; - } else { - // console.log("still might be waiting for something to load..."); - return; - } + } else { + var doneButtons = document.querySelectorAll(".PhotoGridMoreButton.pgmbDisabled"); + if (Date.now() - this.idleSince > 9000 || (doneButtons.length > 0 && doneButtons[0].innerText === "All items loaded") ) { + console.log("finished loading-thumbs, it appears we have reached the bottom"); + this.state = "clicking-first-thumb"; + this.idleSince = null; + return; + } else { + // console.log("still might be waiting for something to load..."); + return; + } + } } if (this.state === "clicking-first-thumb") { @@ -61,26 +65,38 @@ var umbraInstagramBehavior = { } if (this.state === "waiting-big-image") { - var imageFrame = document.querySelectorAll("div.Modal div.Item div.iMedia div.Image"); - if (imageFrame.length > 0) { - var bigImage = new Image(); - bigImage.src = imageFrame[0].getAttribute("src"); - // console.log("bigImage.naturalWidth=" + bigImage.naturalWidth + " bigImage.src=" + bigImage.src); - if (bigImage.src !== this.latestBigImage && bigImage.naturalWidth !== 0) { - console.log("next big image appears loaded, will click right arrow next time"); - this.state = "click-next-big-image"; - this.latestBigImage = bigImage.src; - this.bigImagesLoaded++; - this.idleSince = null; + if(this.currentBigImage == null) { + var imageFrame = document.querySelectorAll("div.Modal div.Item div.iMedia div.Image"); + if (imageFrame.length > 0 && imageFrame[0].getAttribute("src") !== this.previousBigImage ) { + this.currentBigImage = new Image(); + this.currentBigImage.src = imageFrame[0].getAttribute("src"); + //console.log("this.currentBigImage.naturalWidth=" + this.currentBigImage.naturalWidth + " this.currentBigImage.src=" + this.currentBigImage.src); return; - } - } - if (this.bigImagesLoaded >= this.imageCount) { - console.log("looks like we're done, we've loaded all " + this.bigImagesLoaded + " of " + this.imageCount + " big images"); - this.state = "finished"; + } else if(this.idleSince == null ) { + console.log("waiting for image frame to load"); + this.idleSince = Date.now(); + return; + } + } else if (this.currentBigImage.src !== this.previousBigImage && this.currentBigImage.naturalWidth !== 0) { + console.log("next big image appears loaded, will click right arrow next time"); + this.state = "click-next-big-image"; + this.previousBigImage = this.currentBigImage.src; + this.currentBigImage = null; + this.bigImagesLoaded++; + this.idleSince = null; + + if (this.bigImagesLoaded >= this.imageCount) { + console.log("looks like we're done, we've loaded all " + this.bigImagesLoaded + " of " + this.imageCount + " big images"); + this.state = "finished"; + this.idleSince = Date.now(); + } + return; + } else if(this.idleSince == null) { + console.log("Waiting for big image to load"); this.idleSince = Date.now(); + return; } - return; + } if (this.state === "click-next-big-image") {