diff --git a/.github/workflows/autoscroll.yaml b/.github/workflows/autoscroll.yaml index 30dcb4e..3f56e41 100644 --- a/.github/workflows/autoscroll.yaml +++ b/.github/workflows/autoscroll.yaml @@ -38,5 +38,5 @@ jobs: run: cat ./log - name: compare crawl log to expected - run: grep '"msg"' ./log | diff - ./test/expected-autoscroll.log + run: cat ./log | jq -c 'select(.context == "behaviorScript") | .details' | diff - ./test/expected-autoscroll.log diff --git a/dist/behaviors.js b/dist/behaviors.js index e186c91..6c45635 100644 --- a/dist/behaviors.js +++ b/dist/behaviors.js @@ -1 +1 @@ -/*! behaviors.js is part of Webrecorder project. Copyright (C) 2021-2023, Webrecorder Software. Licensed under the Affero General Public License v3. */(()=>{var t={894:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AutoFetcher:()=>l});var o=i(841),s=i(721);const a=/\s*(\S*\s+[\d.]+[wx]),|(?:\s*,(?:\s+|(?=https?:)))/,n=/(url\s*\(\s*[\\"']*)([^)'"]+)([\\"']*\s*\))/gi,r=/(@import\s*[\\"']*)([^)'";]+)([\\"']*\s*;?)/gi;class l extends o.BackgroundBehavior{constructor(t=!1,e=null){super(),this.urlSet=new Set,this.urlQueue=[],this.numPending=0,this.numDone=0,this.headers=e||{},this._donePromise=new Promise((t=>this._markDone=t)),t&&this.start()}get numFetching(){return this.numDone+this.numPending+this.urlQueue.length}async start(){await(0,s.awaitLoad)(),this.run(),this.initObserver(),await(0,s.sleep)(500),this.urlQueue.length||this.numPending||this._markDone(null)}done(){return this._donePromise}async run(){this.extractSrcSrcSetAll(document),this.extractStyleSheets()}isValidUrl(t){return t&&(t.startsWith("http:")||t.startsWith("https:"))}queueUrl(t){try{t=new URL(t,document.baseURI).href}catch(t){return!1}return!!this.isValidUrl(t)&&(!this.urlSet.has(t)&&(this.urlSet.add(t),this.doFetch(t),!0))}async doFetchStream(t){try{const e=await fetch(t,{credentials:"include",referrerPolicy:"origin-when-cross-origin"});this.debug(`Autofetch: started ${t}`);const i=e.body.getReader();let o=null;for(;(o=await i.read())&&!o.done;);return this.debug(`Autofetch: finished ${t}`),!0}catch(t){return this.debug(t),!1}}async doFetchNonCors(t){try{const e=new AbortController;await fetch(t,{mode:"no-cors",credentials:"include",referrerPolicy:"origin-when-cross-origin",headers:this.headers,abort:e}),e.abort(),this.debug(`Autofetch: started non-cors stream for ${t}`)}catch(e){this.debug(`Autofetch: failed non-cors for ${t}`)}}async doFetch(t){if(this.urlQueue.push(t),this.numPending<=6){for(;this.urlQueue.length>0;){const t=this.urlQueue.shift();this.numPending++,!1||await this.doFetchNonCors(t),this.numPending--,this.numDone++}this.numPending||this._markDone(null)}}initObserver(){this.mutationObserver=new MutationObserver((t=>this.observeChange(t))),this.mutationObserver.observe(document.documentElement,{characterData:!1,characterDataOldValue:!1,attributes:!0,attributeOldValue:!0,subtree:!0,childList:!0,attributeFilter:["srcset","loading"]})}processChangedNode(t){switch(t.nodeType){case Node.ATTRIBUTE_NODE:if("srcset"===t.nodeName&&this.extractSrcSetAttr(t.nodeValue),"loading"===t.nodeName&&"lazy"===t.nodeValue){const e=t.parentNode;"IMG"===e.tagName&&e.setAttribute("loading","eager")}break;case Node.TEXT_NODE:t.parentNode&&"STYLE"===t.parentNode.tagName&&this.extractStyleText(t.nodeValue);break;case Node.ELEMENT_NODE:t.sheet&&this.extractStyleSheet(t.sheet),this.extractSrcSrcSet(t),setTimeout((()=>this.extractSrcSrcSetAll(t)),1e3)}}observeChange(t){for(const e of t)if(this.processChangedNode(e.target),"childList"===e.type)for(const t of e.addedNodes)this.processChangedNode(t)}extractSrcSrcSetAll(t){const e=t.querySelectorAll("img[srcset], img[data-srcset], img[data-src], noscript > img[src], img[loading='lazy'], video[srcset], video[data-srcset], video[data-src], audio[srcset], audio[data-srcset], audio[data-src], picture > source[srcset], picture > source[data-srcset], picture > source[data-src], video > source[srcset], video > source[data-srcset], video > source[data-src], audio > source[srcset], audio > source[data-srcset], audio > source[data-src]");for(const t of e)this.extractSrcSrcSet(t)}extractSrcSrcSet(t){if(!t||t.nodeType!==Node.ELEMENT_NODE)return void console.warn("No elem to extract from");const e=t.getAttribute("data-src");e&&this.queueUrl(e),"lazy"===t.getAttribute("loading")&&t.setAttribute("loading","eager");const i=t.getAttribute("srcset");i&&this.extractSrcSetAttr(i);const o=t.getAttribute("data-srcset");o&&this.extractSrcSetAttr(o);const s=t.getAttribute("src");s&&"NOSCRIPT"===t.parentElement.tagName&&this.queueUrl(s)}extractSrcSetAttr(t){for(const e of t.split(a))if(e){const t=e.trim().split(" ");this.queueUrl(t[0])}}extractStyleSheets(t){t=t||document;for(const e of t.styleSheets)this.extractStyleSheet(e)}extractStyleSheet(t){let e;try{e=t.cssRules||t.rules}catch(t){return void this.debug("Can't access stylesheet")}for(const t of e)t.type===CSSRule.MEDIA_RULE&&this.extractStyleText(t.cssText)}extractStyleText(t){const e=(t,e,i,o)=>(this.queueUrl(i),e+i+o);t.replace(n,e).replace(r,e)}}},376:(t,e,i)=>{"use strict";i.r(e),i.d(e,{Autoplay:()=>a});var o=i(841),s=i(721);class a extends o.BackgroundBehavior{constructor(t){super(),this.mediaSet=new Set,this.autofetcher=t,this.numPlaying=0,this.promises=[],this._initDone=()=>null,this.promises.push(new Promise((t=>this._initDone=t))),this.start()}async start(){await(0,s.awaitLoad)(),this.pollAudioVideo(),this._initDone()}async pollAudioVideo(){for(;;){for(const[,t]of document.querySelectorAll("video, audio, picture").entries())t.__bx_autoplay_found||(await this.loadMedia(t),t.__bx_autoplay_found=!0);await(0,s.sleep)(500)}}fetchSrcUrl(t){const e=t.src||t.currentSrc;return!!e&&(!(!e.startsWith("http:")&&!e.startsWith("https:"))&&(this.mediaSet.has(e)||(this.debug("fetch media source URL: "+e),this.mediaSet.add(e),this.autofetcher.queueUrl(e)),!0))}processFetchableUrl(t){let e=this.fetchSrcUrl(t);const i=t.querySelectorAll("source");for(const t of i){const i=this.fetchSrcUrl(t);e=e||i}return e}async loadMedia(t){this.debug("processing media element: "+t.outerHTML);const e=this.processFetchableUrl(t);t.play?e?t.paused||(t.pause(),this.debug("media URL found, pausing playback")):t.paused?(this.debug("no src url found, attempting to click or play: "+t.outerHTML),this.attemptMediaPlay(t).then((async e=>{let i=!0;for(e&&e.then((()=>i=!1));i;)this.processFetchableUrl(t)&&(i=!1),this.debug("Waiting for fixed URL or media to finish: "+t.currentSrc),await(0,s.sleep)(1e3)}))):t.currentSrc&&this.debug("media playing from non-URL source: "+t.currentSrc):this.debug("media not playable, skipping")}async attemptMediaPlay(t){let e;const i=new Promise((t=>{e=t}));let o;const a=new Promise((t=>{o=t}));a.then((()=>this.promises.push(i))),t.addEventListener("loadstart",(()=>{this.debug("loadstart"),o(!0)})),t.addEventListener("playing",(()=>{this.debug("playing"),o(!0)})),t.addEventListener("loadeddata",(()=>this.debug("loadeddata"))),t.addEventListener("ended",(()=>{this.debug("ended"),e()})),t.addEventListener("pause",(()=>{this.debug("pause"),e()})),t.addEventListener("abort",(()=>{this.debug("abort"),e()})),t.addEventListener("error",(()=>{this.debug("error"),e()})),t.addEventListener("stalled",(()=>{this.debug("stalled"),e()})),t.addEventListener("suspend",(()=>{this.debug("suspend"),e()})),t.muted=!0;if(!t.closest("a")){t.click();if(await Promise.race([a,(0,s.sleep)(1e3)]))return i}return t.play(),i}done(){return Promise.allSettled(this.promises)}}},234:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AutoScroll:()=>a});var o=i(841),s=i(721);class a extends o.Behavior{constructor(t){super(),this.autoFetcher=t,this.showMoreQuery="//*[contains(text(), 'show more') or contains(text(), 'Show more')]",this.state={segments:1},this.lastScrollPos=-1,this.samePosCount=0}currScrollPos(){return Math.round(self.scrollY+self.innerHeight)}canScrollMore(){const t=self.document.scrollingElement||self.document.body;return this.currScrollPos()a&&(this.state.segments++,a=n),e||i||(e=(0,s.xpathNode)(this.showMoreQuery)),e&&(0,s.isInViewport)(e)&&(yield this.getState("Clicking 'Show More', awaiting more content"),e.click(),await(0,s.sleep)(s.waitUnit),await Promise.race([(0,s.waitUntil)((()=>self.document.scrollingElement.scrollHeight>n),500),(0,s.sleep)(3e4)]),self.document.scrollingElement.scrollHeight===n&&(i=!0),e=null),self.scrollBy(o),await(0,s.sleep)(75),1===this.state.segments)yield this.getState(`Scrolling down by ${o.top} pixels every 0.075 seconds`),t=2;else{const e=t/(this.state.segments-1);this.debug(`Waiting up to ${e} seconds for more scroll segments`);const i=Date.now();await Promise.race([(0,s.waitUntil)((()=>this.canScrollMore()),75),(0,s.sleep)(e)]),t+=2*(Date.now()-i)}const r=this.currScrollPos();if(r===this.lastScrollPos){if(++this.samePosCount>=2)break}else this.samePosCount=0;this.lastScrollPos=r}}async*scrollUp(){const t={top:-Math.min(.1*self.document.scrollingElement.clientHeight,30),left:0,behavior:"auto"};let e=self.document.scrollingElement.scrollHeight;for(;self.scrollY>0;){const i=self.document.scrollingElement.scrollHeight;i>e&&(this.state.segments++,e=i),self.scrollBy(t),await(0,s.sleep)(75),1===this.state.segments?yield this.getState(`Scrolling up by ${t.top} pixels every 0.075 seconds`):await Promise.race([(0,s.waitUntil)((()=>self.scrollY>0),75),(0,s.sleep)(2e3*(this.state.segments-1))])}}}a.id="Autoscroll"},607:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BehaviorManager:()=>d});var o=i(894),s=i(376),a=i(234),n=i(721),r=i(841),l=i(954);const c={autofetch:!0,autoplay:!0,autoscroll:!0,siteSpecific:!0};class d{constructor(){this.behaviors=[],this.loadedBehaviors=l.default.reduce(((t,e)=>(t[e.id]=e,t)),{}),this.mainBehavior=null,this.inited=!1,this.started=!1,(0,n.behaviorLog)("Loaded behaviors for: "+self.location.href)}init(t=c,e=!1,i=null){if(this.inited&&!e)return;if(this.inited=!0,!self.window)return;if(this.timeout=t.timeout,void 0!==t.log){let e=t.log;"string"==typeof e&&(e=self[e]),"function"==typeof e?(0,n._setLogFunc)(e):!1===e&&(0,n._setLogFunc)(null)}this.autofetch=new o.AutoFetcher(!!t.autofetch,t.fetchHeaders),t.autofetch&&((0,n.behaviorLog)("Enable AutoFetcher"),this.behaviors.push(this.autofetch)),t.autoplay&&((0,n.behaviorLog)("Enable Autoplay"),this.behaviors.push(new s.Autoplay(this.autofetch)));let l=!1;if(self.window.top===self.window){if(t.siteSpecific){if(i)for(const t of i)try{this.load(t)}catch(e){(0,n.behaviorLog)(`Failed to load custom behavior: ${e} ${t}`)}for(const e in this.loadedBehaviors){const i=this.loadedBehaviors[e];if(i.isMatch()){(0,n.behaviorLog)("Starting Site-Specific Behavior: "+e),this.mainBehaviorClass=i;const o="object"==typeof t.siteSpecific&&t.siteSpecific[e]||{};try{this.mainBehavior=new r.BehaviorRunner(i,o)}catch(t){(0,n.behaviorLog)(t.toString(),"error")}l=!0;break}}}return!l&&t.autoscroll&&((0,n.behaviorLog)("Starting Autoscroll"),this.mainBehaviorClass=a.AutoScroll,this.mainBehavior=new a.AutoScroll(this.autofetch)),this.mainBehavior&&(this.behaviors.push(this.mainBehavior),this.mainBehavior,r.Behavior,this.mainBehavior instanceof r.BehaviorRunner)?this.mainBehavior.behaviorProps.id:""}}load(t){if("function"!=typeof t)return void(0,n.behaviorLog)(`Must pass a class object, got ${t}`,"error");if("string"!=typeof t.id)return void(0,n.behaviorLog)('Behavior class must have a string string "id" property',"error");if("function"!=typeof t.isMatch||"function"!=typeof t.init)return void(0,n.behaviorLog)("Behavior class must have an is `isMatch()` and `init()` static methods","error");const e=t.id;(0,n.behaviorLog)(`Loading external class ${e}: ${t}`,"debug"),this.loadedBehaviors[e]=t}async resolve(t){const e=await i(75)(`${t}`);if(Array.isArray(e))for(const t of e)this.load(t);else this.load(e)}async run(t=c,e=!1){if(e&&(this.started=!1),this.started)return void this.unpause();this.init(t,e),await(0,n.awaitLoad)(),this.mainBehavior&&this.mainBehavior.start(),this.started=!0;let i=Promise.allSettled(this.behaviors.map((t=>t.done())));this.timeout?((0,n.behaviorLog)(`Waiting for behaviors to finish or ${this.timeout}ms timeout`),await Promise.race([i,(0,n.sleep)(this.timeout)])):((0,n.behaviorLog)("Waiting for behaviors to finish"),await i),(0,n.behaviorLog)("All Behaviors Done for "+self.location.href),this.mainBehavior&&this.mainBehaviorClass.cleanup&&this.mainBehavior.cleanup()}async runOne(t,e={}){const i=l.default.find((e=>e.name===t));if(void 0===i)return void console.error(`No behavior of name ${t} found`);const o=new r.BehaviorRunner(i,e);o.start(),console.log(`Running behavior: ${t}`),await o.done(),console.log(`Behavior ${t} completed`)}pause(){(0,n.behaviorLog)("Pausing Main Behavior"+this.mainBehaviorClass.name),this.mainBehavior&&this.mainBehavior.pause()}unpause(){this.mainBehavior&&this.mainBehavior.unpause()}doAsyncFetch(t){return(0,n.behaviorLog)("Queueing Async Fetch Url: "+t),this.autofetch.queueUrl(t)}}(0,n._setBehaviorManager)(d),(0,n.installBehaviors)(self)},841:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BackgroundBehavior:()=>s,Behavior:()=>a,BehaviorRunner:()=>n});var o=i(721);class s{debug(t){(0,o.behaviorLog)(t,"debug")}log(t){(0,o.behaviorLog)(t,"info")}}class a extends s{constructor(){super(),this._running=null,this.paused=null,this._unpause=null,this.state={},this.scrollOpts={behavior:"smooth",block:"center",inline:"center"}}start(){this._running=this.run()}done(){return this._running?this._running:Promise.resolve()}async run(){try{for await(const t of this)this.log(t),this.paused&&await this.paused;this.log(this.getState("done!"))}catch(t){this.log(this.getState(t))}}pause(){this.paused||(this.paused=new Promise((t=>{this._unpause=t})))}unpause(){this._unpause&&(this._unpause(),this.paused=null,this._unpause=null)}getState(t,e){return e&&(void 0===this.state[e]?this.state[e]=1:this.state[e]++),{state:this.state,msg:t}}cleanup(){}static load(){self.__bx_behaviors?self.__bx_behaviors.load(this):console.warn(`Could not load ${this.name} behavior: window.__bx_behaviors is not initialized`)}async*[Symbol.asyncIterator](){yield}}class n extends s{constructor(t,e={}){if(super(),this.behaviorProps=t,this.inst=new t,"function"!=typeof this.inst.run||"AsyncGeneratorFunction"!==this.inst.run.constructor.name)throw Error("Invalid behavior: missing `async run*` instance method");let{state:i,opts:s}=t.init();i=i||{},s=s?{...s,...e}:e;const a=o.behaviorLog;this.ctx={Lib:o,state:i,opts:s,log:a},this._running=null,this.paused=null,this._unpause=null}start(){this._running=this.run()}done(){return this._running?this._running:Promise.resolve()}async run(){try{for await(const t of this.inst.run(this.ctx))this.log(t),this.paused&&await this.paused;this.log((0,o.getState)(this.ctx,"done!"))}catch(t){this.log((0,o.getState)(this.ctx,t))}}pause(){this.paused||(this.paused=new Promise((t=>{this._unpause=t})))}unpause(){this._unpause&&(this._unpause(),this.paused=null,this._unpause=null)}cleanup(){}static load(){self.__bx_behaviors?self.__bx_behaviors.load(this):console.warn(`Could not load ${this.name} behavior: window.__bx_behaviors is not initialized`)}}},721:(t,e,i)=>{"use strict";i.r(e),i.d(e,{HistoryState:()=>b,RestoreState:()=>v,_setBehaviorManager:()=>p,_setLogFunc:()=>f,awaitLoad:()=>h,behaviorLog:()=>w,getState:()=>T,installBehaviors:()=>g,isInViewport:()=>E,iterChildElem:()=>L,iterChildMatches:()=>P,openWindow:()=>m,scrollAndClick:()=>n,scrollIntoView:()=>_,scrollToOffset:()=>k,sleep:()=>l,waitUnit:()=>r,waitUntil:()=>c,waitUntilNode:()=>d,xpathNode:()=>y,xpathNodes:()=>S,xpathString:()=>x});let o=console.log,s=null;const a={behavior:"smooth",block:"center",inline:"center"};async function n(t,e=500,i=a){t.scrollIntoView(i),await l(e),t.click()}const r=200;function l(t){return new Promise((e=>setTimeout(e,t)))}async function c(t,e=r){for(;!t();)await l(e)}async function d(t,e=document,i=null,o=1e3,s=r){let a=null,n=!1;const l=c((()=>(a=y(t,e),n||a!==i&&null!==a)),s),d=new Promise((t=>setTimeout((()=>{n=!0,t("TIMEOUT")}),o)));return await Promise.race([l,d]),a}function h(){return new Promise((t=>{"complete"===document.readyState?t(null):window.addEventListener("load",t)}))}function u(t,e){try{t(e)}catch(i){t(JSON.stringify(e))}}function w(t,e="debug"){o&&u(o,{data:t,type:e})}async function m(t){if(self.__bx_open){const e=new Promise((t=>self.__bx_openResolve=t));u(self.__bx_open,{url:t});let i=null;try{if(i=await e,i)return i}catch(t){console.warn(t)}finally{delete self.__bx_openResolve}}return window.open(t)}function f(t){o=t}function p(t){s=t}function g(t){t.__bx_behaviors=new s}class v{constructor(t,e){this.matchValue=x(t,e)}async restore(t,e){let i=null;for(;i=y(t),!i;)await l(100);return y(e.replace("$1",this.matchValue),i)}}class b{constructor(t){this.loc=window.location.href,t()}get changed(){return window.location.href!==this.loc}goBack(t){if(!this.changed)return Promise.resolve(!0);const e=y(t);return new Promise((t=>{window.addEventListener("popstate",(()=>{t(null)}),{once:!0}),e?e.click():window.history.back()}))}}function y(t,e){return e=e||document,document.evaluate(t,e,null,XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue}function*S(t,e){e=e||document;let i=document.evaluate(t,e,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE),o=null;for(;null!==(o=i.iterateNext());)yield o}function x(t,e){return e=e||document,document.evaluate(t,e,null,XPathResult.STRING_TYPE).stringValue}async function*L(t,e,i){let o=t.firstElementChild;for(;o;)yield o,o.nextElementSibling||await Promise.race([c((()=>!!o.nextElementSibling),e),l(i)]),o=o.nextElementSibling}async function*P(t,e,i=r,o=5e3){let s=y(`.//${t}`,e);const a=e=>y(`./following-sibling::${t}`,e);for(;s;){yield s;let t=a(s);t?s=t:(await Promise.race([c((()=>(t=a(s),t)),i),l(o)]),s=t)}}function E(t){var e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&e.right<=(window.innerWidth||document.documentElement.clientWidth)}function k(t,e=0){const i=t.getBoundingClientRect().top+window.pageYOffset-e;window.scrollTo({top:i,behavior:"smooth"})}function _(t,e={behavior:"smooth",block:"center",inline:"center"}){t.scrollIntoView(e)}function T(t,e,i){return void 0===typeof t.state&&(t.state={}),i&&(void 0===t.state[i]?t.state[i]=1:t.state[i]++),{state:t.state,msg:e}}},121:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FacebookTimelineBehavior:()=>s});const o={feed:"//div[@role='feed']",article:".//div[@role='article']",pageletPostList:"//div[@data-pagelet='page']/div[@role='main']//div[@role='main']/div",pageletProfilePostList:"//div[@data-pagelet='page']//div[@data-pagelet='ProfileTimeline']",articleToPostList:"//div[@role='article']/../../../../div",photosOrVideos:`.//a[(contains(@href, '/photos/') or contains(@href, '/photo/?') or contains(@href, '/videos/')) and (starts-with(@href, '${window.location.origin}/') or starts-with(@href, '/'))]`,postQuery:".//a[contains(@href, '/posts/')]",extraLabel:"//*[starts-with(text(), '+')]",nextSlideQuery:"//div[@data-name='media-viewer-nav-container']/div[@data-visualcompletion][2]//div[@role='button']",nextSlide:"//div[@aria-hidden='false']//div[@role='button' and not(@aria-hidden) and @aria-label]",commentList:".//ul[(../h3) or (../h4)]",commentMoreReplies:"./div[2]/div[1]/div[2]/div[@role='button']",commentMoreComments:"./following-sibling::div/div/div[2][@role='button'][./span/span]",viewComments:".//h4/..//div[@role='button']",photoCommentList:"//ul[../h2]",firstPhotoThumbnail:"//div[@role='main']//div[3]//div[contains(@style, 'border-radius')]//div[contains(@style, 'max-width') and contains(@style, 'min-width')]//a[@role='link']",firstVideoThumbnail:"//div[@role='main']//div[contains(@style, 'z-index')]/following-sibling::div/div/div/div[last()]//a[contains(@href, '/videos/') and @aria-hidden!='true']",firstVideoSimple:"//div[@role='main']//a[contains(@href, '/videos/') and @aria-hidden!='true']",mainVideo:"//div[@data-pagelet='root']//div[@role='dialog']//div[@role='main']//video",nextVideo:"following::a[contains(@href, '/videos/') and @aria-hidden!='true']",isPhotoVideoPage:/^.*facebook\.com\/[^/]+\/(photos|videos)\/.+/,isPhotosPage:/^.*facebook\.com\/[^/]+\/photos\/?($|\?)/,isVideosPage:/^.*facebook\.com\/[^/]+\/videos\/?($|\?)/};class s{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?facebook\.com\//)}static init(){return{state:{}}}constructor(){this.extraWindow=null,this.allowNewWindow=!1}async*iterPostFeeds(t){const{iterChildElem:e,waitUnit:i,waitUntil:s,xpathNode:a,xpathNodes:n}=t.Lib,r=Array.from(n(o.feed));if(r&&r.length)for(const n of r)for await(const r of e(n,i,10*s))yield*this.viewPost(t,a(o.article,r));else{const n=a(o.pageletPostList)||a(o.pageletProfilePostList)||a(o.articleToPostList);if(!n)return;for await(const r of e(n,i,10*s))yield*this.viewPost(t,a(o.article,r))}this.extraWindow&&this.extraWindow.close()}async*viewPost(t,e,i=2){const{getState:s,scrollIntoView:a,sleep:n,waitUnit:r,xpathNode:l}=t.Lib;if(!e)return;const c=l(o.postQuery,e);let d=null;c&&(d=new URL(c.href,window.location.href),d.search=""),yield s(t,"Viewing post "+(d||""),"posts"),a(e),await n(2*r),l(".//video",e)&&(yield s(t,"Playing inline video","videos"),await n(2*r));let h=l(o.commentList,e);if(!h){const t=l(o.viewComments,e);t&&(t.click(),await n(2*r)),h=l(o.commentList,e)}yield*this.iterComments(t,h,i),await n(5*r)}async*viewPhotosOrVideos(t,e){const{getState:i,sleep:s,waitUnit:a,xpathNode:n,xpathNodes:r}=t.Lib,l=Array.from(r(o.photosOrVideos,e)),c=new Set;let d=0;for(const e of l){const r=new URL(e.href,window.location.href);if(-1===e.href.indexOf("?fbid")&&(r.search=""),c.has(r.href))continue;const h=e.href.indexOf("/video")>=0?"videos":"photos";++d,c.add(r.href),yield i(t,`Viewing ${h} ${r.href}`,h),e.scrollIntoView(),await s(5*a),e.click(),await s(10*a),this.allowNewWindow&&await this.openNewWindow(t,r.href),d===l.length&&(yield*this.viewExtraObjects(t,e,h,this.allowNewWindow));const u=n(o.nextSlide);u&&(u.click(),await s(2*a))}}async*viewExtraObjects(t,e,i,s){const{getState:a,sleep:n,waitUnit:r,waitUntil:l,xpathNode:c}=t.Lib,d=c(o.extraLabel,e);if(!d)return;const h=Number(d.innerText.slice(1));if(isNaN(h))return;let u;for(let e=0;ewindow.location.href!==u),2*r),yield a(t,`Viewing extra ${i} ${window.location.href}`),s&&await this.openNewWindow(t,window.location.href))}}async openNewWindow(t,e){this.extraWindow?this.extraWindow.location.href=e:this.extraWindow=await t.Lib.openWindow(e)}async*iterComments(t,e,i=2){const{getState:s,scrollIntoView:a,sleep:n,waitUnit:r,xpathNode:l}=t.Lib;if(!e)return void await n(5*r);let c=e.firstElementChild,d=null,h=0;for(;c&&hwindow.location.href!==c),2*a);let d=null;for(;(d=r(o.nextSlideQuery))&&(c=window.location.href,await s(a),d.click(),await s(5*a),await Promise.race([n((()=>window.location.href!==c),2*a),s(3e3)]),window.location.href!==c);){yield e(t,`Viewing photo ${window.location.href}`,"photos");const i=r(o.photoCommentList);yield*this.iterComments(t,i,2),await s(5*a)}}async*iterAllVideos(t){const{getState:e,scrollIntoView:i,sleep:s,waitUnit:a,waitUntil:n,xpathNode:r,xpathNodes:l}=t.Lib,c=r("//video");c&&(i(c),await s(5*a));let d=r(o.firstVideoThumbnail)||r(o.firstVideoSimple);if(d)for(;d;){i(d);let c=window.location.href;d.click(),await n((()=>window.location.href!==c),2*a),yield e(t,"Viewing video: "+window.location.href,"videos"),await s(10*a),await Promise.race([n((()=>{for(const t of l("//video"))if(t.readyState>=3)return!0;return!1}),2*a),s(2e4)]),await s(10*a);const h=r(o.nextSlide);if(!h)break;c=window.location.href,h.click(),await n((()=>window.location.href!==c),2*a),d=r(o.nextVideo,d)}}async*run(t){const{getState:e,sleep:i,xpathNode:s}=t.Lib;if(yield e(t,"Starting..."),await i(2e3),o.isPhotosPage.exec(window.location.href))return t.state={photos:0,comments:0},void(yield*this.iterPhotoSlideShow(t));if(o.isVideosPage.exec(window.location.href))return t.state={videos:0,comments:0},void(yield*this.iterAllVideos(t));if(o.isPhotoVideoPage.exec(window.location.href)){t.state={comments:0};const e=s(o.photoCommentList);yield*this.iterComments(t,e,1e3)}else t.state={posts:0,comments:0,videos:0},yield*this.iterPostFeeds(t)}}s.id="Facebook"},954:(t,e,i)=>{"use strict";i.r(e),i.d(e,{default:()=>l});var o=i(121),s=i(741),a=i(667),n=i(739),r=i(714);const l=[s.InstagramPostsBehavior,n.TwitterTimelineBehavior,o.FacebookTimelineBehavior,a.TelegramBehavior,r.TikTokVideoBehavior,r.TikTokProfileBehavior]},741:(t,e,i)=>{"use strict";i.r(e),i.d(e,{InstagramPostsBehavior:()=>a});const o="//article[@role='presentation']//div[@role='presentation']/following-sibling::button",s={rootPath:"//article/div/div",childMatchSelect:"string(.//a[starts-with(@href, '/')]/@href)",childMatch:"child::div[.//a[@href='$1']]",firstPostInRow:"div[1]/a",postCloseButton:"/html/body/div[last()]/div[1]/button[.//*[@aria-label]]",nextPost:"//button[.//*[local-name() = 'svg' and @aria-label='Next']]",postLoading:"//*[@aria-label='Loading...']",subpostNextOnlyChevron:o,subpostPrevNextChevron:o+"[2]",commentRoot:"//article[@role='presentation']/div[1]/div[2]//ul",viewReplies:"//li//button[span[not(count(*)) and text()!='$1']]",loadMore:"//button[span[@aria-label]]"};class a{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?instagram\.com\/\w[\w.-]+/)}static init(){return{state:{posts:0,slides:0,rows:0,comments:0}}}constructor(){this.maxCommentsTime=1e4,this.postOnlyWindow=null}cleanup(){this.postOnlyWindow&&(this.postOnlyWindow.close(),this.postOnlyWindow=null)}async waitForNext(t,e){return e?(await t.Lib.sleep(t.Lib.waitUnit),e.nextElementSibling?e.nextElementSibling:null):null}async*iterRow(t){const{RestoreState:e,sleep:i,waitUnit:o,xpathNode:a}=t.Lib;let n=a(s.rootPath);if(!n)return;let r=n.firstElementChild;if(r)for(;r;){await i(o);const a=new e(s.childMatchSelect,r);a.matchValue&&(yield r,r=await a.restore(s.rootPath,s.childMatch)),r=await this.waitForNext(t,r)}}async*viewStandalonePost(t,e){const{getState:i,sleep:o,waitUnit:a,waitUntil:n,xpathNode:r,xpathString:l}=t.Lib;let c=r(s.rootPath);if(!c||!c.firstElementChild)return;const d=l(s.childMatchSelect,c.firstElementChild);yield i(t,"Loading single post view for first post: "+d),window.history.replaceState({},"",d),window.dispatchEvent(new PopStateEvent("popstate",{state:{}}));let h=null,u=null;await o(5*a),await n((()=>(h=r(s.rootPath))!==c&&h),5*a),await o(5*a),window.history.replaceState({},"",e),window.dispatchEvent(new PopStateEvent("popstate",{state:{}})),await n((()=>(u=r(s.rootPath))!==h&&u),5*a)}async*iterSubposts(t){const{getState:e,sleep:i,waitUnit:o,xpathNode:a}=t.Lib;let n=a(s.subpostNextOnlyChevron),r=1;for(;n;)n.click(),await i(5*o),yield e(t,`Loading Slide ${++r} for ${window.location.href}`,"slides"),n=a(s.subpostPrevNextChevron);await i(5*o)}async iterComments(t){const{scrollIntoView:e,sleep:i,waitUnit:o,waitUntil:a,xpathNode:n}=t.Lib,r=n(s.commentRoot);if(!r)return;let l=r.firstElementChild,c=!1,d="";for(;l;){e(l),c=!0;let r=n(s.viewReplies.replace("$1",d),l);for(;r;){const e=r.textContent;r.click(),t.state.comments++,await i(2.5*o),await a((()=>e!==r.textContent),o),d=r.textContent,r=n(s.viewReplies.replace("$1",d),l)}if(l.nextElementSibling&&"LI"===l.nextElementSibling.tagName&&!l.nextElementSibling.nextElementSibling){let e=n(s.loadMore,l.nextElementSibling);e&&(e.click(),t.state.comments++,await i(5*o))}l=l.nextElementSibling,await i(2.5*o)}return c}async*iterPosts(t,e){const{getState:i,sleep:o,waitUnit:a,xpathNode:n}=t.Lib;let r=0;for(;e&&++r<=3;)for(e.click(),await o(10*a),yield i(t,"Loading Post: "+window.location.href,"posts"),await fetch(window.location.href),yield*this.iterSubposts(t),yield i(t,"Loaded Comments","comments"),await Promise.race([this.iterComments(t),o(this.maxCommentsTime)]),e=n(s.nextPost);!e&&n(s.postLoading);)await o(2.5*a);await o(5*a)}async*run(t){const{getState:e,scrollIntoView:i,sleep:o,waitUnit:a,xpathNode:n}=t.Lib;window.location.href;for await(const r of this.iterRow(t)){i(r),await o(2.5*a),yield e(t,"Loading Row","rows");const l=n(s.firstPostInRow,r);yield*this.iterPosts(t,l);const c=n(s.postCloseButton);c&&c.click(),await o(5*a)}}}a.id="Instagram"},667:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TelegramBehavior:()=>n});const o="//main//section[@class='tgme_channel_history js-message_history']",s="string(./div[@data-post]/@data-post)",a="string(.//a[@class='tgme_widget_message_link_preview' and @href]/@href)";class n{static isMatch(){return!!window.location.href.match(/https:\/\/t.me\/s\/\w[\w]+/)}static init(){return{state:{messages:0}}}async waitForPrev(t,e){return e?(await t.Lib.sleep(5*t.Lib.waitUnit),e.previousElementSibling?e.previousElementSibling:null):null}async*run(t){const{getState:e,scrollIntoView:i,sleep:n,waitUnit:r,xpathNode:l,xpathString:c}=t.Lib;let d=l(o);if(!d)return;let h=d.lastElementChild;for(;h;){i(h);const o=c(s,h)||"unknown",l=c(a,h);if(l&&l.endsWith(".jpg")||l.endsWith(".png")){yield e(t,"Loading External Image: "+l);const i=new Image;i.src=l,document.body.appendChild(i),await n(2.5*r),document.body.removeChild(i)}yield e(t,"Loading Message: "+o,"messages"),h=await this.waitForPrev(t,h)}}}n.id="Telegram"},714:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BREADTH_ALL:()=>d,TikTokProfileBehavior:()=>u,TikTokVideoBehavior:()=>h});const o="//div[contains(@class, 'CommentListContainer')]",s="div[contains(@class, 'CommentItemContainer')]",a=".//p[contains(@class, 'ReplyActionText')]",n=".//p[starts-with(@data-e2e, 'view-more') and string-length(text()) > 0]",r="//div[starts-with(@data-e2e, 'user-post-item-list')]",l="div[contains(@class, 'DivItemContainerV2')]",c="button[contains(@class, 'StyledCloseIconContainer')]",d=Symbol("BREADTH_ALL");class h{static init(){return{state:{comments:0},opts:{breadth:d}}}static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?tiktok\.com\/@.+\/video\/\d+\/?.*/)}breadthComplete({opts:{breadth:t}},e){return t!==d&&t<=e}async*crawlThread(t,e,i=null,o=0){const{waitUntilNode:s,scrollAndClick:a,getState:r}=t.Lib,l=await s(n,e,i);l&&!this.breadthComplete(t,o)&&(await a(l,500),yield r(t,"View more replies","comments"),yield*this.crawlThread(t,e,l,o+1))}async*expandThread(t,e){const{xpathNode:i,scrollAndClick:o,getState:s}=t.Lib,n=i(a,e);n&&(await o(n,500),yield s(t,"View comment","comments"),yield*this.crawlThread(t,e,null,1))}async*run(t){const{xpathNode:e,iterChildMatches:i,scrollIntoView:a,getState:n}=t.Lib,r=e(o),l=i(s,r);for await(const e of l)a(e),yield n(t,"View comment","comments"),this.breadthComplete(t,0)||(yield*this.expandThread(t,e));yield n(t,"TikTok Video Behavior Complete")}}h.id="TikTokVideo";class u{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?tiktok\.com\/@[a-zA-Z0-9]+(\/?$|\/\?.*)/)}static init(){return{state:{videos:0,comments:0},opts:{breadth:d}}}async*openVideo(t,e){const{HistoryState:i,xpathNode:o,sleep:s}=t.Lib,a=o(".//a",e);if(!a)return;const n=new i((()=>a.click()));if(await s(500),n.changed){const e=new h;yield*e.run(t),await s(500),await n.goBack(c)}}async*run(t){const{xpathNode:e,iterChildMatches:i,scrollIntoView:o,getState:s,sleep:a}=t.Lib,n=e(r),c=i(l,n);for await(const e of c)o(e),yield s(t,"View video","videos"),yield*this.openVideo(t,e),await a(500);yield s(t,"TikTok Profile Behavior Complete")}}u.id="TikTokProfile"},739:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TwitterTimelineBehavior:()=>g});const o="//h1[@role='heading' and @aria-level='1']/following-sibling::div[@aria-label]/*[1]",s=".//article",a="string(.//article//a[starts-with(@href, '/') and @aria-label]/@href)",n="child::div[.//a[@href='$1']]",r=".//div[@role='button' and not(@aria-haspopup) and not(@data-testid)]",l=".//div[@role='blockquote' and @aria-haspopup='false']",c=".//a[@role='link' and starts-with(@href, '/') and contains(@href, '/photo/')]",d="//div[@aria-roledescription='carousel']/div[2]/div[1]//div[@role='button']",h="//div[@aria-roledescription='carousel']/div[2]/div[2]//div[@role='button']",u="//div[@role='presentation']/div[@role='button' and @aria-label]",w="//div[@data-testid='titleContainer']//div[@role='button']",m=".//a[@href='/settings/content_you_see']/parent::div/parent::div/parent::div//div[@role='button']",f=".//*[@role='progressbar']",p=".//div[data-testid='placementTracking']";class g{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?twitter\.com\//)}static init(){return{state:{tweets:0,images:0,videos:0},opts:{maxDepth:0}}}constructor(){this.seenTweets=new Set,this.seenMediaTweets=new Set}showingProgressBar(t,e){const{xpathNode:i}=t.Lib,o=i(f,e);return!!o&&o.clientHeight>10}async waitForNext(t,e){const{sleep:i,waitUnit:o}=t.Lib;if(!e)return null;if(await i(2*o),!e.nextElementSibling)return null;for(;this.showingProgressBar(t,e.nextElementSibling);)await i(o);return e.nextElementSibling}async expandMore(t,e){const{sleep:i,waitUnit:o,xpathNode:s}=t.Lib,a=s(r,e);if(!a)return e;const n=e.previousElementSibling;for(a.click(),await i(o);this.showingProgressBar(t,n.nextElementSibling);)await i(o);return e=n.nextElementSibling}async*infScroll(t){const{scrollIntoView:e,RestoreState:i,sleep:l,waitUnit:c,xpathNode:d}=t.Lib;let h=d(o);if(!h)return;let u=h.firstElementChild;if(u)for(;u;){let h=d(s,u);if(!h&&r&&(u=await this.expandMore(t,u),h=d(s,u)),u&&u.innerText&&e(u),u&&h){await l(c);const t=new i(a,u);yield h,t.matchValue&&(u=await t.restore(o,n))}u=await this.waitForNext(t,u)}}async*mediaPlaying(t,e){const{getState:i,sleep:o,xpathNode:s,xpathString:n}=t.Lib,r=s("(.//video | .//audio)",e);if(!r||r.paused)return;let l,c=null;try{c=new URL(n(a,e.parentElement),window.location.origin).href}catch(t){console.warn(t)}if(r.src.startsWith("https://")&&r.src.indexOf(".mp4")>0)return void(yield i(t,`Loading video for ${c||"unknown"}`,"videos"));if(c){if(this.seenMediaTweets.has(c))return;l=`Waiting for media playback for ${c} to finish`,this.seenMediaTweets.add(c)}else l="Loading video";yield i(t,l,"videos");const d=new Promise((t=>{r.addEventListener("ended",(()=>t(null))),r.addEventListener("abort",(()=>t(null))),r.addEventListener("error",(()=>t(null))),r.addEventListener("pause",(()=>t(null)))}));await Promise.race([d,o(6e4)])}async*clickImages(t,e){const{getState:i,HistoryState:o,sleep:s,waitUnit:a,xpathNode:n}=t.Lib,r=n(c,e);if(r){const e=new o((()=>r.click()));yield i(t,"Loading Image: "+window.location.href,"images"),await s(5*a);let l=n(d),c=window.location.href;for(;l;){if(l.click(),await s(2*a),window.location.href===c){await s(5*a);break}c=window.location.href,yield i(t,"Loading Image: "+window.location.href,"images"),await s(5*a),l=n(h)}await e.goBack(u)}}async*clickTweet(t,e,i){const{getState:o,HistoryState:s,sleep:a,waitUnit:n}=t.Lib,r=new s((()=>e.click()));if(await a(n),r.changed){yield o(t,"Capturing Tweet: "+window.location.href,"tweets");i{var o={".":607,"./":607,"./autofetcher":894,"./autofetcher.ts":894,"./autoplay":376,"./autoplay.ts":376,"./autoscroll":234,"./autoscroll.ts":234,"./index":607,"./index.ts":607,"./lib/behavior":841,"./lib/behavior.ts":841,"./lib/utils":721,"./lib/utils.ts":721,"./site":954,"./site/":954,"./site/facebook":121,"./site/facebook.ts":121,"./site/index":954,"./site/index.ts":954,"./site/instagram":741,"./site/instagram.ts":741,"./site/telegram":667,"./site/telegram.ts":667,"./site/tiktok":714,"./site/tiktok.ts":714,"./site/twitter":739,"./site/twitter.ts":739};function s(t){return Promise.resolve().then((()=>{if(!i.o(o,t)){var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}var s=o[t];return i(s)}))}s.keys=()=>Object.keys(o),s.id=75,t.exports=s}},e={};function i(o){var s=e[o];if(void 0!==s)return s.exports;var a=e[o]={exports:{}};return t[o](a,a.exports,i),a.exports}i.d=(t,e)=>{for(var o in e)i.o(e,o)&&!i.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},i.e=()=>Promise.resolve(),i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},(()=>{"use strict";i(607)})()})(); \ No newline at end of file +/*! behaviors.js is part of Webrecorder project. Copyright (C) 2021-2023, Webrecorder Software. Licensed under the Affero General Public License v3. */(()=>{var t={894:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AutoFetcher:()=>l});var o=i(841),s=i(721);const a=/\s*(\S*\s+[\d.]+[wx]),|(?:\s*,(?:\s+|(?=https?:)))/,n=/(url\s*\(\s*[\\"']*)([^)'"]+)([\\"']*\s*\))/gi,r=/(@import\s*[\\"']*)([^)'";]+)([\\"']*\s*;?)/gi;class l extends o.BackgroundBehavior{constructor(t=!1,e=null){super(),this.urlSet=new Set,this.urlQueue=[],this.numPending=0,this.numDone=0,this.headers=e||{},this._donePromise=new Promise((t=>this._markDone=t)),t&&this.start()}get numFetching(){return this.numDone+this.numPending+this.urlQueue.length}async start(){await(0,s.awaitLoad)(),this.run(),this.initObserver(),await(0,s.sleep)(500),this.urlQueue.length||this.numPending||this._markDone(null)}done(){return this._donePromise}async run(){this.extractSrcSrcSetAll(document),this.extractStyleSheets()}isValidUrl(t){return t&&(t.startsWith("http:")||t.startsWith("https:"))}queueUrl(t){try{t=new URL(t,document.baseURI).href}catch(t){return!1}return!!this.isValidUrl(t)&&(!this.urlSet.has(t)&&(this.urlSet.add(t),this.doFetch(t),!0))}async doFetchStream(t){try{const e=await fetch(t,{credentials:"include",referrerPolicy:"origin-when-cross-origin"});this.debug(`Autofetch: started ${t}`);const i=e.body.getReader();let o=null;for(;(o=await i.read())&&!o.done;);return this.debug(`Autofetch: finished ${t}`),!0}catch(t){return this.debug(t),!1}}async doFetchNonCors(t){try{const e=new AbortController;await fetch(t,{mode:"no-cors",credentials:"include",referrerPolicy:"origin-when-cross-origin",headers:this.headers,abort:e}),e.abort(),this.debug(`Autofetch: started non-cors stream for ${t}`)}catch(e){this.debug(`Autofetch: failed non-cors for ${t}`)}}async doFetch(t){if(this.urlQueue.push(t),this.numPending<=6){for(;this.urlQueue.length>0;){const t=this.urlQueue.shift();this.numPending++,!1||await this.doFetchNonCors(t),this.numPending--,this.numDone++}this.numPending||this._markDone(null)}}initObserver(){this.mutationObserver=new MutationObserver((t=>this.observeChange(t))),this.mutationObserver.observe(document.documentElement,{characterData:!1,characterDataOldValue:!1,attributes:!0,attributeOldValue:!0,subtree:!0,childList:!0,attributeFilter:["srcset","loading"]})}processChangedNode(t){switch(t.nodeType){case Node.ATTRIBUTE_NODE:if("srcset"===t.nodeName&&this.extractSrcSetAttr(t.nodeValue),"loading"===t.nodeName&&"lazy"===t.nodeValue){const e=t.parentNode;"IMG"===e.tagName&&e.setAttribute("loading","eager")}break;case Node.TEXT_NODE:t.parentNode&&"STYLE"===t.parentNode.tagName&&this.extractStyleText(t.nodeValue);break;case Node.ELEMENT_NODE:t.sheet&&this.extractStyleSheet(t.sheet),this.extractSrcSrcSet(t),setTimeout((()=>this.extractSrcSrcSetAll(t)),1e3)}}observeChange(t){for(const e of t)if(this.processChangedNode(e.target),"childList"===e.type)for(const t of e.addedNodes)this.processChangedNode(t)}extractSrcSrcSetAll(t){const e=t.querySelectorAll("img[srcset], img[data-srcset], img[data-src], noscript > img[src], img[loading='lazy'], video[srcset], video[data-srcset], video[data-src], audio[srcset], audio[data-srcset], audio[data-src], picture > source[srcset], picture > source[data-srcset], picture > source[data-src], video > source[srcset], video > source[data-srcset], video > source[data-src], audio > source[srcset], audio > source[data-srcset], audio > source[data-src]");for(const t of e)this.extractSrcSrcSet(t)}extractSrcSrcSet(t){if(!t||t.nodeType!==Node.ELEMENT_NODE)return void console.warn("No elem to extract from");const e=t.getAttribute("data-src");e&&this.queueUrl(e),"lazy"===t.getAttribute("loading")&&t.setAttribute("loading","eager");const i=t.getAttribute("srcset");i&&this.extractSrcSetAttr(i);const o=t.getAttribute("data-srcset");o&&this.extractSrcSetAttr(o);const s=t.getAttribute("src");s&&"NOSCRIPT"===t.parentElement.tagName&&this.queueUrl(s)}extractSrcSetAttr(t){for(const e of t.split(a))if(e){const t=e.trim().split(" ");this.queueUrl(t[0])}}extractStyleSheets(t){t=t||document;for(const e of t.styleSheets)this.extractStyleSheet(e)}extractStyleSheet(t){let e;try{e=t.cssRules||t.rules}catch(t){return void this.debug("Can't access stylesheet")}for(const t of e)t.type===CSSRule.MEDIA_RULE&&this.extractStyleText(t.cssText)}extractStyleText(t){const e=(t,e,i,o)=>(this.queueUrl(i),e+i+o);t.replace(n,e).replace(r,e)}}},376:(t,e,i)=>{"use strict";i.r(e),i.d(e,{Autoplay:()=>a});var o=i(841),s=i(721);class a extends o.BackgroundBehavior{constructor(t){super(),this.mediaSet=new Set,this.autofetcher=t,this.numPlaying=0,this.promises=[],this._initDone=()=>null,this.promises.push(new Promise((t=>this._initDone=t))),this.start()}async start(){await(0,s.awaitLoad)(),this.pollAudioVideo(),this._initDone()}async pollAudioVideo(){for(;;){for(const[,t]of document.querySelectorAll("video, audio, picture").entries())t.__bx_autoplay_found||(await this.loadMedia(t),t.__bx_autoplay_found=!0);await(0,s.sleep)(500)}}fetchSrcUrl(t){const e=t.src||t.currentSrc;return!!e&&(!(!e.startsWith("http:")&&!e.startsWith("https:"))&&(this.mediaSet.has(e)||(this.debug("fetch media source URL: "+e),this.mediaSet.add(e),this.autofetcher.queueUrl(e)),!0))}processFetchableUrl(t){let e=this.fetchSrcUrl(t);const i=t.querySelectorAll("source");for(const t of i){const i=this.fetchSrcUrl(t);e=e||i}return e}async loadMedia(t){this.debug("processing media element: "+t.outerHTML);const e=this.processFetchableUrl(t);t.play?e?t.paused||(t.pause(),this.debug("media URL found, pausing playback")):t.paused?(this.debug("no src url found, attempting to click or play: "+t.outerHTML),this.attemptMediaPlay(t).then((async e=>{let i=!0;for(e&&e.then((()=>i=!1));i;)this.processFetchableUrl(t)&&(i=!1),this.debug("Waiting for fixed URL or media to finish: "+t.currentSrc),await(0,s.sleep)(1e3)}))):t.currentSrc&&this.debug("media playing from non-URL source: "+t.currentSrc):this.debug("media not playable, skipping")}async attemptMediaPlay(t){let e;const i=new Promise((t=>{e=t}));let o;const a=new Promise((t=>{o=t}));a.then((()=>this.promises.push(i))),t.addEventListener("loadstart",(()=>{this.debug("loadstart"),o(!0)})),t.addEventListener("playing",(()=>{this.debug("playing"),o(!0)})),t.addEventListener("loadeddata",(()=>this.debug("loadeddata"))),t.addEventListener("ended",(()=>{this.debug("ended"),e()})),t.addEventListener("pause",(()=>{this.debug("pause"),e()})),t.addEventListener("abort",(()=>{this.debug("abort"),e()})),t.addEventListener("error",(()=>{this.debug("error"),e()})),t.addEventListener("stalled",(()=>{this.debug("stalled"),e()})),t.addEventListener("suspend",(()=>{this.debug("suspend"),e()})),t.muted=!0;if(!t.closest("a")){t.click();if(await Promise.race([a,(0,s.sleep)(1e3)]))return i}return t.play(),i}done(){return Promise.allSettled(this.promises)}}},234:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AutoScroll:()=>a});var o=i(841),s=i(721);class a extends o.Behavior{constructor(t){super(),this.autoFetcher=t,this.showMoreQuery="//*[contains(text(), 'show more') or contains(text(), 'Show more')]",this.state={segments:1},this.lastScrollPos=-1,this.samePosCount=0}currScrollPos(){return Math.round(self.scrollY+self.innerHeight)}canScrollMore(){const t=self.document.scrollingElement||self.document.body;return this.currScrollPos()a&&(this.state.segments++,a=n),e||i||(e=(0,s.xpathNode)(this.showMoreQuery)),e&&(0,s.isInViewport)(e)&&(yield this.getState("Clicking 'Show More', awaiting more content"),e.click(),await(0,s.sleep)(s.waitUnit),await Promise.race([(0,s.waitUntil)((()=>self.document.scrollingElement.scrollHeight>n),500),(0,s.sleep)(3e4)]),self.document.scrollingElement.scrollHeight===n&&(i=!0),e=null),self.scrollBy(o),await(0,s.sleep)(75),1===this.state.segments)yield this.getState(`Scrolling down by ${o.top} pixels every 0.075 seconds`),t=2;else{const e=t/(this.state.segments-1);this.debug(`Waiting up to ${e} seconds for more scroll segments`);const i=Date.now();await Promise.race([(0,s.waitUntil)((()=>this.canScrollMore()),75),(0,s.sleep)(e)]),t+=2*(Date.now()-i)}const r=this.currScrollPos();if(r===this.lastScrollPos){if(++this.samePosCount>=2)break}else this.samePosCount=0;this.lastScrollPos=r}}async*scrollUp(){const t={top:-Math.min(.1*self.document.scrollingElement.clientHeight,30),left:0,behavior:"auto"};let e=self.document.scrollingElement.scrollHeight;for(;self.scrollY>0;){const i=self.document.scrollingElement.scrollHeight;i>e&&(this.state.segments++,e=i),self.scrollBy(t),await(0,s.sleep)(75),1===this.state.segments?yield this.getState(`Scrolling up by ${t.top} pixels every 0.075 seconds`):await Promise.race([(0,s.waitUntil)((()=>self.scrollY>0),75),(0,s.sleep)(2e3*(this.state.segments-1))])}}}a.id="Autoscroll"},607:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BehaviorManager:()=>d});var o=i(894),s=i(376),a=i(234),n=i(721),r=i(841),l=i(954);const c={autofetch:!0,autoplay:!0,autoscroll:!0,siteSpecific:!0};class d{constructor(){this.behaviors=[],this.loadedBehaviors=l.default.reduce(((t,e)=>(t[e.id]=e,t)),{}),this.mainBehavior=null,this.inited=!1,this.started=!1,(0,n.behaviorLog)("Loaded behaviors for: "+self.location.href)}init(t=c,e=!1,i=null){if(this.inited&&!e)return;if(this.inited=!0,!self.window)return;if(this.timeout=t.timeout,void 0!==t.log){let e=t.log;"string"==typeof e&&(e=self[e]),"function"==typeof e?(0,n._setLogFunc)(e):!1===e&&(0,n._setLogFunc)(null)}this.autofetch=new o.AutoFetcher(!!t.autofetch,t.fetchHeaders),t.autofetch&&((0,n.behaviorLog)("Enable AutoFetcher"),this.behaviors.push(this.autofetch)),t.autoplay&&((0,n.behaviorLog)("Enable Autoplay"),this.behaviors.push(new s.Autoplay(this.autofetch)));let l=!1;if(self.window.top===self.window){if(t.siteSpecific){if(i)for(const t of i)try{this.load(t)}catch(e){(0,n.behaviorLog)(`Failed to load custom behavior: ${e} ${t}`)}for(const e in this.loadedBehaviors){const i=this.loadedBehaviors[e];if(i.isMatch()){(0,n.behaviorLog)("Starting Site-Specific Behavior: "+e),this.mainBehaviorClass=i;const o="object"==typeof t.siteSpecific&&t.siteSpecific[e]||{};try{this.mainBehavior=new r.BehaviorRunner(i,o)}catch(t){(0,n.behaviorLog)(t.toString(),"error")}l=!0;break}}}return!l&&t.autoscroll&&((0,n.behaviorLog)("Starting Autoscroll"),this.mainBehaviorClass=a.AutoScroll,this.mainBehavior=new a.AutoScroll(this.autofetch)),this.mainBehavior&&(this.behaviors.push(this.mainBehavior),this.mainBehavior,r.Behavior,this.mainBehavior instanceof r.BehaviorRunner)?this.mainBehavior.behaviorProps.id:""}}load(t){if("function"!=typeof t)return void(0,n.behaviorLog)(`Must pass a class object, got ${t}`,"error");if("string"!=typeof t.id)return void(0,n.behaviorLog)('Behavior class must have a string string "id" property',"error");if("function"!=typeof t.isMatch||"function"!=typeof t.init)return void(0,n.behaviorLog)("Behavior class must have an is `isMatch()` and `init()` static methods","error");const e=t.id;(0,n.behaviorLog)(`Loading external class ${e}: ${t}`,"debug"),this.loadedBehaviors[e]=t}async resolve(t){const e=await i(75)(`${t}`);if(Array.isArray(e))for(const t of e)this.load(t);else this.load(e)}async run(t=c,e=!1){if(e&&(this.started=!1),this.started)return void this.unpause();this.init(t,e),await(0,n.awaitLoad)(),this.mainBehavior&&this.mainBehavior.start(),this.started=!0;let i=Promise.allSettled(this.behaviors.map((t=>t.done())));this.timeout?((0,n.behaviorLog)(`Waiting for behaviors to finish or ${this.timeout}ms timeout`),await Promise.race([i,(0,n.sleep)(this.timeout)])):((0,n.behaviorLog)("Waiting for behaviors to finish"),await i),(0,n.behaviorLog)("All Behaviors Done for "+self.location.href),this.mainBehavior&&this.mainBehaviorClass.cleanup&&this.mainBehavior.cleanup()}async runOne(t,e={}){const i=l.default.find((e=>e.name===t));if(void 0===i)return void console.error(`No behavior of name ${t} found`);const o=new r.BehaviorRunner(i,e);o.start(),console.log(`Running behavior: ${t}`),await o.done(),console.log(`Behavior ${t} completed`)}pause(){(0,n.behaviorLog)("Pausing Main Behavior"+this.mainBehaviorClass.name),this.mainBehavior&&this.mainBehavior.pause()}unpause(){this.mainBehavior&&this.mainBehavior.unpause()}doAsyncFetch(t){return(0,n.behaviorLog)("Queueing Async Fetch Url: "+t),this.autofetch.queueUrl(t)}}(0,n._setBehaviorManager)(d),(0,n.installBehaviors)(self)},841:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BackgroundBehavior:()=>s,Behavior:()=>a,BehaviorRunner:()=>n});var o=i(721);class s{debug(t){(0,o.behaviorLog)(t,"debug")}log(t){(0,o.behaviorLog)(t,"info")}}class a extends s{constructor(){super(),this._running=null,this.paused=null,this._unpause=null,this.state={},this.scrollOpts={behavior:"smooth",block:"center",inline:"center"}}start(){this._running=this.run()}done(){return this._running?this._running:Promise.resolve()}async run(){try{for await(const t of this)this.log(t),this.paused&&await this.paused;this.log(this.getState("done!"))}catch(t){this.log(this.getState(t))}}pause(){this.paused||(this.paused=new Promise((t=>{this._unpause=t})))}unpause(){this._unpause&&(this._unpause(),this.paused=null,this._unpause=null)}getState(t,e){return e&&(void 0===this.state[e]?this.state[e]=1:this.state[e]++),{state:this.state,msg:t}}cleanup(){}static load(){self.__bx_behaviors?self.__bx_behaviors.load(this):console.warn(`Could not load ${this.name} behavior: window.__bx_behaviors is not initialized`)}async*[Symbol.asyncIterator](){yield}}class n extends s{constructor(t,e={}){if(super(),this.behaviorProps=t,this.inst=new t,"function"!=typeof this.inst.run||"AsyncGeneratorFunction"!==this.inst.run.constructor.name)throw Error("Invalid behavior: missing `async run*` instance method");let{state:i,opts:s}=t.init();i=i||{},s=s?{...s,...e}:e;const a=o.behaviorLog;this.ctx={Lib:o,state:i,opts:s,log:a},this._running=null,this.paused=null,this._unpause=null}start(){this._running=this.run()}done(){return this._running?this._running:Promise.resolve()}async run(){try{for await(const t of this.inst.run(this.ctx))this.log(t),this.paused&&await this.paused;this.log((0,o.getState)(this.ctx,"done!"))}catch(t){this.log((0,o.getState)(this.ctx,t))}}pause(){this.paused||(this.paused=new Promise((t=>{this._unpause=t})))}unpause(){this._unpause&&(this._unpause(),this.paused=null,this._unpause=null)}cleanup(){}static load(){self.__bx_behaviors?self.__bx_behaviors.load(this):console.warn(`Could not load ${this.name} behavior: window.__bx_behaviors is not initialized`)}}},721:(t,e,i)=>{"use strict";i.r(e),i.d(e,{HistoryState:()=>b,RestoreState:()=>v,_setBehaviorManager:()=>p,_setLogFunc:()=>f,awaitLoad:()=>h,behaviorLog:()=>w,getState:()=>T,installBehaviors:()=>g,isInViewport:()=>E,iterChildElem:()=>L,iterChildMatches:()=>P,openWindow:()=>m,scrollAndClick:()=>n,scrollIntoView:()=>_,scrollToOffset:()=>k,sleep:()=>l,waitUnit:()=>r,waitUntil:()=>c,waitUntilNode:()=>d,xpathNode:()=>y,xpathNodes:()=>S,xpathString:()=>x});let o=console.log,s=null;const a={behavior:"smooth",block:"center",inline:"center"};async function n(t,e=500,i=a){t.scrollIntoView(i),await l(e),t.click()}const r=200;function l(t){return new Promise((e=>setTimeout(e,t)))}async function c(t,e=r){for(;!t();)await l(e)}async function d(t,e=document,i=null,o=1e3,s=r){let a=null,n=!1;const l=c((()=>(a=y(t,e),n||a!==i&&null!==a)),s),d=new Promise((t=>setTimeout((()=>{n=!0,t("TIMEOUT")}),o)));return await Promise.race([l,d]),a}function h(){return new Promise((t=>{"complete"===document.readyState?t(null):window.addEventListener("load",t)}))}function u(t,e){try{t(e)}catch(i){t(JSON.stringify(e))}}function w(t,e="debug"){o&&u(o,{data:t,type:e})}async function m(t){if(self.__bx_open){const e=new Promise((t=>self.__bx_openResolve=t));u(self.__bx_open,{url:t});let i=null;try{if(i=await e,i)return i}catch(t){console.warn(t)}finally{delete self.__bx_openResolve}}return window.open(t)}function f(t){o=t}function p(t){s=t}function g(t){t.__bx_behaviors=new s}class v{constructor(t,e){this.matchValue=x(t,e)}async restore(t,e){let i=null;for(;i=y(t),!i;)await l(100);return y(e.replace("$1",this.matchValue),i)}}class b{constructor(t){this.loc=window.location.href,t()}get changed(){return window.location.href!==this.loc}goBack(t){if(!this.changed)return Promise.resolve(!0);const e=y(t);return new Promise((t=>{window.addEventListener("popstate",(()=>{t(null)}),{once:!0}),e?e.click():window.history.back()}))}}function y(t,e){return e=e||document,document.evaluate(t,e,null,XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue}function*S(t,e){e=e||document;let i=document.evaluate(t,e,null,XPathResult.ORDERED_NODE_ITERATOR_TYPE),o=null;for(;null!==(o=i.iterateNext());)yield o}function x(t,e){return e=e||document,document.evaluate(t,e,null,XPathResult.STRING_TYPE).stringValue}async function*L(t,e,i){let o=t.firstElementChild;for(;o;)yield o,o.nextElementSibling||await Promise.race([c((()=>!!o.nextElementSibling),e),l(i)]),o=o.nextElementSibling}async function*P(t,e,i=r,o=5e3){let s=y(`.//${t}`,e);const a=e=>y(`./following-sibling::${t}`,e);for(;s;){yield s;let t=a(s);t?s=t:(await Promise.race([c((()=>(t=a(s),t)),i),l(o)]),s=t)}}function E(t){var e=t.getBoundingClientRect();return e.top>=0&&e.left>=0&&e.bottom<=(window.innerHeight||document.documentElement.clientHeight)&&e.right<=(window.innerWidth||document.documentElement.clientWidth)}function k(t,e=0){const i=t.getBoundingClientRect().top+window.pageYOffset-e;window.scrollTo({top:i,behavior:"smooth"})}function _(t,e={behavior:"smooth",block:"center",inline:"center"}){t.scrollIntoView(e)}function T(t,e,i){return void 0===typeof t.state&&(t.state={}),i&&(void 0===t.state[i]?t.state[i]=1:t.state[i]++),{state:t.state,msg:e}}},121:(t,e,i)=>{"use strict";i.r(e),i.d(e,{FacebookTimelineBehavior:()=>s});const o={feed:"//div[@role='feed']",article:".//div[@role='article']",pageletPostList:"//div[@data-pagelet='page']/div[@role='main']//div[@role='main']/div",pageletProfilePostList:"//div[@data-pagelet='page']//div[@data-pagelet='ProfileTimeline']",articleToPostList:"//div[@role='article']/../../../../div",photosOrVideos:`.//a[(contains(@href, '/photos/') or contains(@href, '/photo/?') or contains(@href, '/videos/')) and (starts-with(@href, '${window.location.origin}/') or starts-with(@href, '/'))]`,postQuery:".//a[contains(@href, '/posts/')]",extraLabel:"//*[starts-with(text(), '+')]",nextSlideQuery:"//div[@data-name='media-viewer-nav-container']/div[@data-visualcompletion][2]//div[@role='button']",nextSlide:"//div[@aria-hidden='false']//div[@role='button' and not(@aria-hidden) and @aria-label]",commentList:".//ul[(../h3) or (../h4)]",commentMoreReplies:"./div[2]/div[1]/div[2]/div[@role='button']",commentMoreComments:"./following-sibling::div/div/div[2][@role='button'][./span/span]",viewComments:".//h4/..//div[@role='button']",photoCommentList:"//ul[../h2]",firstPhotoThumbnail:"//div[@role='main']//div[3]//div[contains(@style, 'border-radius')]//div[contains(@style, 'max-width') and contains(@style, 'min-width')]//a[@role='link']",firstVideoThumbnail:"//div[@role='main']//div[contains(@style, 'z-index')]/following-sibling::div/div/div/div[last()]//a[contains(@href, '/videos/') and @aria-hidden!='true']",firstVideoSimple:"//div[@role='main']//a[contains(@href, '/videos/') and @aria-hidden!='true']",mainVideo:"//div[@data-pagelet='root']//div[@role='dialog']//div[@role='main']//video",nextVideo:"following::a[contains(@href, '/videos/') and @aria-hidden!='true']",isPhotoVideoPage:/^.*facebook\.com\/[^/]+\/(photos|videos)\/.+/,isPhotosPage:/^.*facebook\.com\/[^/]+\/photos\/?($|\?)/,isVideosPage:/^.*facebook\.com\/[^/]+\/videos\/?($|\?)/};class s{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?facebook\.com\//)}static init(){return{state:{}}}constructor(){this.extraWindow=null,this.allowNewWindow=!1}async*iterPostFeeds(t){const{iterChildElem:e,waitUnit:i,waitUntil:s,xpathNode:a,xpathNodes:n}=t.Lib,r=Array.from(n(o.feed));if(r&&r.length)for(const n of r)for await(const r of e(n,i,10*s))yield*this.viewPost(t,a(o.article,r));else{const n=a(o.pageletPostList)||a(o.pageletProfilePostList)||a(o.articleToPostList);if(!n)return;for await(const r of e(n,i,10*s))yield*this.viewPost(t,a(o.article,r))}this.extraWindow&&this.extraWindow.close()}async*viewPost(t,e,i=2){const{getState:s,scrollIntoView:a,sleep:n,waitUnit:r,xpathNode:l}=t.Lib;if(!e)return;const c=l(o.postQuery,e);let d=null;c&&(d=new URL(c.href,window.location.href),d.search=""),yield s(t,"Viewing post "+(d||""),"posts"),a(e),await n(2*r),l(".//video",e)&&(yield s(t,"Playing inline video","videos"),await n(2*r));let h=l(o.commentList,e);if(!h){const t=l(o.viewComments,e);t&&(t.click(),await n(2*r)),h=l(o.commentList,e)}yield*this.iterComments(t,h,i),await n(5*r)}async*viewPhotosOrVideos(t,e){const{getState:i,sleep:s,waitUnit:a,xpathNode:n,xpathNodes:r}=t.Lib,l=Array.from(r(o.photosOrVideos,e)),c=new Set;let d=0;for(const e of l){const r=new URL(e.href,window.location.href);if(-1===e.href.indexOf("?fbid")&&(r.search=""),c.has(r.href))continue;const h=e.href.indexOf("/video")>=0?"videos":"photos";++d,c.add(r.href),yield i(t,`Viewing ${h} ${r.href}`,h),e.scrollIntoView(),await s(5*a),e.click(),await s(10*a),this.allowNewWindow&&await this.openNewWindow(t,r.href),d===l.length&&(yield*this.viewExtraObjects(t,e,h,this.allowNewWindow));const u=n(o.nextSlide);u&&(u.click(),await s(2*a))}}async*viewExtraObjects(t,e,i,s){const{getState:a,sleep:n,waitUnit:r,waitUntil:l,xpathNode:c}=t.Lib,d=c(o.extraLabel,e);if(!d)return;const h=Number(d.innerText.slice(1));if(isNaN(h))return;let u;for(let e=0;ewindow.location.href!==u),2*r),yield a(t,`Viewing extra ${i} ${window.location.href}`),s&&await this.openNewWindow(t,window.location.href))}}async openNewWindow(t,e){this.extraWindow?this.extraWindow.location.href=e:this.extraWindow=await t.Lib.openWindow(e)}async*iterComments(t,e,i=2){const{getState:s,scrollIntoView:a,sleep:n,waitUnit:r,xpathNode:l}=t.Lib;if(!e)return void await n(5*r);let c=e.firstElementChild,d=null,h=0;for(;c&&hwindow.location.href!==c),2*a);let d=null;for(;(d=r(o.nextSlideQuery))&&(c=window.location.href,await s(a),d.click(),await s(5*a),await Promise.race([n((()=>window.location.href!==c),2*a),s(3e3)]),window.location.href!==c);){yield e(t,`Viewing photo ${window.location.href}`,"photos");const i=r(o.photoCommentList);yield*this.iterComments(t,i,2),await s(5*a)}}async*iterAllVideos(t){const{getState:e,scrollIntoView:i,sleep:s,waitUnit:a,waitUntil:n,xpathNode:r,xpathNodes:l}=t.Lib,c=r("//video");c&&(i(c),await s(5*a));let d=r(o.firstVideoThumbnail)||r(o.firstVideoSimple);if(d)for(;d;){i(d);let c=window.location.href;d.click(),await n((()=>window.location.href!==c),2*a),yield e(t,"Viewing video: "+window.location.href,"videos"),await s(10*a),await Promise.race([n((()=>{for(const t of l("//video"))if(t.readyState>=3)return!0;return!1}),2*a),s(2e4)]),await s(10*a);const h=r(o.nextSlide);if(!h)break;c=window.location.href,h.click(),await n((()=>window.location.href!==c),2*a),d=r(o.nextVideo,d)}}async*run(t){const{getState:e,sleep:i,xpathNode:s}=t.Lib;if(yield e(t,"Starting..."),await i(2e3),o.isPhotosPage.exec(window.location.href))return t.state={photos:0,comments:0},void(yield*this.iterPhotoSlideShow(t));if(o.isVideosPage.exec(window.location.href))return t.state={videos:0,comments:0},void(yield*this.iterAllVideos(t));if(o.isPhotoVideoPage.exec(window.location.href)){t.state={comments:0};const e=s(o.photoCommentList);yield*this.iterComments(t,e,1e3)}else t.state={posts:0,comments:0,videos:0},yield*this.iterPostFeeds(t)}}s.id="Facebook"},954:(t,e,i)=>{"use strict";i.r(e),i.d(e,{default:()=>l});var o=i(121),s=i(741),a=i(667),n=i(739),r=i(714);const l=[s.InstagramPostsBehavior,n.TwitterTimelineBehavior,o.FacebookTimelineBehavior,a.TelegramBehavior,r.TikTokVideoBehavior,r.TikTokProfileBehavior]},741:(t,e,i)=>{"use strict";i.r(e),i.d(e,{InstagramPostsBehavior:()=>a});const o="//article[@role='presentation']//div[@role='presentation']/following-sibling::button",s={rootPath:"//article/div/div",childMatchSelect:"string(.//a[starts-with(@href, '/')]/@href)",childMatch:"child::div[.//a[@href='$1']]",firstPostInRow:"div[1]/a",postCloseButton:"/html/body/div[last()]/div[1]/button[.//*[@aria-label]]",nextPost:"//button[.//*[local-name() = 'svg' and @aria-label='Next']]",postLoading:"//*[@aria-label='Loading...']",subpostNextOnlyChevron:o,subpostPrevNextChevron:o+"[2]",commentRoot:"//article[@role='presentation']/div[1]/div[2]//ul",viewReplies:"//li//button[span[not(count(*)) and text()!='$1']]",loadMore:"//button[span[@aria-label]]"};class a{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?instagram\.com\/\w[\w.-]+/)}static init(){return{state:{posts:0,slides:0,rows:0,comments:0}}}constructor(){this.maxCommentsTime=1e4,this.postOnlyWindow=null}cleanup(){this.postOnlyWindow&&(this.postOnlyWindow.close(),this.postOnlyWindow=null)}async waitForNext(t,e){return e?(await t.Lib.sleep(t.Lib.waitUnit),e.nextElementSibling?e.nextElementSibling:null):null}async*iterRow(t){const{RestoreState:e,sleep:i,waitUnit:o,xpathNode:a}=t.Lib;let n=a(s.rootPath);if(!n)return;let r=n.firstElementChild;if(r)for(;r;){await i(o);const a=new e(s.childMatchSelect,r);a.matchValue&&(yield r,r=await a.restore(s.rootPath,s.childMatch)),r=await this.waitForNext(t,r)}}async*viewStandalonePost(t,e){const{getState:i,sleep:o,waitUnit:a,waitUntil:n,xpathNode:r,xpathString:l}=t.Lib;let c=r(s.rootPath);if(!c||!c.firstElementChild)return;const d=l(s.childMatchSelect,c.firstElementChild);yield i(t,"Loading single post view for first post: "+d),window.history.replaceState({},"",d),window.dispatchEvent(new PopStateEvent("popstate",{state:{}}));let h=null,u=null;await o(5*a),await n((()=>(h=r(s.rootPath))!==c&&h),5*a),await o(5*a),window.history.replaceState({},"",e),window.dispatchEvent(new PopStateEvent("popstate",{state:{}})),await n((()=>(u=r(s.rootPath))!==h&&u),5*a)}async*iterSubposts(t){const{getState:e,sleep:i,waitUnit:o,xpathNode:a}=t.Lib;let n=a(s.subpostNextOnlyChevron),r=1;for(;n;)n.click(),await i(5*o),yield e(t,`Loading Slide ${++r} for ${window.location.href}`,"slides"),n=a(s.subpostPrevNextChevron);await i(5*o)}async iterComments(t){const{scrollIntoView:e,sleep:i,waitUnit:o,waitUntil:a,xpathNode:n}=t.Lib,r=n(s.commentRoot);if(!r)return;let l=r.firstElementChild,c=!1,d="";for(;l;){e(l),c=!0;let r=n(s.viewReplies.replace("$1",d),l);for(;r;){const e=r.textContent;r.click(),t.state.comments++,await i(2.5*o),await a((()=>e!==r.textContent),o),d=r.textContent,r=n(s.viewReplies.replace("$1",d),l)}if(l.nextElementSibling&&"LI"===l.nextElementSibling.tagName&&!l.nextElementSibling.nextElementSibling){let e=n(s.loadMore,l.nextElementSibling);e&&(e.click(),t.state.comments++,await i(5*o))}l=l.nextElementSibling,await i(2.5*o)}return c}async*iterPosts(t,e){const{getState:i,sleep:o,waitUnit:a,xpathNode:n}=t.Lib;let r=0;for(;e&&++r<=3;)for(e.click(),await o(10*a),yield i(t,"Loading Post: "+window.location.href,"posts"),await fetch(window.location.href),yield*this.iterSubposts(t),yield i(t,"Loaded Comments","comments"),await Promise.race([this.iterComments(t),o(this.maxCommentsTime)]),e=n(s.nextPost);!e&&n(s.postLoading);)await o(2.5*a);await o(5*a)}async*run(t){const{getState:e,scrollIntoView:i,sleep:o,waitUnit:a,xpathNode:n}=t.Lib;for await(const r of this.iterRow(t)){i(r),await o(2.5*a),yield e(t,"Loading Row","rows");const l=n(s.firstPostInRow,r);yield*this.iterPosts(t,l);const c=n(s.postCloseButton);c&&c.click(),await o(5*a)}}}a.id="Instagram"},667:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TelegramBehavior:()=>n});const o="//main//section[@class='tgme_channel_history js-message_history']",s="string(./div[@data-post]/@data-post)",a="string(.//a[@class='tgme_widget_message_link_preview' and @href]/@href)";class n{static isMatch(){return!!window.location.href.match(/https:\/\/t.me\/s\/\w[\w]+/)}static init(){return{state:{messages:0}}}async waitForPrev(t,e){return e?(await t.Lib.sleep(5*t.Lib.waitUnit),e.previousElementSibling?e.previousElementSibling:null):null}async*run(t){const{getState:e,scrollIntoView:i,sleep:n,waitUnit:r,xpathNode:l,xpathString:c}=t.Lib;let d=l(o);if(!d)return;let h=d.lastElementChild;for(;h;){i(h);const o=c(s,h)||"unknown",l=c(a,h);if(l&&l.endsWith(".jpg")||l.endsWith(".png")){yield e(t,"Loading External Image: "+l);const i=new Image;i.src=l,document.body.appendChild(i),await n(2.5*r),document.body.removeChild(i)}yield e(t,"Loading Message: "+o,"messages"),h=await this.waitForPrev(t,h)}}}n.id="Telegram"},714:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BREADTH_ALL:()=>d,TikTokProfileBehavior:()=>u,TikTokVideoBehavior:()=>h});const o="//div[contains(@class, 'CommentListContainer')]",s="div[contains(@class, 'CommentItemContainer')]",a=".//p[contains(@class, 'ReplyActionText')]",n=".//p[starts-with(@data-e2e, 'view-more') and string-length(text()) > 0]",r="//div[starts-with(@data-e2e, 'user-post-item-list')]",l="div[contains(@class, 'DivItemContainerV2')]",c="button[contains(@class, 'StyledCloseIconContainer')]",d=Symbol("BREADTH_ALL");class h{static init(){return{state:{comments:0},opts:{breadth:d}}}static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?tiktok\.com\/@.+\/video\/\d+\/?.*/)}breadthComplete({opts:{breadth:t}},e){return t!==d&&t<=e}async*crawlThread(t,e,i=null,o=0){const{waitUntilNode:s,scrollAndClick:a,getState:r}=t.Lib,l=await s(n,e,i);l&&!this.breadthComplete(t,o)&&(await a(l,500),yield r(t,"View more replies","comments"),yield*this.crawlThread(t,e,l,o+1))}async*expandThread(t,e){const{xpathNode:i,scrollAndClick:o,getState:s}=t.Lib,n=i(a,e);n&&(await o(n,500),yield s(t,"View comment","comments"),yield*this.crawlThread(t,e,null,1))}async*run(t){const{xpathNode:e,iterChildMatches:i,scrollIntoView:a,getState:n}=t.Lib,r=e(o),l=i(s,r);for await(const e of l)a(e),yield n(t,"View comment","comments"),this.breadthComplete(t,0)||(yield*this.expandThread(t,e));yield n(t,"TikTok Video Behavior Complete")}}h.id="TikTokVideo";class u{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?tiktok\.com\/@[a-zA-Z0-9]+(\/?$|\/\?.*)/)}static init(){return{state:{videos:0,comments:0},opts:{breadth:d}}}async*openVideo(t,e){const{HistoryState:i,xpathNode:o,sleep:s}=t.Lib,a=o(".//a",e);if(!a)return;const n=new i((()=>a.click()));if(await s(500),n.changed){const e=new h;yield*e.run(t),await s(500),await n.goBack(c)}}async*run(t){const{xpathNode:e,iterChildMatches:i,scrollIntoView:o,getState:s,sleep:a}=t.Lib,n=e(r),c=i(l,n);for await(const e of c)o(e),yield s(t,"View video","videos"),yield*this.openVideo(t,e),await a(500);yield s(t,"TikTok Profile Behavior Complete")}}u.id="TikTokProfile"},739:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TwitterTimelineBehavior:()=>g});const o="//h1[@role='heading' and @aria-level='1']/following-sibling::div[@aria-label]/*[1]",s=".//article",a="string(.//article//a[starts-with(@href, '/') and @aria-label]/@href)",n="child::div[.//a[@href='$1']]",r=".//div[@role='button' and not(@aria-haspopup) and not(@data-testid)]",l=".//div[@role='blockquote' and @aria-haspopup='false']",c=".//a[@role='link' and starts-with(@href, '/') and contains(@href, '/photo/')]",d="//div[@aria-roledescription='carousel']/div[2]/div[1]//div[@role='button']",h="//div[@aria-roledescription='carousel']/div[2]/div[2]//div[@role='button']",u="//div[@role='presentation']/div[@role='button' and @aria-label]",w="//div[@data-testid='titleContainer']//div[@role='button']",m=".//a[@href='/settings/content_you_see']/parent::div/parent::div/parent::div//div[@role='button']",f=".//*[@role='progressbar']",p=".//div[data-testid='placementTracking']";class g{static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?twitter\.com\//)}static init(){return{state:{tweets:0,images:0,videos:0},opts:{maxDepth:0}}}constructor(){this.seenTweets=new Set,this.seenMediaTweets=new Set}showingProgressBar(t,e){const{xpathNode:i}=t.Lib,o=i(f,e);return!!o&&o.clientHeight>10}async waitForNext(t,e){const{sleep:i,waitUnit:o}=t.Lib;if(!e)return null;if(await i(2*o),!e.nextElementSibling)return null;for(;this.showingProgressBar(t,e.nextElementSibling);)await i(o);return e.nextElementSibling}async expandMore(t,e){const{sleep:i,waitUnit:o,xpathNode:s}=t.Lib,a=s(r,e);if(!a)return e;const n=e.previousElementSibling;for(a.click(),await i(o);this.showingProgressBar(t,n.nextElementSibling);)await i(o);return e=n.nextElementSibling}async*infScroll(t){const{scrollIntoView:e,RestoreState:i,sleep:l,waitUnit:c,xpathNode:d}=t.Lib;let h=d(o);if(!h)return;let u=h.firstElementChild;if(u)for(;u;){let h=d(s,u);if(!h&&r&&(u=await this.expandMore(t,u),h=d(s,u)),u&&u.innerText&&e(u),u&&h){await l(c);const t=new i(a,u);yield h,t.matchValue&&(u=await t.restore(o,n))}u=await this.waitForNext(t,u)}}async*mediaPlaying(t,e){const{getState:i,sleep:o,xpathNode:s,xpathString:n}=t.Lib,r=s("(.//video | .//audio)",e);if(!r||r.paused)return;let l,c=null;try{c=new URL(n(a,e.parentElement),window.location.origin).href}catch(t){console.warn(t)}if(r.src.startsWith("https://")&&r.src.indexOf(".mp4")>0)return void(yield i(t,`Loading video for ${c||"unknown"}`,"videos"));if(c){if(this.seenMediaTweets.has(c))return;l=`Waiting for media playback for ${c} to finish`,this.seenMediaTweets.add(c)}else l="Loading video";yield i(t,l,"videos");const d=new Promise((t=>{r.addEventListener("ended",(()=>t(null))),r.addEventListener("abort",(()=>t(null))),r.addEventListener("error",(()=>t(null))),r.addEventListener("pause",(()=>t(null)))}));await Promise.race([d,o(6e4)])}async*clickImages(t,e){const{getState:i,HistoryState:o,sleep:s,waitUnit:a,xpathNode:n}=t.Lib,r=n(c,e);if(r){const e=new o((()=>r.click()));yield i(t,"Loading Image: "+window.location.href,"images"),await s(5*a);let l=n(d),c=window.location.href;for(;l;){if(l.click(),await s(2*a),window.location.href===c){await s(5*a);break}c=window.location.href,yield i(t,"Loading Image: "+window.location.href,"images"),await s(5*a),l=n(h)}await e.goBack(u)}}async*clickTweet(t,e,i){const{getState:o,HistoryState:s,sleep:a,waitUnit:n}=t.Lib,r=new s((()=>e.click()));if(await a(n),r.changed){yield o(t,"Capturing Tweet: "+window.location.href,"tweets");i{var o={".":607,"./":607,"./autofetcher":894,"./autofetcher.ts":894,"./autoplay":376,"./autoplay.ts":376,"./autoscroll":234,"./autoscroll.ts":234,"./index":607,"./index.ts":607,"./lib/behavior":841,"./lib/behavior.ts":841,"./lib/utils":721,"./lib/utils.ts":721,"./site":954,"./site/":954,"./site/facebook":121,"./site/facebook.ts":121,"./site/index":954,"./site/index.ts":954,"./site/instagram":741,"./site/instagram.ts":741,"./site/telegram":667,"./site/telegram.ts":667,"./site/tiktok":714,"./site/tiktok.ts":714,"./site/twitter":739,"./site/twitter.ts":739};function s(t){return Promise.resolve().then((()=>{if(!i.o(o,t)){var e=new Error("Cannot find module '"+t+"'");throw e.code="MODULE_NOT_FOUND",e}var s=o[t];return i(s)}))}s.keys=()=>Object.keys(o),s.id=75,t.exports=s}},e={};function i(o){var s=e[o];if(void 0!==s)return s.exports;var a=e[o]={exports:{}};return t[o](a,a.exports,i),a.exports}i.d=(t,e)=>{for(var o in e)i.o(e,o)&&!i.o(t,o)&&Object.defineProperty(t,o,{enumerable:!0,get:e[o]})},i.e=()=>Promise.resolve(),i.o=(t,e)=>Object.prototype.hasOwnProperty.call(t,e),i.r=t=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},(()=>{"use strict";i(607)})()})(); \ No newline at end of file diff --git a/src/site/instagram.ts b/src/site/instagram.ts index ccd3769..2367131 100644 --- a/src/site/instagram.ts +++ b/src/site/instagram.ts @@ -223,7 +223,7 @@ export class InstagramPostsBehavior { async* run(ctx) { const { getState, scrollIntoView, sleep, waitUnit, xpathNode } = ctx.Lib; - const origLoc = window.location.href; + //const origLoc = window.location.href; //yield* this.viewStandalonePost(ctx, origLoc); diff --git a/test/expected-autoscroll.log b/test/expected-autoscroll.log index 433c6f1..938f5b9 100644 --- a/test/expected-autoscroll.log +++ b/test/expected-autoscroll.log @@ -1,2 +1,2 @@ -{"state":{"segments":1},"msg":"Skipping autoscroll, page seems to not be responsive to scrolling events"} -{"state":{"segments":1},"msg":"done!"} +{"state":{"segments":1},"msg":"Skipping autoscroll, page seems to not be responsive to scrolling events","page":"https://www.iana.org/numbers","workerid":0} +{"state":{"segments":1},"msg":"done!","page":"https://www.iana.org/numbers","workerid":0}