node-red-contrib-tts-ultimate 1.0.36 → 1.0.40
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/.vscode/launch.json +17 -0
- package/CHANGELOG.md +18 -0
- package/README.md +26 -15
- package/package.json +4 -4
- package/ttsultimate/ttsultimate-config.html +4 -8
- package/ttsultimate/ttsultimate-config.js +45 -46
- package/ttsultimate/ttsultimate.html +1 -1
- package/ttsultimate/ttsultimate.js +57 -64
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Usare IntelliSense per informazioni sui possibili attributi.
|
|
3
|
+
// Al passaggio del mouse vengono visualizzate le descrizioni degli attributi esistenti.
|
|
4
|
+
// Per altre informazioni, visitare: https://go.microsoft.com/fwlink/?linkid=830387
|
|
5
|
+
"version": "0.2.0",
|
|
6
|
+
"configurations": [
|
|
7
|
+
{
|
|
8
|
+
"type": "pwa-node",
|
|
9
|
+
"request": "launch",
|
|
10
|
+
"name": "Launch Program",
|
|
11
|
+
"skipFiles": [
|
|
12
|
+
"<node_internals>/**"
|
|
13
|
+
],
|
|
14
|
+
"program": "${workspaceFolder}/ttsultimate/ttsultimate.js"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.paypal.me/techtoday)
|
|
4
4
|
|
|
5
|
+
<p>
|
|
6
|
+
<b>Version 1.0.40</b> January 2022<br/>
|
|
7
|
+
- NEW: you can now select your own folder to save the TTS cached files.<br/>
|
|
8
|
+
- NEW: getting rid of file lenght issue by hashing the TTS cached files requested from TTS engines. Now the file names will be MD5 HEX hashed.<br/>
|
|
9
|
+
- NEW: now the input messages are passed through to the output pin.<br/>
|
|
10
|
+
- CAUTION: due to the new file management, the node will need to download again the TTS files from your TTS engine. Keep it in mind, because you can be charged by Amazon, Google or Microsoft.<br/>
|
|
11
|
+
<p>
|
|
12
|
+
<p>
|
|
13
|
+
<b>Version 1.0.39</b> January 2022<br/>
|
|
14
|
+
- SSML: fixed an issue prevent using it.<br/>
|
|
15
|
+
- SSML: if SSML is enabled, the text auto split function is disabled, to avoid splitting SSML XML text.<br/>
|
|
16
|
+
- Microsoft Azure: update TTS engine to 1.19.0<br/>
|
|
17
|
+
- Google paid TTS: update TTS engine to 3.4.0<br/>
|
|
18
|
+
<p>
|
|
19
|
+
<b>Version 1.0.38</b> December 2021<br/>
|
|
20
|
+
- Removed some unwanted startup logs.<br/>
|
|
21
|
+
- Fixed ownfile sample code. Thanks to plats98.<br/>
|
|
22
|
+
<p>
|
|
5
23
|
<p>
|
|
6
24
|
<b>Version 1.0.36</b> November 2021<br/>
|
|
7
25
|
- NEW: Autosplit function: you can now set the maximum lenght of the text-parts, in case your spoken text is too long for the allowed TTS Engine limits.<br/>
|
package/README.md
CHANGED
|
@@ -126,10 +126,11 @@ On each deploy or node-red restart, delete all tts files in the cache. This is u
|
|
|
126
126
|
Don't delete the files cached. Useful if you wish to keep the tts files, even in case of internet outages, node-red restart or reboots.
|
|
127
127
|
<br/>
|
|
128
128
|
|
|
129
|
-
**
|
|
129
|
+
**Cache root folder**
|
|
130
130
|
<br/>
|
|
131
|
-
|
|
132
|
-
This
|
|
131
|
+
Set your preferred output folder for the files downloaded by the TTS Engine.<br/>
|
|
132
|
+
This is useful if you wish to save the TTS cached files in a folder accessible, for example, by a third party web servers to serve an AirPlay2 speaker.<br/>
|
|
133
|
+
Leave this field blank for the default.<br/>
|
|
133
134
|
<br/>
|
|
134
135
|
<br/>
|
|
135
136
|
|
|
@@ -141,6 +142,9 @@ Select the TTS SERVICE ENGINE NODE, as stated above.
|
|
|
141
142
|
**Voice**<br/>
|
|
142
143
|
Select your preferred voice. If you use Amazon, Polly voices will be displayed. If you use Google, google voices will be displayed. Google service without authentication, has a limited set of voices.
|
|
143
144
|
|
|
145
|
+
**Enable SSML**<br/>
|
|
146
|
+
Enable the SSML XML notation. Please be aware, not all the TTS engines supports that.
|
|
147
|
+
|
|
144
148
|
**Rate**<br/>
|
|
145
149
|
Only avaiable if you choose Google TTS Engine (with credentials). Specifies the speech speed (Between 0.25 and 4.0, default 1).
|
|
146
150
|
|
|
@@ -236,18 +240,21 @@ The node has two output pins. The first pin is to signal play status, the second
|
|
|
236
240
|
**OUTPUT PIN 1**<br/>
|
|
237
241
|
Payload is ***true*** when the node has finished playing, ***false*** if the node is playing<br/>
|
|
238
242
|
In case you selected ***No player, only output file name.*** in the **Player** property, you'll get a message with an additional property *filesArray*, containing an array of all mp3 files ready to be played with third party nodes.<br/>
|
|
243
|
+
The property ***passThroughMessage*** contains the input msg passed through the output.<br/>
|
|
244
|
+
|
|
239
245
|
```js
|
|
240
246
|
{
|
|
241
247
|
"payload":true,
|
|
248
|
+
"passThroughMessage" : {original message object}
|
|
242
249
|
"filesArray":[
|
|
243
250
|
{
|
|
244
|
-
"file":"/Users/supergiovane/.node-red/sonospollyttsstorage/hailingpermanentfiles/
|
|
251
|
+
"file":"/Users/supergiovane/.node-red/sonospollyttsstorage/hailingpermanentfiles/hail.mp3"
|
|
245
252
|
},
|
|
246
253
|
{
|
|
247
|
-
"file":"/Users/supergiovane/.node-red/sonospollyttsstorage/ttsfiles/
|
|
254
|
+
"file":"/Users/supergiovane/.node-red/sonospollyttsstorage/ttsfiles/345938475938457.mp3"
|
|
248
255
|
},
|
|
249
256
|
{
|
|
250
|
-
"file":"/Users/supergiovane/.node-red/sonospollyttsstorage/ttsfiles/
|
|
257
|
+
"file":"/Users/supergiovane/.node-red/sonospollyttsstorage/ttsfiles/3666HJGH565656.mp3"
|
|
251
258
|
}
|
|
252
259
|
],
|
|
253
260
|
"_msgid":"8b6b22a45dfd5236"
|
|
@@ -272,17 +279,19 @@ The property is a JSON object.
|
|
|
272
279
|
<img src='https://github.com/Supergiovane/node-red-contrib-tts-ultimate/raw/master/img/setConfig.png' width="80%">
|
|
273
280
|
|
|
274
281
|
**msg.setConfig**<br/>
|
|
275
|
-
This is the property where you can set all the things. It must be
|
|
282
|
+
This is the property where you can set all the things. It must be a JSON Object with the below specified properties.<br/>
|
|
283
|
+
The setting is retained until the node receives another msg.setConfig or until node-red is restarted.<br/>
|
|
276
284
|
|
|
277
|
-
**setMainPlayerIP**<br/>
|
|
278
|
-
Sets the main player IP. This will also be the coordinator if you have a group of players
|
|
285
|
+
> **property setMainPlayerIP**<br/>
|
|
286
|
+
Sets the main player IP. This will also be the coordinator if you have a group of players.
|
|
279
287
|
|
|
280
|
-
**setPlayerGroupArray**<br/>
|
|
281
|
-
Sets the array of players beloging to the group, if any.<br/>
|
|
282
|
-
If you have only one additional player, you need to ever put it into an array. See below.
|
|
288
|
+
> **property setPlayerGroupArray**<br/>
|
|
289
|
+
Sets the array of players beloging to the group, if any.<br/>
|
|
290
|
+
If you have only one additional player, you need to ever put it into an array. See below.
|
|
283
291
|
|
|
284
292
|
```js
|
|
285
|
-
// Set player IP
|
|
293
|
+
// Set main player IP
|
|
294
|
+
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
286
295
|
var config= {
|
|
287
296
|
setMainPlayerIP:"192.168.1.109"
|
|
288
297
|
};
|
|
@@ -292,6 +301,7 @@ return msg;
|
|
|
292
301
|
|
|
293
302
|
```js
|
|
294
303
|
// Set player IP and additional players
|
|
304
|
+
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
295
305
|
var config= {
|
|
296
306
|
setMainPlayerIP:"192.168.1.109",
|
|
297
307
|
setPlayerGroupArray:[
|
|
@@ -306,6 +316,7 @@ return msg;
|
|
|
306
316
|
|
|
307
317
|
```js
|
|
308
318
|
// If you have only one additional player
|
|
319
|
+
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
309
320
|
var config= {
|
|
310
321
|
setMainPlayerIP:"192.168.1.109",
|
|
311
322
|
setPlayerGroupArray:["192.168.1.110"]
|
|
@@ -339,7 +350,7 @@ return msg;
|
|
|
339
350
|
> Adjust the nodes according to your setup
|
|
340
351
|
|
|
341
352
|
```js
|
|
342
|
-
[{"id":"db0ea33.f1186e","type":"ttsultimate","z":"c6efd2b6.ab02e8","name":"","voice":"en-AU-Standard-A#en-AU#FEMALE","ssml":false,"sonosipaddress":"192.168.1.109","sonosvolume":"25","sonoshailing":"Hailing_Hailing.mp3","config":"4f941d61.f52c4c","propertyType":{},"rules":[],"x":670,"y":240,"wires":[[]]},{"id":"c7fb2970.271978","type":"
|
|
353
|
+
[{"id":"db0ea33.f1186e","type":"ttsultimate","z":"c6efd2b6.ab02e8","name":"","voice":"en-AU-Standard-A#en-AU#FEMALE","ssml":false,"sonosipaddress":"192.168.1.109","sonosvolume":"25","sonoshailing":"Hailing_Hailing.mp3","config":"4f941d61.f52c4c","propertyType":{},"rules":[],"x":670,"y":240,"wires":[[]]},{"id":"c7fb2970.271978","type":"ownfileultimate","z":"c6efd2b6.ab02e8","name":"","selectedFile":"OwnFile_Tur geoeffnet.mp3","x":490,"y":220,"wires":[["db0ea33.f1186e"]]},{"id":"fef80c5b.49f9e","type":"inject","z":"c6efd2b6.ab02e8","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":220,"wires":[["c7fb2970.271978"]]},{"id":"807f0f6c.6d59c","type":"comment","z":"c6efd2b6.ab02e8","name":"You can upload your own voice messages and use it with ttsultimate","info":"","x":310,"y":180,"wires":[]},{"id":"536e58b3.bb8468","type":"ownfileultimate","z":"c6efd2b6.ab02e8","name":"","selectedFile":"OwnFile_Tur geoeffnet.mp3","x":490,"y":260,"wires":[["db0ea33.f1186e"]]},{"id":"26c339f9.346fbe","type":"inject","z":"c6efd2b6.ab02e8","name":"","topic":"","payload":"true","payloadType":"bool","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":260,"wires":[["25016441.6447bc"]]},{"id":"25016441.6447bc","type":"function","z":"c6efd2b6.ab02e8","name":"Dynamically Select file","func":"// Override the selected file.\nmsg.selectedFile=\"Porta aperta\"\nreturn msg;","outputs":1,"noerr":0,"x":300,"y":260,"wires":[["536e58b3.bb8468"]]},{"id":"4f941d61.f52c4c","type":"ttsultimate-config","z":"","name":"GoogleTTS","noderedipaddress":"192.168.1.219","noderedport":"1980","purgediratrestart":"leave","ttsservice":"googletts"}]
|
|
343
354
|
```
|
|
344
355
|
</details>
|
|
345
356
|
|
|
@@ -348,7 +359,7 @@ This node allow you to upload your custom message and play it via ttsultimate wi
|
|
|
348
359
|
**Name**<br/>
|
|
349
360
|
Node name
|
|
350
361
|
|
|
351
|
-
**File to be
|
|
362
|
+
**File to be played** <br/>
|
|
352
363
|
Select a file to be played. You can upload one or multiple files at the same time via the "upload" button.
|
|
353
364
|
|
|
354
365
|
**Priority**<br/>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-red-contrib-tts-ultimate",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.40",
|
|
4
4
|
"description": "Transforms the text in speech and hear it using Sonos player or generate an audio file to be used with third parties nodes. Works with voices from Amazon, Google (without credentials as well), Microsoft TTS Azure, or your own voice. You can also only create a TTS file to be read by third party nodes. Update of the popular SonosPollyTTS node.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"google",
|
|
17
17
|
"voice",
|
|
18
18
|
"amazon",
|
|
19
|
+
"azure",
|
|
19
20
|
"tts",
|
|
20
21
|
"sonos",
|
|
21
22
|
"IOT",
|
|
@@ -38,16 +39,15 @@
|
|
|
38
39
|
"homepage": "https://github.com/Supergiovane/node-red-contrib-tts-ultimate",
|
|
39
40
|
"dependencies": {
|
|
40
41
|
"aws-sdk": "2.816.0",
|
|
41
|
-
"crypto-js": "^3.1.9-1",
|
|
42
42
|
"fs": "0.0.1-security",
|
|
43
43
|
"sonos": "1.14.1",
|
|
44
44
|
"util": ">=0.10.1",
|
|
45
45
|
"formidable": "1.2.2",
|
|
46
46
|
"os": ">=0.1.1",
|
|
47
47
|
"path": ">=0.12.7",
|
|
48
|
-
"@google-cloud/text-to-speech": "3.
|
|
48
|
+
"@google-cloud/text-to-speech": "3.4.0",
|
|
49
49
|
"google-translate-tts": ">=0.2.1",
|
|
50
|
-
"microsoft-cognitiveservices-speech-sdk": ">=1.
|
|
50
|
+
"microsoft-cognitiveservices-speech-sdk": ">=1.19.0"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"eslint": ">=4.18.2",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
},
|
|
19
19
|
purgediratrestart: { value: "leave", required: false },
|
|
20
20
|
ttsservice: { value: "googletranslate", required: false },
|
|
21
|
-
|
|
21
|
+
TTSRootFolderPath: { value: "", required: false }
|
|
22
22
|
|
|
23
23
|
},
|
|
24
24
|
credentials: {
|
|
@@ -33,10 +33,6 @@
|
|
|
33
33
|
oneditprepare: function () {
|
|
34
34
|
var node = this;
|
|
35
35
|
|
|
36
|
-
// 01/11/2021
|
|
37
|
-
//if (node.limitTTSFilenameLenght === undefined) {
|
|
38
|
-
// $("#node-config-input-limitTTSFilenameLenght").val(220);
|
|
39
|
-
//}
|
|
40
36
|
// 21/03/2020 Check if the node is the absolute first in the flow. In this case, it has no http server instatiaced
|
|
41
37
|
$.getJSON('ttsultimateGetEthAddress', (data) => {
|
|
42
38
|
$("#pleaseDeploy").hide();
|
|
@@ -215,10 +211,10 @@
|
|
|
215
211
|
</div>
|
|
216
212
|
|
|
217
213
|
<div class="form-row">
|
|
218
|
-
<label for="node-config-input-
|
|
219
|
-
<input type="text" id="node-config-input-
|
|
214
|
+
<label for="node-config-input-TTSRootFolderPath"><i class="fa fa-folder-o"></i> Cache root folder</label>
|
|
215
|
+
<input type="text" id="node-config-input-TTSRootFolderPath" placeholder="The folder must exist. Leave blank for default">
|
|
220
216
|
</div>
|
|
221
|
-
|
|
217
|
+
|
|
222
218
|
</div>
|
|
223
219
|
|
|
224
220
|
</script>
|
|
@@ -20,10 +20,9 @@ module.exports = function (RED) {
|
|
|
20
20
|
RED.nodes.createNode(this, config);
|
|
21
21
|
var node = this;
|
|
22
22
|
node.noderedipaddress = typeof config.noderedipaddress === "undefined" ? "" : config.noderedipaddress;
|
|
23
|
-
node.userDir = path.join(RED.settings.userDir, "sonospollyttsstorage"); // 09/03/2020 Storage of ttsultimate (otherwise, at each upgrade to a newer version, the node path is wiped out and recreated, loosing all custom files)
|
|
24
23
|
node.whoIsUsingTheServer = ""; // Client node.id using the server, because only a ttsultimate node can use the serve at once.
|
|
25
24
|
node.ttsservice = config.ttsservice || "googletranslate";
|
|
26
|
-
node.
|
|
25
|
+
node.TTSRootFolderPath = (config.TTSRootFolderPath === undefined || config.TTSRootFolderPath === "") ? path.join(RED.settings.userDir, "sonospollyttsstorage") : path.join(config.TTSRootFolderPath, "sonospollyttsstorage");
|
|
27
26
|
// node.polly = null;
|
|
28
27
|
// node.googleTTS = null;
|
|
29
28
|
// node.googleTranslateTTS = null;
|
|
@@ -44,38 +43,38 @@ module.exports = function (RED) {
|
|
|
44
43
|
return true;
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
|
-
if (!setupDirectory(node.
|
|
48
|
-
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up MAIN directory: ' + node.
|
|
46
|
+
if (!setupDirectory(node.TTSRootFolderPath)) {
|
|
47
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up MAIN directory: ' + node.TTSRootFolderPath);
|
|
49
48
|
}
|
|
50
|
-
if (!setupDirectory(path.join(node.
|
|
51
|
-
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up cache directory: ' + path.join(node.
|
|
49
|
+
if (!setupDirectory(path.join(node.TTSRootFolderPath, "ttsfiles"))) {
|
|
50
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up cache directory: ' + path.join(node.TTSRootFolderPath, "ttsfiles"));
|
|
52
51
|
} else {
|
|
53
|
-
RED.log.info('ttsultimate-config ' + node.id + ': TTS cache set to ' + path.join(node.
|
|
52
|
+
RED.log.info('ttsultimate-config ' + node.id + ': TTS cache set to ' + path.join(node.TTSRootFolderPath, "ttsfiles"));
|
|
54
53
|
}
|
|
55
|
-
if (!setupDirectory(path.join(node.
|
|
56
|
-
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set google creds directory: ' + path.join(node.
|
|
54
|
+
if (!setupDirectory(path.join(node.TTSRootFolderPath, "ttsultimategooglecredentials"))) {
|
|
55
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set google creds directory: ' + path.join(node.TTSRootFolderPath, "ttsultimategooglecredentials"));
|
|
57
56
|
} else {
|
|
58
|
-
RED.log.info('ttsultimate-config ' + node.id + ': google credentials path set to ' + path.join(node.
|
|
57
|
+
RED.log.info('ttsultimate-config ' + node.id + ': google credentials path set to ' + path.join(node.TTSRootFolderPath, "ttsultimategooglecredentials"));
|
|
59
58
|
}
|
|
60
|
-
if (!setupDirectory(path.join(node.
|
|
61
|
-
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up hailing directory: ' + path.join(node.
|
|
59
|
+
if (!setupDirectory(path.join(node.TTSRootFolderPath, "hailingpermanentfiles"))) {
|
|
60
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up hailing directory: ' + path.join(node.TTSRootFolderPath, "hailingpermanentfiles"));
|
|
62
61
|
} else {
|
|
63
|
-
RED.log.info('ttsultimate-config ' + node.id + ': hailing path set to ' + path.join(node.
|
|
62
|
+
RED.log.info('ttsultimate-config ' + node.id + ': hailing path set to ' + path.join(node.TTSRootFolderPath, "hailingpermanentfiles"));
|
|
64
63
|
// 09/03/2020 Copy defaults to the userDir
|
|
65
64
|
fs.readdirSync(path.join(__dirname, "hailingpermanentfiles")).forEach(file => {
|
|
66
65
|
try {
|
|
67
|
-
fs.copyFileSync(path.join(__dirname, "hailingpermanentfiles", file), path.join(node.
|
|
66
|
+
fs.copyFileSync(path.join(__dirname, "hailingpermanentfiles", file), path.join(node.TTSRootFolderPath, "hailingpermanentfiles", file));
|
|
68
67
|
} catch (error) { }
|
|
69
68
|
});
|
|
70
69
|
}
|
|
71
|
-
if (!setupDirectory(path.join(node.
|
|
72
|
-
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up permanent files directory: ' + path.join(node.
|
|
70
|
+
if (!setupDirectory(path.join(node.TTSRootFolderPath, "ttspermanentfiles"))) {
|
|
71
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up permanent files directory: ' + path.join(node.TTSRootFolderPath, "ttspermanentfiles"));
|
|
73
72
|
} else {
|
|
74
|
-
RED.log.info('ttsultimate-config ' + node.id + ': permanent files path set to ' + path.join(node.
|
|
73
|
+
RED.log.info('ttsultimate-config ' + node.id + ': permanent files path set to ' + path.join(node.TTSRootFolderPath, "ttspermanentfiles"));
|
|
75
74
|
// 09/03/2020 // Copy the samples of permanent files into the userDir
|
|
76
75
|
fs.readdirSync(path.join(__dirname, "ttspermanentfiles")).forEach(file => {
|
|
77
76
|
try {
|
|
78
|
-
fs.copyFileSync(path.join(__dirname, "ttspermanentfiles", file), path.join(node.
|
|
77
|
+
fs.copyFileSync(path.join(__dirname, "ttspermanentfiles", file), path.join(node.TTSRootFolderPath, "ttspermanentfiles", file));
|
|
79
78
|
} catch (error) { }
|
|
80
79
|
});
|
|
81
80
|
}
|
|
@@ -97,7 +96,7 @@ module.exports = function (RED) {
|
|
|
97
96
|
RED.log.warn("ttsultimate-config " + node.id + ": Polly service disabled. " + error.message)
|
|
98
97
|
}
|
|
99
98
|
} else {
|
|
100
|
-
RED.log.
|
|
99
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Polly service not used.");
|
|
101
100
|
}
|
|
102
101
|
|
|
103
102
|
|
|
@@ -105,8 +104,8 @@ module.exports = function (RED) {
|
|
|
105
104
|
if (node.ttsservice === "googletts") {
|
|
106
105
|
try {
|
|
107
106
|
// 23/12/2020 Set environment path of googleTTS
|
|
108
|
-
RED.log.info("ttsultimate-config " + node.id + ": Google credentials are stored in the file " + path.join(node.
|
|
109
|
-
process.env.GOOGLE_APPLICATION_CREDENTIALS = path.join(node.
|
|
107
|
+
RED.log.info("ttsultimate-config " + node.id + ": Google credentials are stored in the file " + path.join(node.TTSRootFolderPath, "ttsultimategooglecredentials", "googlecredentials.json"));
|
|
108
|
+
process.env.GOOGLE_APPLICATION_CREDENTIALS = path.join(node.TTSRootFolderPath, "ttsultimategooglecredentials", "googlecredentials.json");
|
|
110
109
|
try {
|
|
111
110
|
node.googleTTS = new GoogleTTS.TextToSpeechClient();
|
|
112
111
|
RED.log.info("ttsultimate-config " + node.id + ": Google TTS service enabled. ")
|
|
@@ -118,7 +117,7 @@ module.exports = function (RED) {
|
|
|
118
117
|
}
|
|
119
118
|
|
|
120
119
|
} else {
|
|
121
|
-
RED.log.
|
|
120
|
+
// RED.log.info("ttsultimate-config " + node.id + ": Google TTS service not used.");
|
|
122
121
|
}
|
|
123
122
|
|
|
124
123
|
|
|
@@ -128,10 +127,10 @@ module.exports = function (RED) {
|
|
|
128
127
|
try {
|
|
129
128
|
node.googleTranslateTTS = GoogleTranslate;
|
|
130
129
|
} catch (error) {
|
|
131
|
-
RED.log.
|
|
130
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
|
|
132
131
|
}
|
|
133
132
|
} else {
|
|
134
|
-
RED.log.
|
|
133
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
|
|
135
134
|
}
|
|
136
135
|
|
|
137
136
|
|
|
@@ -180,13 +179,13 @@ module.exports = function (RED) {
|
|
|
180
179
|
}
|
|
181
180
|
} catch (error) {
|
|
182
181
|
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error parsing Microsoft Azure TTS voices: ' + error.message);
|
|
183
|
-
node.microsoftAzureTTSVoiceList.push({ name: "Error parsing Microsoft Azure voices: " + error.message, id: "Ivy" });
|
|
182
|
+
node.microsoftAzureTTSVoiceList.push({ name: "Error parsing Microsoft Azure voices: " + error.message + " Check cretentials, deploy and restart node-red.", id: "Ivy" });
|
|
184
183
|
}
|
|
185
184
|
})
|
|
186
185
|
})
|
|
187
186
|
reqAzure.on('error', error => {
|
|
188
187
|
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error contacting Azure for getting the voices list: ' + error.message);
|
|
189
|
-
node.microsoftAzureTTSVoiceList.push({ name: "Error getting Microsoft Azure voices: " + error.message, id: "Ivy" })
|
|
188
|
+
node.microsoftAzureTTSVoiceList.push({ name: "Error getting Microsoft Azure voices: " + error.message + " Check cretentials, deploy and restart node-red.", id: "Ivy" })
|
|
190
189
|
reqAzure.end();
|
|
191
190
|
})
|
|
192
191
|
reqAzure.end();
|
|
@@ -202,7 +201,7 @@ module.exports = function (RED) {
|
|
|
202
201
|
RED.log.warn("ttsultimate-config " + node.id + ": Microsoft AzureTTS service disabled. " + error.message)
|
|
203
202
|
}
|
|
204
203
|
} else {
|
|
205
|
-
RED.log.
|
|
204
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Microsoft AzureTTS service not used. ");
|
|
206
205
|
}
|
|
207
206
|
// #########################################
|
|
208
207
|
|
|
@@ -265,7 +264,7 @@ module.exports = function (RED) {
|
|
|
265
264
|
var jListOwnFiles = [];
|
|
266
265
|
var sName = "";
|
|
267
266
|
try {
|
|
268
|
-
fs.readdirSync(path.join(node.
|
|
267
|
+
fs.readdirSync(path.join(node.TTSRootFolderPath, "hailingpermanentfiles")).forEach(file => {
|
|
269
268
|
if (file.indexOf("Hailing_") > -1) {
|
|
270
269
|
sName = file.replace("Hailing_", "").replace(".mp3", "");
|
|
271
270
|
jListOwnFiles.push({ name: sName, filename: file });
|
|
@@ -280,7 +279,7 @@ module.exports = function (RED) {
|
|
|
280
279
|
RED.httpAdmin.get("/deleteHailingFile", RED.auth.needsPermission('TTSConfigNode.read'), function (req, res) {
|
|
281
280
|
// Delete the file
|
|
282
281
|
try {
|
|
283
|
-
var newPath = path.join(node.
|
|
282
|
+
var newPath = path.join(node.TTSRootFolderPath, "hailingpermanentfiles", req.query.FileName);
|
|
284
283
|
fs.unlinkSync(newPath)
|
|
285
284
|
} catch (error) { }
|
|
286
285
|
res.json({ status: 220 });
|
|
@@ -292,7 +291,7 @@ module.exports = function (RED) {
|
|
|
292
291
|
form.parse(req, function (err, fields, files) {
|
|
293
292
|
try {
|
|
294
293
|
if (files.customHailing.name.indexOf(".mp3") !== -1) {
|
|
295
|
-
var newPath = path.join(node.
|
|
294
|
+
var newPath = path.join(node.TTSRootFolderPath, "hailingpermanentfiles", "Hailing_" + files.customHailing.name);
|
|
296
295
|
// 30/12/2020 To avoid XDEV issue: oldpath and newpath are not on the same mounted filesystem. (Linux permits a filesystem to be mounted at multiple points,
|
|
297
296
|
// but rename() does not work across different mount points, even if the same filesystem is mounted on both.)
|
|
298
297
|
// Instead of renaming it, i must copy the file and then delete the old one.
|
|
@@ -325,7 +324,7 @@ module.exports = function (RED) {
|
|
|
325
324
|
if (err) { };
|
|
326
325
|
// Allow only json
|
|
327
326
|
if (files.googleCreds.name.indexOf(".json") !== -1) {
|
|
328
|
-
var newPath = path.join(node.
|
|
327
|
+
var newPath = path.join(node.TTSRootFolderPath, "ttsultimategooglecredentials", "googlecredentials.json");
|
|
329
328
|
// Set the environment variable
|
|
330
329
|
process.env.GOOGLE_APPLICATION_CREDENTIALS = newPath;
|
|
331
330
|
// 30/12/2020 To avoid XDEV issue: oldpath and newpath are not on the same mounted filesystem. (Linux permits a filesystem to be mounted at multiple points,
|
|
@@ -365,7 +364,7 @@ module.exports = function (RED) {
|
|
|
365
364
|
node.polly.describeVoices(jfiltroVoci, function (err, data) {
|
|
366
365
|
if (err) {
|
|
367
366
|
RED.log.warn('ttsultimate-config ' + node.id + ': Error getting polly voices ' + err);
|
|
368
|
-
jListVoices.push({ name: "Error retrieving voices. " + err, id: "Ivy" })
|
|
367
|
+
jListVoices.push({ name: "Error retrieving voices. " + err + " Check cretentials, deploy and restart node-red.", id: "Ivy" })
|
|
369
368
|
res.json(jListVoices)
|
|
370
369
|
} else {
|
|
371
370
|
for (let index = 0; index < data.Voices.length; index++) {
|
|
@@ -392,15 +391,15 @@ module.exports = function (RED) {
|
|
|
392
391
|
});
|
|
393
392
|
res.json(jListVoices)
|
|
394
393
|
} catch (error) {
|
|
395
|
-
RED.log.error('ttsultimate-config ' + node.id + ': Error getting google TTS voices ' + error.message);
|
|
396
|
-
jListVoices.push({ name: "Error getting Google TTS voices. " + error.message, id: "Ivy" })
|
|
394
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Error getting google TTS voices ' + error.message + " Please deploy and restart node-red.");
|
|
395
|
+
jListVoices.push({ name: "Error getting Google TTS voices. " + error.message + " Check credentials, deploy and restart node-red.", id: "Ivy" })
|
|
397
396
|
res.json(jListVoices)
|
|
398
397
|
}
|
|
399
398
|
};
|
|
400
399
|
try {
|
|
401
400
|
listVoices();
|
|
402
401
|
} catch (error) {
|
|
403
|
-
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting google TTS voices ' + error.message);
|
|
402
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting google TTS voices ' + error.message + " Please deploy and restart node-red.");
|
|
404
403
|
}
|
|
405
404
|
|
|
406
405
|
} else if (ttsservice === "googletranslate") {
|
|
@@ -413,14 +412,14 @@ module.exports = function (RED) {
|
|
|
413
412
|
res.json(jListVoices)
|
|
414
413
|
} catch (error) {
|
|
415
414
|
RED.log.error('ttsultimate-config ' + node.id + ': Error getting google Translate voices ' + error.message);
|
|
416
|
-
jListVoices.push({ name: "Error getting Google Translate voices. " + error.message, id: "Ivy" })
|
|
415
|
+
jListVoices.push({ name: "Error getting Google Translate voices. " + error.message + " Deploy and restart node-red.", id: "Ivy" })
|
|
417
416
|
res.json(jListVoices)
|
|
418
417
|
}
|
|
419
418
|
};
|
|
420
419
|
try {
|
|
421
420
|
listVoices();
|
|
422
421
|
} catch (error) {
|
|
423
|
-
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting google Translate voices ' + error.message);
|
|
422
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting google Translate voices ' + error.message + " Please deploy and restart node-red.");
|
|
424
423
|
}
|
|
425
424
|
|
|
426
425
|
} else if (ttsservice === "microsoftazuretts") {
|
|
@@ -442,7 +441,7 @@ module.exports = function (RED) {
|
|
|
442
441
|
// Allow only mp3
|
|
443
442
|
try {
|
|
444
443
|
if (files.customTTS.name.indexOf(".mp3") !== -1) {
|
|
445
|
-
var newPath = path.join(node.
|
|
444
|
+
var newPath = path.join(node.TTSRootFolderPath, "ttspermanentfiles", "OwnFile_" + files.customTTS.name);
|
|
446
445
|
// 30/12/2020 To avoid XDEV issue: oldpath and newpath are not on the same mounted filesystem. (Linux permits a filesystem to be mounted at multiple points,
|
|
447
446
|
// but rename() does not work across different mount points, even if the same filesystem is mounted on both.)
|
|
448
447
|
// Instead of renaming it, i must copy the file and then delete the old one.
|
|
@@ -472,7 +471,7 @@ module.exports = function (RED) {
|
|
|
472
471
|
var jListOwnFiles = [];
|
|
473
472
|
var sName = "";
|
|
474
473
|
try {
|
|
475
|
-
fs.readdirSync(path.join(node.
|
|
474
|
+
fs.readdirSync(path.join(node.TTSRootFolderPath, "ttspermanentfiles")).forEach(file => {
|
|
476
475
|
if (file.indexOf("OwnFile_") > -1) {
|
|
477
476
|
sName = file.replace("OwnFile_", '').replace(".mp3", '');
|
|
478
477
|
jListOwnFiles.push({ name: sName, filename: file });
|
|
@@ -489,12 +488,12 @@ module.exports = function (RED) {
|
|
|
489
488
|
if (req.query.FileName == "DELETEallFiles") {
|
|
490
489
|
// Delete all OwnFiles_
|
|
491
490
|
try {
|
|
492
|
-
fs.readdir(path.join(node.
|
|
491
|
+
fs.readdir(path.join(node.TTSRootFolderPath, "ttspermanentfiles"), (err, files) => {
|
|
493
492
|
files.forEach(function (file) {
|
|
494
493
|
if (file.indexOf("OwnFile_") !== -1) {
|
|
495
|
-
RED.log.warn("ttsultimate-config " + node.id + ": Deleted file " + path.join(node.
|
|
494
|
+
RED.log.warn("ttsultimate-config " + node.id + ": Deleted file " + path.join(node.TTSRootFolderPath, "ttspermanentfiles", file));
|
|
496
495
|
try {
|
|
497
|
-
fs.unlinkSync(path.join(node.
|
|
496
|
+
fs.unlinkSync(path.join(node.TTSRootFolderPath, "ttspermanentfiles", file));
|
|
498
497
|
} catch (error) { }
|
|
499
498
|
}
|
|
500
499
|
});
|
|
@@ -504,7 +503,7 @@ module.exports = function (RED) {
|
|
|
504
503
|
} else {
|
|
505
504
|
// Delete only one file
|
|
506
505
|
try {
|
|
507
|
-
var newPath = path.join(node.
|
|
506
|
+
var newPath = path.join(node.TTSRootFolderPath, "ttspermanentfiles", req.query.FileName);
|
|
508
507
|
try {
|
|
509
508
|
fs.unlinkSync(newPath)
|
|
510
509
|
} catch (error) { }
|
|
@@ -533,13 +532,13 @@ module.exports = function (RED) {
|
|
|
533
532
|
if (node.purgediratrestart === "purge") {
|
|
534
533
|
// Delete all files, that are'nt OwnFiles_
|
|
535
534
|
try {
|
|
536
|
-
fs.readdirSync(path.join(node.
|
|
535
|
+
fs.readdirSync(path.join(node.TTSRootFolderPath, "ttsfiles"), (err, files) => {
|
|
537
536
|
try {
|
|
538
537
|
if (files.length > 0) {
|
|
539
538
|
files.forEach(function (file) {
|
|
540
|
-
RED.log.info("ttsultimate-config " + node.id + ": Deleted TTS file " + path.join(node.
|
|
539
|
+
RED.log.info("ttsultimate-config " + node.id + ": Deleted TTS file " + path.join(node.TTSRootFolderPath, "ttsfiles", file));
|
|
541
540
|
try {
|
|
542
|
-
fs.unlinkSync(path.join(node.
|
|
541
|
+
fs.unlinkSync(path.join(node.TTSRootFolderPath, "ttsfiles", file));
|
|
543
542
|
} catch (error) {
|
|
544
543
|
}
|
|
545
544
|
});
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
</div>
|
|
40
40
|
<div class="form-row">
|
|
41
41
|
<label></label>
|
|
42
|
-
<input type="checkbox" id="node-input-ssml" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;"> Enable SSML</label>
|
|
42
|
+
<input type="checkbox" id="node-input-ssml" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;"> Enable SSML (unsupported by Google without authentication)</label>
|
|
43
43
|
</div>
|
|
44
44
|
<div class="form-row">
|
|
45
45
|
<label for="node-input-sonoshailing"><i class="fa fa-bell"></i> Hailing</label>
|
|
@@ -2,11 +2,10 @@ module.exports = function (RED) {
|
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
4
|
var fs = require('fs');
|
|
5
|
-
var MD5 = require('crypto-js').MD5;
|
|
6
5
|
var util = require('util');
|
|
7
6
|
var path = require('path');
|
|
8
7
|
const sonos = require('sonos');
|
|
9
|
-
|
|
8
|
+
const crypto = require("crypto");
|
|
10
9
|
|
|
11
10
|
function slug(_text) {
|
|
12
11
|
var sRet = _text;
|
|
@@ -64,7 +63,7 @@ module.exports = function (RED) {
|
|
|
64
63
|
node.msg = {}; // 08/05/2019 Node message
|
|
65
64
|
node.msg.completed = true;
|
|
66
65
|
node.msg.connectionerror = true;
|
|
67
|
-
node.userDir = path.join(RED.settings.userDir, "sonospollyttsstorage")
|
|
66
|
+
node.userDir = node.server.TTSRootFolderPath === undefined ? path.join(RED.settings.userDir, "sonospollyttsstorage") : node.server.TTSRootFolderPath;
|
|
68
67
|
node.oAdditionalSonosPlayers = []; // 20/03/2020 Contains other players to be grouped
|
|
69
68
|
node.rules = config.rules || [{}];
|
|
70
69
|
node.sNoderedURL = "";
|
|
@@ -78,7 +77,8 @@ module.exports = function (RED) {
|
|
|
78
77
|
node.speakingrate = config.speakingrate === undefined ? "1" : config.speakingrate; // 21/09/2021 AudioConfig speakingrate
|
|
79
78
|
node.unmuteIfMuted = config.unmuteIfMuted === undefined ? false : config.unmuteIfMuted; // 21/10/2021 Unmute if previiously muted.
|
|
80
79
|
node.sonosCoordinatorIsPreviouslyMuted = false;
|
|
81
|
-
|
|
80
|
+
node.passThroughMessage = {};
|
|
81
|
+
|
|
82
82
|
if (typeof node.server !== "undefined" && node.server !== null) {
|
|
83
83
|
node.sNoderedURL = node.server.sNoderedURL || "";
|
|
84
84
|
}
|
|
@@ -536,7 +536,7 @@ module.exports = function (RED) {
|
|
|
536
536
|
RED.log.error("ttsultimate: Error grouping speakers: " + error.message);
|
|
537
537
|
}
|
|
538
538
|
|
|
539
|
-
node.send([{ payload: node.msg.completed }, null]);
|
|
539
|
+
node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed }, null]);
|
|
540
540
|
|
|
541
541
|
// 24/08/2021 If something was playing, stop the player https://github.com/Supergiovane/node-red-contrib-tts-ultimate/issues/32
|
|
542
542
|
try {
|
|
@@ -591,11 +591,11 @@ module.exports = function (RED) {
|
|
|
591
591
|
voice: { name: node.voiceId.split("#")[0], languageCode: node.voiceId.split("#")[1], ssmlGender: node.voiceId.split("#")[2] },
|
|
592
592
|
audioConfig: { audioEncoding: "MP3", speakingRate: parseFloat(node.speakingrate), pitch: parseFloat(node.speakingpitch), },
|
|
593
593
|
};
|
|
594
|
-
params.input = node.ssml ===
|
|
594
|
+
params.input = node.ssml === false ? { text: msg } : { ssml: msg };
|
|
595
595
|
data = await synthesizeSpeechGoogleTTS([node.server.googleTTS, params]);
|
|
596
596
|
} else if (node.server.ttsservice === "googletranslate") {
|
|
597
597
|
node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Downloading from Google Translate...' });
|
|
598
|
-
// VoiceId is: code
|
|
598
|
+
// VoiceId is: code. SSML is not supported by google translate
|
|
599
599
|
const params = {
|
|
600
600
|
text: msg,
|
|
601
601
|
voice: node.voiceId,
|
|
@@ -777,7 +777,7 @@ module.exports = function (RED) {
|
|
|
777
777
|
setTimeout(() => {
|
|
778
778
|
node.msg.completed = true;
|
|
779
779
|
node.currentMSGbeingSpoken = {};
|
|
780
|
-
node.send([{ payload: node.msg.completed }, null]);
|
|
780
|
+
node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed }, null]);
|
|
781
781
|
node.bBusyPlayingQueue = false
|
|
782
782
|
node.server.whoIsUsingTheServer = ""; // Signal to other ttsultimate node, that i'm not using the Sonos device anymore
|
|
783
783
|
}, 1000)
|
|
@@ -790,7 +790,7 @@ module.exports = function (RED) {
|
|
|
790
790
|
setTimeout(() => {
|
|
791
791
|
node.msg.completed = true;
|
|
792
792
|
node.currentMSGbeingSpoken = {};
|
|
793
|
-
node.send([{ payload: node.msg.completed, filesArray: noPlayerFileArray }, null]);
|
|
793
|
+
node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed, filesArray: noPlayerFileArray }, null]);
|
|
794
794
|
node.bBusyPlayingQueue = false
|
|
795
795
|
node.server.whoIsUsingTheServer = ""; // Signal to other ttsultimate node, that i'm not using the Sonos device anymore
|
|
796
796
|
}, 1000)
|
|
@@ -811,6 +811,9 @@ module.exports = function (RED) {
|
|
|
811
811
|
// return;
|
|
812
812
|
// }
|
|
813
813
|
|
|
814
|
+
// 05/01/2022 Set the passtrough message o come cazzo si scrive
|
|
815
|
+
node.passThroughMessage = RED.util.cloneMessage(msg);
|
|
816
|
+
|
|
814
817
|
// 09/01/2021 Set the main player and groups IP on request
|
|
815
818
|
// *********************************
|
|
816
819
|
if (msg.hasOwnProperty("setConfig")) {
|
|
@@ -941,39 +944,46 @@ module.exports = function (RED) {
|
|
|
941
944
|
}
|
|
942
945
|
// ########################
|
|
943
946
|
|
|
944
|
-
|
|
945
|
-
//
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
}
|
|
947
|
+
// // 03/01/2022 if ssml is enabled, disable the auto split function
|
|
948
|
+
// if (!node.ssml) {
|
|
949
|
+
// // SSML disabled
|
|
950
|
+
// // 30/01/2021 split the text if it's too long, otherwies i'll have issues with filename too long.
|
|
951
|
+
// if (msg.payload.length >= node.server.limitTTSFilenameLenght) {
|
|
952
|
+
// let sTemp = "";
|
|
953
|
+
// let aSeps = [".", ",", ":", ";", "!", "?"];
|
|
954
|
+
// let sPayload = msg.payload.replace(/[\r\n]+/gm, "");
|
|
955
|
+
// for (let index = 0; index < sPayload.length; index++) {
|
|
956
|
+
// const element = sPayload.substr(index, 1);
|
|
957
|
+
// sTemp += element;
|
|
958
|
+
// if (aSeps.indexOf(element) > -1 && sTemp.length > 20) {
|
|
959
|
+
// const oMsg = RED.util.cloneMessage(msg);
|
|
960
|
+
// oMsg.payload = sTemp;
|
|
961
|
+
// node.tempMSGStorage.push(oMsg);
|
|
962
|
+
// sTemp = "";
|
|
963
|
+
// }
|
|
964
|
+
// if (sTemp.length > node.server.limitTTSFilenameLenght && element === " ") {
|
|
965
|
+
// // Split using space
|
|
966
|
+
// const oMsg = RED.util.cloneMessage(msg);
|
|
967
|
+
// oMsg.payload = sTemp;
|
|
968
|
+
// node.tempMSGStorage.push(oMsg);
|
|
969
|
+
// sTemp = "";
|
|
970
|
+
// }
|
|
971
|
+
// }
|
|
972
|
+
// // Remaining
|
|
973
|
+
// const oMsg = RED.util.cloneMessage(msg);
|
|
974
|
+
// oMsg.payload = sTemp;
|
|
975
|
+
// node.tempMSGStorage.push(oMsg);
|
|
976
|
+
|
|
977
|
+
// } else {
|
|
978
|
+
// node.tempMSGStorage.push(msg);
|
|
979
|
+
// }
|
|
980
|
+
// } else {
|
|
981
|
+
// // SSML enabled
|
|
982
|
+
// node.tempMSGStorage.push(msg);
|
|
983
|
+
// }
|
|
975
984
|
|
|
976
985
|
// Starts main queue watching
|
|
986
|
+
node.tempMSGStorage.push(msg);
|
|
977
987
|
node.waitForQueue();
|
|
978
988
|
|
|
979
989
|
});
|
|
@@ -1001,7 +1011,7 @@ module.exports = function (RED) {
|
|
|
1001
1011
|
clearTimeout(node.oTimerSonosConnectionCheck);
|
|
1002
1012
|
if (node.timerbTimeOutPlay !== null) clearTimeout(node.timerbTimeOutPlay);
|
|
1003
1013
|
node.msg.completed = true;
|
|
1004
|
-
node.send([{ payload: node.msg.completed }, null]);
|
|
1014
|
+
node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed }, null]);
|
|
1005
1015
|
node.setNodeStatus({ fill: "green", shape: "ring", text: "Shutdown" });
|
|
1006
1016
|
node.flushQueue();
|
|
1007
1017
|
done();
|
|
@@ -1069,28 +1079,12 @@ module.exports = function (RED) {
|
|
|
1069
1079
|
});
|
|
1070
1080
|
};
|
|
1071
1081
|
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
// Filename format: "text_voice.mp3"
|
|
1080
|
-
var filename = util.format('%s_%s%s%s%s.%s', basename, _sVoice, _speakingpitch, _speakingrate, ssml_text, extension);
|
|
1081
|
-
|
|
1082
|
-
// If filename is too long, cut it and add hash
|
|
1083
|
-
if (filename.length > 250) {
|
|
1084
|
-
var hash = MD5(basename);
|
|
1085
|
-
|
|
1086
|
-
// Filename format: "text_hash_voice.mp3"
|
|
1087
|
-
var ending = util.format('_%s_%s%s%s%s.%s', hash, _sVoice, _speakingpitch, _speakingrate, ssml_text, extension);
|
|
1088
|
-
var beginning = basename.slice(0, 250 - ending.length);
|
|
1089
|
-
|
|
1090
|
-
filename = beginning + ending;
|
|
1091
|
-
}
|
|
1092
|
-
|
|
1093
|
-
return filename;
|
|
1082
|
+
// 04/01/2021 hashing filename to avoid issues with long filenames.
|
|
1083
|
+
function getFilename(_text, _sVoice, _isSSML, _extension, _speakingpitch, _speakingrate) {
|
|
1084
|
+
let sTextToBeHashed = _text.concat(_sVoice, _isSSML, _speakingpitch, _speakingrate);
|
|
1085
|
+
const hashSum = crypto.createHash('md5');
|
|
1086
|
+
hashSum.update(sTextToBeHashed);
|
|
1087
|
+
return hashSum.digest('hex') + "." + _extension;
|
|
1094
1088
|
}
|
|
1095
1089
|
|
|
1096
1090
|
function notifyError(msg, err) {
|
|
@@ -1103,7 +1097,6 @@ module.exports = function (RED) {
|
|
|
1103
1097
|
});
|
|
1104
1098
|
// Set error in message
|
|
1105
1099
|
msg.error = errorMessage;
|
|
1106
|
-
|
|
1107
1100
|
}
|
|
1108
1101
|
|
|
1109
1102
|
|