Skip to content

Commit

Permalink
add 'startEarly' option to init opts, which will enable autoplay / au…
Browse files Browse the repository at this point in the history
…tofetch to detect URLs as soon as possible. (#64)

* add 'startEarly' option to init opts, which will enable autoplay / autofetch to
observer / poll possible URLs ondomcontentloaded event
otherwise, autoplay/autofetch start running only when run() is called
  • Loading branch information
ikreymer authored Sep 14, 2023
1 parent 16d7821 commit f191544
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 20 deletions.
2 changes: 1 addition & 1 deletion dist/behaviors.js

Large diffs are not rendered by default.

48 changes: 32 additions & 16 deletions src/autofetcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,46 +22,48 @@ const MAX_CONCURRENT = 6;

// ===========================================================================
export class AutoFetcher extends BackgroundBehavior {
urlSet: Set<string>;
urlQueue: string[];
urlSet: Set<string> = new Set();
pendingQueue: string[] = [];
waitQueue: string[] = [];
mutationObserver: MutationObserver;
numPending: number;
numDone: number;
numPending: number = 0;
numDone: number = 0;
headers: object;
_donePromise: Promise<null>;
_markDone: (value: any) => void;
active: boolean;
running = false;

static id = "AutoFetcher";

constructor(active = false, headers = null) {
constructor(active = false, headers = null, startEarly = false) {
super();
this.urlSet = new Set();
this.urlQueue = [];
this.numPending = 0;
this.numDone = 0;

this.headers = headers || {};

this._donePromise = new Promise((resolve) => this._markDone = resolve);

this.active = active;
if (this.active && startEarly) {
document.addEventListener("DOMContentLoaded", () => this.initObserver());
}
}

get numFetching() {
return this.numDone + this.numPending + this.urlQueue.length;
return this.numDone + this.numPending + this.pendingQueue.length;
}

async start() {
if (!this.active) {
return;
}

this.run();
this.initObserver();

this.run();

sleep(500).then(() => {
if (!this.urlQueue.length && !this.numPending) {
if (!this.pendingQueue.length && !this.numPending) {
this._markDone(null);
}
});
Expand All @@ -72,6 +74,13 @@ export class AutoFetcher extends BackgroundBehavior {
}

async run() {
this.running = true;

for (const url of this.waitQueue) {
this.doFetch(url);
}
this.waitQueue = [];

this.extractSrcSrcSetAll(document);
this.extractStyleSheets();
}
Expand All @@ -97,7 +106,11 @@ export class AutoFetcher extends BackgroundBehavior {

this.urlSet.add(url);

this.doFetch(url);
if (!this.running) {
this.waitQueue.push(url);
} else {
this.doFetch(url);
}

return true;
}
Expand Down Expand Up @@ -143,10 +156,10 @@ export class AutoFetcher extends BackgroundBehavior {
}

async doFetch(url: string) {
this.urlQueue.push(url);
this.pendingQueue.push(url);
if (this.numPending <= MAX_CONCURRENT) {
while (this.urlQueue.length > 0) {
const url = this.urlQueue.shift();
while (this.pendingQueue.length > 0) {
const url = this.pendingQueue.shift();

this.numPending++;

Expand All @@ -169,6 +182,9 @@ export class AutoFetcher extends BackgroundBehavior {
}

initObserver() {
if (this.mutationObserver) {
return;
}
this.mutationObserver = new MutationObserver((changes) => this.observeChange(changes));

this.mutationObserver.observe(document.documentElement, {
Expand Down
24 changes: 23 additions & 1 deletion src/autoplay.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,26 @@ export class Autoplay extends BackgroundBehavior {
numPlaying: number;
promises: Promise<any>[];
_initDone: Function;
running = false;
polling = false;

static id = "Autoplay";

constructor(autofetcher: AutoFetcher) {
constructor(autofetcher: AutoFetcher, startEarly = false) {
super();
this.mediaSet = new Set();
this.autofetcher = autofetcher;
this.numPlaying = 0;
this.promises = [];
this._initDone = () => null;
this.promises.push(new Promise((resolve) => this._initDone = resolve));
if (startEarly) {
document.addEventListener("DOMContentLoaded", () => this.pollAudioVideo());
}
}

async start() {
this.running = true;
//this.initObserver();

this.pollAudioVideo();
Expand All @@ -34,16 +40,32 @@ export class Autoplay extends BackgroundBehavior {
async pollAudioVideo() {
const run = true;

if (this.polling) {
return
}

this.polling = true;

while (run) {
for (const [, elem] of document.querySelectorAll("video, audio, picture").entries()) {
if (!elem["__bx_autoplay_found"]) {

if (!this.running) {
if (this.processFetchableUrl(elem)) {
elem["__bx_autoplay_found"] = true;
}
continue;
}

await this.loadMedia(elem);
elem["__bx_autoplay_found"] = true;
}
}

await sleep(500);
}

this.polling = false;
}

fetchSrcUrl(source) {
Expand Down
5 changes: 3 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ interface BehaviorManagerOpts {
siteSpecific?: boolean | object;
timeout?: number;
fetchHeaders?: object | null;
startEarly?: boolean | null;
}

const DEFAULT_OPTS: BehaviorManagerOpts = {autofetch: true, autoplay: true, autoscroll: true, siteSpecific: true};
Expand Down Expand Up @@ -76,7 +77,7 @@ export class BehaviorManager {
}
}

this.autofetch = new AutoFetcher(!!opts.autofetch, opts.fetchHeaders);
this.autofetch = new AutoFetcher(!!opts.autofetch, opts.fetchHeaders, opts.startEarly);

if (opts.autofetch) {
behaviorLog("Using AutoFetcher");
Expand All @@ -85,7 +86,7 @@ export class BehaviorManager {

if (opts.autoplay) {
behaviorLog("Using Autoplay");
this.behaviors.push(new Autoplay(this.autofetch));
this.behaviors.push(new Autoplay(this.autofetch, opts.startEarly));
}

if (self.window.top !== self.window) {
Expand Down

0 comments on commit f191544

Please sign in to comment.