node-red-contrib-tts-ultimate 1.0.33 → 1.0.37
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 +16 -0
- package/README.md +28 -10
- package/package.json +2 -1
- package/ttsultimate/ttsultimate-config.html +19 -8
- package/ttsultimate/ttsultimate-config.js +96 -75
- package/ttsultimate/ttsultimate.html +9 -2
- package/ttsultimate/ttsultimate.js +69 -21
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.paypal.me/techtoday)
|
|
4
4
|
|
|
5
|
+
<p>
|
|
6
|
+
<b>Version 1.0.37</b> December 2021<br/>
|
|
7
|
+
- Removed some unwanted startup logs.<br/>
|
|
8
|
+
<p>
|
|
9
|
+
<p>
|
|
10
|
+
<b>Version 1.0.36</b> November 2021<br/>
|
|
11
|
+
- 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/>
|
|
12
|
+
<p>
|
|
13
|
+
<p>
|
|
14
|
+
<b>Version 1.0.35</b> October 2021<br/>
|
|
15
|
+
- NEW: You can force unmuting all players, then restore their previous state once finished playing.<br/>
|
|
16
|
+
<p>
|
|
17
|
+
<p>
|
|
18
|
+
<b>Version 1.0.34</b> October 2021<br/>
|
|
19
|
+
- FIX: fixed an issue in retrieving voices if you have more than one TTS engine enabled at the same time.<br/>
|
|
20
|
+
<p>
|
|
5
21
|
<p>
|
|
6
22
|
<b>Version 1.0.33</b> October 2021<br/>
|
|
7
23
|
- NEW VOICE ENGINE: Microsoft Azure TTS.<br/>
|
package/README.md
CHANGED
|
@@ -104,9 +104,10 @@ For Google TTS Engine, you can choose pitch and speed rate of the voice.
|
|
|
104
104
|
|
|
105
105
|
* **TTS Service using Microsot Azure TTS**<br/>
|
|
106
106
|
For Microsoft Azure TTS Engine, you need to have a microsoft account and register to the Azure portal.<br/>
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
107
|
+
See my **YOUTUBE video**, here! https://youtu.be/asXajNpRWME<br/>
|
|
108
|
+
You need to register here https://portal.azure.com, then ceate a Voice Service (please click here https://portal.azure.com/#create/Microsoft.CognitiveServicesSpeechServices), then click on the left "Keys and Endpoint" menu and copy/paste the KEY and your Location (for example westus).<br/>
|
|
109
|
+
Then paste both into the TTS-Ultimate engine configuration window and restart node-red.<br/>
|
|
110
|
+
|
|
110
111
|
<br/>
|
|
111
112
|
|
|
112
113
|
|
|
@@ -124,6 +125,12 @@ On each deploy or node-red restart, delete all tts files in the cache. This is u
|
|
|
124
125
|
***Leave the TTS cache folder untouched*** (suggested only if you have enough disk space)<br/>
|
|
125
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.
|
|
126
127
|
<br/>
|
|
128
|
+
|
|
129
|
+
**Autosplit max length
|
|
130
|
+
<br/>
|
|
131
|
+
Due to some limitations in text lenght, applied by the online TTS Engines, TTS-Ultimate is capable to split your long text to be spoken, in shorter texts in an intelligent way.<br/>
|
|
132
|
+
This field allow you to set the maximum lenght (**in chars**) of each splitted text part. The default is **220** and is OK for most cases. You can change this valut to whatever you want but keep in mind, that your TTS engine can either cut the text or return an error, if the text is too long. As the cached filename is equal to the text being spoken, you could also hit the maximum filename lenght of your filesystem. So keep the default value, unless you absolute need to change it.<br/>
|
|
133
|
+
<br/>
|
|
127
134
|
<br/>
|
|
128
135
|
|
|
129
136
|
# TTS-ULTIMATE NODE
|
|
@@ -150,6 +157,9 @@ In case you select ***No player, only output file name***, you'll get a message
|
|
|
150
157
|
**Volume** <br/>
|
|
151
158
|
Set the preferred TTS volume, from "0" to "100" (can be overridden by passing <code>msg.volume = "40";</code> to the node)
|
|
152
159
|
|
|
160
|
+
**Unmute** <br/>
|
|
161
|
+
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)
|
|
162
|
+
|
|
153
163
|
**Main Sonos Player** <br/>
|
|
154
164
|
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/>
|
|
155
165
|
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.
|
|
@@ -163,6 +173,10 @@ Here you can add all additional players that will be grouped toghether to the *M
|
|
|
163
173
|
**msg.volume**<br/>
|
|
164
174
|
Set the volume (values between "0" and "100" with quotes)</br>
|
|
165
175
|
|
|
176
|
+
**msg.unmute**<br/>
|
|
177
|
+
*true*: Unmute all players then mutes it again once finished playing.</br>
|
|
178
|
+
*false*: Leave the player as they are.</br>
|
|
179
|
+
|
|
166
180
|
**msg.nohailing**<br/>
|
|
167
181
|
Temporarely doesn't play the Hailing sound prior to the message (values "true" or "1" with quotes)</br>
|
|
168
182
|
|
|
@@ -258,17 +272,19 @@ The property is a JSON object.
|
|
|
258
272
|
<img src='https://github.com/Supergiovane/node-red-contrib-tts-ultimate/raw/master/img/setConfig.png' width="80%">
|
|
259
273
|
|
|
260
274
|
**msg.setConfig**<br/>
|
|
261
|
-
This is the property where you can set all the things. It must be
|
|
275
|
+
This is the property where you can set all the things. It must be a JSON Object with the below specified properties.<br/>
|
|
276
|
+
The setting is retained until the node receives another msg.setConfig or until node-red is restarted.<br/>
|
|
262
277
|
|
|
263
|
-
**setMainPlayerIP**<br/>
|
|
264
|
-
Sets the main player IP. This will also be the coordinator if you have a group of players
|
|
278
|
+
> **property setMainPlayerIP**<br/>
|
|
279
|
+
Sets the main player IP. This will also be the coordinator if you have a group of players.
|
|
265
280
|
|
|
266
|
-
**setPlayerGroupArray**<br/>
|
|
267
|
-
Sets the array of players beloging to the group, if any.<br/>
|
|
268
|
-
If you have only one additional player, you need to ever put it into an array. See below.
|
|
281
|
+
> **property setPlayerGroupArray**<br/>
|
|
282
|
+
Sets the array of players beloging to the group, if any.<br/>
|
|
283
|
+
If you have only one additional player, you need to ever put it into an array. See below.
|
|
269
284
|
|
|
270
285
|
```js
|
|
271
|
-
// Set player IP
|
|
286
|
+
// Set main player IP
|
|
287
|
+
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
272
288
|
var config= {
|
|
273
289
|
setMainPlayerIP:"192.168.1.109"
|
|
274
290
|
};
|
|
@@ -278,6 +294,7 @@ return msg;
|
|
|
278
294
|
|
|
279
295
|
```js
|
|
280
296
|
// Set player IP and additional players
|
|
297
|
+
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
281
298
|
var config= {
|
|
282
299
|
setMainPlayerIP:"192.168.1.109",
|
|
283
300
|
setPlayerGroupArray:[
|
|
@@ -292,6 +309,7 @@ return msg;
|
|
|
292
309
|
|
|
293
310
|
```js
|
|
294
311
|
// If you have only one additional player
|
|
312
|
+
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
295
313
|
var config= {
|
|
296
314
|
setMainPlayerIP:"192.168.1.109",
|
|
297
315
|
setPlayerGroupArray:["192.168.1.110"]
|
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.37",
|
|
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",
|
|
@@ -17,7 +17,8 @@
|
|
|
17
17
|
type: "text"
|
|
18
18
|
},
|
|
19
19
|
purgediratrestart: { value: "leave", required: false },
|
|
20
|
-
ttsservice: { value: "googletranslate", required: false }
|
|
20
|
+
ttsservice: { value: "googletranslate", required: false },
|
|
21
|
+
limitTTSFilenameLenght: { value: 220, required: false, validate: RED.validators.number() }
|
|
21
22
|
|
|
22
23
|
},
|
|
23
24
|
credentials: {
|
|
@@ -32,6 +33,10 @@
|
|
|
32
33
|
oneditprepare: function () {
|
|
33
34
|
var node = this;
|
|
34
35
|
|
|
36
|
+
// 01/11/2021
|
|
37
|
+
//if (node.limitTTSFilenameLenght === undefined) {
|
|
38
|
+
// $("#node-config-input-limitTTSFilenameLenght").val(220);
|
|
39
|
+
//}
|
|
35
40
|
// 21/03/2020 Check if the node is the absolute first in the flow. In this case, it has no http server instatiaced
|
|
36
41
|
$.getJSON('ttsultimateGetEthAddress', (data) => {
|
|
37
42
|
$("#pleaseDeploy").hide();
|
|
@@ -61,16 +66,16 @@
|
|
|
61
66
|
$("#node-config-input-ttsservice").change(function (e) {
|
|
62
67
|
if ($("#node-config-input-ttsservice").val() == "polly") {
|
|
63
68
|
$("#GoogleForm").hide();
|
|
64
|
-
$("#microsoftAzureForm").hide();
|
|
69
|
+
$("#microsoftAzureForm").hide();
|
|
65
70
|
$("#pollyForm").show();
|
|
66
71
|
} else if ($("#node-config-input-ttsservice").val() == "googletts") {
|
|
67
|
-
$("#microsoftAzureForm").hide();
|
|
72
|
+
$("#microsoftAzureForm").hide();
|
|
68
73
|
$("#pollyForm").hide();
|
|
69
74
|
$("#GoogleForm").show();
|
|
70
75
|
} else if ($("#node-config-input-ttsservice").val() == "googletranslate") {
|
|
71
76
|
$("#pollyForm").hide();
|
|
72
77
|
$("#GoogleForm").hide();
|
|
73
|
-
$("#microsoftAzureForm").hide();
|
|
78
|
+
$("#microsoftAzureForm").hide();
|
|
74
79
|
} else if ($("#node-config-input-ttsservice").val() == "microsoftazuretts") {
|
|
75
80
|
$("#pollyForm").hide();
|
|
76
81
|
$("#GoogleForm").hide();
|
|
@@ -192,12 +197,12 @@
|
|
|
192
197
|
</div>
|
|
193
198
|
<div id="microsoftAzureForm">
|
|
194
199
|
<div class="form-row">
|
|
195
|
-
<label style="width:
|
|
196
|
-
<input
|
|
200
|
+
<label style="width:35%" for="node-config-input-mssubscriptionKey"><i class="fa fa-user"></i> Azure subscription key</label>
|
|
201
|
+
<input style="width:58%" type="text" id="node-config-input-mssubscriptionKey">
|
|
197
202
|
</div>
|
|
198
203
|
<div class="form-row">
|
|
199
|
-
<label style="width:
|
|
200
|
-
<input style="width:
|
|
204
|
+
<label style="width:35%" for="node-config-input-mslocation"><i class="fa fa-user"></i> Azure location (ex:westeurope)</label>
|
|
205
|
+
<input style="width:58%" type="text" id="node-config-input-mslocation">
|
|
201
206
|
</div>
|
|
202
207
|
</div>
|
|
203
208
|
|
|
@@ -208,6 +213,12 @@
|
|
|
208
213
|
<option value="leave">Leave the TTS cache folder untouched (not suggested if you have less disk space)</option>
|
|
209
214
|
</select>
|
|
210
215
|
</div>
|
|
216
|
+
|
|
217
|
+
<div class="form-row">
|
|
218
|
+
<label for="node-config-input-limitTTSFilenameLenght"><i class="fa fa-file"></i> Autosplit max length (chars)</label>
|
|
219
|
+
<input type="text" id="node-config-input-limitTTSFilenameLenght">
|
|
220
|
+
</div>
|
|
221
|
+
|
|
211
222
|
</div>
|
|
212
223
|
|
|
213
224
|
</script>
|
|
@@ -23,6 +23,11 @@ module.exports = function (RED) {
|
|
|
23
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
24
|
node.whoIsUsingTheServer = ""; // Client node.id using the server, because only a ttsultimate node can use the serve at once.
|
|
25
25
|
node.ttsservice = config.ttsservice || "googletranslate";
|
|
26
|
+
node.limitTTSFilenameLenght = config.limitTTSFilenameLenght === undefined ? 220 : config.limitTTSFilenameLenght;
|
|
27
|
+
// node.polly = null;
|
|
28
|
+
// node.googleTTS = null;
|
|
29
|
+
// node.googleTranslateTTS = null;
|
|
30
|
+
// node.microsoftAzureTTS = null;
|
|
26
31
|
|
|
27
32
|
// 03/06/2019 you can select the temp dir
|
|
28
33
|
//#region "SETUP PATHS"
|
|
@@ -40,22 +45,22 @@ module.exports = function (RED) {
|
|
|
40
45
|
}
|
|
41
46
|
}
|
|
42
47
|
if (!setupDirectory(node.userDir)) {
|
|
43
|
-
RED.log.error('ttsultimate-config: Unable to set up MAIN directory: ' + node.userDir);
|
|
48
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up MAIN directory: ' + node.userDir);
|
|
44
49
|
}
|
|
45
50
|
if (!setupDirectory(path.join(node.userDir, "ttsfiles"))) {
|
|
46
|
-
RED.log.error('ttsultimate-config: Unable to set up cache directory: ' + path.join(node.userDir, "ttsfiles"));
|
|
51
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up cache directory: ' + path.join(node.userDir, "ttsfiles"));
|
|
47
52
|
} else {
|
|
48
|
-
RED.log.info('ttsultimate-config: TTS cache set to ' + path.join(node.userDir, "ttsfiles"));
|
|
53
|
+
RED.log.info('ttsultimate-config ' + node.id + ': TTS cache set to ' + path.join(node.userDir, "ttsfiles"));
|
|
49
54
|
}
|
|
50
55
|
if (!setupDirectory(path.join(node.userDir, "ttsultimategooglecredentials"))) {
|
|
51
|
-
RED.log.error('ttsultimate-config: Unable to set google creds directory: ' + path.join(node.userDir, "ttsultimategooglecredentials"));
|
|
56
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set google creds directory: ' + path.join(node.userDir, "ttsultimategooglecredentials"));
|
|
52
57
|
} else {
|
|
53
|
-
RED.log.info('ttsultimate-config: google credentials path set to ' + path.join(node.userDir, "ttsultimategooglecredentials"));
|
|
58
|
+
RED.log.info('ttsultimate-config ' + node.id + ': google credentials path set to ' + path.join(node.userDir, "ttsultimategooglecredentials"));
|
|
54
59
|
}
|
|
55
60
|
if (!setupDirectory(path.join(node.userDir, "hailingpermanentfiles"))) {
|
|
56
|
-
RED.log.error('ttsultimate-config: Unable to set up hailing directory: ' + path.join(node.userDir, "hailingpermanentfiles"));
|
|
61
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up hailing directory: ' + path.join(node.userDir, "hailingpermanentfiles"));
|
|
57
62
|
} else {
|
|
58
|
-
RED.log.info('ttsultimate-config: hailing path set to ' + path.join(node.userDir, "hailingpermanentfiles"));
|
|
63
|
+
RED.log.info('ttsultimate-config ' + node.id + ': hailing path set to ' + path.join(node.userDir, "hailingpermanentfiles"));
|
|
59
64
|
// 09/03/2020 Copy defaults to the userDir
|
|
60
65
|
fs.readdirSync(path.join(__dirname, "hailingpermanentfiles")).forEach(file => {
|
|
61
66
|
try {
|
|
@@ -64,9 +69,9 @@ module.exports = function (RED) {
|
|
|
64
69
|
});
|
|
65
70
|
}
|
|
66
71
|
if (!setupDirectory(path.join(node.userDir, "ttspermanentfiles"))) {
|
|
67
|
-
RED.log.error('ttsultimate-config: Unable to set up permanent files directory: ' + path.join(node.userDir, "ttspermanentfiles"));
|
|
72
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Unable to set up permanent files directory: ' + path.join(node.userDir, "ttspermanentfiles"));
|
|
68
73
|
} else {
|
|
69
|
-
RED.log.info('ttsultimate-config: permanent files path set to ' + path.join(node.userDir, "ttspermanentfiles"));
|
|
74
|
+
RED.log.info('ttsultimate-config ' + node.id + ': permanent files path set to ' + path.join(node.userDir, "ttspermanentfiles"));
|
|
70
75
|
// 09/03/2020 // Copy the samples of permanent files into the userDir
|
|
71
76
|
fs.readdirSync(path.join(__dirname, "ttspermanentfiles")).forEach(file => {
|
|
72
77
|
try {
|
|
@@ -79,62 +84,75 @@ module.exports = function (RED) {
|
|
|
79
84
|
|
|
80
85
|
//#region "INSTANTIATE SERVICE ENGINES"
|
|
81
86
|
// POLLY
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
if (node.ttsservice === "polly") {
|
|
88
|
+
var params = {
|
|
89
|
+
accessKeyId: node.credentials.accessKey,
|
|
90
|
+
secretAccessKey: node.credentials.secretKey,
|
|
91
|
+
apiVersion: '2016-06-10'
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
node.polly = new AWS.Polly(params);
|
|
95
|
+
RED.log.info("ttsultimate-config " + node.id + ": Polly service enabled.")
|
|
96
|
+
} catch (error) {
|
|
97
|
+
RED.log.warn("ttsultimate-config " + node.id + ": Polly service disabled. " + error.message)
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Polly service not used.");
|
|
92
101
|
}
|
|
93
102
|
|
|
103
|
+
|
|
94
104
|
// Google TTS with authentication
|
|
95
105
|
if (node.ttsservice === "googletts") {
|
|
96
106
|
try {
|
|
97
107
|
// 23/12/2020 Set environment path of googleTTS
|
|
98
|
-
RED.log.info("ttsultimate-config: Google credentials are stored in the file " + path.join(node.userDir, "ttsultimategooglecredentials", "googlecredentials.json"));
|
|
108
|
+
RED.log.info("ttsultimate-config " + node.id + ": Google credentials are stored in the file " + path.join(node.userDir, "ttsultimategooglecredentials", "googlecredentials.json"));
|
|
99
109
|
process.env.GOOGLE_APPLICATION_CREDENTIALS = path.join(node.userDir, "ttsultimategooglecredentials", "googlecredentials.json");
|
|
110
|
+
try {
|
|
111
|
+
node.googleTTS = new GoogleTTS.TextToSpeechClient();
|
|
112
|
+
RED.log.info("ttsultimate-config " + node.id + ": Google TTS service enabled. ")
|
|
113
|
+
} catch (error) {
|
|
114
|
+
RED.log.warn("ttsultimate-config " + node.id + ": Google TTS service disabled. " + error.message)
|
|
115
|
+
}
|
|
100
116
|
} catch (error) {
|
|
101
|
-
RED.log.warn("ttsultimate.
|
|
117
|
+
RED.log.warn("ttsultimate-config " + node.id + ": Google TTS service error: " + error.message)
|
|
102
118
|
}
|
|
103
119
|
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
node.googleTTS = new GoogleTTS.TextToSpeechClient();
|
|
107
|
-
RED.log.info("ttsultimate.config: Google Translate free service enabled. ")
|
|
108
|
-
} catch (error) {
|
|
109
|
-
RED.log.warn("ttsultimate.config: Google Translate free service disabled. " + error.message)
|
|
120
|
+
} else {
|
|
121
|
+
// RED.log.info("ttsultimate-config " + node.id + ": Google TTS service not used.");
|
|
110
122
|
}
|
|
111
123
|
|
|
112
124
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
125
|
+
|
|
126
|
+
// Google Translate without authentication
|
|
127
|
+
if (node.ttsservice === "googletranslate") {
|
|
128
|
+
try {
|
|
129
|
+
node.googleTranslateTTS = GoogleTranslate;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
|
|
132
|
+
}
|
|
133
|
+
} else {
|
|
134
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Google Translate free service not used.");
|
|
117
135
|
}
|
|
118
136
|
|
|
119
137
|
|
|
120
|
-
// 12/10/2021 Microsoft Azure TTS SpeechConfig.fromSubscription(subscriptionKey, serviceRegion)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
+
// 12/10/2021 Microsoft Azure TTS SpeechConfig.fromSubscription(subscriptionKey, serviceRegion)
|
|
139
|
+
if (node.ttsservice === "microsoftazuretts") {
|
|
140
|
+
// #########################################
|
|
141
|
+
node.setMicrosoftAzureVoice = function (_voiceName) {
|
|
142
|
+
let speechConfig = microsoftAzureTTS.SpeechConfig.fromSubscription(node.credentials.mssubscriptionKey, node.credentials.mslocation);
|
|
143
|
+
speechConfig.speechSynthesisVoiceName = _voiceName;
|
|
144
|
+
speechConfig.speechSynthesisOutputFormat = microsoftAzureTTS.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
|
|
145
|
+
node.microsoftAzureTTS = new microsoftAzureTTS.SpeechSynthesizer(speechConfig);
|
|
146
|
+
return node.microsoftAzureTTS;
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
|
|
150
|
+
let speechConfig = microsoftAzureTTS.SpeechConfig.fromSubscription(node.credentials.mssubscriptionKey, node.credentials.mslocation);
|
|
151
|
+
//speechConfig.speechSynthesisLanguage = "it-IT";
|
|
152
|
+
//speechConfig.speechSynthesisVoiceName = "it-IT-IsabellaNeural";
|
|
153
|
+
speechConfig.speechSynthesisOutputFormat = microsoftAzureTTS.SpeechSynthesisOutputFormat.Audio16Khz32KBitRateMonoMp3;
|
|
154
|
+
node.microsoftAzureTTS = new microsoftAzureTTS.SpeechSynthesizer(speechConfig);
|
|
155
|
+
node.microsoftAzureTTSVoiceList = [];
|
|
138
156
|
// Get the voices
|
|
139
157
|
async function listVoicesAzure() {
|
|
140
158
|
const httpsAzure = require('https')
|
|
@@ -155,33 +173,36 @@ module.exports = function (RED) {
|
|
|
155
173
|
resVoices.on('end', () => {
|
|
156
174
|
try {
|
|
157
175
|
let oVoices = JSON.parse(sChunkResponse);
|
|
158
|
-
RED.log.info('ttsultimate-config: Microsoft Azure voices count: ' + oVoices.length);
|
|
176
|
+
RED.log.info('ttsultimate-config ' + node.id + ': Microsoft Azure voices count: ' + oVoices.length);
|
|
159
177
|
for (let index = 0; index < oVoices.length; index++) {
|
|
160
178
|
const element = oVoices[index];
|
|
161
179
|
node.microsoftAzureTTSVoiceList.push({ name: element.ShortName + " (" + element.Gender + ")", id: element.ShortName })
|
|
162
180
|
}
|
|
163
181
|
} catch (error) {
|
|
164
|
-
RED.log.error('ttsultimate-config: listVoices: Error parsing Microsoft Azure TTS voices: ' + error.message);
|
|
182
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error parsing Microsoft Azure TTS voices: ' + error.message);
|
|
165
183
|
node.microsoftAzureTTSVoiceList.push({ name: "Error parsing Microsoft Azure voices: " + error.message, id: "Ivy" });
|
|
166
184
|
}
|
|
167
185
|
})
|
|
168
186
|
})
|
|
169
187
|
reqAzure.on('error', error => {
|
|
170
|
-
RED.log.error('ttsultimate-config: listVoices: Error contacting Azure for getting the voices list: ' + error.message);
|
|
188
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error contacting Azure for getting the voices list: ' + error.message);
|
|
171
189
|
node.microsoftAzureTTSVoiceList.push({ name: "Error getting Microsoft Azure voices: " + error.message, id: "Ivy" })
|
|
172
190
|
reqAzure.end();
|
|
173
191
|
})
|
|
174
192
|
reqAzure.end();
|
|
175
193
|
};
|
|
176
|
-
RED.log.info("ttsultimate.
|
|
194
|
+
RED.log.info("ttsultimate-config " + node.id + ": Microsoft AzureTTS service enabled.")
|
|
177
195
|
try {
|
|
178
196
|
listVoicesAzure();
|
|
179
197
|
} catch (error) {
|
|
180
|
-
RED.log.error('ttsultimate-config: listVoices: Error getting Microsoft Azure voices: ' + error.message);
|
|
198
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting Microsoft Azure voices: ' + error.message);
|
|
181
199
|
}
|
|
200
|
+
|
|
201
|
+
} catch (error) {
|
|
202
|
+
RED.log.warn("ttsultimate-config " + node.id + ": Microsoft AzureTTS service disabled. " + error.message)
|
|
182
203
|
}
|
|
183
|
-
}
|
|
184
|
-
RED.log.
|
|
204
|
+
} else {
|
|
205
|
+
//RED.log.info("ttsultimate-config " + node.id + ": Microsoft AzureTTS service not used. ");
|
|
185
206
|
}
|
|
186
207
|
// #########################################
|
|
187
208
|
|
|
@@ -232,7 +253,7 @@ module.exports = function (RED) {
|
|
|
232
253
|
//return groups[0].CoordinatorDevice().togglePlayback()
|
|
233
254
|
})
|
|
234
255
|
}).catch(e => {
|
|
235
|
-
RED.log.warn('ttsultimate-config: Error in discovery ' + e);
|
|
256
|
+
RED.log.warn('ttsultimate-config ' + node.id + ': Error in discovery ' + e);
|
|
236
257
|
res.json("ERRORDISCOVERY");
|
|
237
258
|
})
|
|
238
259
|
} catch (error) { }
|
|
@@ -327,7 +348,7 @@ module.exports = function (RED) {
|
|
|
327
348
|
});
|
|
328
349
|
|
|
329
350
|
// 26/10/2020 Supergiovane, get the updated voice list.
|
|
330
|
-
RED.httpAdmin.get("/ttsgetvoices", RED.auth.needsPermission('TTSConfigNode.read'), function (req, res) {
|
|
351
|
+
RED.httpAdmin.get("/ttsgetvoices" + encodeURIComponent(node.id), RED.auth.needsPermission('TTSConfigNode.read'), function (req, res) {
|
|
331
352
|
var ttsservice = req.query.ttsservice;// Retrieve the ttsservice engine
|
|
332
353
|
var jListVoices = [];
|
|
333
354
|
|
|
@@ -343,7 +364,7 @@ module.exports = function (RED) {
|
|
|
343
364
|
};
|
|
344
365
|
node.polly.describeVoices(jfiltroVoci, function (err, data) {
|
|
345
366
|
if (err) {
|
|
346
|
-
RED.log.warn('ttsultimate-config: Error getting polly voices ' + err);
|
|
367
|
+
RED.log.warn('ttsultimate-config ' + node.id + ': Error getting polly voices ' + err);
|
|
347
368
|
jListVoices.push({ name: "Error retrieving voices. " + err, id: "Ivy" })
|
|
348
369
|
res.json(jListVoices)
|
|
349
370
|
} else {
|
|
@@ -371,7 +392,7 @@ module.exports = function (RED) {
|
|
|
371
392
|
});
|
|
372
393
|
res.json(jListVoices)
|
|
373
394
|
} catch (error) {
|
|
374
|
-
RED.log.error('ttsultimate-config: Error getting google TTS voices ' + error.message);
|
|
395
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Error getting google TTS voices ' + error.message);
|
|
375
396
|
jListVoices.push({ name: "Error getting Google TTS voices. " + error.message, id: "Ivy" })
|
|
376
397
|
res.json(jListVoices)
|
|
377
398
|
}
|
|
@@ -379,7 +400,7 @@ module.exports = function (RED) {
|
|
|
379
400
|
try {
|
|
380
401
|
listVoices();
|
|
381
402
|
} catch (error) {
|
|
382
|
-
RED.log.error('ttsultimate-config: listVoices: Error getting google TTS voices ' + error.message);
|
|
403
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting google TTS voices ' + error.message);
|
|
383
404
|
}
|
|
384
405
|
|
|
385
406
|
} else if (ttsservice === "googletranslate") {
|
|
@@ -391,7 +412,7 @@ module.exports = function (RED) {
|
|
|
391
412
|
});
|
|
392
413
|
res.json(jListVoices)
|
|
393
414
|
} catch (error) {
|
|
394
|
-
RED.log.error('ttsultimate-config: Error getting google Translate voices ' + error.message);
|
|
415
|
+
RED.log.error('ttsultimate-config ' + node.id + ': Error getting google Translate voices ' + error.message);
|
|
395
416
|
jListVoices.push({ name: "Error getting Google Translate voices. " + error.message, id: "Ivy" })
|
|
396
417
|
res.json(jListVoices)
|
|
397
418
|
}
|
|
@@ -399,7 +420,7 @@ module.exports = function (RED) {
|
|
|
399
420
|
try {
|
|
400
421
|
listVoices();
|
|
401
422
|
} catch (error) {
|
|
402
|
-
RED.log.error('ttsultimate-config: listVoices: Error getting google Translate voices ' + error.message);
|
|
423
|
+
RED.log.error('ttsultimate-config ' + node.id + ': listVoices: Error getting google Translate voices ' + error.message);
|
|
403
424
|
}
|
|
404
425
|
|
|
405
426
|
} else if (ttsservice === "microsoftazuretts") {
|
|
@@ -471,7 +492,7 @@ module.exports = function (RED) {
|
|
|
471
492
|
fs.readdir(path.join(node.userDir, "ttspermanentfiles"), (err, files) => {
|
|
472
493
|
files.forEach(function (file) {
|
|
473
494
|
if (file.indexOf("OwnFile_") !== -1) {
|
|
474
|
-
RED.log.warn("ttsultimate-config: Deleted file " + path.join(node.userDir, "ttspermanentfiles", file));
|
|
495
|
+
RED.log.warn("ttsultimate-config " + node.id + ": Deleted file " + path.join(node.userDir, "ttspermanentfiles", file));
|
|
475
496
|
try {
|
|
476
497
|
fs.unlinkSync(path.join(node.userDir, "ttspermanentfiles", file));
|
|
477
498
|
} catch (error) { }
|
|
@@ -502,11 +523,11 @@ module.exports = function (RED) {
|
|
|
502
523
|
node.noderedport = typeof config.noderedport === "undefined" ? "1980" : config.noderedport;
|
|
503
524
|
// 11/11/2019 NEW in V 1.1.0, changed webserver behaviour. Redirect pre V. 1.1.0 1880 ports to the nde default 1980
|
|
504
525
|
if (node.noderedport.trim() == "1880") {
|
|
505
|
-
RED.log.warn("ttsultimate-config: The webserver port ist 1880. Please change it to another port, not to conflict with default node-red 1880 port. I've changed this temporarly for you to 1980");
|
|
526
|
+
RED.log.warn("ttsultimate-config " + node.id + ": The webserver port ist 1880. Please change it to another port, not to conflict with default node-red 1880 port. I've changed this temporarly for you to 1980");
|
|
506
527
|
node.noderedport = "1980";
|
|
507
528
|
}
|
|
508
529
|
node.sNoderedURL = "http://" + node.noderedipaddress.trim() + ":" + node.noderedport.trim(); // 11/11/2019 New Endpoint to overcome https problem.
|
|
509
|
-
RED.log.info('ttsultimate-config: Node-Red node.js Endpoint will be created here: ' + node.sNoderedURL + "/tts");
|
|
530
|
+
RED.log.info('ttsultimate-config ' + node.id + ': Node-Red node.js Endpoint will be created here: ' + node.sNoderedURL + "/tts");
|
|
510
531
|
|
|
511
532
|
// 26/02/2020
|
|
512
533
|
if (node.purgediratrestart === "purge") {
|
|
@@ -516,7 +537,7 @@ module.exports = function (RED) {
|
|
|
516
537
|
try {
|
|
517
538
|
if (files.length > 0) {
|
|
518
539
|
files.forEach(function (file) {
|
|
519
|
-
RED.log.info("ttsultimate-config: Deleted TTS file " + path.join(node.userDir, "ttsfiles", file));
|
|
540
|
+
RED.log.info("ttsultimate-config " + node.id + ": Deleted TTS file " + path.join(node.userDir, "ttsfiles", file));
|
|
520
541
|
try {
|
|
521
542
|
fs.unlinkSync(path.join(node.userDir, "ttsfiles", file));
|
|
522
543
|
} catch (error) {
|
|
@@ -552,7 +573,7 @@ module.exports = function (RED) {
|
|
|
552
573
|
if (path.extname(query.f) === ".mp3" && path.dirname(path.dirname(query.f)).endsWith("sonospollyttsstorage")) {
|
|
553
574
|
var readStream = fs.createReadStream(query.f);
|
|
554
575
|
readStream.on("error", function (error) {
|
|
555
|
-
RED.log.error("ttsultimate-config: Playsonos error opening stream : " + query.f + ' : ' + error);
|
|
576
|
+
RED.log.error("ttsultimate-config " + node.id + ": Playsonos error opening stream : " + query.f + ' : ' + error);
|
|
556
577
|
res.end();
|
|
557
578
|
return;
|
|
558
579
|
});
|
|
@@ -565,13 +586,13 @@ module.exports = function (RED) {
|
|
|
565
586
|
// http://localhost:1980/tts?f=/etc/passwd
|
|
566
587
|
|
|
567
588
|
} else {
|
|
568
|
-
RED.log.error("ttsultimate-config: Playsonos RED.httpAdmin file not found: " + query.f);
|
|
589
|
+
RED.log.error("ttsultimate-config " + node.id + ": Playsonos RED.httpAdmin file not found: " + query.f);
|
|
569
590
|
res.write("File not found");
|
|
570
591
|
res.end();
|
|
571
592
|
}
|
|
572
593
|
|
|
573
594
|
} catch (error) {
|
|
574
|
-
RED.log.error("ttsultimate-config: Playsonos RED.httpAdmin error: " + error + " on: " + query.f);
|
|
595
|
+
RED.log.error("ttsultimate-config " + node.id + ": Playsonos RED.httpAdmin error: " + error + " on: " + query.f);
|
|
575
596
|
res.end();
|
|
576
597
|
}
|
|
577
598
|
|
|
@@ -581,23 +602,23 @@ module.exports = function (RED) {
|
|
|
581
602
|
try {
|
|
582
603
|
node.oWebserver = http.createServer(requestHandler);
|
|
583
604
|
node.oWebserver.on('error', function (e) {
|
|
584
|
-
RED.log.error("ttsultimate-config: " + node.ID + " error starting webserver on port " + sWebport + " " + e);
|
|
605
|
+
RED.log.error("ttsultimate-config " + node.id + ": " + node.ID + " error starting webserver on port " + sWebport + " " + e);
|
|
585
606
|
});
|
|
586
607
|
} catch (error) {
|
|
587
608
|
// Already open. Close it and redo.
|
|
588
|
-
RED.log.error("ttsultimate-config: Webserver creation error: " + error);
|
|
609
|
+
RED.log.error("ttsultimate-config " + node.id + ": Webserver creation error: " + error);
|
|
589
610
|
}
|
|
590
611
|
|
|
591
612
|
try {
|
|
592
613
|
node.oWebserver.listen(sWebport, (err) => {
|
|
593
614
|
if (err) {
|
|
594
|
-
RED.log.error("ttsultimate-config: error listening webserver on port " + sWebport + " " + err);
|
|
615
|
+
RED.log.error("ttsultimate-config " + node.id + ": error listening webserver on port " + sWebport + " " + err);
|
|
595
616
|
}
|
|
596
617
|
});
|
|
597
618
|
|
|
598
619
|
} catch (error) {
|
|
599
620
|
// In case oWebserver is null
|
|
600
|
-
RED.log.error("ttsultimate-config: error listening webserver on port " + sWebport + " " + error);
|
|
621
|
+
RED.log.error("ttsultimate-config " + node.id + ": error listening webserver on port " + sWebport + " " + error);
|
|
601
622
|
}
|
|
602
623
|
// #################################
|
|
603
624
|
|
|
@@ -607,7 +628,7 @@ module.exports = function (RED) {
|
|
|
607
628
|
node.on('close', function (done) {
|
|
608
629
|
// 11/11/2019 Close the Webserver
|
|
609
630
|
try {
|
|
610
|
-
node.oWebserver.close(function () { RED.log.info("ttsultimate-config: Webserver UP. Closing down."); });
|
|
631
|
+
node.oWebserver.close(function () { RED.log.info("ttsultimate-config " + node.id + ": Webserver UP. Closing down."); });
|
|
611
632
|
} catch (error) {
|
|
612
633
|
|
|
613
634
|
}
|
|
@@ -58,6 +58,11 @@
|
|
|
58
58
|
<label for="node-input-sonosvolume"><i class="fa fa-volume-up"></i> Volume</label>
|
|
59
59
|
<input type="text" id="node-input-sonosvolume" style="width:150px">
|
|
60
60
|
</div>
|
|
61
|
+
<div class="form-row">
|
|
62
|
+
<label for="node-input-unmuteIfMuted"><i class="fa fa-bell-slash-o"></i> Unmute</label>
|
|
63
|
+
<input type="checkbox" id="node-input-unmuteIfMuted" style="margin-left: 0px; vertical-align: top; width: auto !important;"> <label style="width:auto !important;"> Unmute, then restore previous state after play.</label>
|
|
64
|
+
</div>
|
|
65
|
+
|
|
61
66
|
<div class="form-row">
|
|
62
67
|
<label><i class="fa fa-upload"></i> Upload hail</label>
|
|
63
68
|
<input id="ownFileUpload" type="file" multiple="multiple">
|
|
@@ -128,7 +133,9 @@
|
|
|
128
133
|
rules: { value: [] },
|
|
129
134
|
playertype: { value: "sonos", required: false },
|
|
130
135
|
speakingrate: { value: "1", required: false },
|
|
131
|
-
speakingpitch: { value: "0", required: false}
|
|
136
|
+
speakingpitch: { value: "0", required: false },
|
|
137
|
+
unmuteIfMuted: { value: true }
|
|
138
|
+
|
|
132
139
|
},
|
|
133
140
|
inputs: 1,
|
|
134
141
|
outputs: 2,
|
|
@@ -216,7 +223,7 @@
|
|
|
216
223
|
.find('option')
|
|
217
224
|
.remove()
|
|
218
225
|
.end();
|
|
219
|
-
$.getJSON("ttsgetvoices?ttsservice=" + oNodeServer.ttsservice, new Date().getTime(), (data) => {
|
|
226
|
+
$.getJSON("ttsgetvoices" + encodeURIComponent(oNodeServer.id) + "?ttsservice=" + oNodeServer.ttsservice, new Date().getTime(), (data) => {
|
|
220
227
|
var aVoices = data.sort(compareVoices);
|
|
221
228
|
for (let index = 0; index < aVoices.length; index++) {
|
|
222
229
|
const oVoice = aVoices[index];
|
|
@@ -76,7 +76,9 @@ module.exports = function (RED) {
|
|
|
76
76
|
node.playertype = config.playertype === undefined ? "sonos" : config.playertype; // 20/09/2021 Player type
|
|
77
77
|
node.speakingpitch = config.speakingpitch === undefined ? "0" : config.speakingpitch; // 21/09/2021 AudioConfig speakingpitch
|
|
78
78
|
node.speakingrate = config.speakingrate === undefined ? "1" : config.speakingrate; // 21/09/2021 AudioConfig speakingrate
|
|
79
|
-
|
|
79
|
+
node.unmuteIfMuted = config.unmuteIfMuted === undefined ? false : config.unmuteIfMuted; // 21/10/2021 Unmute if previiously muted.
|
|
80
|
+
node.sonosCoordinatorIsPreviouslyMuted = false;
|
|
81
|
+
|
|
80
82
|
if (typeof node.server !== "undefined" && node.server !== null) {
|
|
81
83
|
node.sNoderedURL = node.server.sNoderedURL || "";
|
|
82
84
|
}
|
|
@@ -243,18 +245,29 @@ module.exports = function (RED) {
|
|
|
243
245
|
});
|
|
244
246
|
}
|
|
245
247
|
|
|
246
|
-
//
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
248
|
+
// 21/10/2021 Sync wrapper
|
|
249
|
+
function GETMutedSync() {
|
|
250
|
+
return new Promise((resolve, reject) => {
|
|
251
|
+
node.SonosClient.getMuted().then(state => {
|
|
252
|
+
resolve(state);
|
|
253
|
+
}).catch(err => {
|
|
254
|
+
RED.log.error("ttsultimate: Error GETMutedSync: " + err.message);
|
|
255
|
+
reject(err);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// 21/10/2021 Sync wrapper
|
|
261
|
+
function SETMutedSync(_muted) {
|
|
262
|
+
return new Promise((resolve, reject) => {
|
|
263
|
+
node.SonosClient.setMuted(_muted).then(state => {
|
|
264
|
+
resolve(state);
|
|
265
|
+
}).catch(err => {
|
|
266
|
+
RED.log.error("ttsultimate: Error SETMutedSync: " + err.message);
|
|
267
|
+
reject(err);
|
|
268
|
+
});
|
|
269
|
+
});
|
|
270
|
+
}
|
|
258
271
|
|
|
259
272
|
// 20/03/2020 Join Coordinator queue
|
|
260
273
|
// ######################################################
|
|
@@ -262,11 +275,12 @@ module.exports = function (RED) {
|
|
|
262
275
|
// 05/07/2021 Get the main coordinator player previous volume set by app
|
|
263
276
|
try {
|
|
264
277
|
node.sonosCoordinatorPreviousVolumeSetByApp = await GETVOLUMESync();
|
|
278
|
+
node.sonosCoordinatorIsPreviouslyMuted = await GETMutedSync();
|
|
265
279
|
} catch (error) {
|
|
266
280
|
node.sonosCoordinatorPreviousVolumeSetByApp = node.sSonosVolume;
|
|
281
|
+
node.sonosCoordinatorIsPreviouslyMuted = false;
|
|
267
282
|
}
|
|
268
283
|
// 30/03/2020 in the middle of coronavirus emergency. Group Speakers
|
|
269
|
-
// You don't have to worry about who is the coordinator.
|
|
270
284
|
for (let index = 0; index < node.oAdditionalSonosPlayers.length; index++) {
|
|
271
285
|
const element = node.oAdditionalSonosPlayers[index];
|
|
272
286
|
try {
|
|
@@ -280,6 +294,12 @@ module.exports = function (RED) {
|
|
|
280
294
|
} catch (error) {
|
|
281
295
|
RED.log.warn("ttsultimate: Error setting volume of joined device " + error.message);
|
|
282
296
|
}
|
|
297
|
+
// 21/10/2021 set the previous mute/unmute state
|
|
298
|
+
try {
|
|
299
|
+
element.isPreviouslyMuted = await element.getMuted();
|
|
300
|
+
} catch (error) {
|
|
301
|
+
RED.log.warn("ttsultimate: Error getMuted of joined device " + error.message);
|
|
302
|
+
}
|
|
283
303
|
};
|
|
284
304
|
}
|
|
285
305
|
|
|
@@ -291,6 +311,14 @@ module.exports = function (RED) {
|
|
|
291
311
|
} catch (error) {
|
|
292
312
|
RED.log.warn("ttsultimate: Error set preious volume on main coordinator in ungroupSpeakers " + error.message);
|
|
293
313
|
}
|
|
314
|
+
// 21/10/2021 Unmute?
|
|
315
|
+
if (node.unmuteIfMuted && node.sonosCoordinatorIsPreviouslyMuted) {
|
|
316
|
+
try {
|
|
317
|
+
await SETMutedSync(true);
|
|
318
|
+
} catch (error) {
|
|
319
|
+
RED.log.warn("ttsultimate: Error set preivous mute state on main coordinator in ungroupSpeakers " + error.message);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
294
322
|
|
|
295
323
|
for (let index = 0; index < node.oAdditionalSonosPlayers.length; index++) {
|
|
296
324
|
const element = node.oAdditionalSonosPlayers[index];
|
|
@@ -307,6 +335,14 @@ module.exports = function (RED) {
|
|
|
307
335
|
RED.log.warn("ttsultimate: Error set previous volume on group device " + error.message);
|
|
308
336
|
}
|
|
309
337
|
}
|
|
338
|
+
// 21/10/2021 Unmute?
|
|
339
|
+
if (node.unmuteIfMuted && element.isPreviouslyMuted) {
|
|
340
|
+
try {
|
|
341
|
+
await element.setMuted(true);
|
|
342
|
+
} catch (error) {
|
|
343
|
+
RED.log.warn("ttsultimate: Error set previous mute state on group device " + error.message);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
310
346
|
}
|
|
311
347
|
}
|
|
312
348
|
// ######################################################
|
|
@@ -617,12 +653,15 @@ module.exports = function (RED) {
|
|
|
617
653
|
volTemp = node.sSonosVolume;
|
|
618
654
|
}
|
|
619
655
|
await SETVOLUMESync(volTemp);
|
|
656
|
+
if (node.unmuteIfMuted) await SETMutedSync(false); // 21/10/2021 Unmute
|
|
657
|
+
|
|
620
658
|
if (node.oAdditionalSonosPlayers.length > 0) {
|
|
621
659
|
// 05/07/2021 set the volume of additional coordinatores
|
|
622
660
|
for (let index = 0; index < node.oAdditionalSonosPlayers.length; index++) {
|
|
623
661
|
const element = node.oAdditionalSonosPlayers[index];
|
|
624
662
|
try {
|
|
625
663
|
await element.setVolume(volTemp);
|
|
664
|
+
if (node.unmuteIfMuted) await element.setMuted(false); // 21/10/2021 Unmute
|
|
626
665
|
} catch (error) {
|
|
627
666
|
RED.log.error("ttsultimate: Handlequeue: Unable to set the volume on additional player " + error.message);
|
|
628
667
|
}
|
|
@@ -767,6 +806,10 @@ module.exports = function (RED) {
|
|
|
767
806
|
}
|
|
768
807
|
|
|
769
808
|
node.on('input', function (msg) {
|
|
809
|
+
// if (msg.hasOwnProperty("banana")) {
|
|
810
|
+
// node.SonosClient.setMuted(msg.banana);
|
|
811
|
+
// return;
|
|
812
|
+
// }
|
|
770
813
|
|
|
771
814
|
// 09/01/2021 Set the main player and groups IP on request
|
|
772
815
|
// *********************************
|
|
@@ -819,6 +862,12 @@ module.exports = function (RED) {
|
|
|
819
862
|
return;
|
|
820
863
|
}
|
|
821
864
|
|
|
865
|
+
|
|
866
|
+
// 21/10/2021 force unmute
|
|
867
|
+
if (msg.hasOwnProperty("unmute")) {
|
|
868
|
+
node.unmuteIfMuted = msg.unmute;
|
|
869
|
+
}
|
|
870
|
+
|
|
822
871
|
// 05/12/2020 handling Hailing
|
|
823
872
|
var hailingMSG = null;
|
|
824
873
|
if (msg.hasOwnProperty("nohailing") && (msg.nohailing == "1" || msg.nohailing.toLowerCase() == "true")) {
|
|
@@ -894,8 +943,7 @@ module.exports = function (RED) {
|
|
|
894
943
|
|
|
895
944
|
|
|
896
945
|
// 30/01/2021 split the text if it's too long, otherwies i'll have issues with filename too long.
|
|
897
|
-
|
|
898
|
-
if (msg.payload.length >= iLimitTTSFilenameLenght) {
|
|
946
|
+
if (msg.payload.length >= node.server.limitTTSFilenameLenght) {
|
|
899
947
|
let sTemp = "";
|
|
900
948
|
let aSeps = [".", ",", ":", ";", "!", "?"];
|
|
901
949
|
let sPayload = msg.payload.replace(/[\r\n]+/gm, "");
|
|
@@ -908,7 +956,7 @@ module.exports = function (RED) {
|
|
|
908
956
|
node.tempMSGStorage.push(oMsg);
|
|
909
957
|
sTemp = "";
|
|
910
958
|
}
|
|
911
|
-
if (sTemp.length >
|
|
959
|
+
if (sTemp.length > node.server.limitTTSFilenameLenght && element === " ") {
|
|
912
960
|
// Split using space
|
|
913
961
|
const oMsg = RED.util.cloneMessage(msg);
|
|
914
962
|
oMsg.payload = sTemp;
|
|
@@ -998,7 +1046,7 @@ module.exports = function (RED) {
|
|
|
998
1046
|
|
|
999
1047
|
// 12/10/2021 Microsoft Azure TTS Service
|
|
1000
1048
|
async function synthesizeSpeechMicrosoftAzureTTS(ttsService, params) {
|
|
1001
|
-
|
|
1049
|
+
|
|
1002
1050
|
return new Promise(function (resolve, reject) {
|
|
1003
1051
|
try {
|
|
1004
1052
|
|
|
@@ -1009,14 +1057,14 @@ module.exports = function (RED) {
|
|
|
1009
1057
|
params.text,
|
|
1010
1058
|
result => {
|
|
1011
1059
|
ttsService.close();
|
|
1012
|
-
resolve
|
|
1060
|
+
resolve(Buffer.from(result.audioData));
|
|
1013
1061
|
},
|
|
1014
1062
|
error => {
|
|
1015
1063
|
ttsService.close();
|
|
1016
|
-
reject
|
|
1064
|
+
reject(error);
|
|
1017
1065
|
});
|
|
1018
1066
|
} catch (error) {
|
|
1019
|
-
reject
|
|
1067
|
+
reject(error);
|
|
1020
1068
|
}
|
|
1021
1069
|
});
|
|
1022
1070
|
};
|