node-red-contrib-tts-ultimate 1.0.56 → 2.0.1

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/CHANGELOG.md CHANGED
@@ -2,6 +2,15 @@
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 2.0.1</b> August 2023<br/>
7
+ - NEW: added Elevenlabs TTS engine https://elevenlabs.io.<br/>
8
+ </p>
9
+ <p>
10
+ <b>Version 2.0.0</b> June 2023<br/>
11
+ - Bumped paid Google TTS, free google TTS and Ms TTS dependencies.<br/>
12
+ - Moved help to the node-red's help pane.<br/>
13
+ </p>
5
14
  <p>
6
15
  <b>Version 1.0.56</b> March 2023<br/>
7
16
  - NEW: Added Node Name property, in the TTS Ultimate node.<br/>
package/README.md CHANGED
@@ -26,7 +26,7 @@
26
26
  ## DESCRIPTION
27
27
  This node transforms a text into a speech audio that you can hear natively via <b>SONOS</b> speakers.<br/>
28
28
  You can also generate an audio file for bluetooth speakers, web pages, etc.<br/>
29
- 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/>
29
+ Uses Amazon Polly (standard and neural engines), Google TTS voices (even without credentials nor registration) and Microsoft TTS Azure voices, ElevenLabs.io TTS 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/>
30
30
  The node can also create a ***TTS file (without the use of any Sonos device)***, to be read by third parties nodes.<br/>
31
31
  This is a major ***upgrade from the previously popular node SonosPollyTTS*** (SonosPollyTTS is not developed anymore).<br/>
32
32
 
@@ -39,7 +39,7 @@ This is a major ***upgrade from the previously popular node SonosPollyTTS*** (So
39
39
  ## FEATURES
40
40
  * **Native Sonos support**: hear the TTS audio directly via Sonos. You can also group speakers, set an hailing sound, choose the volume of each speaker etc.
41
41
  * **Output audio file**: the node can just create the TTS file to be used by other nodes. In this case, you doesn't need to use Sonos as player.
42
- * **Amazon Voices, Gooogle Translate Voices, Google TTS Voices and Microsoft TTS Azure voices** are all supported, with all avaiables languages and genders.
42
+ * **Amazon Voices, Gooogle Translate Voices, Google TTS Voices, Microsoft TTS Azure voices and Elevenlabs.io voices** are all supported, with all avaiables languages and genders.
43
43
  * **Automatic grouping** is supported. You can group all players you want to play your announcements.
44
44
  * **Automatic discovery** of your players.
45
45
  * **Automatic resume of music** queue (including radio stations, but here, some users reports problem resuming ***radio stations*** and, because of lack of Sonos API documentation, the issue cannot currently be fixed), at exact track, at exact time.
@@ -140,69 +140,8 @@ Leave this field blank for the default.<br/>
140
140
 
141
141
  # TTS-ULTIMATE NODE
142
142
 
143
- **TTS Service**<br/>
144
- Select the TTS SERVICE ENGINE NODE, as stated above.
145
-
146
- **Voice**<br/>
147
- 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.
148
-
149
- **Enable SSML**<br/>
150
- Enable the SSML XML notation. Please be aware, not all the TTS engines supports that.
151
-
152
- **Rate**<br/>
153
- Only avaiable if you choose Google TTS Engine (with credentials). Specifies the speech speed (Between 0.25 and 4.0, default 1).
154
-
155
- **Pitch**<br/>
156
- Only avaiable if you choose Google TTS Engine (with credentials). Specifies the speech pitch (Between -20.0 and 20.0, default 0).
157
-
158
- **Hailing**<br/>
159
- Before the first TTS message of the message queues, Sonos will play an "hailing" sound. You can select the hailing or totally disable it.
160
-
161
- **Player**<br/>
162
- Select the player. If you select not to use a player, the node will output a msg with an array of files, ready to be played by third party nodes.<br/>
163
- In case you select ***No player, only output file name***, 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. Please see below the **OUTPUT MESSAGES FROM THE NODE** section.
164
-
165
- **Volume** <br/>
166
- Set the preferred TTS volume, from "0" to "100" (can be overridden by passing <code>msg.volume = "40";</code> to the node)
167
-
168
- **Unmute** <br/>
169
- Unmute the main and the addotional players, then restore the previous mute state once finished. (Can be overridden by passing <code>msg.unmute = true;</code> to the node)
170
-
171
- **Main Sonos Player** <br/>
172
- Select your Sonos primary player. (It's strongly suggested to set a fixed IP for this player; you can reserve an IP using the DHCP Reservation function of your router/firewall's DHCP Server).<br/>
173
- It's possibile to group players, so your announcement can be played on all selected players. For this to happen, you need to select your primary coordinator player. All other players will be then controlled by this coordinator.
174
-
175
- **Additional Players** <br/>
176
- Here you can add all additional players that will be grouped toghether to the *Main Sonos Player* coordinator group. You can add a player using the "ADD" button, below the list.<br/>
177
- For each additional player, you can adjust their volume, based on the **Main Sonos Player** volume -+100.
178
-
179
-
180
143
  ## INPUT MESSAGES TO THE NODE <br/>
181
144
 
182
- **msg.volume**<br/>
183
- Set the volume (values between "0" and "100" with quotes)</br>
184
-
185
- **msg.unmute**<br/>
186
- *true*: Unmute all players then mutes it again once finished playing.</br>
187
- *false*: Leave the player as they are.</br>
188
-
189
- **msg.nohailing**<br/>
190
- Temporarely doesn't play the Hailing sound prior to the message (values "true" or "1" with quotes)</br>
191
-
192
- **msg.payload** <br/>
193
- The text to be spoken (for example msg.payload = "Hello World!";). You can also play an mp3 stored on an http server, by passing the URL to the payload ( <code>msg.payload = "http://www.myserver.com/alarm.mp3"</code>)</br>
194
-
195
- **msg.sonoshailing**<br/>
196
- Overrides the selected hailing and plays the filename you passed in. Please double check the spelling of the filename (must be the same as you can see in the dropdown list of your hailing files, in the ttsultimate config window) and do not include the <b>.mp3</b> extenson. For example *node.sonoshailing="ComputerCall"*<br/>
197
-
198
- **msg.priority**<br/>
199
- If set to <b>true</b>, the inbound flow message will cancel the current TTS queue, will stop the current phrase being spoken and the node will play this priority message.<br/>
200
- If there are other priority messages in the queue, they will be retained and the inbound priority flow message is added to the queue.<br/>
201
- If the inbound priority flow message is the first in the priority queue, the hailing is played first (if the hailing has been enabled or if the hailing has been overridden by *node.sonoshailing*)<br/>
202
-
203
- **msg.stop**<br/>
204
- If set to <b>true</b>, stops whatever is playing and clears the TTS queue.<br/>
205
-
206
145
  *Examples*
207
146
 
208
147
  ```js
@@ -245,44 +184,6 @@ msg.stop = true;
245
184
  return msg;
246
185
  ```
247
186
 
248
- ## OUTPUT MESSAGES FROM THE NODE
249
-
250
- The node has two output pins. The first pin is to signal play status, the second one, is to signal an error.
251
-
252
- **OUTPUT PIN 1**<br/>
253
- Payload is ***true*** when the node has finished playing, ***false*** if the node is playing<br/>
254
- 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/>
255
- The property ***passThroughMessage*** contains the input msg passed through the output.<br/>
256
-
257
- ```js
258
- {
259
- "payload":true,
260
- "passThroughMessage" : {original message object}
261
- "filesArray":[
262
- {
263
- "file":"/Users/supergiovane/.node-red/sonospollyttsstorage/hailingpermanentfiles/hail.mp3"
264
- },
265
- {
266
- "file":"/Users/supergiovane/.node-red/sonospollyttsstorage/ttsfiles/345938475938457.mp3"
267
- },
268
- {
269
- "file":"/Users/supergiovane/.node-red/sonospollyttsstorage/ttsfiles/3666HJGH565656.mp3"
270
- }
271
- ],
272
- "_msgid":"8b6b22a45dfd5236"
273
- }
274
- ```
275
-
276
- **OUTPUT PIN 2**<br/>
277
- Payload is ***true*** when error occurs (for example, lost connection with Sonos Player), otherwise ***false***.<br/>
278
-
279
- In this sample, you see the TTS-Ultimate node connected with two debug nodes, to catch the errors.
280
-
281
- <img src='https://github.com/Supergiovane/node-red-contrib-tts-ultimate/raw/master/img/error.png' width="80%">
282
-
283
- <br/>
284
- <br/>
285
-
286
187
  ## CHANGE CONFIGURATION VIA MSG PROPERTY
287
188
 
288
189
  You can change the configuration of tts-ultimate, *via msg.setConfig* property.<br/>
@@ -290,18 +191,6 @@ The property is a JSON object.
290
191
 
291
192
  <img src='https://github.com/Supergiovane/node-red-contrib-tts-ultimate/raw/master/img/setConfig.png' width="80%">
292
193
 
293
- **msg.setConfig**<br/>
294
- This is the property where you can set all the things. It must be a JSON Object with the below specified properties.<br/>
295
- The setting is retained until the node receives another msg.setConfig or until node-red is restarted.<br/>
296
-
297
- > **property setMainPlayerIP**<br/>
298
- Sets the main player IP. This will also be the coordinator if you have a group of players.
299
-
300
- > **property setPlayerGroupArray**<br/>
301
- Sets the array of players beloging to the group, if any.<br/>
302
- You can also specify the volume variation from the main volume player, to adapt the additional player's perceived volume to the main sonos player volume.<br/>
303
- For example, if you have a speaker mounted in celiling, having less perceived volume, you can "push" the volume up, to match the whole perceived volume. Just add **#** after the IP and a number from -100 to 100 to subtract or add volume ***compared to the main sonos volume***. For example, if the sonos main player volume is 40, you can push this celing speaker's volume to further 10, so it'll have the real volume of 50. See below, the example.<br/>
304
- Note: Even if you have only one additional player, you need to put it into an array.
305
194
 
306
195
  ```js
307
196
  // Set main player IP
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "node-red-contrib-tts-ultimate",
3
- "version": "1.0.56",
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.",
3
+ "version": "2.0.1",
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, ElevenLabs.io TTS 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": {
7
7
  "test": "test"
@@ -23,7 +23,8 @@
23
23
  "speech",
24
24
  "ttsultimate",
25
25
  "sonospollytts",
26
- "neural"
26
+ "neural",
27
+ "elevenlabs"
27
28
  ],
28
29
  "node-red": {
29
30
  "nodes": {
@@ -39,22 +40,22 @@
39
40
  },
40
41
  "homepage": "https://github.com/Supergiovane/node-red-contrib-tts-ultimate",
41
42
  "dependencies": {
42
- "aws-sdk": "2.816.0",
43
+ "aws-sdk": "2.1404.0",
44
+ "@aws-sdk/client-polly":"3.215.0",
43
45
  "fs": "0.0.1-security",
44
46
  "sonos": "1.14.1",
45
- "util": ">=0.10.1",
46
47
  "formidable": "1.2.2",
47
- "os": ">=0.1.1",
48
48
  "path": ">=0.12.7",
49
- "@google-cloud/text-to-speech": "3.4.0",
49
+ "@google-cloud/text-to-speech": "4.2.2",
50
50
  "google-translate-tts": ">=0.3.0",
51
- "microsoft-cognitiveservices-speech-sdk": "1.24.1"
51
+ "microsoft-cognitiveservices-speech-sdk": "1.29.0",
52
+ "elevenlabs-node":"1.1.3"
52
53
  },
53
54
  "devDependencies": {
54
55
  "eslint": ">=4.18.2",
55
56
  "eslint-config-google": "^0.7.1"
56
57
  },
57
58
  "engines": {
58
- "node": ">=8.9.4"
59
+ "node": ">=14.0.0"
59
60
  }
60
61
  }
@@ -181,7 +181,7 @@
181
181
  </script>
182
182
 
183
183
 
184
- <script type="text/x-red" data-template-name="ownfileultimate">
184
+ <script type="text/html" data-template-name="ownfileultimate">
185
185
  <div class="form-row">
186
186
  <b>OwnFile configuration</b>&nbsp&nbsp&nbsp&nbsp<span style="color:red"><i class="fa fa-question-circle"></i>&nbsp<a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-tts-ultimate"><u>Help online</u></a></span>
187
187
  <br/>
@@ -209,7 +209,7 @@
209
209
  </div>
210
210
  </script>
211
211
 
212
- <script type="text/x-red" data-help-name="ownfileultimate">
212
+ <script type="text/markdown" data-help-name="ownfileultimate">
213
213
  <p>
214
214
  <a href="https://www.paypal.me/techtoday" target="_blank"><img src='https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square' width='30%'></a>
215
215
  </p>
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
  module.exports = function (RED) {
5
- var formidable = require('formidable');
5
+ var formidable = import('formidable');
6
6
  var fs = require('fs');
7
7
  var path = require('path');
8
8
 
@@ -1,5 +1,5 @@
1
1
  <script type="text/javascript">
2
-
2
+
3
3
  RED.nodes.registerType("ttsultimate-config", {
4
4
  category: 'config',
5
5
  defaults:
@@ -26,24 +26,25 @@
26
26
  accessKey: { type: "text" },
27
27
  secretKey: { type: "password" },
28
28
  mssubscriptionKey: { type: "text" },
29
- mslocation: { type: "text" }
29
+ mslocation: { type: "text" },
30
+ elevenlabsKey:{ type: "text" }
30
31
  },
31
32
  label: function () {
32
33
  return this.name || "";
33
34
  },
34
35
  oneditprepare: function () {
35
36
  var node = this;
36
-
37
+
37
38
  // 21/03/2020 Check if the node is the absolute first in the flow. In this case, it has no http server instatiaced
38
39
  // $.getJSON('ttsultimateGetEthAddress', (data) => {
39
- $("#pleaseDeploy").hide();
40
- $("#allGUI").show();
40
+ $("#pleaseDeploy").hide();
41
+ $("#allGUI").show();
41
42
  // }).fail(function (jqxhr) {
42
43
  // $("#pleaseDeploy").show();
43
44
  // $("#allGUI").hide();
44
45
  // });
45
46
 
46
-
47
+
47
48
  if (node.noderedipaddress === undefined) {
48
49
  // Put the default address of the machine
49
50
  $.getJSON('ttsultimateGetEthAddress', (data) => {
@@ -65,19 +66,28 @@
65
66
  if ($("#node-config-input-ttsservice").val() == "polly") {
66
67
  $("#GoogleForm").hide();
67
68
  $("#microsoftAzureForm").hide();
69
+ $("#elevenlabsForm").hide();
68
70
  $("#pollyForm").show();
69
71
  } else if ($("#node-config-input-ttsservice").val() == "googletts") {
70
72
  $("#microsoftAzureForm").hide();
71
73
  $("#pollyForm").hide();
74
+ $("#elevenlabsForm").hide();
72
75
  $("#GoogleForm").show();
73
76
  } else if ($("#node-config-input-ttsservice").val() == "googletranslate") {
74
77
  $("#pollyForm").hide();
75
78
  $("#GoogleForm").hide();
76
79
  $("#microsoftAzureForm").hide();
80
+ $("#elevenlabsForm").hide();
77
81
  } else if ($("#node-config-input-ttsservice").val() == "microsoftazuretts") {
78
82
  $("#pollyForm").hide();
79
83
  $("#GoogleForm").hide();
84
+ $("#elevenlabsForm").hide();
80
85
  $("#microsoftAzureForm").show();
86
+ } else if ($("#node-config-input-ttsservice").val() == "elevenlabs") {
87
+ $("#pollyForm").hide();
88
+ $("#GoogleForm").hide();
89
+ $("#microsoftAzureForm").hide();
90
+ $("#elevenlabsForm").show();
81
91
  }
82
92
  });
83
93
  // ##########################################################
@@ -136,7 +146,7 @@
136
146
  </script>
137
147
 
138
148
 
139
- <script type="text/x-red" data-template-name="ttsultimate-config">
149
+ <script type="text/html" data-template-name="ttsultimate-config">
140
150
  <div id="pleaseDeploy">
141
151
  <p align="center"> THIS IS YOUR FIRST CONFIG-NODE<br/> AND I NEED TO CREATE SOME THINGS<br/> BEFORE LETTING YOU PROCEED.<br/><b>PLEASE SAVE, FULL DEPLOY <br/>AND RE-OPEN THIS WINDOW</b><br/>
142
152
  TO BE ABLE TO FINISH THE CONFIGURATION SETUP<br/>
@@ -173,7 +183,8 @@
173
183
  <option value="polly">Amazon Polly</option>
174
184
  <option value="googletts">Google TTS</option>
175
185
  <option value="googletranslate">Google without authentication</option>
176
- <option value="microsoftazuretts">Microsoft Azure TTS</option>
186
+ <option value="microsoftazuretts">Microsoft Azure TTS</option>
187
+ <option value="elevenlabs">ElevenLabs TTS (elevenlabs.io)</option>
177
188
  </select>&nbsp&nbsp<b><span style="color:red"><i class="fa fa-question-circle"></i>&nbsp<a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-tts-ultimate"><u>Help configure</u></a></span>
178
189
  </div>
179
190
  <div id="pollyForm">
@@ -202,7 +213,12 @@
202
213
  <input style="width:58%" type="text" id="node-config-input-mslocation">
203
214
  </div>
204
215
  </div>
205
-
216
+ <div id="elevenlabsForm">
217
+ <div class="form-row">
218
+ <label style="width:35%" for="node-config-input-elevenlabsKey"><i class="fa fa-user"></i> <a href="https://elevenlabs.io" target="_new">Elevenlabs</a>API key</label>
219
+ <input style="width:58%" type="text" id="node-config-input-elevenlabsKey">
220
+ </div>
221
+ </div>
206
222
  <div class="form-row">
207
223
  <label for="node-config-input-purgediratrestart"><i class="fa fa-folder-o"></i> TTS Cache</label>
208
224
  <select id="node-config-input-purgediratrestart">
@@ -221,7 +237,7 @@
221
237
  </script>
222
238
 
223
239
 
224
- <script type="text/x-red" data-help-name="ttsultimate-config">
240
+ <script type="text/markdown" data-help-name="ttsultimate-config">
225
241
  <p>
226
242
  <a href="https://www.paypal.me/techtoday" target="_blank"><img src='https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square' width='30%'></a>
227
243
  </p>
@@ -10,11 +10,13 @@ module.exports = function (RED) {
10
10
  }
11
11
 
12
12
 
13
-
13
+ // Setting up the engines
14
14
  const AWS = require('aws-sdk');
15
15
  const GoogleTTS = require('@google-cloud/text-to-speech');
16
16
  const GoogleTranslate = require('google-translate-tts'); // TTS without credentials, limited to 200 chars per row.
17
17
  const microsoftAzureTTS = require("microsoft-cognitiveservices-speech-sdk"); // 12/10/2021
18
+ const elevenlabsTTS = require("elevenlabs-node"); // 03/08/2023
19
+
18
20
  var fs = require('fs');
19
21
  var path = require("path");
20
22
  var formidable = require('formidable');
@@ -144,7 +146,6 @@ module.exports = function (RED) {
144
146
  //RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
145
147
  }
146
148
 
147
-
148
149
  // 12/10/2021 Microsoft Azure TTS SpeechConfig.fromSubscription(subscriptionKey, serviceRegion)
149
150
  if (node.ttsservice === "microsoftazuretts") {
150
151
  // #########################################
@@ -216,6 +217,44 @@ module.exports = function (RED) {
216
217
  }
217
218
  // #########################################
218
219
 
220
+ // elevenlabsTTS
221
+ if (node.ttsservice === "elevenlabs") {
222
+ node.elevenlabsTTSVoiceList = []
223
+ try {
224
+ node.elevenlabsTTS = elevenlabsTTS;
225
+ try {
226
+ node.elevenlabsTTS.getVoices(node.credentials.elevenlabsKey).then((res) => {
227
+ try {
228
+ res.voices.forEach(element => {
229
+ node.elevenlabsTTSVoiceList.push({ name: element.labels.accent + " - " + element.name + " (" + element.labels.gender + ")", id: element.voice_id })
230
+ });
231
+ node.elevenlabsTTSVoiceList.sort(function (a, b) {
232
+ let x = a.name.toLowerCase();
233
+ let y = b.name.toLowerCase();
234
+ if (x < y) { return -1; }
235
+ if (x > y) { return 1; }
236
+ return 0;
237
+ });
238
+ } catch (error) {
239
+ RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting elevenlabs 2 voices: ' + error.message);
240
+ node.elevenlabsTTSVoiceList.push({ name: "Error getting elevenlabs 2 voices: " + error.message + " Check cretentials, deploy and restart node-red.", id: "Ivy" })
241
+ }
242
+
243
+ });
244
+ } catch (error) {
245
+ RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting elevenlabs voices: ' + error.message);
246
+ node.elevenlabsTTSVoiceList.push({ name: "Error getting elevenlabs voices: " + error.message + " Check cretentials, deploy and restart node-red.", id: "Ivy" })
247
+ }
248
+ RED.log.info("ttsultimate-config " + node.id + ": elevenlabsTTS service enabled.")
249
+ } catch (error) {
250
+ RED.log.warn("ttsultimate-config " + node.id + ": elevenlabsTTS service disabled. " + error.message)
251
+ }
252
+
253
+ } else {
254
+ //RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
255
+ }
256
+
257
+
219
258
  //#endregion
220
259
 
221
260
 
@@ -455,7 +494,10 @@ module.exports = function (RED) {
455
494
 
456
495
  } else if (ttsservice === "microsoftazuretts") {
457
496
  res.json(node.microsoftAzureTTSVoiceList);
497
+ } else if (ttsservice === "elevenlabs") {
498
+ res.json(node.elevenlabsTTSVoiceList);
458
499
  }
500
+
459
501
  });
460
502
 
461
503
  // ########################################################
@@ -673,7 +715,8 @@ module.exports = function (RED) {
673
715
  accessKey: { type: "text" },
674
716
  secretKey: { type: "password" },
675
717
  mssubscriptionKey: { type: "text" },
676
- mslocation: { type: "text" }
718
+ mslocation: { type: "text" },
719
+ elevenlabsKey: { type: "text" }
677
720
  }
678
721
  });
679
722
 
@@ -1,14 +1,4 @@
1
- <script type="text/x-red" data-help-name="ttsultimate">
2
- <p>
3
- <a href="https://www.paypal.me/techtoday" target="_blank"><img src='https://img.shields.io/badge/Donate-PayPal-blue.svg?style=flat-square' width='30%'></a>
4
- </p>
5
- <p>
6
- Configuration help is in the <a href="https://github.com/Supergiovane/node-red-contrib-tts-ultimate/blob/master/README.md">README</a><br/>
7
- </p>
8
-
9
- </script>
10
-
11
- <script type="text/x-red" data-template-name="ttsultimate">
1
+ <script type="text/html" data-template-name="ttsultimate">
12
2
  <div class="form-row">
13
3
  <b>TTS Ultimate configuration</b>&nbsp&nbsp&nbsp&nbsp<span style="color:red"><i class="fa fa-question-circle"></i>&nbsp<a target="_blank" href="https://github.com/Supergiovane/node-red-contrib-tts-ultimate"><u>Help online</u></a></span>
14
4
  <br/>
@@ -415,7 +405,7 @@
415
405
  for (let index = -100; index < 100; index += 5) {
416
406
  let sTesto = "";
417
407
  if (index === 0) sTesto = "Same volume as Main Sonos Player";
418
- if (index < 0) sTesto = "Decrease volume by " + Math.abs(index) ;
408
+ if (index < 0) sTesto = "Decrease volume by " + Math.abs(index);
419
409
  if (index > 0) sTesto = "Increase volume by " + index;
420
410
  oAdjustVolume.append($("<option></option>")
421
411
  .attr("value", index)
@@ -516,4 +506,58 @@
516
506
  $("#node-input-rule-container").editableList('height', height);
517
507
  }
518
508
  });
509
+ </script>
510
+
511
+ <script type="text/markdown" data-help-name="ttsultimate">
512
+ <p>This node transforms a text into a speech audio that you can hear natively via SONOS speakers, or save it to a file.</p>
513
+
514
+ **General**
515
+ |Property|Description|
516
+ |--|--|
517
+ | TTS Service | Select the TTS SERVICE ENGINE NODE. |
518
+ | Voice | 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. |
519
+ | Enable SSML | Enable the SSML XML notation. Please be aware, not all the TTS engines supports that.|
520
+ | Rate | Only avaiable if you choose Google TTS Engine (with credentials). Specifies the speech speed (Between 0.25 and 4.0, default 1). |
521
+ | Pitch | Only avaiable if you choose Google TTS Engine (with credentials). Specifies the speech pitch (Between -20.0 and 20.0, default 0). |
522
+ | Hailing | Before the first TTS message of the message queues, Sonos will play an "hailing" sound. You can select the hailing or totally disable it. |
523
+ | Player | Select the player. If you select not to use a player, the node will output a msg with an array of files, ready to be played by third party nodes. In case you select No player, only output file name, 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. Please see below the OUTPUT MESSAGES FROM THE NODE section. |
524
+ | Volume | Set the preferred TTS volume, from "0" to "100" (can be overridden by passing msg.volume = "40"; to the node). |
525
+ | Unmute | Unmute the main and the addotional players, then restore the previous mute state once finished. (Can be overridden by passing msg.unmute = true; to the node). |
526
+ | Main Sonos Player | Select your Sonos primary player. (It's strongly suggested to set a fixed IP for this player; you can reserve an IP using the DHCP Reservation function of your router/firewall's DHCP Server). It's possibile to group players, so your announcement can be played on all selected players. For this to happen, you need to select your primary coordinator player. All other players will be then controlled by this coordinator. |
527
+ | Additional Players | Here you can add all additional players that will be grouped toghether to the Main Sonos Player coordinator group. You can add a player using the "ADD" button, below the list. For each additional player, you can adjust their volume, based on the Main Sonos Player volume -+100. |
528
+
529
+ <br/>
530
+
531
+ ### Inputs
532
+
533
+ : volume (string) : Set the volume (values between "0" and "100").
534
+ : unmute (boolean) : *true* Unmute all players then mutes it again once finished playing. *false* Leaves the player as they are.
535
+ : nohailing (string) : Temporary stop playing the Hailing sound prior to the message (values "true" or "1" with quotes).
536
+ : payload (string | file) : The text to be spoken (for example msg.payload = "Hello World!"). You can also play an mp3 stored on an http server, by passing the URL to the payload ( msg.payload = "www.myserver.com/alarm.mp3").
537
+ : sonoshailing (string) : Overrides the selected hailing and plays the filename you passed in. Please double check the spelling of the filename (must be the same as you can see in the dropdown list of your hailing files, in the ttsultimate config window) and do not include the .mp3 extenson. For example node.sonoshailing="ComputerCall".
538
+ : priority (boolean) : If set to true, the inbound flow message will cancel the current TTS queue, will stop the current phrase being spoken and the node will play this priority message. If there are other priority messages in the queue, they will be retained and the inbound priority flow message is added to the queue. If the inbound priority flow message is the first in the priority queue, the hailing is played first (if the hailing has been enabled or if the hailing has been overridden by node.sonoshailing).
539
+ : stop (boolean) : If set to true, stops whatever is playing and clears the TTS queue.
540
+ : setConfig (json) : This is the property where you can set all the things. It must be a JSON Object with the below specified properties. The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
541
+ : setConfig {setMainPlayerIP} (string) : Sets the main player IP. This will also be the coordinator if you have a group of players.
542
+ : setConfig {setPlayerGroupArray} (array) : Sets the array of players beloging to the group, if any. You can also specify the volume variation from the main volume player, to adapt the additional player's perceived volume to the main sonos player volume. For example, if you have a speaker mounted in celiling, having less perceived volume, you can "push" the volume up, to match the whole perceived volume. Just add # after the IP and a number from -100 to 100 to subtract or add volume compared to the main sonos volume. For example, if the sonos main player volume is 40, you can push this celing speaker's volume to further 10, so it'll have the real volume of 50. See below, the example. Even if you have only one additional player, you need to put it into an array.
543
+
544
+ ### Output
545
+
546
+ The node has two output pins. The first pin is to signal play status, the second one, is to signal an error
547
+
548
+ 1. Standard output
549
+ : payload (boolean) : Payload is true when the node has finished playing, false if the node is playing. 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. The property passThroughMessage contains the input msg passed through the output.
550
+ : passThroughMessage (json) : Original message object.
551
+ : filesArray (array of string) : Arrays of generated files name, including paths.
552
+
553
+ 2. Error
554
+ : payload (boolean) : Payload is true when error occurs (for example, lost connection with Sonos Player), otherwise false.
555
+
556
+ ### Samples
557
+
558
+ [You'll find useful samples here](https://github.com/Supergiovane/node-red-contrib-tts-ultimate)
559
+
560
+ [Find it useful?](https://www.paypal.me/techtoday)
561
+
562
+ <br/>
519
563
  </script>
@@ -1,8 +1,9 @@
1
+ const { Readable } = require('stream');
2
+
1
3
  module.exports = function (RED) {
2
4
  'use strict';
3
5
 
4
6
  var fs = require('fs');
5
- var util = require('util');
6
7
  var path = require('path');
7
8
  const sonos = require('sonos');
8
9
  const crypto = require("crypto");
@@ -427,8 +428,6 @@ module.exports = function (RED) {
427
428
  node.setNodeStatus({ fill: 'grey', shape: 'ring', text: 'Initialized.' });
428
429
 
429
430
 
430
-
431
-
432
431
  // 22/09/2020 Flush Queue and set to stopped
433
432
  node.flushQueue = () => {
434
433
  // 10/04/2018 Remove the TTS message from the queue
@@ -635,7 +634,16 @@ module.exports = function (RED) {
635
634
  voice: node.voiceId
636
635
  };
637
636
  data = await synthesizeSpeechMicrosoftAzureTTS(node.server.microsoftAzureTTS, params);
637
+ } else if (node.server.ttsservice === "elevenlabs") {
638
+ node.setNodeStatus({ fill: 'green', shape: 'ring', text: 'Downloading from elevenLabs TTS...' });
639
+ // VoiceId is: code
640
+ const params = {
641
+ text: msg,
642
+ voice: node.voiceId
643
+ };
644
+ data = await synthesizeSpeechElevenLabs(node.server.elevenlabsTTS, params);
638
645
  }
646
+
639
647
  // Save the downloaded file into the cache
640
648
  try {
641
649
  fs.writeFileSync(sFileToBePlayed, data);
@@ -739,7 +747,7 @@ module.exports = function (RED) {
739
747
  state = "";
740
748
  node.timerbTimeOutPlay = setTimeout(() => {
741
749
  node.bTimeOutPlay = true;
742
- }, 60000*10); // 10 minutes timeout
750
+ }, 60000 * 10); // 10 minutes timeout
743
751
  while (state !== "stopped" && !node.bTimeOutPlay) {
744
752
  try {
745
753
  state = await getCurrentStateSync();
@@ -1111,7 +1119,6 @@ module.exports = function (RED) {
1111
1119
  throw (error);
1112
1120
  }
1113
1121
  };
1114
-
1115
1122
  // 12/10/2021 Microsoft Azure TTS Service
1116
1123
  async function synthesizeSpeechMicrosoftAzureTTS(ttsService, params) {
1117
1124
 
@@ -1136,6 +1143,39 @@ module.exports = function (RED) {
1136
1143
  }
1137
1144
  });
1138
1145
  };
1146
+ // elevenLabs TTS Service
1147
+ function synthesizeSpeechElevenLabs(ttsService, params) {
1148
+ // const params = {
1149
+ // text: msg,
1150
+ // voice: node.voiceId
1151
+ // };
1152
+ function stream2buffer(stream) {
1153
+ return new Promise((resolve, reject) => {
1154
+ try {
1155
+ const _buf = [];
1156
+
1157
+ stream.on("data", (chunk) => _buf.push(chunk));
1158
+ stream.on("end", () => resolve(Buffer.concat(_buf)));
1159
+ stream.on("error", (err) => reject(err));
1160
+ } catch (error) {
1161
+ }
1162
+ });
1163
+ }
1164
+ return new Promise((resolve, reject) => {
1165
+ // "model_id": "eleven_multilingual_v1",
1166
+ ttsService.textToSpeechStream(node.server.credentials.elevenlabsKey, params.voice, params.text, null,null,"eleven_multilingual_v1").then((res) => {
1167
+ try {
1168
+ if (res !== undefined) {
1169
+ resolve(stream2buffer(res));
1170
+ } else {
1171
+ reject(new Error("Please check credentials. The stream cannot be read from the elevenlabs TTS server"))
1172
+ }
1173
+ } catch (error) {
1174
+ reject(error)
1175
+ }
1176
+ });
1177
+ });
1178
+ }
1139
1179
 
1140
1180
  // 04/01/2021 hashing filename to avoid issues with long filenames.
1141
1181
  function getFilename(_text, _sVoice, _isSSML, _extension, _speakingpitch, _speakingrate) {