single-file-cli 2.0.63 → 2.0.65
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/.github/workflows/docker-publish.yml +29 -0
- package/build.sh +1 -1
- package/compile.sh +1 -1
- package/deno.json +1 -1
- package/lib/cdp-client.js +65 -65
- package/lib/single-file-bundle.js +1 -1
- package/lib/version.js +1 -1
- package/options.js +29 -4
- package/package.json +1 -1
- package/resources/single-file.ico +0 -0
- package/single-file-cli-api.js +7 -4
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
name: Publish Docker image
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
docker:
|
|
9
|
+
runs-on: ubuntu-latest
|
|
10
|
+
steps:
|
|
11
|
+
-
|
|
12
|
+
name: Set up QEMU
|
|
13
|
+
uses: docker/setup-qemu-action@v3
|
|
14
|
+
-
|
|
15
|
+
name: Set up Docker Buildx
|
|
16
|
+
uses: docker/setup-buildx-action@v3
|
|
17
|
+
-
|
|
18
|
+
name: Login to Docker Hub
|
|
19
|
+
uses: docker/login-action@v3
|
|
20
|
+
with:
|
|
21
|
+
username: ${{ secrets.DOCKER_USERNAME }}
|
|
22
|
+
password: ${{ secrets.DOCKER_TOKEN }}
|
|
23
|
+
-
|
|
24
|
+
name: Build and push
|
|
25
|
+
uses: docker/build-push-action@v6
|
|
26
|
+
with:
|
|
27
|
+
push: true
|
|
28
|
+
tags: ${{ secrets.DOCKER_USERNAME }}/singlefile:latest
|
|
29
|
+
platforms: linux/amd64,linux/arm64doc
|
package/build.sh
CHANGED
package/compile.sh
CHANGED
|
@@ -8,7 +8,7 @@ deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ex
|
|
|
8
8
|
deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output=./dist/single-file-x86_64-apple-darwin --target=x86_64-apple-darwin ./single-file
|
|
9
9
|
deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output=./dist/single-file-x86_64-linux --target=x86_64-unknown-linux-gnu ./single-file
|
|
10
10
|
deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output=./dist/single-file-aarch64-linux --target=aarch64-unknown-linux-gnu ./single-file
|
|
11
|
-
deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output=./dist/single-file.exe --target=x86_64-pc-windows-msvc ./single-file
|
|
11
|
+
deno compile --allow-read --allow-write --allow-net --allow-env --allow-run --ext=js --output=./dist/single-file.exe --target=x86_64-pc-windows-msvc --icon=./resources/single-file.ico ./single-file
|
|
12
12
|
|
|
13
13
|
dev_id=$(security find-identity -p codesigning -v | grep "Apple Development" | awk '{print $2}')
|
|
14
14
|
codesign -f -s $dev_id ./dist/single-file-aarch64-apple-darwin
|
package/deno.json
CHANGED
package/lib/cdp-client.js
CHANGED
|
@@ -33,9 +33,9 @@ const MINIMIZED_WINDOW_STATE = "minimized";
|
|
|
33
33
|
const SINGLE_FILE_WORLD_NAME = "singlefile";
|
|
34
34
|
const EMPTY_PAGE_URL = "about:blank";
|
|
35
35
|
const CAPTURE_SCREENSHOT_FUNCTION_NAME = "captureScreenshot";
|
|
36
|
-
const
|
|
36
|
+
const PRINT_TO_PDF_FUNCTION_NAME = "printToPDF";
|
|
37
37
|
const SET_SCREENSHOT_FUNCTION_NAME = "setScreenshot";
|
|
38
|
-
const SET_PDF_FUNCTION_NAME = "
|
|
38
|
+
const SET_PDF_FUNCTION_NAME = "setPDF";
|
|
39
39
|
const SET_PAGE_DATA_FUNCTION_NAME = "setPageData";
|
|
40
40
|
const REDIRECT_STATUS_CODES = [301, 302, 303, 307, 308];
|
|
41
41
|
|
|
@@ -53,7 +53,15 @@ async function getPageData(options) {
|
|
|
53
53
|
let targetInfo;
|
|
54
54
|
try {
|
|
55
55
|
targetInfo = await CDP.createTarget(EMPTY_PAGE_URL);
|
|
56
|
-
const
|
|
56
|
+
const consoleMessages = [];
|
|
57
|
+
const { Browser, Security, Page, Emulation, Fetch, Network, Runtime, Debugger, Console } = new CDP(targetInfo);
|
|
58
|
+
if (options.consoleMessagesFile) {
|
|
59
|
+
await Console.enable();
|
|
60
|
+
Console.addEventListener("messageAdded", ({ params }) => {
|
|
61
|
+
const { message } = params;
|
|
62
|
+
consoleMessages.push(message);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
57
65
|
if (options.browserStartMinimized) {
|
|
58
66
|
const { windowId, bounds } = await Browser.getWindowForTarget({ targetId: targetInfo.id });
|
|
59
67
|
if (bounds.windowState !== MINIMIZED_WINDOW_STATE) {
|
|
@@ -182,47 +190,34 @@ async function getPageData(options) {
|
|
|
182
190
|
loadPage({ Page, Runtime }, options),
|
|
183
191
|
options.browserDebug ? waitForDebuggerReady({ Debugger }) : Promise.resolve()
|
|
184
192
|
]);
|
|
185
|
-
if (options.browserWaitDelay) {
|
|
186
|
-
await new Promise(resolve => setTimeout(resolve, options.browserWaitDelay));
|
|
187
|
-
}
|
|
188
193
|
await Runtime.addBinding({ name: SET_PAGE_DATA_FUNCTION_NAME, executionContextId: contextId });
|
|
189
|
-
const pageDataPromise = new Promise(resolve => {
|
|
190
|
-
let pageDataResponse = "";
|
|
191
|
-
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
192
|
-
if (params.name === SET_PAGE_DATA_FUNCTION_NAME) {
|
|
193
|
-
const { payload } = params;
|
|
194
|
-
if (payload.length) {
|
|
195
|
-
pageDataResponse += payload;
|
|
196
|
-
} else {
|
|
197
|
-
const result = JSON.parse(pageDataResponse);
|
|
198
|
-
if (result.content instanceof Array) {
|
|
199
|
-
result.content = new Uint8Array(result.content);
|
|
200
|
-
}
|
|
201
|
-
resolve(result);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
194
|
if (options.embedScreenshot && options.compressContent) {
|
|
207
195
|
await Runtime.addBinding({ name: CAPTURE_SCREENSHOT_FUNCTION_NAME, executionContextId: contextId });
|
|
208
196
|
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
209
197
|
if (params.name === CAPTURE_SCREENSHOT_FUNCTION_NAME) {
|
|
210
198
|
try {
|
|
211
|
-
|
|
199
|
+
let screenshotOptions = { captureBeyondViewport: true };
|
|
200
|
+
if (options.embedScreenshotOptions) {
|
|
201
|
+
try {
|
|
202
|
+
screenshotOptions = JSON.parse(options.embedScreenshotOptions);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
// ignored
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
screenshotOptions.format = "png";
|
|
208
|
+
const { data } = await Page.captureScreenshot(screenshotOptions);
|
|
209
|
+
await Runtime.evaluate({ expression: `globalThis.${SET_SCREENSHOT_FUNCTION_NAME}(${JSON.stringify(data)})`, contextId });
|
|
212
210
|
} catch (error) {
|
|
213
|
-
await Runtime.evaluate({
|
|
214
|
-
expression: `globalThis.${SET_SCREENSHOT_FUNCTION_NAME}(${JSON.stringify([])})`,
|
|
215
|
-
contextId
|
|
216
|
-
});
|
|
211
|
+
await Runtime.evaluate({ expression: `globalThis.${SET_SCREENSHOT_FUNCTION_NAME}(${JSON.stringify("")})`, contextId });
|
|
217
212
|
}
|
|
218
213
|
}
|
|
219
214
|
});
|
|
220
215
|
}
|
|
221
216
|
if (options.embedPdf) {
|
|
222
|
-
await Runtime.addBinding({ name:
|
|
217
|
+
await Runtime.addBinding({ name: PRINT_TO_PDF_FUNCTION_NAME, executionContextId: contextId });
|
|
223
218
|
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
224
|
-
if (params.name ===
|
|
225
|
-
let pdfOptions;
|
|
219
|
+
if (params.name === PRINT_TO_PDF_FUNCTION_NAME) {
|
|
220
|
+
let pdfOptions = {};
|
|
226
221
|
if (options.embedPdfOptions) {
|
|
227
222
|
try {
|
|
228
223
|
pdfOptions = JSON.parse(options.embedPdfOptions);
|
|
@@ -231,18 +226,36 @@ async function getPageData(options) {
|
|
|
231
226
|
}
|
|
232
227
|
}
|
|
233
228
|
try {
|
|
234
|
-
|
|
229
|
+
const { data } = await Page.printToPDF(pdfOptions);
|
|
230
|
+
await Runtime.evaluate({ expression: `globalThis.${SET_PDF_FUNCTION_NAME}(${JSON.stringify(data)})`, contextId });
|
|
235
231
|
} catch (error) {
|
|
236
|
-
await Runtime.evaluate({
|
|
237
|
-
expression: `globalThis.${SET_PDF_FUNCTION_NAME}ƒƒ(${JSON.stringify([])})`,
|
|
238
|
-
contextId
|
|
239
|
-
});
|
|
232
|
+
await Runtime.evaluate({ expression: `globalThis.${SET_PDF_FUNCTION_NAME}(${JSON.stringify("")})`, contextId });
|
|
240
233
|
}
|
|
241
234
|
}
|
|
242
235
|
});
|
|
243
236
|
}
|
|
237
|
+
const pageDataPromise = new Promise(resolve => {
|
|
238
|
+
let pageDataResponse = "";
|
|
239
|
+
Runtime.addEventListener("bindingCalled", async ({ params }) => {
|
|
240
|
+
if (params.name === SET_PAGE_DATA_FUNCTION_NAME) {
|
|
241
|
+
const { payload } = params;
|
|
242
|
+
if (payload.length) {
|
|
243
|
+
pageDataResponse += payload;
|
|
244
|
+
} else {
|
|
245
|
+
const result = JSON.parse(pageDataResponse);
|
|
246
|
+
if (result.content instanceof Array) {
|
|
247
|
+
result.content = new Uint8Array(result.content);
|
|
248
|
+
}
|
|
249
|
+
resolve(result);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
if (options.browserWaitDelay) {
|
|
255
|
+
await new Promise(resolve => setTimeout(resolve, options.browserWaitDelay));
|
|
256
|
+
}
|
|
244
257
|
const { result } = await Runtime.evaluate({
|
|
245
|
-
expression: `(${getPageDataScriptSource.toString()})(${JSON.stringify(options)},${JSON.stringify([SET_SCREENSHOT_FUNCTION_NAME, SET_PDF_FUNCTION_NAME, SET_PAGE_DATA_FUNCTION_NAME])})`,
|
|
258
|
+
expression: `(${getPageDataScriptSource.toString()})(${JSON.stringify(options)},${JSON.stringify([SET_SCREENSHOT_FUNCTION_NAME, SET_PDF_FUNCTION_NAME, SET_PAGE_DATA_FUNCTION_NAME, CAPTURE_SCREENSHOT_FUNCTION_NAME, PRINT_TO_PDF_FUNCTION_NAME])})`,
|
|
246
259
|
awaitPromise: true,
|
|
247
260
|
returnByValue: true,
|
|
248
261
|
contextId
|
|
@@ -252,6 +265,10 @@ async function getPageData(options) {
|
|
|
252
265
|
throw new Error(description);
|
|
253
266
|
}
|
|
254
267
|
const pageData = await pageDataPromise;
|
|
268
|
+
if (options.consoleMessagesFile) {
|
|
269
|
+
await Console.disable();
|
|
270
|
+
pageData.consoleMessages = consoleMessages;
|
|
271
|
+
}
|
|
255
272
|
Object.assign(pageData, httpInfo);
|
|
256
273
|
return pageData;
|
|
257
274
|
} catch (error) {
|
|
@@ -270,44 +287,27 @@ async function getPageData(options) {
|
|
|
270
287
|
}
|
|
271
288
|
}
|
|
272
289
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
const dataURI = "data:image/png;base64," + data;
|
|
276
|
-
const screenshotData = Array.from(new Uint8Array(await (await fetch(dataURI)).arrayBuffer()));
|
|
277
|
-
await Runtime.evaluate({
|
|
278
|
-
expression: `globalThis.${SET_SCREENSHOT_FUNCTION_NAME}(${JSON.stringify(screenshotData)})`,
|
|
279
|
-
contextId
|
|
280
|
-
});
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
async function onCapturePdf({ Page, Runtime }, contextId, options = {}) {
|
|
284
|
-
const { data } = await Page.printToPDF(options);
|
|
285
|
-
const pdfData = Array.from(new Uint8Array(await (await fetch("data:application/pdf;base64," + data)).arrayBuffer()));
|
|
286
|
-
await Runtime.evaluate({
|
|
287
|
-
expression: `globalThis.${SET_PDF_FUNCTION_NAME}(${JSON.stringify(pdfData)})`,
|
|
288
|
-
contextId
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function getPageDataScriptSource(options, [SET_SCREENSHOT_FUNCTION_NAME, SET_PDF_FUNCTION_NAME, SET_PAGE_DATA_FUNCTION_NAME]) {
|
|
293
|
-
if ((options.embedScreenshot && options.compressContent) || options.embedPdf) {
|
|
290
|
+
function getPageDataScriptSource(options, [SET_SCREENSHOT_FUNCTION_NAME, SET_PDF_FUNCTION_NAME, SET_PAGE_DATA_FUNCTION_NAME, CAPTURE_SCREENSHOT_FUNCTION_NAME, PRINT_TO_PDF_FUNCTION_NAME]) {
|
|
291
|
+
if ((options.embedScreenshot || options.embedPdf) && options.compressContent) {
|
|
294
292
|
let screenshot, pdf;
|
|
295
|
-
if (options.embedScreenshot
|
|
296
|
-
screenshot = new Promise(resolve => globalThis[SET_SCREENSHOT_FUNCTION_NAME] =
|
|
293
|
+
if (options.embedScreenshot) {
|
|
294
|
+
screenshot = new Promise(resolve => globalThis[SET_SCREENSHOT_FUNCTION_NAME] = async data =>
|
|
295
|
+
resolve(Array.from(new Uint8Array(await (await fetch("data:image/png;base64," + data)).arrayBuffer()))));
|
|
297
296
|
}
|
|
298
297
|
if (options.embedPdf) {
|
|
299
|
-
pdf = new Promise(resolve => globalThis[SET_PDF_FUNCTION_NAME] =
|
|
298
|
+
pdf = new Promise(resolve => globalThis[SET_PDF_FUNCTION_NAME] = async data =>
|
|
299
|
+
resolve(Array.from(new Uint8Array(await (await fetch("data:application/pdf;base64," + data)).arrayBuffer()))));
|
|
300
300
|
}
|
|
301
301
|
let pendingCapture;
|
|
302
302
|
options.onprogress = async event => {
|
|
303
303
|
if (event.type == event.RESOURCES_INITIALIZING && window == top && !pendingCapture) {
|
|
304
304
|
pendingCapture = true;
|
|
305
|
-
if (globalThis
|
|
306
|
-
globalThis
|
|
305
|
+
if (globalThis[CAPTURE_SCREENSHOT_FUNCTION_NAME]) {
|
|
306
|
+
globalThis[CAPTURE_SCREENSHOT_FUNCTION_NAME]("");
|
|
307
307
|
options.embeddedImage = await screenshot;
|
|
308
308
|
}
|
|
309
|
-
if (globalThis
|
|
310
|
-
globalThis
|
|
309
|
+
if (globalThis[PRINT_TO_PDF_FUNCTION_NAME]) {
|
|
310
|
+
globalThis[PRINT_TO_PDF_FUNCTION_NAME]("");
|
|
311
311
|
options.embeddedPdf = await pdf;
|
|
312
312
|
}
|
|
313
313
|
}
|