single-file-cli 2.0.19 → 2.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.MD +0 -6
- package/deno.json +1 -1
- package/lib/cdp-client.js +98 -39
- package/lib/version.js +1 -1
- package/package.json +1 -1
package/README.MD
CHANGED
|
@@ -80,9 +80,6 @@ Make sure Chrome or a Chromium-based browser is installed in the default folder.
|
|
|
80
80
|
|
|
81
81
|
```sh
|
|
82
82
|
unzip master.zip .
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
```sh
|
|
86
83
|
cd single-file-cli-master
|
|
87
84
|
```
|
|
88
85
|
|
|
@@ -90,9 +87,6 @@ Make sure Chrome or a Chromium-based browser is installed in the default folder.
|
|
|
90
87
|
|
|
91
88
|
```sh
|
|
92
89
|
git clone --depth 1 --recursive https://github.com/gildas-lormeau/single-file-cli.git
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
```sh
|
|
96
90
|
cd single-file-cli
|
|
97
91
|
```
|
|
98
92
|
|
package/deno.json
CHANGED
package/lib/cdp-client.js
CHANGED
|
@@ -96,16 +96,22 @@ async function getPageData(options) {
|
|
|
96
96
|
worldName: SINGLE_FILE_WORLD_NAME
|
|
97
97
|
});
|
|
98
98
|
const [contextId] = await Promise.all([
|
|
99
|
-
|
|
99
|
+
loadPage({ Page, Runtime }, options),
|
|
100
100
|
options.browserDebug ? waitForDebuggerReady({ Debugger }) : Promise.resolve()
|
|
101
101
|
]);
|
|
102
|
+
if (options.browserWaitDelay) {
|
|
103
|
+
setTimeout(() => resolve, options.browserWaitDelay);
|
|
104
|
+
}
|
|
102
105
|
const { result } = await Runtime.evaluate({
|
|
103
106
|
expression: `singlefile.getPageData(${JSON.stringify(options)})`,
|
|
104
107
|
awaitPromise: true,
|
|
105
108
|
returnByValue: true,
|
|
106
109
|
contextId
|
|
107
110
|
});
|
|
108
|
-
const { value } = result;
|
|
111
|
+
const { value, subtype, description } = result;
|
|
112
|
+
if (subtype === "error") {
|
|
113
|
+
throw new Error(description);
|
|
114
|
+
}
|
|
109
115
|
if (options.compressContent) {
|
|
110
116
|
value.content = new Uint8Array(value.content);
|
|
111
117
|
}
|
|
@@ -126,7 +132,7 @@ async function getPageData(options) {
|
|
|
126
132
|
}
|
|
127
133
|
}
|
|
128
134
|
|
|
129
|
-
async function
|
|
135
|
+
async function loadPage({ Page, Runtime }, options) {
|
|
130
136
|
await Runtime.enable();
|
|
131
137
|
await Page.enable();
|
|
132
138
|
try {
|
|
@@ -134,7 +140,7 @@ async function navigate({ Page, Runtime }, options) {
|
|
|
134
140
|
const loadTimeoutAbortSignal = loadTimeoutAbortController.signal;
|
|
135
141
|
const [contextId] = await Promise.race([
|
|
136
142
|
Promise.all([getTopFrameContextId({ Page, Runtime }, options), Page.navigate({ url: options.url })]),
|
|
137
|
-
|
|
143
|
+
waitForLoadTimeout(loadTimeoutAbortSignal, options.browserLoadMaxTime)
|
|
138
144
|
]);
|
|
139
145
|
if (!loadTimeoutAbortSignal.aborted) {
|
|
140
146
|
loadTimeoutAbortController.abort();
|
|
@@ -146,34 +152,82 @@ async function navigate({ Page, Runtime }, options) {
|
|
|
146
152
|
}
|
|
147
153
|
}
|
|
148
154
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
await new Promise(resolve => {
|
|
155
|
+
function getTopFrameContextId({ Page, Runtime }, options) {
|
|
156
|
+
return new Promise((resolve, reject) => {
|
|
152
157
|
const FRAME_NAVIGATED_EVENT = "frameNavigated";
|
|
153
158
|
const CONTEXT_CREATED_EVENT = "executionContextCreated";
|
|
159
|
+
const CONTEXT_DESTROYED_EVENT = "executionContextDestroyed";
|
|
160
|
+
const contextIds = [];
|
|
161
|
+
let frameId, navigationAbortController;
|
|
154
162
|
Page.addEventListener(FRAME_NAVIGATED_EVENT, onFrameNavigated);
|
|
155
|
-
Runtime.addEventListener(CONTEXT_CREATED_EVENT,
|
|
163
|
+
Runtime.addEventListener(CONTEXT_CREATED_EVENT, onExecutionContextCreated);
|
|
164
|
+
Runtime.addEventListener(CONTEXT_DESTROYED_EVENT, onExecutionContextDestroyed);
|
|
156
165
|
|
|
157
166
|
async function onFrameNavigated({ params }) {
|
|
158
167
|
const { frame } = params;
|
|
159
168
|
if (!frame.parentId) {
|
|
160
169
|
frameId = frame.id;
|
|
161
|
-
|
|
170
|
+
if (navigationAbortController) {
|
|
171
|
+
navigationAbortController.abort();
|
|
172
|
+
}
|
|
173
|
+
navigationAbortController = new AbortController();
|
|
174
|
+
await onTopFrameNavigated(navigationAbortController.signal);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
async function onTopFrameNavigated(navigationSignal) {
|
|
179
|
+
await waitForPageReady({ Page }, frameId, options, navigationSignal);
|
|
180
|
+
if (!navigationSignal.aborted) {
|
|
162
181
|
Page.removeEventListener(FRAME_NAVIGATED_EVENT, onFrameNavigated);
|
|
163
|
-
Runtime.removeEventListener(CONTEXT_CREATED_EVENT,
|
|
164
|
-
|
|
182
|
+
Runtime.removeEventListener(CONTEXT_CREATED_EVENT, onExecutionContextCreated);
|
|
183
|
+
Runtime.removeEventListener(CONTEXT_DESTROYED_EVENT, onExecutionContextDestroyed);
|
|
184
|
+
let contextId;
|
|
185
|
+
if (contextIds.length) {
|
|
186
|
+
let contextIdIndex = 0;
|
|
187
|
+
do {
|
|
188
|
+
if (await testExecutionContext(contextIds[contextIdIndex])) {
|
|
189
|
+
contextId = contextIds[contextIdIndex];
|
|
190
|
+
}
|
|
191
|
+
contextIdIndex++;
|
|
192
|
+
} while (contextId === undefined && contextIdIndex < contextIds.length);
|
|
193
|
+
}
|
|
194
|
+
if (contextId === undefined) {
|
|
195
|
+
reject(new Error("Execution context not found"));
|
|
196
|
+
} else {
|
|
197
|
+
resolve(contextId);
|
|
198
|
+
}
|
|
165
199
|
}
|
|
166
200
|
}
|
|
167
201
|
|
|
168
|
-
function
|
|
202
|
+
function onExecutionContextCreated({ params }) {
|
|
169
203
|
const { context } = params;
|
|
170
204
|
const { name, origin, auxData } = context;
|
|
171
205
|
if (frameId !== undefined && origin === "://" && name === SINGLE_FILE_WORLD_NAME && auxData && auxData.frameId === frameId) {
|
|
172
|
-
|
|
206
|
+
contextIds.push(context.id);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function onExecutionContextDestroyed({ params }) {
|
|
211
|
+
const { executionContextId } = params;
|
|
212
|
+
const index = contextIds.indexOf(executionContextId);
|
|
213
|
+
if (index > -1) {
|
|
214
|
+
contextIds.splice(index, 1);
|
|
173
215
|
}
|
|
174
216
|
}
|
|
217
|
+
|
|
218
|
+
async function testExecutionContext(contextId) {
|
|
219
|
+
try {
|
|
220
|
+
const { result } = await Runtime.evaluate({
|
|
221
|
+
expression: "singlefile !== undefined",
|
|
222
|
+
contextId
|
|
223
|
+
});
|
|
224
|
+
return result.value === true;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
// ignored
|
|
227
|
+
}
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
175
230
|
});
|
|
176
|
-
return contextId;
|
|
177
231
|
}
|
|
178
232
|
|
|
179
233
|
function waitForLoadTimeout(abortSignal, maxDelay) {
|
|
@@ -194,41 +248,46 @@ function waitForLoadTimeout(abortSignal, maxDelay) {
|
|
|
194
248
|
});
|
|
195
249
|
}
|
|
196
250
|
|
|
197
|
-
async function waitForPageReady({ Page }, topFrameId, options) {
|
|
251
|
+
async function waitForPageReady({ Page }, topFrameId, options, navigationSignal) {
|
|
198
252
|
await Page.setLifecycleEventsEnabled({ enabled: true });
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (
|
|
207
|
-
|
|
208
|
-
|
|
253
|
+
try {
|
|
254
|
+
await new Promise(resolve => {
|
|
255
|
+
const LIFE_CYCLE_EVENT = "lifecycleEvent";
|
|
256
|
+
Page.addEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
|
|
257
|
+
|
|
258
|
+
function onLifecycleEvent({ params }) {
|
|
259
|
+
const { name, frameId } = params;
|
|
260
|
+
if (frameId === topFrameId) {
|
|
261
|
+
if (name === options.browserWaitUntil || name === INTERACTIVE_TIME_STATE || navigationSignal.aborted) {
|
|
262
|
+
Page.removeEventListener(LIFE_CYCLE_EVENT, onLifecycleEvent);
|
|
263
|
+
resolve();
|
|
264
|
+
}
|
|
209
265
|
}
|
|
210
266
|
}
|
|
267
|
+
});
|
|
268
|
+
} finally {
|
|
269
|
+
if (!navigationSignal.aborted) {
|
|
270
|
+
await Page.setLifecycleEventsEnabled({ enabled: false });
|
|
211
271
|
}
|
|
212
|
-
});
|
|
213
|
-
await Page.setLifecycleEventsEnabled({ enabled: false });
|
|
214
|
-
if (options.browserWaitDelay) {
|
|
215
|
-
setTimeout(() => resolve, options.browserWaitDelay);
|
|
216
272
|
}
|
|
217
273
|
}
|
|
218
274
|
|
|
219
275
|
async function waitForDebuggerReady({ Debugger }) {
|
|
220
276
|
await Debugger.enable();
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
277
|
+
try {
|
|
278
|
+
await Debugger.pause();
|
|
279
|
+
await new Promise(resolve => {
|
|
280
|
+
const RESUMED_EVENT = "resumed";
|
|
281
|
+
Debugger.addEventListener(RESUMED_EVENT, onResumed);
|
|
225
282
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
283
|
+
function onResumed() {
|
|
284
|
+
Debugger.removeEventListener(RESUMED_EVENT, onResumed);
|
|
285
|
+
resolve();
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
} finally {
|
|
289
|
+
await Debugger.disable();
|
|
290
|
+
}
|
|
232
291
|
}
|
|
233
292
|
|
|
234
293
|
function getBrowserOptions(options) {
|
package/lib/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = "2.0.
|
|
1
|
+
export const version = "2.0.20";
|