node-red-contrib-tts-ultimate 1.0.40 → 1.0.43

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.
@@ -11,7 +11,7 @@
11
11
  "skipFiles": [
12
12
  "<node_internals>/**"
13
13
  ],
14
- "program": "${workspaceFolder}/ttsultimate/ttsultimate.js"
14
+ "program": "${file}"
15
15
  }
16
16
  ]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -2,97 +2,113 @@
2
2
 
3
3
  [![Donate via PayPal](https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square)](https://www.paypal.me/techtoday)
4
4
 
5
+ <p>
6
+ <b>Version 1.0.43</b> March 2022<br/>
7
+ - Simplified the configuration by auto discover some IP.<br/>
8
+ - FIX: fixed minor glitches.<br/>
9
+ </p>
10
+ <p>
11
+ <b>Version 1.0.42</b> March 2022<br/>
12
+ - FIX: fix purging option that wasn't working if you set to always purge the cached files at startup.<br/>
13
+ - FIX: invalid code in some sync functions.<br/>
14
+ </p>
15
+ <p>
16
+ <b>Version 1.0.41</b> March 2022<br/>
17
+ - NEW: for Polly TTS, you can choose between neural and standard engine.<br/>
18
+ </p>
5
19
  <p>
6
20
  <b>Version 1.0.40</b> January 2022<br/>
7
21
  - NEW: you can now select your own folder to save the TTS cached files.<br/>
8
22
  - 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
23
  - NEW: now the input messages are passed through to the output pin.<br/>
10
24
  - 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>
25
+ </p>
12
26
  <p>
13
27
  <b>Version 1.0.39</b> January 2022<br/>
14
28
  - SSML: fixed an issue prevent using it.<br/>
15
29
  - SSML: if SSML is enabled, the text auto split function is disabled, to avoid splitting SSML XML text.<br/>
16
30
  - Microsoft Azure: update TTS engine to 1.19.0<br/>
17
31
  - Google paid TTS: update TTS engine to 3.4.0<br/>
32
+ </p>
18
33
  <p>
19
34
  <b>Version 1.0.38</b> December 2021<br/>
20
35
  - Removed some unwanted startup logs.<br/>
21
36
  - Fixed ownfile sample code. Thanks to plats98.<br/>
22
- <p>
37
+ </p>
23
38
  <p>
24
39
  <b>Version 1.0.36</b> November 2021<br/>
25
40
  - 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/>
26
- <p>
41
+ </p>
27
42
  <p>
28
43
  <b>Version 1.0.35</b> October 2021<br/>
29
44
  - NEW: You can force unmuting all players, then restore their previous state once finished playing.<br/>
30
- <p>
45
+ </p>
31
46
  <p>
32
47
  <b>Version 1.0.34</b> October 2021<br/>
33
48
  - FIX: fixed an issue in retrieving voices if you have more than one TTS engine enabled at the same time.<br/>
34
- <p>
49
+ </p>
35
50
  <p>
36
51
  <b>Version 1.0.33</b> October 2021<br/>
37
52
  - NEW VOICE ENGINE: Microsoft Azure TTS.<br/>
38
- <p>
53
+ </p>
39
54
  <p>
40
55
  <b>Version 1.0.32</b> September 2021<br/>
41
56
  - Fix few restore issues. Line-in restore fix and only when it was playing. Amazon Music and Spotify considered as stream instead of music queue.<br/>
42
- <p>
57
+ </p>
43
58
  <p>
44
59
  <b>Version 1.0.31</b> September 2021<br/>
45
60
  - NEW: you can now choose voice PITCH and RATE. Avaiable only with Google TTS engine with credentials.<br/>
46
- <p>
61
+ </p>
47
62
  <p>
48
63
  <b>Version 1.0.29</b> September 2021<br/>
49
64
  - NEW: you can now choose not to use Sonos as player. In this case, the node will output an array of mp3, ready to be played by third parties nodes.<br/>
50
- <p>
65
+ </p>
51
66
  <p>
52
67
  <b>Version 1.0.28</b> September 2021<br/>
53
68
  - Fixed queue resuming play even if was in stop (only occurs in some circumstances).<br/>
54
- <p>
69
+ </p>
55
70
  <p>
56
71
  <b>Version 1.0.27</b> September 2021<br/>
57
72
  - Hided some unwanted logs.<br/>
58
- <p>
73
+ </p>
59
74
  <p>
60
75
  <b>Version 1.0.26</b> August 2021<br/>
61
76
  - FIX: after playing tts, if you have no previous queue and you are on old Sonos V1, the last TTS played remains in the queue (it shouldn't).<br/>
62
- <p>
77
+ </p>
63
78
  <p>
64
79
  <b>Version 1.0.25</b> August 2021<br/>
65
80
  - Optimized setting volume speed.<br/>
66
- <p>
81
+ </p>
67
82
  <p>
68
83
  <b>Version 1.0.24</b> August 2021<br/>
69
84
  - Fixed a little issue with sonos beam, switching volumes with a 1-2 seconds delay.<br/>
70
- <p>
85
+ </p>
71
86
  <p>
72
87
  <b>Version 1.0.23</b> August 2021<br/>
73
88
  - Fixed a volume issue. The playing queue was jumping briefly at TTS volume before stopping. That was annoiyng.<br/>
74
89
  - Fixed issues with some async function not really async, so there was glitches in volume settings, seeking and so on, specially with playlist and queues.<br/>
75
90
  - There are known issues with resuming play of sonos streams, they work for a while, then stop.<br/>
76
- <p>
91
+ </p>
77
92
  <p>
78
93
  <b>Version 1.0.22</b> Juli 2021<br/>
79
94
  - The additional players don't obey to msg.volume input node message override (they instead get the volume set by the config window, that is OK, but they must also obey to the override msg). Fixed<br/>
80
- <p>
95
+ </p>
81
96
  <p>
82
97
  <b>Version 1.0.21</b> Juli 2021<br/>
83
98
  - The additional players in the group, now reverts to the previous volume after the speech.<br/>
84
- <p>
99
+ </p>
85
100
  <p>
86
101
  <b>Version 1.0.20</b> May 2021<br/>
87
102
  - Fixed an issue preventing TTS working on Windows machines. Thanks @McFozzy75<br/>
88
- <p>
103
+ </p>
89
104
  <p>
90
105
  <b>Version 1.0.19</b> February 2021<br/>
91
106
  - The previous limit of 200 chars (before the TTS text is automatically split) has been increased to 220.<br/>
92
- <p>
107
+ </p>
93
108
  <p>
94
109
  <b>Version 1.0.18</b> January 2021<br/>
95
110
  - Better handling of payloads long more than 200 chars.<br/>
111
+ </p>
96
112
  <p>
97
113
  <b>Version 1.0.16</b> January 2021<br/>
98
114
  - Currently, the FREE GOOGLE TRANSLATE TTS engine has changed some voice codes. I've been fixed that. You need to do nothing.<br/>
package/README.md CHANGED
@@ -23,7 +23,7 @@
23
23
 
24
24
  ## DESCRIPTION
25
25
  This node transforms a text into a speech audio. You can generate an audio file, or hear the voice through Sonos, bluetooth speakers, web pages, etc.<br/>
26
- Uses Amazon Polly, Google TTS voices (even without credentials nor registration) and Microsoft TTS Azure voices, and you can use it with **your own audio file** as well and it can be used **totally offline** even without the use of TTS, without internet connection.<br/>
26
+ Uses Amazon Polly (standard and neural engines), Google TTS voices (even without credentials nor registration) and Microsoft TTS Azure voices, and you can use it with **your own audio file** as well and it can be used **totally offline** even without the use of TTS, without internet connection.<br/>
27
27
  The node can also create a ***TTS file (without the use of any Sonos device)***, to be read by third parties nodes.<br/>
28
28
  This is a major ***upgrade from the previously popular node SonosPollyTTS*** (SonosPollyTTS is not developed anymore).<br/>
29
29
  **Node v.12.0.0 or newer is needed**.
@@ -112,7 +112,7 @@ For Google TTS Engine, you can choose pitch and speed rate of the voice.
112
112
 
113
113
 
114
114
  **Node-Red IP**<br/>
115
- set IP of your node-red machine. Sonos will connect to this address in order to play TTS. You can also write any value you want, for example 127.0.0.1 in this field (**don't leave this field blank in any case**), if you don't want to use Sonos as player. Please see below, the section **TTS-ULTIMATE NODE**, property **Player**.
115
+ set IP of your node-red machine. Write **AUTODISCOVER** to allow the node to auto discover your IP.
116
116
 
117
117
  **Host Port**<br/>
118
118
  Sonos will connect to this port in order to play TTS. Default 1980. Choose a free port. Do not use 1880 or any other port already in use on your computer.
@@ -140,7 +140,7 @@ Leave this field blank for the default.<br/>
140
140
  Select the TTS SERVICE ENGINE NODE, as stated above.
141
141
 
142
142
  **Voice**<br/>
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
+ Select your preferred voice. If you use Amazon, Polly voices will be displayed (standard and neural). If you use Google, google voices will be displayed. Google service without authentication, has a limited set of voices.
144
144
 
145
145
  **Enable SSML**<br/>
146
146
  Enable the SSML XML notation. Please be aware, not all the TTS engines supports that.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-red-contrib-tts-ultimate",
3
- "version": "1.0.40",
3
+ "version": "1.0.43",
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": {
@@ -22,7 +22,8 @@
22
22
  "IOT",
23
23
  "speech",
24
24
  "ttsultimate",
25
- "sonospollytts"
25
+ "sonospollytts",
26
+ "neural"
26
27
  ],
27
28
  "node-red": {
28
29
  "nodes": {
@@ -81,7 +81,7 @@
81
81
  return;
82
82
  }
83
83
  // The only way is to wait some time, then refresh
84
- setTimeout(function () {
84
+ let t = setTimeout(function () {
85
85
  node.refreshListaFiles().then((success, error) => {
86
86
  $("#ownFileUpload").val("");// Otherwise will not re-upload a file with the same name
87
87
  $("#node-input-selectedFile").val("OwnFile_" + file.name);
@@ -1,4 +1,5 @@
1
1
  <script type="text/javascript">
2
+
2
3
  RED.nodes.registerType("ttsultimate-config", {
3
4
  category: 'config',
4
5
  defaults:
@@ -6,7 +7,7 @@
6
7
  name: { value: "TTS Service" },
7
8
  noderedipaddress:
8
9
  {
9
- value: "",
10
+ value: "AUTODISCOVER",
10
11
  required: false,
11
12
  type: "text"
12
13
  },
@@ -32,17 +33,18 @@
32
33
  },
33
34
  oneditprepare: function () {
34
35
  var node = this;
35
-
36
+
36
37
  // 21/03/2020 Check if the node is the absolute first in the flow. In this case, it has no http server instatiaced
37
- $.getJSON('ttsultimateGetEthAddress', (data) => {
38
- $("#pleaseDeploy").hide();
38
+ // $.getJSON('ttsultimateGetEthAddress', (data) => {
39
+ $("#pleaseDeploy").hide();
39
40
  $("#allGUI").show();
40
- }).fail(function (jqxhr) {
41
- $("#pleaseDeploy").show();
42
- $("#allGUI").hide();
43
- });
41
+ // }).fail(function (jqxhr) {
42
+ // $("#pleaseDeploy").show();
43
+ // $("#allGUI").hide();
44
+ // });
44
45
 
45
- if (typeof node.noderedipaddress === "undefined") {
46
+
47
+ if (node.noderedipaddress === undefined) {
46
48
  // Put the default address of the machine
47
49
  $.getJSON('ttsultimateGetEthAddress', (data) => {
48
50
  $("#node-config-input-noderedipaddress").val(data);
@@ -157,7 +159,6 @@
157
159
  <label for="node-config-input-noderedipaddress"><i class="fa fa-globe"></i> Node-Red IP</label>
158
160
  <input type="text" id="node-config-input-noderedipaddress">
159
161
  </div>
160
- <div class="form-tips" style="margin-top: 8px;background-color:lightgrey;text-align:center">Above option: don't leave this field blank in any case. If you don't use Sonos players, set it to 127.0.0.1. See the README on gitHub.</div>
161
162
  <br/>
162
163
 
163
164
  <div class="form-row">
@@ -19,7 +19,11 @@ module.exports = function (RED) {
19
19
  function TTSConfigNode(config) {
20
20
  RED.nodes.createNode(this, config);
21
21
  var node = this;
22
- node.noderedipaddress = typeof config.noderedipaddress === "undefined" ? "" : config.noderedipaddress;
22
+ node.noderedipaddress = config.noderedipaddress;
23
+ if (node.noderedipaddress === undefined || node.noderedipaddress === "AUTODISCOVER") {
24
+ node.noderedipaddress = GetEthAddress();
25
+ RED.log.info('ttsultimate-config ' + node.id + ': Autodiscover current IP ' + node.noderedipaddress);
26
+ }
23
27
  node.whoIsUsingTheServer = ""; // Client node.id using the server, because only a ttsultimate node can use the serve at once.
24
28
  node.ttsservice = config.ttsservice || "googletranslate";
25
29
  node.TTSRootFolderPath = (config.TTSRootFolderPath === undefined || config.TTSRootFolderPath === "") ? path.join(RED.settings.userDir, "sonospollyttsstorage") : path.join(config.TTSRootFolderPath, "sonospollyttsstorage");
@@ -212,6 +216,9 @@ module.exports = function (RED) {
212
216
  // ######################################################
213
217
  // 21/03/2019 Endpoint for retrieving the default IP
214
218
  RED.httpAdmin.get("/ttsultimateGetEthAddress", RED.auth.needsPermission('TTSConfigNode.read'), function (req, res) {
219
+ res.json(GetEthAddress());
220
+ });
221
+ function GetEthAddress() {
215
222
  var oiFaces = oOS.networkInterfaces();
216
223
  var jListInterfaces = [];
217
224
  try {
@@ -229,13 +236,12 @@ module.exports = function (RED) {
229
236
  })
230
237
  } catch (error) { }
231
238
  if (jListInterfaces.length > 0) {
232
- res.json(jListInterfaces[0].address); // Retunr the first usable IP
239
+ return(jListInterfaces[0].address); // Retunr the first usable IP
233
240
  } else {
234
- res.json("NO ETH INTERFACE FOUND");
241
+ return("NO ETH INTERFACE FOUND");
235
242
  }
236
-
237
- });
238
-
243
+ }
244
+
239
245
  // 20/03/2020 in the middle of coronavirus, get the sonos groups
240
246
  RED.httpAdmin.get("/sonosgetAllGroups", RED.auth.needsPermission('TTSConfigNode.read'), function (req, res) {
241
247
  var jListGroups = [];
@@ -369,7 +375,13 @@ module.exports = function (RED) {
369
375
  } else {
370
376
  for (let index = 0; index < data.Voices.length; index++) {
371
377
  const oVoice = data.Voices[index];
372
- jListVoices.push({ name: oVoice.LanguageName + " (" + oVoice.LanguageCode + ") " + oVoice.Name + " - " + oVoice.Gender, id: oVoice.Id })
378
+ if (oVoice.hasOwnProperty("SupportedEngines")) {
379
+ oVoice.SupportedEngines.forEach(voicetype => {
380
+ jListVoices.push({ name: oVoice.LanguageName + " (" + oVoice.LanguageCode + ") " + oVoice.Name + " - " + oVoice.Gender + " - " + voicetype, id: oVoice.Id + "#engineType:" + voicetype })
381
+ });
382
+ } else {
383
+ jListVoices.push({ name: oVoice.LanguageName + " (" + oVoice.LanguageCode + ") " + oVoice.Name + " - " + oVoice.Gender, id: oVoice.Id })
384
+ }
373
385
  }
374
386
  res.json(jListVoices)
375
387
  }
@@ -532,22 +544,20 @@ module.exports = function (RED) {
532
544
  if (node.purgediratrestart === "purge") {
533
545
  // Delete all files, that are'nt OwnFiles_
534
546
  try {
535
- fs.readdirSync(path.join(node.TTSRootFolderPath, "ttsfiles"), (err, files) => {
536
- try {
537
- if (files.length > 0) {
538
- files.forEach(function (file) {
539
- RED.log.info("ttsultimate-config " + node.id + ": Deleted TTS file " + path.join(node.TTSRootFolderPath, "ttsfiles", file));
540
- try {
541
- fs.unlinkSync(path.join(node.TTSRootFolderPath, "ttsfiles", file));
542
- } catch (error) {
543
- }
544
- });
545
- };
546
- } catch (error) {
547
+ let files = fs.readdirSync(path.join(node.TTSRootFolderPath, "ttsfiles"));
548
+ try {
549
+ if (files.length > 0) {
550
+ files.forEach(function (file) {
551
+ RED.log.info("ttsultimate-config " + node.id + ": Deleted TTS file " + path.join(node.TTSRootFolderPath, "ttsfiles", file));
552
+ try {
553
+ fs.unlinkSync(path.join(node.TTSRootFolderPath, "ttsfiles", file));
554
+ } catch (error) {
555
+ }
556
+ });
557
+ };
558
+ } catch (error) { }
547
559
 
548
- }
549
560
 
550
- });
551
561
  } catch (error) { }
552
562
  };
553
563
 
@@ -566,13 +576,13 @@ module.exports = function (RED) {
566
576
  var query = url_parts.query;
567
577
 
568
578
  res.setHeader('Content-Disposition', 'attachment; filename=tts.mp3')
569
- if (fs.existsSync(query.f)) {
579
+ if (fs.existsSync(query.f.toString())) {
570
580
  // 26/01/2021 security check
571
581
  // File should be something like mydocs/.node-red/sonospollyttsstorage/ttsfiles/Hello_de-DE.mp3
572
- if (path.extname(query.f) === ".mp3" && path.dirname(path.dirname(query.f)).endsWith("sonospollyttsstorage")) {
573
- var readStream = fs.createReadStream(query.f);
582
+ if (path.extname(query.f.toString()) === ".mp3" && path.dirname(path.dirname(query.f.toString())).endsWith("sonospollyttsstorage")) {
583
+ var readStream = fs.createReadStream(query.f.toString());
574
584
  readStream.on("error", function (error) {
575
- RED.log.error("ttsultimate-config " + node.id + ": Playsonos error opening stream : " + query.f + ' : ' + error);
585
+ RED.log.error("ttsultimate-config " + node.id + ": Playsonos error opening stream : " + query.f.toString() + ' : ' + error);
576
586
  res.end();
577
587
  return;
578
588
  });
@@ -631,7 +641,7 @@ module.exports = function (RED) {
631
641
  } catch (error) {
632
642
 
633
643
  }
634
- setTimeout(function () {
644
+ let t = setTimeout(function () {
635
645
  // Wait some time to allow time to do promises.
636
646
  done();
637
647
  }, 500);
@@ -202,7 +202,7 @@
202
202
  // 24/12/2020 Check if the node is the absolute first in the flow. In this case, it has no http server instatiaced
203
203
  // !oNodeServer.hasOwnProperty("noderedipaddress") is when the config node exists, but not deployed
204
204
  // oNodeServer.noderedipaddress === "" is when the config node has been deployed, but not configured
205
- if (oNodeServer === null || !oNodeServer.hasOwnProperty("noderedipaddress")) {
205
+ if (oNodeServer === null || oNodeServer === undefined || !oNodeServer.hasOwnProperty("noderedipaddress")) {
206
206
  $("#pleaseDeploy").show();
207
207
  $("#allGUI").hide();
208
208
  } else if (oNodeServer.hasOwnProperty("noderedipaddress") && oNodeServer.noderedipaddress === "") {
@@ -216,7 +216,7 @@
216
216
  };
217
217
 
218
218
 
219
- // 26/10/2020 Retrieve all avaiables polly voices
219
+ // 26/10/2020 Retrieve all avaiables voices
220
220
  // #####################################
221
221
  function getVoices() {
222
222
  $('#node-input-voice')
@@ -336,7 +336,7 @@
336
336
  }
337
337
  // Refresh the combo
338
338
  // The only way is to wait some time, then refresh
339
- setTimeout(function () {
339
+ let t = setTimeout(function () {
340
340
  node.refreshHailingList().then((success, error) => {
341
341
  $("#ownFileUpload").val("");// Otherwise will not re-upload a file with the same name
342
342
  $("#node-input-sonoshailing").val("Hailing_" + file.name);
@@ -52,7 +52,7 @@ module.exports = function (RED) {
52
52
  return;
53
53
  }
54
54
  node.ssml = config.ssml;
55
- node.oTimerSonosConnectionCheck;
55
+ node.oTimerSonosConnectionCheck = null;
56
56
  node.sSonosIPAddress = "";
57
57
  node.sonosCoordinatorGroupName = "";
58
58
  node.sonoshailing = "0"; // Hailing file
@@ -78,6 +78,7 @@ module.exports = function (RED) {
78
78
  node.unmuteIfMuted = config.unmuteIfMuted === undefined ? false : config.unmuteIfMuted; // 21/10/2021 Unmute if previiously muted.
79
79
  node.sonosCoordinatorIsPreviouslyMuted = false;
80
80
  node.passThroughMessage = {};
81
+ node.bTimeOutPlay = false;
81
82
 
82
83
  if (typeof node.server !== "undefined" && node.server !== null) {
83
84
  node.sNoderedURL = node.server.sNoderedURL || "";
@@ -120,7 +121,7 @@ module.exports = function (RED) {
120
121
  return new Promise((resolve, reject) => {
121
122
  node.SonosClient.play(_toPlay).then(result => {
122
123
  if (iWaitAfterSync > 2000) console.log("PLAYSYNC")
123
- setTimeout(() => {
124
+ let t = setTimeout(() => {
124
125
  resolve(true);
125
126
  }, iWaitAfterSync);
126
127
  }).catch(err => {
@@ -135,7 +136,7 @@ module.exports = function (RED) {
135
136
  return new Promise((resolve, reject) => {
136
137
  node.SonosClient.seek(_Position).then(result => {
137
138
  if (iWaitAfterSync > 2000) console.log("SEEKSync", _Position)
138
- setTimeout(() => {
139
+ let t = setTimeout(() => {
139
140
  resolve(true);
140
141
  }, iWaitAfterSync);
141
142
  }).catch(err => {
@@ -154,7 +155,7 @@ module.exports = function (RED) {
154
155
  STOPSync(); // The SetQueue automatically starts playing, so i need to stop it now!
155
156
  } catch (error) {
156
157
  }
157
- setTimeout(() => {
158
+ let t = setTimeout(() => {
158
159
  resolve(true);
159
160
  }, iWaitAfterSync);
160
161
  }).catch(err => {
@@ -169,7 +170,7 @@ module.exports = function (RED) {
169
170
  return new Promise((resolve, reject) => {
170
171
  node.SonosClient.selectTrack(_queuePositiom).then(result => {
171
172
  if (iWaitAfterSync > 2000) console.log("SELECTTRACKSync", _queuePositiom)
172
- setTimeout(() => {
173
+ let t = setTimeout(() => {
173
174
  resolve(true);
174
175
  }, iWaitAfterSync);
175
176
  }).catch(err => {
@@ -184,7 +185,7 @@ module.exports = function (RED) {
184
185
  return new Promise((resolve, reject) => {
185
186
  node.SonosClient.stop().then(result => {
186
187
  if (iWaitAfterSync > 2000) console.log("STOPSync")
187
- setTimeout(() => {
188
+ let t = setTimeout(() => {
188
189
  resolve(true);
189
190
  }, iWaitAfterSync);
190
191
  }).catch(err => {
@@ -509,7 +510,7 @@ module.exports = function (RED) {
509
510
  }
510
511
  }
511
512
  }
512
- setTimeout(() => { return true; }, 5000); // Wait some seconds
513
+ let t = setTimeout(() => { return true; }, 5000); // Wait some seconds
513
514
  };
514
515
 
515
516
  // Handle the queue
@@ -578,9 +579,16 @@ module.exports = function (RED) {
578
579
  OutputFormat: "mp3",
579
580
  SampleRate: '22050',
580
581
  Text: msg,
581
- TextType: node.ssml ? 'ssml' : 'text',
582
- VoiceId: node.voiceId
582
+ TextType: node.ssml ? 'ssml' : 'text'
583
583
  };
584
+ // 02/03/2022 check wether standard or neural engine is POLLY is selected
585
+ if (node.voiceId.includes("#engineType:")) {
586
+ params.VoiceId = node.voiceId.split("#engineType:")[0];
587
+ params.Engine = node.voiceId.split("#engineType:")[1];
588
+ } else {
589
+ params.VoiceId = node.voiceId;
590
+ }
591
+
584
592
  data = await synthesizeSpeechPolly([node.server.polly, params]);
585
593
  } else if (node.server.ttsservice === "googletts") {
586
594
  node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Downloading from Google TTS...' });
@@ -612,13 +620,14 @@ module.exports = function (RED) {
612
620
  data = await synthesizeSpeechMicrosoftAzureTTS(node.server.microsoftAzureTTS, params);
613
621
  }
614
622
  // Save the downloaded file into the cache
615
- fs.writeFileSync(sFileToBePlayed, data, function (error, result) {
616
- if (error) {
617
- RED.log.error("ttsultimate: node id: " + node.id + " Unable to save the file " + error.message);
618
- node.setNodeStatus({ fill: "red", shape: "ring", text: "Unable to save the file " + sFileToBePlayed + " " + error.message });
619
- throw (error);
620
- }
621
- });
623
+ try {
624
+ fs.writeFileSync(sFileToBePlayed, data);
625
+ } catch (error) {
626
+ RED.log.error("ttsultimate: node id: " + node.id + " Unable to save the file " + error.message);
627
+ node.setNodeStatus({ fill: "red", shape: "ring", text: "Unable to save the file " + sFileToBePlayed + " " + error.message });
628
+ throw (error);
629
+ }
630
+
622
631
  } catch (error) {
623
632
  RED.log.error("ttsultimate: node id: " + node.id + " Error Downloading TTS: " + error.message + ". THE TTS SERVICE MAY BE DOWN.");
624
633
  node.setNodeStatus({ fill: 'red', shape: 'ring', text: 'Error Downloading TTS:' + error.message });
@@ -774,7 +783,7 @@ module.exports = function (RED) {
774
783
  }
775
784
 
776
785
  // Signal end playing
777
- setTimeout(() => {
786
+ let t = setTimeout(() => {
778
787
  node.msg.completed = true;
779
788
  node.currentMSGbeingSpoken = {};
780
789
  node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed }, null]);
@@ -787,7 +796,7 @@ module.exports = function (RED) {
787
796
  // Output the array of files
788
797
 
789
798
  // Signal end playing
790
- setTimeout(() => {
799
+ let t = setTimeout(() => {
791
800
  node.msg.completed = true;
792
801
  node.currentMSGbeingSpoken = {};
793
802
  node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed, filesArray: noPlayerFileArray }, null]);