Skip to content

Commit 73b9cc7

Browse files
committed
Added filename to download path
1 parent b4eb27d commit 73b9cc7

File tree

2 files changed

+79
-11
lines changed

2 files changed

+79
-11
lines changed

puppeteer/page/download.html

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
delay: { value: 0 },
1111
downloadPath: { value: "", required: false },
1212
downloadPathtype: { value: "str" },
13+
fileName: { value: "", required: false },
14+
fileNametype: { value: "str" },
1315
name: { value: "" },
1416
},
1517
inputs: 1,
@@ -36,6 +38,11 @@
3638
types: ["str", "msg", "flow", "global"],
3739
typeField: "#node-input-downloadPathtype",
3840
});
41+
$("#node-input-fileName").typedInput({
42+
type: "str",
43+
types: ["str", "msg", "flow", "global"],
44+
typeField: "#node-input-fileNametype",
45+
});
3946
},
4047
});
4148
</script>
@@ -69,26 +76,38 @@
6976
<input id="node-input-downloadPath"></input>
7077
<input type="hidden" id="node-input-downloadPathtype"></input>
7178
</div>
79+
<div class="form-row">
80+
<label for="node-input-fileName"><i class="fa fa-file-o"></i> File name</label>
81+
<input id="node-input-fileName"></input>
82+
<input type="hidden" id="node-input-fileNametype"></input>
83+
</div>
7284
<div class="form-row">
7385
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
7486
<input type="text" id="node-input-name" style="width:70%;" placeholder="Name" />
7587
</div>
88+
<div class="form-tips">
89+
<span data-i18n="[html]tip1">This node downloads a file by clicking on a specified selector. Essetially that can be done with the click node as well, but here you can specify download location and also if this node is followed by rename node with specified download path and filename, it can change the filename directly, but in order to get this to work, in the rename node the old file path needs to be set to <code>msg.old</code> and the new file path needs to be set to <code>msg.new</code>. The output of this node is a <b>msg</b> which contains <code>msg.puppeteer</code>, <code>msg.new & msg.old</code> (<b><u style="text-decoration-color: #fe6d73">only when download path and file path are specified</u></b>) and <code>msg.error</code> when an error ocurred.
90+
</div>
7691
</script>
7792

7893
<script type="text/x-red" data-help-name="puppeteer-page-download">
79-
<p>Click on Chrome</p>
94+
<p>Dowload a file</p>
8095
<h3>Inputs</h3>
8196
<dl class="message-properties">
8297
<dt>Selector<span class="property-type">string</span></dt>
8398
<dd>A <a href="#interface-selector" title="Selector">selector</a> to search for element to click. If there are multiple elements satisfying the selector, the first will be clicked.</dd>
8499
<dt>Button<span class="property-type">string</span></dt>
85100
<dd>Slows down Puppeteer operations by the specified amount of milliseconds. Useful so that you can see what is going on.&lt;"left"|"right"|"middle"&gt; Defaults to <code>left</code>.</dd>
86101
<dt>Click Count<span class="property-type">number</span></dt>
87-
<dd>Whether to run browser in <a href="https://developers.google.com/web/updates/2017/04/headless-chrome" rel="nofollow">headless mode</a>. Defaults to <code>false</code>, it will show Chrome when <code>devtools</code> option is <code>true</code>.defaults to 1. See <a href="https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail" title="UIEvent.detail" rel="nofollow">UIEvent.detail</a>.</dd>
88102
<dt>Delay<span class="property-type">number</span></dt>
89-
<dd>Specify custom debugging port. Pass <code>0</code> to discover a random port. Defaults to <code>0</code>.Time to wait between <code>mousedown</code> and <code>mouseup</code> in milliseconds. Defaults to 0.</dd>
103+
<dt>Download path<span class="property-type">string</span></dt>
104+
<dd>Specify custom download path. Leave the field blank for default download path. Defaults to user's default browser download path.</dd>
105+
<dt>File name<span class="property-type">string</span></dt>
106+
<dd>Specify custom file name. Leave the field blank for default file name. Please note that in order for this to work this node needs to be followed by the rename node. Defaults to default file name.</dd>
90107
</dl>
91108
<h3>Details</h3>
92109
<p>This method fetches an element with <code>selector</code>, scrolls it into view if needed, and then uses <code>page.mouse</code> to click in the center of the element.
93-
If there's no element matching <code>selector</code>, the method throws an error.</p>
110+
If there's no element matching <code>selector</code>, the method throws an error. The main difference between this and click node is that with this node you can specify
111+
download path and file name. But, in order the custom filename to work, this node must have download path and file name specified and be followed by a rename node where
112+
the old file path should be set to <code>msg.old</code> and the new file path should be set to <code>msg.new</code></p>
94113
</script>

puppeteer/page/download.js

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,22 @@ module.exports = function (RED) {
3939
);
4040
}
4141

42+
// Parsing the fileName from string input or from msg object
43+
let fileName =
44+
nodeConfig.fileNametype == "msg"
45+
? eval(nodeConfig.fileNametype + "." + nodeConfig.fileName)
46+
: nodeConfig.fileName;
47+
// If the type of fileName is set to flow or global, it needs to be parsed differently
48+
if (
49+
nodeConfig.fileNametype == "flow" ||
50+
nodeConfig.fileNametype == "global"
51+
) {
52+
// Parsing the fileName
53+
fileName = this.context()[nodeConfig.fileNametype].get(
54+
nodeConfig.fileName
55+
);
56+
}
57+
4258
// If download path is defined
4359
if (downloadPath && downloadPath != "") {
4460
// Enable requests interception
@@ -53,7 +69,37 @@ module.exports = function (RED) {
5369
interceptedRequest.continue(); // Continue the requets as usual
5470
}
5571
});
72+
73+
if (fileName && fileName != "") {
74+
msg.puppeteer.page.on("response", async (response) => {
75+
// node.warn(response);
76+
const url = response.url();
77+
const headers = response.headers();
78+
const regex = /filename\*?=[^'']*''([^']*)/;
79+
80+
if (headers["content-disposition"]) {
81+
const match = regex.exec(headers["content-disposition"]);
82+
node.warn(headers["content-disposition"]);
83+
if (match && match[1]) {
84+
const fs = require("fs");
85+
const downloadedFileName = match[1];
86+
const extensionRegex = /\.[^.]*$/;
87+
const extension = extensionRegex.exec(downloadedFileName);
88+
if(extension) {
89+
msg.old = `${downloadPath}/${downloadedFileName}`;
90+
msg.new = `${downloadPath}/${fileName}${extension[0]}`;
91+
node.send(msg);
92+
}
93+
// extension ? msg.old
94+
// : node.send({ payload: null });
95+
// const fileExtension = extension ? fs.renameSync(`${downloadPath}/${downloadedFileName}`, `${downloadPath}/${fileName}.${extension[0]}`) : node.warn(`File has no extension! saved as ${downloadedFileName} in ${downloadPath}!`);
96+
// fs.renameSync(`${downloadPath}/${downloadedFileName}`, `${downloadPath}/${fileName}.${extension}`);
97+
}
98+
}
99+
});
100+
}
56101
}
102+
57103
// Waiting for the specified selector
58104
node.status({
59105
fill: "blue",
@@ -81,9 +127,9 @@ module.exports = function (RED) {
81127
shape: "dot",
82128
text: `Clicked ${selector}`,
83129
});
84-
// Sending the msg
85-
send(msg);
86-
130+
if (!fileName || fileName == "")
131+
// Sending the msg
132+
send(msg);
87133
} catch (e) {
88134
// If an error occured
89135
node.error(e);
@@ -95,10 +141,13 @@ module.exports = function (RED) {
95141
}
96142

97143
// Clear status of the node
98-
setTimeout(() => {
99-
done();
100-
node.status({});
101-
}, (msg.error) ? 10000 : 3000);
144+
setTimeout(
145+
() => {
146+
done();
147+
node.status({});
148+
},
149+
msg.error ? 10000 : 3000
150+
);
102151
});
103152
this.on("close", function () {
104153
node.status({});

0 commit comments

Comments
 (0)