diff --git a/Dockerfile b/Dockerfile index 1988efca..7ec76f05 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG BROWSER_VERSION=1.73.104 +ARG BROWSER_VERSION=1.74.48 ARG BROWSER_IMAGE_BASE=webrecorder/browsertrix-browser-base:brave-${BROWSER_VERSION} FROM ${BROWSER_IMAGE_BASE} @@ -39,7 +39,7 @@ ADD config/ /app/ ADD html/ /app/html/ -ARG RWP_VERSION=2.2.4 +ARG RWP_VERSION=2.2.5 ADD https://cdn.jsdelivr.net/npm/replaywebpage@${RWP_VERSION}/ui.js /app/html/rwp/ ADD https://cdn.jsdelivr.net/npm/replaywebpage@${RWP_VERSION}/sw.js /app/html/rwp/ ADD https://cdn.jsdelivr.net/npm/replaywebpage@${RWP_VERSION}/adblock/adblock.gz /app/html/rwp/adblock.gz diff --git a/behaviors.js b/behaviors.js new file mode 100644 index 00000000..13acd666 --- /dev/null +++ b/behaviors.js @@ -0,0 +1 @@ +/*! behaviors.js is part of Webrecorder project. Copyright (C) 2021-2025, Webrecorder Software. Licensed under the Affero General Public License v3. */(()=>{var t={480:(t,e,i)=>{"use strict";function o(t,e=document,i=null){return s(t,!0,e,i)}function s(t,e,i,o=null){t=function(t){function e(){o&&(a.length>0&&/^[~+>]$/.test(a[a.length-1])&&a.push(" "),a.push(o))}var i,o,s,n,a=[],r=[0],l=0,c=/(?:[^\\]|(?:^|[^\\])(?:\\\\)+)$/,d=/^\s+$/,h=[/\s+|\/\*|["'>~+[(]/g,/\s+|\/\*|["'[\]()]/g,/\s+|\/\*|["'[\]()]/g,null,/\*\//g];for(t=t.trim();;){if(o="",(s=h[r[r.length-1]]).lastIndex=l,!(i=s.exec(t))){o=t.substr(l),e();break}if((n=l)<(l=s.lastIndex)-i[0].length&&(o=t.substring(n,l-i[0].length)),r[r.length-1]<3){if(e(),"["===i[0])r.push(1);else if("("===i[0])r.push(2);else if(/^["']$/.test(i[0]))r.push(3),h[3]=new RegExp(i[0],"g");else if("/*"===i[0])r.push(4);else if(/^[\])]$/.test(i[0])&&r.length>0)r.pop();else if(/^(?:\s+|[~+>])$/.test(i[0])&&(a.length>0&&!d.test(a[a.length-1])&&0===r[r.length-1]&&a.push(" "),1===r[r.length-1]&&5===a.length&&"="===a[2].charAt(a[2].length-1)&&(a[4]=" "+a[4]),d.test(i[0])))continue;a.push(i[0])}else a[a.length-1]+=o,c.test(a[a.length-1])&&(4===r[r.length-1]&&(a.length<2||d.test(a[a.length-2])?a.pop():a[a.length-1]=" ",i[0]=""),r.pop()),a[a.length-1]+=i[0]}return a.join("").trim()}(t);let s=i.querySelector(t);if(document.head.createShadowRoot||document.head.attachShadow){if(!e&&s)return s;return n(t,",").reduce(((t,s)=>{if(!e&&t)return t;const l=n(s.replace(/^\s+/g,"").replace(/\s*([>+~]+)\s*/g,"$1")," ").filter((t=>!!t)).map((t=>n(t,">"))),c=l.length-1,d=function(t=null,e,i=null){let o=[];if(i)o=i;else{const t=function(e){for(let i=0;ie.matches(t))):o}(l[c][l[c].length-1],i,o),h=function(t,e,i){return o=>{let s=e,n=o,l=!1;for(;n&&!a(n);){let e=!0;if(1===t[s].length)e=n.matches(t[s]);else{const o=[].concat(t[s]).reverse();let a=n;for(const t of o){if(!a||!a.matches(t)){e=!1;break}a=r(a,i)}}if(e&&0===s){l=!0;break}e&&s--,n=r(n,i)}return l}}(l,c,i);return e?t=t.concat(d.filter(h)):(t=d.find(h))||null}),e?[]:null)}return e?i.querySelectorAll(t):s}function n(t,e){return t.match(/\\?.|^$/g).reduce(((t,i)=>('"'!==i||t.sQuote?"'"!==i||t.quote?t.quote||t.sQuote||i!==e?t.a[t.a.length-1]+=i:t.a.push(""):(t.sQuote^=1,t.a[t.a.length-1]+=i):(t.quote^=1,t.a[t.a.length-1]+=i),t)),{a:[""]}).a}function a(t){return t.nodeType===Node.DOCUMENT_FRAGMENT_NODE||t.nodeType===Node.DOCUMENT_NODE}function r(t,e){const i=t.parentNode;return i&&i.host&&11===i.nodeType?i.host:i===e?null:i}i.d(e,{Jp:()=>o})},702:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AutoClick:()=>n});var o=i(841),s=i(721);class n extends o.BackgroundBehavior{_donePromise;_markDone;selector;seenElem=new WeakSet;constructor(t="a"){super(),this.selector=t,this._donePromise=new Promise((t=>this._markDone=t))}nextSameOriginLink(){try{const t=document.querySelectorAll(this.selector);for(const e of t){const t=e;if((!t.href||t.href.startsWith(self.location.origin))&&(t.isConnected&&(!t.checkVisibility||t.checkVisibility())&&!this.seenElem.has(t)))return this.seenElem.add(t),t}}catch(t){this.debug(t.toString())}return null}async start(){const t=self.location.href,e=t=>(t.preventDefault(),!1);for(window.addEventListener("beforeunload",e);;){const e=this.nextSameOriginLink();if(!e)break;await this.processElem(e,t)}window.removeEventListener("beforeunload",e),this._markDone()}async processElem(t,e){try{if(!getEventListeners(t).click)return}catch(t){}if(t.target)return;const i=self;if(t.href){if(i.__bx_addSet&&!await i.__bx_addSet(t.href))return;this.debug("Clicking on link: "+t.href)}else this.debug("Click empty link");t.click(),await(0,s.sleep)(250),self.location.href!=e&&await new Promise((t=>{window.addEventListener("popstate",(()=>{t(null)}),{once:!0}),window.history.back()}))}catch(t){this.debug(t.toString())}done(){return this._donePromise}}},894:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AutoFetcher:()=>c});var o=i(480),s=i(841),n=i(721);const a=/\s*(\S*\s+[\d.]+[wx]),|(?:\s*,(?:\s+|(?=https?:)))/,r=/(url\s*\(\s*[\\"']*)([^)'"]+)([\\"']*\s*\))/gi,l=/(@import\s*[\\"']*)([^)'";]+)([\\"']*\s*;?)/gi;class c extends s.BackgroundBehavior{urlSet=new Set;pendingQueue=[];waitQueue=[];mutationObserver;numPending=0;numDone=0;headers;_donePromise;_markDone;active;running=!1;static id="AutoFetcher";constructor(t=!1,e=null,i=!1){super(),this.headers=e||{},this._donePromise=new Promise((t=>this._markDone=t)),this.active=t,this.active&&i&&document.addEventListener("DOMContentLoaded",(()=>this.initObserver()))}get numFetching(){return this.numDone+this.numPending+this.pendingQueue.length}async start(){this.active&&(this.initObserver(),this.run(),(0,n.sleep)(500).then((()=>{this.pendingQueue.length||this.numPending||this._markDone(null)})))}done(){return this._donePromise}async run(){this.running=!0;for(const t of this.waitQueue)this.doFetch(t);this.waitQueue=[],this.extractSrcSrcSetAll(document),this.extractStyleSheets(),this.extractDataAttributes(document)}isValidUrl(t){return t&&(t.startsWith("http:")||t.startsWith("https:"))}queueUrl(t,e=!1){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.running||e?this.doFetch(t):this.waitQueue.push(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.pendingQueue.push(t),this.numPending<=6){for(;this.pendingQueue.length>0;){const t=this.pendingQueue.shift();this.numPending++;let e=!1;self.__bx_fetch&&(e=await self.__bx_fetch(t)),e||await this.doFetchNonCors(t),this.numPending--,this.numDone++}this.numPending||this._markDone(null)}}initObserver(){this.mutationObserver||(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),setTimeout((()=>this.extractDataAttributes(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=(0,o.Jp)("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]",t);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&&(i||o||"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(r,e).replace(l,e)}extractDataAttributes(t){for(const e of(0,n.xpathNodes)("//@*[starts-with(name(), 'data-') and (starts-with(., 'http') or starts-with(., '/') or starts-with(., './') or starts-with(., '../'))]",t))this.queueUrl(e.value)}}},376:(t,e,i)=>{"use strict";i.r(e),i.d(e,{Autoplay:()=>a});var o=i(480),s=i(841),n=i(721);class a extends s.BackgroundBehavior{mediaSet;autofetcher;numPlaying;promises;_initDone;running=!1;polling=!1;static id="Autoplay";constructor(t,e=!1){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))),e&&document.addEventListener("DOMContentLoaded",(()=>this.pollAudioVideo()))}async start(){this.running=!0,this.pollAudioVideo(),this._initDone()}async pollAudioVideo(){if(!this.polling){for(this.polling=!0;;){for(const[,t]of(0,o.Jp)("video, audio, picture").entries())if(!t.__bx_autoplay_found){if(!this.running){this.processFetchableUrl(t)&&(t.__bx_autoplay_found=!0);continue}await this.loadMedia(t),t.__bx_autoplay_found=!0}await(0,n.sleep)(500)}this.polling=!1}}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||t.currentTime?(t.paused?this.debug("no src url found, attempting to click or play: "+t.outerHTML):this.debug("media already playing, waiting for full playback to finish: "+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,n.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 s=new Promise((t=>{o=t}));if(s.then((()=>this.promises.push(i))),!t.paused&&t.currentTime>0&&o(),t.addEventListener("loadstart",(()=>{this.debug("media event: loadstart"),o(!0)})),t.addEventListener("playing",(()=>{this.debug("media event: playing"),o(!0)})),t.addEventListener("loadeddata",(()=>this.debug("media event: loadeddata"))),t.addEventListener("ended",(()=>{this.debug("media event: ended"),e()})),t.addEventListener("pause",(()=>{this.debug("media event: pause"),e()})),t.addEventListener("abort",(()=>{this.debug("media event: abort"),e()})),t.addEventListener("error",(()=>{this.debug("media event: error"),e()})),t.addEventListener("stalled",(()=>{this.debug("media event: stalled"),e()})),t.addEventListener("suspend",(()=>{this.debug("media event: suspend"),e()})),t.muted=!0,!t.paused&&t.currentTime>0)return i;return!t.closest("a")&&(t.click(),await Promise.race([s,(0,n.sleep)(1e3)]))?(this.debug("play started after media.click()"),i):(t.play(),await Promise.race([s,(0,n.sleep)(1e3)])&&this.debug("play started after media.play()"),i)}done(){return Promise.allSettled(this.promises)}}},234:(t,e,i)=>{"use strict";i.r(e),i.d(e,{AutoScroll:()=>n});var o=i(841),s=i(721);class n extends o.Behavior{autoFetcher;showMoreQuery;state={segments:1};lastScrollPos;samePosCount;origPath;constructor(t){super(),this.autoFetcher=t,this.showMoreQuery="//*[contains(text(), 'show more') or contains(text(), 'Show more')]",this.lastScrollPos=-1,this.samePosCount=0,this.origPath=document.location.pathname}static id="Autoscroll";currScrollPos(){return Math.round(self.scrollY+self.innerHeight)}canScrollMore(){const t=self.document.scrollingElement||self.document.body;return this.currScrollPos()=2)return!0;const t=self.document.scrollingElement.scrollHeight,e=this.autoFetcher.numFetching,i=.98*document.scrollingElement.scrollHeight-self.innerHeight;return window.scrollTo({top:i,left:0,behavior:"smooth"}),await(0,s.sleep)(500),(t!==self.document.scrollingElement.scrollHeight||en&&(this.state.segments++,n=a),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>a),500),(0,s.sleep)(3e4)]),self.document.scrollingElement.scrollHeight===a&&(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))])}}}},607:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BehaviorManager:()=>h});var o=i(894),s=i(376),n=i(234),a=i(702),r=i(721),l=i(841),c=i(954);const d={autofetch:!0,autoplay:!0,autoscroll:!0,autoclick:!0,siteSpecific:!0};class h{autofetch;behaviors;loadedBehaviors;mainBehavior;mainBehaviorClass;inited;started;timeout;opts;constructor(){this.behaviors=[],this.loadedBehaviors=c.default.reduce(((t,e)=>(t[e.id]=e,t)),{}),this.mainBehavior=null,this.inited=!1,this.started=!1,(0,r.behaviorLog)("Loaded behaviors for: "+self.location.href)}init(t=d,e=!1,i=null){if((!this.inited||e)&&(this.inited=!0,this.opts=t,self.window)){if(this.timeout=t.timeout,void 0!==t.log){let e=t.log;"string"==typeof e&&(e=self[e]),"function"==typeof e?(0,r._setLogFunc)(e):!1===e&&(0,r._setLogFunc)(null)}if(this.autofetch=new o.AutoFetcher(!!t.autofetch,t.fetchHeaders,t.startEarly),t.autofetch&&((0,r.behaviorLog)("Using AutoFetcher"),this.behaviors.push(this.autofetch)),t.autoplay&&((0,r.behaviorLog)("Using Autoplay"),this.behaviors.push(new s.Autoplay(this.autofetch,t.startEarly))),t.autoclick&&((0,r.behaviorLog)("Using AutoClick"),this.behaviors.push(new a.AutoClick(t.clickSelector||"a"))),this.isInTopFrame()&&i)for(const t of i)try{this.load(t)}catch(e){(0,r.behaviorLog)(`Failed to load custom behavior: ${e} ${t}`)}}}selectMainBehavior(){if(this.mainBehavior)return;const t=this.opts;let e=!1;if(t.siteSpecific)for(const i in this.loadedBehaviors){const o=this.loadedBehaviors[i];if(o.isMatch()){(0,r.behaviorLog)("Using Site-Specific Behavior: "+i),this.mainBehaviorClass=o;const s="object"==typeof t.siteSpecific&&t.siteSpecific[i]||{};try{this.mainBehavior=new l.BehaviorRunner(o,s)}catch(t){(0,r.behaviorLog)(t.toString(),"error")}e=!0;break}}return!e&&t.autoscroll&&((0,r.behaviorLog)("Using Autoscroll"),this.mainBehaviorClass=n.AutoScroll,this.mainBehavior=new n.AutoScroll(this.autofetch)),this.mainBehavior&&(this.behaviors.push(this.mainBehavior),this.mainBehavior instanceof l.BehaviorRunner)?this.mainBehavior.behaviorProps.id:""}load(t){if("function"!=typeof t)return void(0,r.behaviorLog)(`Must pass a class object, got ${t}`,"error");if("string"!=typeof t.id)return void(0,r.behaviorLog)('Behavior class must have a string string "id" property',"error");if("function"!=typeof t.isMatch||"function"!=typeof t.init)return void(0,r.behaviorLog)("Behavior class must have an is `isMatch()` and `init()` static methods","error");const e=t.id;(0,r.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 awaitPageLoad(){this.selectMainBehavior(),this.mainBehavior?.awaitPageLoad&&await this.mainBehavior.awaitPageLoad()}async run(t=d,e=!1){if(e&&(this.started=!1),this.started)return void this.unpause();this.init(t,e),this.selectMainBehavior(),await(0,r.awaitLoad)(),this.behaviors.forEach((t=>{(0,r.behaviorLog)("Starting behavior: "+t.constructor.id||0),t.start()})),this.started=!0,await(0,r.sleep)(500);let i=Promise.allSettled(this.behaviors.map((t=>t.done())));this.timeout?((0,r.behaviorLog)(`Waiting for behaviors to finish or ${this.timeout}ms timeout`),await Promise.race([i,(0,r.sleep)(this.timeout)])):((0,r.behaviorLog)("Waiting for behaviors to finish"),await i),(0,r.behaviorLog)("All Behaviors Done for "+self.location.href),this.mainBehavior&&this.mainBehaviorClass.cleanup&&this.mainBehavior.cleanup()}async runOne(t,e={}){const i=c.default.find((e=>e.name===t));if(void 0===i)return void console.error(`No behavior of name ${t} found`);const o=new l.BehaviorRunner(i,e);o.start(),console.log(`Running behavior: ${t}`),await o.done(),console.log(`Behavior ${t} completed`)}pause(){(0,r.behaviorLog)("Pausing Main Behavior"+this.mainBehaviorClass.name),this.behaviors.forEach((t=>t.pause()))}unpause(){this.behaviors.forEach((t=>t.unpause()))}doAsyncFetch(t){return(0,r.behaviorLog)("Queueing Async Fetch Url: "+t),this.autofetch.queueUrl(t,!0)}isInTopFrame(){return self.window.top===self.window||window.__WB_replay_top===self.window}}(0,r._setBehaviorManager)(h),(0,r.installBehaviors)(self)},841:(t,e,i)=>{"use strict";i.r(e),i.d(e,{BackgroundBehavior:()=>s,Behavior:()=>n,BehaviorRunner:()=>a});var o=i(721);class s{debug(t){(0,o.behaviorLog)(t,"debug")}log(t){(0,o.behaviorLog)(t,"info")}}class n extends s{_running;paused;_unpause;state;scrollOpts;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(){}async awaitPageLoad(){}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 a extends s{inst;behaviorProps;ctx;_running;paused;_unpause;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 n=o.behaviorLog;this.ctx={Lib:o,state:i,opts:s,log:n},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(){}async awaitPageLoad(){this.inst.awaitPageLoad&&await this.inst.awaitPageLoad(this.ctx)}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:()=>y,RestoreState:()=>b,_setBehaviorManager:()=>p,_setLogFunc:()=>g,addLink:()=>m,awaitLoad:()=>h,behaviorLog:()=>w,getState:()=>N,installBehaviors:()=>v,isInViewport:()=>k,iterChildElem:()=>P,iterChildMatches:()=>_,openWindow:()=>f,scrollAndClick:()=>a,scrollIntoView:()=>T,scrollToOffset:()=>E,sleep:()=>l,waitUnit:()=>r,waitUntil:()=>c,waitUntilNode:()=>d,xpathNode:()=>S,xpathNodes:()=>x,xpathString:()=>L});let o=console.log,s=null;const n={behavior:"smooth",block:"center",inline:"center"};async function a(t,e=500,i=n){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 n=null,a=!1;const l=c((()=>(n=S(t,e),a||n!==i&&null!==n)),s),d=new Promise((t=>setTimeout((()=>{a=!0,t("TIMEOUT")}),o)));return await Promise.race([l,d]),n}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})}function m(t){self.__bx_addLink&&self.__bx_addLink(t)}async function f(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 g(t){o=t}function p(t){s=t}function v(t){t.__bx_behaviors=new s}class b{matchValue;constructor(t,e){this.matchValue=L(t,e)}async restore(t,e){let i=null;for(;i=S(t),!i;)await l(100);return S(e.replace("$1",this.matchValue),i)}}class y{loc;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=S(t);return new Promise((t=>{window.addEventListener("popstate",(()=>{t(null)}),{once:!0}),e?e.click():window.history.back()}))}}function S(t,e){return e=e||document,document.evaluate(t,e,null,XPathResult.FIRST_ORDERED_NODE_TYPE).singleNodeValue}function*x(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 L(t,e){return e=e||document,document.evaluate(t,e,null,XPathResult.STRING_TYPE).stringValue}async function*P(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*_(t,e,i=r,o=5e3){let s=S(`.//${t}`,e);const n=e=>S(`./following-sibling::${t}`,e);for(;s;){yield s;let t=n(s);t?s=t:(await Promise.race([c((()=>(t=n(s),t)),i),l(o)]),s=t)}}function k(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 E(t,e=0){const i=t.getBoundingClientRect().top+window.pageYOffset-e;window.scrollTo({top:i,behavior:"smooth"})}function T(t,e={behavior:"smooth",block:"center",inline:"center"}){t.scrollIntoView(e)}function N(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{extraWindow;allowNewWindow;static id="Facebook";static isMatch(){return!1}static init(){return{state:{}}}constructor(){this.extraWindow=null,this.allowNewWindow=!1}async*iterPostFeeds(t){const{iterChildElem:e,waitUnit:i,waitUntil:s,xpathNode:n,xpathNodes:a}=t.Lib,r=Array.from(a(o.feed));if(r&&r.length)for(const a of r)for await(const r of e(a,i,10*s))yield*this.viewPost(t,n(o.article,r));else{const a=n(o.pageletPostList)||n(o.pageletProfilePostList)||n(o.articleToPostList);if(!a)return;for await(const r of e(a,i,10*s))yield*this.viewPost(t,n(o.article,r))}this.extraWindow&&this.extraWindow.close()}async*viewPost(t,e,i=2){const{getState:s,scrollIntoView:n,sleep:a,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"),n(e),await a(2*r),l(".//video",e)&&(yield s(t,"Playing inline video","videos"),await a(2*r));let h=l(o.commentList,e);if(!h){const t=l(o.viewComments,e);t&&(t.click(),await a(2*r)),h=l(o.commentList,e)}yield*this.iterComments(t,h,i),await a(5*r)}async*viewPhotosOrVideos(t,e){const{getState:i,sleep:s,waitUnit:n,xpathNode:a,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*n),e.click(),await s(10*n),this.allowNewWindow&&await this.openNewWindow(t,r.href),d===l.length&&(yield*this.viewExtraObjects(t,e,h,this.allowNewWindow));const u=a(o.nextSlide);u&&(u.click(),await s(2*n))}}async*viewExtraObjects(t,e,i,s){const{getState:n,sleep:a,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 n(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:n,sleep:a,waitUnit:r,xpathNode:l}=t.Lib;if(!e)return void await a(5*r);let c=e.firstElementChild,d=null,h=0;for(;c&&hwindow.location.href!==c),2*n);let d=null;for(;(d=r(o.nextSlideQuery))&&(c=window.location.href,await s(n),d.click(),await s(5*n),await Promise.race([a((()=>window.location.href!==c),2*n),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*n)}}async*iterAllVideos(t){const{getState:e,scrollIntoView:i,sleep:s,waitUnit:n,waitUntil:a,xpathNode:r,xpathNodes:l}=t.Lib,c=r("//video");c&&(i(c),await s(5*n));let d=r(o.firstVideoThumbnail)||r(o.firstVideoSimple);if(d)for(;d;){i(d);let c=window.location.href;d.click(),await a((()=>window.location.href!==c),2*n),yield e(t,"Viewing video: "+window.location.href,"videos"),await s(10*n),await Promise.race([a((()=>{for(const t of l("//video"))if(t.readyState>=3)return!0;return!1}),2*n),s(2e4)]),await s(10*n);const h=r(o.nextSlide);if(!h)break;c=window.location.href,h.click(),await a((()=>window.location.href!==c),2*n),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)}}},954:(t,e,i)=>{"use strict";i.r(e),i.d(e,{default:()=>l});var o=i(121),s=i(741),n=i(667),a=i(739),r=i(714);const l=[s.InstagramPostsBehavior,a.TwitterTimelineBehavior,o.FacebookTimelineBehavior,n.TelegramBehavior,r.TikTokVideoBehavior,r.TikTokProfileBehavior]},741:(t,e,i)=>{"use strict";i.r(e),i.d(e,{InstagramPostsBehavior:()=>n});const o="//article[@role='presentation']//div[@role='presentation']/following-sibling::button",s={rootPath:"//main/div/div[2]/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/div[last()]/div/div",viewReplies:"ul/li//button[span[not(count(*)) and contains(text(), '(')]]",loadMore:"//button[span[@aria-label]]",pageLoadWaitUntil:"//main"};class n{maxCommentsTime;postOnlyWindow;static id="Instagram";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:n}=t.Lib;let a=n(s.rootPath);if(!a)return;let r=a.firstElementChild;if(r)for(;r;){await i(o);const n=new e(s.childMatchSelect,r);n.matchValue&&(yield r,r=await n.restore(s.rootPath,s.childMatch)),r=await this.waitForNext(t,r)}}async*viewStandalonePost(t,e){const{getState:i,sleep:o,waitUnit:n,waitUntil:a,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*n),await a((()=>(h=r(s.rootPath))!==c&&h),5*n),await o(5*n),window.history.replaceState({},"",e),window.dispatchEvent(new PopStateEvent("popstate",{state:{}})),await a((()=>(u=r(s.rootPath))!==h&&u),5*n)}async*iterSubposts(t){const{getState:e,sleep:i,waitUnit:o,xpathNode:n}=t.Lib;let a=n(s.subpostNextOnlyChevron),r=1;for(;a;)a.click(),await i(5*o),yield e(t,`Loading Slide ${++r} for ${window.location.href}`,"slides"),a=n(s.subpostPrevNextChevron);await i(5*o)}async iterComments(t){const{scrollIntoView:e,sleep:i,waitUnit:o,waitUntil:n,xpathNode:a}=t.Lib,r=a(s.commentRoot);if(!r)return;let l=r.firstElementChild,c=!1;const d=t=>a(s.viewReplies,t);for(;l;){e(l),c=!0;let r=d(l);for(;r;){const e=r.textContent;r.click(),t.state.comments++,await i(2.5*o),await n((()=>e!==r.textContent),o),r=d(l)}if(l.nextElementSibling&&"LI"===l.nextElementSibling.tagName&&!l.nextElementSibling.nextElementSibling){let e=a(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:n,xpathNode:a}=t.Lib;let r=0;for(;e&&++r<=3;)for(e.click(),await o(10*n),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=a(s.nextPost);!e&&a(s.postLoading);)await o(2.5*n);await o(5*n)}async*run(t){const{getState:e,scrollIntoView:i,sleep:o,waitUnit:n,xpathNode:a}=t.Lib;for await(const r of this.iterRow(t)){i(r),await o(2.5*n),yield e(t,"Loading Row","rows");const l=a(s.firstPostInRow,r);yield*this.iterPosts(t,l);const c=a(s.postCloseButton);c&&c.click(),await o(5*n)}}async awaitPageLoad(t){const{Lib:e,log:i}=t,{waitUntilNode:o}=e;i("Waiting for Instagram to fully load","info"),await o(s.pageLoadWaitUntil,document,null,3e4)}}},667:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TelegramBehavior:()=>a});const o="//main//section[@class='tgme_channel_history js-message_history']",s="string(./div[@data-post]/@data-post)",n="string(.//a[@class='tgme_widget_message_link_preview' and @href]/@href)";class a{static id="Telegram";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:a,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(n,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 a(2.5*r),document.body.removeChild(i)}yield e(t,"Loading Message: "+o,"messages"),h=await this.waitForPrev(t,h)}}}},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')]",n=".//p[contains(@class, 'ReplyActionText')]",a=".//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 id="TikTokVideo";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:n,getState:r}=t.Lib,l=await s(a,e,i);l&&!this.breadthComplete(t,o)&&(await n(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,a=i(n,e);a&&(await o(a,500),yield s(t,"View comment","comments"),yield*this.crawlThread(t,e,null,1))}async*run(t){const{xpathNode:e,iterChildMatches:i,scrollIntoView:n,getState:a}=t.Lib,r=e(o),l=i(s,r);for await(const e of l)n(e),yield a(t,"View comment","comments"),this.breadthComplete(t,0)||(yield*this.expandThread(t,e));yield a(t,"TikTok Video Behavior Complete")}}class u{static id="TikTokProfile";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,n=o(".//a",e);if(!n)return;const a=new i((()=>n.click()));if(await s(500),a.changed){const e=new h;yield*e.run(t),await s(500),await a.goBack(c)}}async*run(t){const{xpathNode:e,iterChildMatches:i,scrollIntoView:o,getState:s,sleep:n}=t.Lib,a=e(r),c=i(l,a);for await(const e of c)o(e),yield s(t,"View video","videos"),yield*this.openVideo(t,e),await n(500);yield s(t,"TikTok Profile Behavior Complete")}}},739:(t,e,i)=>{"use strict";i.r(e),i.d(e,{TwitterTimelineBehavior:()=>p});const o="//h1[@role='heading' and @aria-level='1']/following-sibling::div[@aria-label]//div[@style]",s=".//article",n="string(.//article//a[starts-with(@href, '/') and @aria-label]/@href)",a="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']",g=".//div[data-testid='placementTracking']";class p{seenTweets;seenMediaTweets;static id="Twitter";static isMatch(){return!!window.location.href.match(/https:\/\/(www\.)?(x|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,n=s(r,e);if(!n)return e;const a=e.previousElementSibling;for(n.click(),await i(o);this.showingProgressBar(t,a.nextElementSibling);)await i(o);return e=a.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(n,u);yield h,t.matchValue&&(u=await t.restore(o,a))}u=await this.waitForNext(t,u)}}async*mediaPlaying(t,e){const{getState:i,sleep:o,xpathNode:s,xpathString:a}=t.Lib,r=s("(.//video | .//audio)",e);if(!r||r.paused)return;let l,c=null;try{c=new URL(a(n,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:n,xpathNode:a}=t.Lib,r=a(c,e);if(r){const e=new o((()=>r.click()));yield i(t,"Loading Image: "+window.location.href,"images"),await s(5*n);let l=a(d),c=window.location.href;for(;l;){if(l.click(),await s(2*n),window.location.href===c){await s(5*n);break}c=window.location.href,yield i(t,"Loading Image: "+window.location.href,"images"),await s(5*n),l=a(h)}await e.goBack(u)}}async*clickTweet(t,e,i){const{getState:o,HistoryState:s,sleep:n,waitUnit:a}=t.Lib,r=new s((()=>e.click()));if(await n(a),r.changed){yield o(t,"Capturing Tweet: "+window.location.href,"tweets");i{var o={".":607,"./":607,"./autoclick":702,"./autoclick.ts":702,"./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 n=e[o]={exports:{}};return t[o](n,n.exports,i),n.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/docs/docs/user-guide/cli-options.md b/docs/docs/user-guide/cli-options.md index fb449c97..9a33a479 100644 --- a/docs/docs/user-guide/cli-options.md +++ b/docs/docs/user-guide/cli-options.md @@ -50,11 +50,14 @@ Options: e-page-application crawling or when different hashtags load dynamic cont ent - --selectLinks one or more selectors for extracting + --selectLinks, --linkSelector One or more selectors for extracting links, in the format [css selector] ->[property to use],[css selector]-> @[attribute to use] [array] [default: ["a[href]->href"]] + --clickSelector Selector for elements to click when + using the autoclick behavior + [string] [default: "a"] --blockRules Additional rules for blocking certai n URLs from being loaded, by URL reg ex and optionally via text match in @@ -75,7 +78,8 @@ Options: [string] [default: "crawl-@ts"] --headless Run in headless mode, otherwise star t xvfb [boolean] [default: false] - --driver JS driver for the crawler [string] + --driver Custom driver for the crawler, if an + y [string] --generateCDX, --generatecdx, --gene If set, generate index (CDXJ) for us rateCdx e with pywb after crawl is done [boolean] [default: false] @@ -142,8 +146,7 @@ Options: o crawl working directory) [string] --behaviors Which background behaviors to enable on each page - [array] [choices: "autoplay", "autofetch", "autoscroll", "siteSpecific"] [defa - ult: ["autoplay","autofetch","autoscroll","siteSpecific"]] + [array] [default: ["autoplay","autofetch","autoscroll","siteSpecific"]] --behaviorTimeout If >0, timeout (in seconds) for in-p age behavior will run on each page. If 0, a behavior can run until finis @@ -163,8 +166,10 @@ Options: hich contains the browser profile di rectory [string] --screenshot Screenshot options for crawler, can - include: view, thumbnail, fullPage - [array] [choices: "view", "thumbnail", "fullPage"] [default: []] + include: view, thumbnail, fullPage, + fullPageFinal + [array] [choices: "view", "thumbnail", "fullPage", "fullPageFinal"] [default: + []] --screencastPort If set to a non-zero value, starts a n HTTP server with screencast access ible on this port @@ -251,9 +256,15 @@ Options: failing due to non-200 responses [boolean] [default: false] --customBehaviors Custom behavior files to inject. Val - ues can be URLs, paths to individual - behavior files, or paths to a direc - tory of behavior files + id values: URL to file, path to file + , path to directory of behaviors, UR + L to Git repo of behaviors (prefixed + with git+, optionally specify branc + h and relative path to a directory w + ithin repo as branch and path query + parameters, e.g. --customBehaviors " + git+https://git.example.com/repo.git + ?branch=dev&path=some/dir" [array] [default: []] --debugAccessRedis if set, runs internal redis without protected mode to allow external acc diff --git a/package.json b/package.json index a27f83ca..8f71b907 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "browsertrix-crawler", - "version": "1.4.2", + "version": "1.5.0-beta.2", "main": "browsertrix-crawler", "type": "module", "repository": "https://github.com/webrecorder/browsertrix-crawler", @@ -18,7 +18,7 @@ "dependencies": { "@novnc/novnc": "1.4.0", "@webrecorder/wabac": "^2.20.8", - "browsertrix-behaviors": "^0.6.6", + "browsertrix-behaviors": "^0.7.0", "client-zip": "^2.4.5", "css-selector-parser": "^3.0.5", "fetch-socks": "^1.3.0", @@ -31,7 +31,7 @@ "p-queue": "^7.3.4", "pixelmatch": "^5.3.0", "pngjs": "^7.0.0", - "puppeteer-core": "^23.7.1", + "puppeteer-core": "^24.1.0", "sax": "^1.3.0", "sharp": "^0.32.6", "tsc": "^2.0.4", diff --git a/src/crawler.ts b/src/crawler.ts index 61f0a2ea..0472399e 100644 --- a/src/crawler.ts +++ b/src/crawler.ts @@ -32,12 +32,7 @@ import { ScreenCaster, WSTransport } from "./util/screencaster.js"; import { Screenshots } from "./util/screenshots.js"; import { initRedis } from "./util/redis.js"; import { logger, formatErr, LogDetails } from "./util/logger.js"; -import { - WorkerOpts, - WorkerState, - closeWorkers, - runWorkers, -} from "./util/worker.js"; +import { WorkerState, closeWorkers, runWorkers } from "./util/worker.js"; import { sleep, timedRun, secondsElapsed } from "./util/timing.js"; import { collectCustomBehaviors, getInfoString } from "./util/file_reader.js"; @@ -689,14 +684,9 @@ export class Crawler { return !!seed.isIncluded(url, depth, extraHops, logDetails); } - async setupPage({ - page, - cdp, - workerid, - callbacks, - recorder, - frameIdToExecId, - }: WorkerOpts) { + async setupPage(opts: WorkerState) { + const { page, cdp, workerid, callbacks, frameIdToExecId, recorder } = opts; + await this.browser.setupPage({ page, cdp }); await this.setupExecContextEvents(cdp, frameIdToExecId); @@ -775,6 +765,87 @@ self.__bx_behaviors.selectMainBehavior(); await this.browser.addInitScript(page, initScript); } + + // only add if running with autoclick behavior + if (this.params.behaviors.includes("autoclick")) { + // Ensure off-page navigation is canceled while behavior is running + page.on("dialog", async (dialog) => { + let accepted = true; + if (dialog.type() === "beforeunload") { + if (opts.pageBlockUnload) { + accepted = false; + await dialog.dismiss(); + } else { + await dialog.accept(); + } + } else { + await dialog.accept(); + } + logger.debug("JS Dialog", { + accepted, + blockingUnload: opts.pageBlockUnload, + message: dialog.message(), + type: dialog.type(), + page: page.url(), + workerid, + }); + }); + + // Close any windows opened during navigation from autoclick + await cdp.send("Target.setDiscoverTargets", { discover: true }); + + cdp.on("Target.targetCreated", async (params) => { + const { targetInfo } = params; + const { type, openerFrameId, targetId } = targetInfo; + + try { + if ( + type === "page" && + openerFrameId && + opts.frameIdToExecId.has(openerFrameId) + ) { + await cdp.send("Target.closeTarget", { targetId }); + } else { + logger.warn("Extra target not closed", { targetInfo }); + } + + await cdp.send("Runtime.runIfWaitingForDebugger"); + } catch (e) { + // target likely already closed + } + }); + + void cdp.send("Target.setAutoAttach", { + autoAttach: true, + waitForDebuggerOnStart: true, + flatten: false, + }); + + if (this.recording) { + await cdp.send("Page.enable"); + + cdp.on("Page.windowOpen", async (params) => { + const { seedId, depth, extraHops = 0, url } = opts.data; + + const logDetails = { page: url, workerid }; + + await this.queueInScopeUrls( + seedId, + [params.url], + depth, + extraHops, + false, + logDetails, + ); + }); + } + } + + await page.exposeFunction("__bx_addSet", (data: string) => + this.crawlState.addToUserSet(data), + ); + + // await page.exposeFunction("__bx_hasSet", (data: string) => this.crawlState.hasUserSet(data)); } async setupExecContextEvents( @@ -932,6 +1003,7 @@ self.__bx_behaviors.selectMainBehavior(); } opts.markPageUsed(); + opts.pageBlockUnload = false; if (auth) { await page.setExtraHTTPHeaders({ Authorization: auth }); @@ -955,8 +1027,12 @@ self.__bx_behaviors.selectMainBehavior(); ); data.favicon = await this.getFavicon(page, logDetails); + opts.pageBlockUnload = true; + await this.doPostLoadActions(opts); + opts.pageBlockUnload = false; + await this.awaitPageExtraDelay(opts); } @@ -1111,7 +1187,7 @@ self.__bx_behaviors.selectMainBehavior(); } } - async teardownPage({ workerid }: WorkerOpts) { + async teardownPage({ workerid }: WorkerState) { if (this.screencaster) { await this.screencaster.stopById(workerid); } diff --git a/src/create-login-profile.ts b/src/create-login-profile.ts index 1e217c6e..327e58c4 100755 --- a/src/create-login-profile.ts +++ b/src/create-login-profile.ts @@ -17,6 +17,7 @@ import { CDPSession, Page, PuppeteerLifeCycleEvent } from "puppeteer-core"; import { getInfoString } from "./util/file_reader.js"; import { DISPLAY } from "./util/constants.js"; import { initProxy } from "./util/proxy.js"; +//import { sleep } from "./util/timing.js"; const profileHTML = fs.readFileSync( new URL("../html/createProfile.html", import.meta.url), @@ -437,6 +438,27 @@ class InteractiveBrowser { // attempt to keep everything to initial tab if headless if (this.params.headless) { + void cdp.send("Target.setDiscoverTargets", { discover: true }); + + cdp.on("Target.targetCreated", async (params) => { + const { targetInfo } = params; + const { type, openerFrameId } = targetInfo; + + if (type === "page" && openerFrameId) { + await cdp.send("Target.closeTarget", { + targetId: params.targetInfo.targetId, + }); + } + + await cdp.send("Runtime.runIfWaitingForDebugger"); + }); + + void cdp.send("Target.setAutoAttach", { + autoAttach: true, + waitForDebuggerOnStart: true, + flatten: false, + }); + cdp.send("Page.enable").catch((e) => logger.warn("Page.enable error", e)); cdp.on("Page.windowOpen", async (resp) => { diff --git a/src/replaycrawler.ts b/src/replaycrawler.ts index 7189e95d..5d360dfc 100644 --- a/src/replaycrawler.ts +++ b/src/replaycrawler.ts @@ -3,7 +3,7 @@ import { Crawler } from "./crawler.js"; import { ReplayServer } from "./util/replayserver.js"; import { sleep } from "./util/timing.js"; import { logger, formatErr } from "./util/logger.js"; -import { WorkerOpts, WorkerState } from "./util/worker.js"; +import { WorkerState } from "./util/worker.js"; import { PageState } from "./util/state.js"; import { PageInfoRecord, PageInfoValue, Recorder } from "./util/recorder.js"; @@ -718,7 +718,7 @@ export class ReplayCrawler extends Crawler { return text; } - async teardownPage(opts: WorkerOpts) { + async teardownPage(opts: WorkerState) { const { page } = opts; await this.processPageInfo(page); await super.teardownPage(opts); diff --git a/src/util/argParser.ts b/src/util/argParser.ts index 86641d62..4c9db398 100644 --- a/src/util/argParser.ts +++ b/src/util/argParser.ts @@ -15,6 +15,7 @@ import { EXTRACT_TEXT_TYPES, SERVICE_WORKER_OPTS, DEFAULT_SELECTORS, + BEHAVIOR_TYPES, ExtractSelector, } from "./constants.js"; import { ScopedSeed } from "./seeds.js"; @@ -165,6 +166,7 @@ class ArgParser { }, selectLinks: { + alias: "linkSelector", describe: "One or more selectors for extracting links, in the format [css selector]->[property to use],[css selector]->@[attribute to use]", type: "array", @@ -172,6 +174,13 @@ class ArgParser { coerce, }, + clickSelector: { + describe: + "Selector for elements to click when using the autoclick behavior", + type: "string", + default: "a", + }, + blockRules: { describe: "Additional rules for blocking certain URLs from being loaded, by URL regex and optionally via text match in an iframe", @@ -351,7 +360,6 @@ class ArgParser { describe: "Which background behaviors to enable on each page", type: "array", default: ["autoplay", "autofetch", "autoscroll", "siteSpecific"], - choices: ["autoplay", "autofetch", "autoscroll", "siteSpecific"], coerce, }, @@ -693,9 +701,20 @@ class ArgParser { // background behaviors to apply const behaviorOpts: { [key: string]: string | boolean } = {}; if (argv.behaviors.length > 0) { - argv.behaviors.forEach((x: string) => (behaviorOpts[x] = true)); + argv.behaviors.forEach((x: string) => { + if (BEHAVIOR_TYPES.includes(x)) { + behaviorOpts[x] = true; + } else { + logger.warn( + "Unknown behavior specified, ignoring", + { behavior: x }, + "behavior", + ); + } + }); behaviorOpts.log = BEHAVIOR_LOG_FUNC; behaviorOpts.startEarly = true; + behaviorOpts.clickSelector = argv.clickSelector; argv.behaviorOpts = JSON.stringify(behaviorOpts); } else { argv.behaviorOpts = ""; diff --git a/src/util/browser.ts b/src/util/browser.ts index 6526e295..df47d727 100644 --- a/src/util/browser.ts +++ b/src/util/browser.ts @@ -15,7 +15,7 @@ import puppeteer, { Frame, HTTPRequest, Page, - PuppeteerLaunchOptions, + LaunchOptions, Viewport, } from "puppeteer-core"; import { CDPSession, Target, Browser as PptrBrowser } from "puppeteer-core"; @@ -108,7 +108,7 @@ export class Browser { }; } - const launchOpts: PuppeteerLaunchOptions = { + const launchOpts: LaunchOptions = { args, headless, executablePath: this.getBrowserExe(), @@ -126,7 +126,7 @@ export class Browser { ? undefined : (target) => this.targetFilter(target), }; - await this._init(launchOpts, ondisconnect); + await this._init(launchOpts, recording, ondisconnect); } targetFilter(target: Target) { @@ -388,8 +388,9 @@ export class Browser { } } - async _init( - launchOpts: PuppeteerLaunchOptions, + private async _init( + launchOpts: LaunchOptions, + recording: boolean, // eslint-disable-next-line @typescript-eslint/ban-types ondisconnect: Function | null = null, ) { @@ -399,7 +400,9 @@ export class Browser { this.firstCDP = await target.createCDPSession(); - await this.browserContextFetch(); + if (recording) { + await this.browserContextFetch(); + } if (ondisconnect) { this.browser.on("disconnected", (err) => ondisconnect(err)); diff --git a/src/util/constants.ts b/src/util/constants.ts index 99ea25b3..72506c6c 100644 --- a/src/util/constants.ts +++ b/src/util/constants.ts @@ -46,4 +46,12 @@ export const DEFAULT_SELECTORS: ExtractSelector[] = [ }, ]; +export const BEHAVIOR_TYPES = [ + "autoplay", + "autofetch", + "autoscroll", + "autoclick", + "siteSpecific", +]; + export const DISPLAY = ":99"; diff --git a/src/util/state.ts b/src/util/state.ts index f29f5454..00aa9860 100644 --- a/src/util/state.ts +++ b/src/util/state.ts @@ -837,6 +837,10 @@ return inx; return await this.redis.srem(key, status + "|" + url); } + async addToUserSet(value: string) { + return (await this.redis.sadd(this.key + ":user", value)) === 1; + } + async logError(error: string) { return await this.redis.lpush(this.ekey, error); } diff --git a/src/util/worker.ts b/src/util/worker.ts index c1e44cfd..66f8e1b0 100644 --- a/src/util/worker.ts +++ b/src/util/worker.ts @@ -18,7 +18,7 @@ const NEW_WINDOW_TIMEOUT = 20; const TEARDOWN_TIMEOUT = 10; const FINISHED_TIMEOUT = 60; -export type WorkerOpts = { +export type WorkerState = { page: Page; cdp: CDPSession; workerid: WorkerId; @@ -31,10 +31,7 @@ export type WorkerOpts = { markPageUsed: () => void; frameIdToExecId: Map; isAuthSet?: boolean; -}; - -// =========================================================================== -export type WorkerState = WorkerOpts & { + pageBlockUnload?: boolean; data: PageState; }; @@ -53,7 +50,7 @@ export class PageWorker { // eslint-disable-next-line @typescript-eslint/ban-types callbacks?: Record; - opts?: WorkerOpts; + opts?: WorkerState; // TODO: Fix this the next time the file is edited. // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -135,7 +132,8 @@ export class PageWorker { } } - async initPage(url: string): Promise { + async initPage(pagestate: PageState): Promise { + const { url } = pagestate; let reuse = !this.crashed && !!this.opts && !!this.page; if (!this.alwaysReuse) { reuse = this.reuseCount <= MAX_REUSE && this.isSameOrigin(url); @@ -146,6 +144,7 @@ export class PageWorker { { reuseCount: this.reuseCount, ...this.logDetails }, "worker", ); + this.opts!.data = pagestate; return this.opts!; } else if (this.page) { await this.closePage(); @@ -192,6 +191,8 @@ export class PageWorker { this.reuseCount++; } }, + pageBlockUnload: false, + data: pagestate, }; if (this.recorder) { @@ -370,10 +371,10 @@ export class PageWorker { } // init page (new or reuse) - const opts = await this.initPage(data.url); + const opts = await this.initPage(data); // run timed crawl of page - await this.timedCrawlPage({ ...opts, data }); + await this.timedCrawlPage(opts); loggedWaiting = false; } else { diff --git a/tests/rollover-writer.test.js b/tests/rollover-writer.test.js index 0c90fb2a..9226d0da 100644 --- a/tests/rollover-writer.test.js +++ b/tests/rollover-writer.test.js @@ -3,7 +3,7 @@ import fs from "fs"; test("set rollover to 500K and ensure individual WARCs rollover, including screenshots", async () => { child_process.execSync( - "docker run -v $PWD/test-crawls:/crawls webrecorder/browsertrix-crawler crawl --url https://old.webrecorder.net/ --limit 5 --exclude community --collection rollover-500K --rolloverSize 500000 --screenshot view" + "docker run -v $PWD/test-crawls:/crawls webrecorder/browsertrix-crawler crawl --url https://old.webrecorder.net/ --limit 5 --exclude community --collection rollover-500K --rolloverSize 500000 --screenshot view --logging debug" ); const warcLists = fs.readdirSync("test-crawls/collections/rollover-500K/archive"); diff --git a/yarn.lock b/yarn.lock index e9b877d5..683c81e9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -719,15 +719,15 @@ tslib "^2.7.0" tsyringe "^4.8.0" -"@puppeteer/browsers@2.4.1": - version "2.4.1" - resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.4.1.tgz#7afd271199cc920ece2ff25109278be0a3e8a225" - integrity sha512-0kdAbmic3J09I6dT8e9vE2JOCSt13wHCW5x/ly8TSt2bDtuIWe2TgLZZDHdcziw9AVCzflMAXCrVyRIhIs44Ng== +"@puppeteer/browsers@2.7.0": + version "2.7.0" + resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.7.0.tgz#dad70b30458f4e0855b2f402055f408823cc67c5" + integrity sha512-bO61XnTuopsz9kvtfqhVbH6LTM1koxK0IlBR+yuVrM2LB7mk8+5o1w18l5zqd5cs8xlf+ntgambqRqGifMDjog== dependencies: - debug "^4.3.7" + debug "^4.4.0" extract-zip "^2.0.1" progress "^2.0.3" - proxy-agent "^6.4.0" + proxy-agent "^6.5.0" semver "^7.6.3" tar-fs "^3.0.6" unbzip2-stream "^1.4.3" @@ -1062,13 +1062,18 @@ acorn@^8.10.0, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== -agent-base@^7.0.2, agent-base@^7.1.0, agent-base@^7.1.1: +agent-base@^7.1.0: version "7.1.1" resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.1.tgz#bdbded7dfb096b751a2a087eeeb9664725b2e317" integrity sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA== dependencies: debug "^4.3.4" +agent-base@^7.1.2: + version "7.1.3" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.3.tgz#29435eb821bc4194633a5b89e5bc4703bafc25a1" + integrity sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw== + ajv@^6.12.4: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" @@ -1435,10 +1440,10 @@ browserslist@^4.24.0: node-releases "^2.0.18" update-browserslist-db "^1.1.1" -browsertrix-behaviors@^0.6.6: - version "0.6.6" - resolved "https://registry.yarnpkg.com/browsertrix-behaviors/-/browsertrix-behaviors-0.6.6.tgz#10bcccfb091c051f5c886d5f69487e6d184078de" - integrity sha512-UPNcU9dV0nAvUwJHKKYCkuqdYdlMjK7AWYDyr4xBpSq55xmEh2wQlwQyDyJuUUUrhJNII4NqXK24hVXPdvf5VA== +browsertrix-behaviors@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/browsertrix-behaviors/-/browsertrix-behaviors-0.7.0.tgz#a08b7d3e9cd449d0d76b14a438e28472124fd1a4" + integrity sha512-t0X74puXJsH8sVkkVZwEdo8L5E1PYtzX/RkVXM4fwwBIL804bOB8WIV+5Dfwov/odaukhB67KZhM00hN60SiBA== dependencies: query-selector-shadow-dom "^1.0.1" @@ -1534,13 +1539,12 @@ chownr@^1.1.1: resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== -chromium-bidi@0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.8.0.tgz#ffd79dad7db1fcc874f1c55fcf46ded05a884269" - integrity sha512-uJydbGdTw0DEUjhoogGveneJVWX/9YuqkWePzMmkBYwtdAqo5d3J/ovNKFr+/2hWXYmYCr6it8mSSTIj6SS6Ug== +chromium-bidi@0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/chromium-bidi/-/chromium-bidi-0.11.0.tgz#9c3c42ee7b42d8448e9fce8d649dc8bfbcc31153" + integrity sha512-6CJWHkNRoyZyjV9Rwv2lYONZf1Xm0IuDyNq97nwSsxxP3wf5Bwy15K5rOvVKMtJ127jJBmxFUanSAOjgFRxgrA== dependencies: mitt "3.0.1" - urlpattern-polyfill "10.0.0" zod "3.23.8" ci-info@^3.2.0: @@ -1696,7 +1700,7 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -1710,6 +1714,13 @@ debug@^3.2.7: dependencies: ms "^2.1.1" +debug@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decode-uri-component@^0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -1784,10 +1795,10 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -devtools-protocol@0.0.1367902: - version "0.0.1367902" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1367902.tgz#7333bfc4466c5a54a4c6de48a9dfbcb4b811660c" - integrity sha512-XxtPuC3PGakY6PD7dG66/o8KwJ/LkH2/EKe19Dcw58w53dv4/vSQEkn/SzuyhHE2q4zPgCkxQBxus3VV4ql+Pg== +devtools-protocol@0.0.1380148: + version "0.0.1380148" + resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.1380148.tgz#7dcdad06515135b244ff05878ca8019e041c1c55" + integrity sha512-1CJABgqLxbYxVI+uJY/UDUHJtJ0KZTSjNYJYKqd9FRoXT33WDakDHNxRapMEgzeJ/C3rcs01+avshMnPmKQbvA== diff-sequences@^29.6.3: version "29.6.3" @@ -2603,12 +2614,12 @@ http-status-codes@^2.1.4: resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.3.0.tgz#987fefb28c69f92a43aecc77feec2866349a8bfc" integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== -https-proxy-agent@^7.0.3, https-proxy-agent@^7.0.5: - version "7.0.5" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz#9e8b5013873299e11fab6fd548405da2d6c602b2" - integrity sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw== +https-proxy-agent@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz#da8dfeac7da130b05c2ba4b59c9b6cd66611a6b9" + integrity sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw== dependencies: - agent-base "^7.0.2" + agent-base "^7.1.2" debug "4" human-signals@^2.1.0: @@ -3834,19 +3845,19 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -pac-proxy-agent@^7.0.1: - version "7.0.2" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz#0fb02496bd9fb8ae7eb11cfd98386daaac442f58" - integrity sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg== +pac-proxy-agent@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-7.1.0.tgz#da7c3b5c4cccc6655aaafb701ae140fb23f15df2" + integrity sha512-Z5FnLVVZSnX7WjBg0mhDtydeRZ1xMcATZThjySQUHqr+0ksP8kqaw23fNKkaaN/Z8gwLUs/W7xdl0I75eP2Xyw== dependencies: "@tootallnate/quickjs-emscripten" "^0.23.0" - agent-base "^7.0.2" + agent-base "^7.1.2" debug "^4.3.4" get-uri "^6.0.1" http-proxy-agent "^7.0.0" - https-proxy-agent "^7.0.5" + https-proxy-agent "^7.0.6" pac-resolver "^7.0.1" - socks-proxy-agent "^8.0.4" + socks-proxy-agent "^8.0.5" pac-resolver@^7.0.1: version "7.0.1" @@ -4056,19 +4067,19 @@ prop-types@^15.8.1: object-assign "^4.1.1" react-is "^16.13.1" -proxy-agent@^6.4.0: - version "6.4.0" - resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.4.0.tgz#b4e2dd51dee2b377748aef8d45604c2d7608652d" - integrity sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ== +proxy-agent@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-6.5.0.tgz#9e49acba8e4ee234aacb539f89ed9c23d02f232d" + integrity sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A== dependencies: - agent-base "^7.0.2" + agent-base "^7.1.2" debug "^4.3.4" http-proxy-agent "^7.0.1" - https-proxy-agent "^7.0.3" + https-proxy-agent "^7.0.6" lru-cache "^7.14.1" - pac-proxy-agent "^7.0.1" + pac-proxy-agent "^7.1.0" proxy-from-env "^1.1.0" - socks-proxy-agent "^8.0.2" + socks-proxy-agent "^8.0.5" proxy-from-env@^1.1.0: version "1.1.0" @@ -4088,15 +4099,15 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== -puppeteer-core@^23.7.1: - version "23.9.0" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-23.9.0.tgz#24add69fb58dde4ac49d165872b44a30d2bf5b32" - integrity sha512-hLVrav2HYMVdK0YILtfJwtnkBAwNOztUdR4aJ5YKDvgsbtagNr6urUJk9HyjRA9e+PaLI3jzJ0wM7A4jSZ7Qxw== +puppeteer-core@^24.1.0: + version "24.1.0" + resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-24.1.0.tgz#4ea006ab26077dfbf6c72e2cf74797a7ff6db468" + integrity sha512-ReefWoQgqdyl67uWEBy/TMZ4mAB7hP0JB5HIxSE8B1ot/4ningX1gmzHCOSNfMbTiS/VJHCvaZAe3oJTXph7yw== dependencies: - "@puppeteer/browsers" "2.4.1" - chromium-bidi "0.8.0" - debug "^4.3.7" - devtools-protocol "0.0.1367902" + "@puppeteer/browsers" "2.7.0" + chromium-bidi "0.11.0" + debug "^4.4.0" + devtools-protocol "0.0.1380148" typed-query-selector "^2.12.0" ws "^8.18.0" @@ -4445,12 +4456,12 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -socks-proxy-agent@^8.0.2, socks-proxy-agent@^8.0.4: - version "8.0.4" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz#9071dca17af95f483300316f4b063578fa0db08c" - integrity sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw== +socks-proxy-agent@^8.0.5: + version "8.0.5" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz#b9cdb4e7e998509d7659d689ce7697ac21645bee" + integrity sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw== dependencies: - agent-base "^7.1.1" + agent-base "^7.1.2" debug "^4.3.4" socks "^2.8.3" @@ -4959,11 +4970,6 @@ url-join@^4.0.1: resolved "https://registry.yarnpkg.com/url-join/-/url-join-4.0.1.tgz#b642e21a2646808ffa178c4c5fda39844e12cde7" integrity sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA== -urlpattern-polyfill@10.0.0: - version "10.0.0" - resolved "https://registry.yarnpkg.com/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz#f0a03a97bfb03cdf33553e5e79a2aadd22cac8ec" - integrity sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg== - util-deprecate@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"