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.
- package/.vscode/launch.json +1 -1
- package/CHANGELOG.md +35 -19
- package/README.md +3 -3
- package/package.json +3 -2
- package/ttsultimate/ownfileultimate.html +1 -1
- package/ttsultimate/ttsultimate-config.html +11 -10
- package/ttsultimate/ttsultimate-config.js +36 -26
- package/ttsultimate/ttsultimate.html +3 -3
- package/ttsultimate/ttsultimate.js +27 -18
package/.vscode/launch.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -2,97 +2,113 @@
|
|
|
2
2
|
|
|
3
3
|
[](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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
69
|
+
</p>
|
|
55
70
|
<p>
|
|
56
71
|
<b>Version 1.0.27</b> September 2021<br/>
|
|
57
72
|
- Hided some unwanted logs.<br/>
|
|
58
|
-
|
|
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
|
-
|
|
77
|
+
</p>
|
|
63
78
|
<p>
|
|
64
79
|
<b>Version 1.0.25</b> August 2021<br/>
|
|
65
80
|
- Optimized setting volume speed.<br/>
|
|
66
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
38
|
+
// $.getJSON('ttsultimateGetEthAddress', (data) => {
|
|
39
|
+
$("#pleaseDeploy").hide();
|
|
39
40
|
$("#allGUI").show();
|
|
40
|
-
}).fail(function (jqxhr) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
});
|
|
41
|
+
// }).fail(function (jqxhr) {
|
|
42
|
+
// $("#pleaseDeploy").show();
|
|
43
|
+
// $("#allGUI").hide();
|
|
44
|
+
// });
|
|
44
45
|
|
|
45
|
-
|
|
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 =
|
|
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
|
-
|
|
239
|
+
return(jListInterfaces[0].address); // Retunr the first usable IP
|
|
233
240
|
} else {
|
|
234
|
-
|
|
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
|
-
|
|
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")
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
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
|
|
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
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
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]);
|