node-red-contrib-tts-ultimate 1.0.41 → 1.0.44
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 +15 -0
- package/README.md +12 -8
- package/package.json +1 -1
- package/ttsultimate/ownfileultimate.html +1 -1
- package/ttsultimate/ttsultimate-config.html +11 -10
- package/ttsultimate/ttsultimate-config.js +29 -25
- package/ttsultimate/ttsultimate.html +33 -16
- package/ttsultimate/ttsultimate.js +47 -30
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,21 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.paypal.me/techtoday)
|
|
4
4
|
|
|
5
|
+
<p>
|
|
6
|
+
<b>Version 1.0.44</b> April 2022<br/>
|
|
7
|
+
- NEW: you can now adjust the additional player's volume, adapting it to the main sonos player volume. This is useful in case you've some recessed speakers, "speaking" too low or some too near speakers, "speaking" too high. You can adapt the volume in the config window or dinamically via msg input.<br/>
|
|
8
|
+
- Updated the README.<br/>
|
|
9
|
+
</p>
|
|
10
|
+
<p>
|
|
11
|
+
<b>Version 1.0.43</b> March 2022<br/>
|
|
12
|
+
- Simplified the configuration by auto discover some IP.<br/>
|
|
13
|
+
- FIX: fixed minor glitches.<br/>
|
|
14
|
+
</p>
|
|
15
|
+
<p>
|
|
16
|
+
<b>Version 1.0.42</b> March 2022<br/>
|
|
17
|
+
- FIX: fix purging option that wasn't working if you set to always purge the cached files at startup.<br/>
|
|
18
|
+
- FIX: invalid code in some sync functions.<br/>
|
|
19
|
+
</p>
|
|
5
20
|
<p>
|
|
6
21
|
<b>Version 1.0.41</b> March 2022<br/>
|
|
7
22
|
- NEW: for Polly TTS, you can choose between neural and standard engine.<br/>
|
package/README.md
CHANGED
|
@@ -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.
|
|
@@ -169,7 +169,8 @@ Select your Sonos primary player. (It's strongly suggested to set a fixed IP for
|
|
|
169
169
|
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.
|
|
170
170
|
|
|
171
171
|
**Additional Players** <br/>
|
|
172
|
-
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
|
|
172
|
+
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/>
|
|
173
|
+
For each additional player, you can adjust their volume, based on the **Main Sonos Player** volume -+100.
|
|
173
174
|
|
|
174
175
|
|
|
175
176
|
## INPUT MESSAGES TO THE NODE <br/>
|
|
@@ -287,7 +288,9 @@ The setting is retained until the node receives another msg.setConfig or until n
|
|
|
287
288
|
|
|
288
289
|
> **property setPlayerGroupArray**<br/>
|
|
289
290
|
Sets the array of players beloging to the group, if any.<br/>
|
|
290
|
-
|
|
291
|
+
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/>
|
|
292
|
+
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/>
|
|
293
|
+
Note: Even if you have only one additional player, you need to put it into an array.
|
|
291
294
|
|
|
292
295
|
```js
|
|
293
296
|
// Set main player IP
|
|
@@ -300,14 +303,15 @@ return msg;
|
|
|
300
303
|
```
|
|
301
304
|
|
|
302
305
|
```js
|
|
303
|
-
// Set player IP and additional players
|
|
306
|
+
// Set player IP and additional players with their optional adapted volume, relative to the main sonos player volume.
|
|
307
|
+
// You can specify the aditional player's volume adaptation
|
|
304
308
|
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
305
309
|
var config= {
|
|
306
310
|
setMainPlayerIP:"192.168.1.109",
|
|
307
311
|
setPlayerGroupArray:[
|
|
308
|
-
"192.168.1.110",
|
|
309
|
-
"192.168.1.111",
|
|
310
|
-
"192.168.1.112"
|
|
312
|
+
"192.168.1.110", // This additional player will use the same volume as the main sonos player.
|
|
313
|
+
"192.168.1.111#-10", // This additional player will use the main sonos player's volume, minus 10.
|
|
314
|
+
"192.168.1.112#20" // This additional player will use the main sonos player's volume, plus 20.
|
|
311
315
|
]
|
|
312
316
|
};
|
|
313
317
|
msg.setConfig = config;
|
|
@@ -315,7 +319,7 @@ return msg;
|
|
|
315
319
|
```
|
|
316
320
|
|
|
317
321
|
```js
|
|
318
|
-
// If you have only one additional player
|
|
322
|
+
// If you have only one additional player, without setting their adjusted volume.
|
|
319
323
|
// The setting is retained until the node receives another msg.setConfig or until node-red is restarted.
|
|
320
324
|
var config= {
|
|
321
325
|
setMainPlayerIP:"192.168.1.109",
|
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.44",
|
|
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": {
|
|
@@ -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 = [];
|
|
@@ -538,22 +544,20 @@ module.exports = function (RED) {
|
|
|
538
544
|
if (node.purgediratrestart === "purge") {
|
|
539
545
|
// Delete all files, that are'nt OwnFiles_
|
|
540
546
|
try {
|
|
541
|
-
fs.readdirSync(path.join(node.TTSRootFolderPath, "ttsfiles")
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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) { }
|
|
553
559
|
|
|
554
|
-
}
|
|
555
560
|
|
|
556
|
-
});
|
|
557
561
|
} catch (error) { }
|
|
558
562
|
};
|
|
559
563
|
|
|
@@ -572,13 +576,13 @@ module.exports = function (RED) {
|
|
|
572
576
|
var query = url_parts.query;
|
|
573
577
|
|
|
574
578
|
res.setHeader('Content-Disposition', 'attachment; filename=tts.mp3')
|
|
575
|
-
if (fs.existsSync(query.f)) {
|
|
579
|
+
if (fs.existsSync(query.f.toString())) {
|
|
576
580
|
// 26/01/2021 security check
|
|
577
581
|
// File should be something like mydocs/.node-red/sonospollyttsstorage/ttsfiles/Hello_de-DE.mp3
|
|
578
|
-
if (path.extname(query.f) === ".mp3" && path.dirname(path.dirname(query.f)).endsWith("sonospollyttsstorage")) {
|
|
579
|
-
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());
|
|
580
584
|
readStream.on("error", function (error) {
|
|
581
|
-
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);
|
|
582
586
|
res.end();
|
|
583
587
|
return;
|
|
584
588
|
});
|
|
@@ -637,7 +641,7 @@ module.exports = function (RED) {
|
|
|
637
641
|
} catch (error) {
|
|
638
642
|
|
|
639
643
|
}
|
|
640
|
-
setTimeout(function () {
|
|
644
|
+
let t = setTimeout(function () {
|
|
641
645
|
// Wait some time to allow time to do promises.
|
|
642
646
|
done();
|
|
643
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 === "") {
|
|
@@ -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);
|
|
@@ -402,16 +402,32 @@
|
|
|
402
402
|
//#region ADDITIONAL PLAYERS
|
|
403
403
|
// 20/03/2020 ADDITIONAL PLAYERS
|
|
404
404
|
// ##########################################################
|
|
405
|
-
var previousValueType = { value: "prev", label: this._("switch.previous"), hasValue: false };
|
|
405
|
+
//var previousValueType = { value: "prev", label: this._("switch.previous"), hasValue: false };
|
|
406
|
+
|
|
407
|
+
// Add Selectbox with the volume for the additional players
|
|
408
|
+
function addAdditionalPlayerVolumeUI(row, _currentVolume = 0) {
|
|
409
|
+
let oAdjustVolume = $('<select/>', { class: "rowRulePlayerHostAdjustVolume", type: "text", style: "width:200px; margin-left: 5px; text-align: left;" }).appendTo(row);
|
|
410
|
+
for (let index = -100; index < 100; index += 5) {
|
|
411
|
+
let sTesto = "";
|
|
412
|
+
if (index === 0) sTesto = "Same volume as Main Sonos Player";
|
|
413
|
+
if (index < 0) sTesto = "Decrease volume by " + Math.abs(index) ;
|
|
414
|
+
if (index > 0) sTesto = "Increase volume by " + index;
|
|
415
|
+
oAdjustVolume.append($("<option></option>")
|
|
416
|
+
.attr("value", index)
|
|
417
|
+
.text(sTesto)
|
|
418
|
+
)
|
|
419
|
+
}
|
|
420
|
+
oAdjustVolume.val(_currentVolume);
|
|
421
|
+
}
|
|
406
422
|
function resizeRule(rule) { }
|
|
423
|
+
|
|
407
424
|
$("#node-input-rule-container").css('min-height', '150px').css('min-width', '450px').editableList({
|
|
408
425
|
addItem: function (container, i, opt) { // row, index, data
|
|
409
|
-
// opt.r is: { topic: rowRuleTopic, devicename: rowRuleDeviceName, dpt:rowRuleDPT, send: rowRuleSend}
|
|
410
426
|
|
|
411
427
|
if (!opt.hasOwnProperty('r')) {
|
|
412
428
|
opt.r = {};
|
|
413
429
|
}
|
|
414
|
-
|
|
430
|
+
let rule = opt.r;
|
|
415
431
|
if (!opt.hasOwnProperty('i')) {
|
|
416
432
|
opt._i = Math.floor((0x99999 - 0x10000) * Math.random()).toString();
|
|
417
433
|
}
|
|
@@ -422,8 +438,7 @@
|
|
|
422
438
|
|
|
423
439
|
|
|
424
440
|
var row = $('<div class="form-row"/>').appendTo(container);
|
|
425
|
-
var oPlayer = $('<label>Discovering.... wait...</label>', { class: "rowRulePlayerHost", type: "text", style: "width:
|
|
426
|
-
|
|
441
|
+
var oPlayer = $('<label>Discovering.... wait...</label>', { class: "rowRulePlayerHost", type: "text", style: "width:200px; margin-left: 5px; text-align: left;" }).appendTo(row);
|
|
427
442
|
oPlayer.on("change", function () {
|
|
428
443
|
resizeRule(container);
|
|
429
444
|
});
|
|
@@ -432,16 +447,18 @@
|
|
|
432
447
|
if (typeof data === "string" && data == "ERRORDISCOVERY") { // 10/04/2020 if error in discovery, fallback to manual IP input
|
|
433
448
|
// Transform the dropdown to a simple input
|
|
434
449
|
oPlayer.remove();
|
|
435
|
-
oPlayer = $('<input/>', { class: "rowRulePlayerHost", type: "text", style: "width:
|
|
450
|
+
oPlayer = $('<input/>', { class: "rowRulePlayerHost", type: "text", style: "width:200px; margin-left: 5px; text-align: left;" }).appendTo(row);
|
|
451
|
+
addAdditionalPlayerVolumeUI(row, rule.hostVolumeAdjust);
|
|
436
452
|
} else {
|
|
437
453
|
oPlayer.remove();
|
|
438
|
-
oPlayer = $('<select/>', { class: "rowRulePlayerHost", type: "text", style: "width:
|
|
454
|
+
oPlayer = $('<select/>', { class: "rowRulePlayerHost", type: "text", style: "width:200px; margin-left: 5px; text-align: left;" }).appendTo(row);
|
|
439
455
|
data.sort().forEach(oGroup => {
|
|
440
456
|
oPlayer.append($("<option></option>")
|
|
441
457
|
.attr("value", oGroup.host)
|
|
442
458
|
.text(oGroup.name + " (" + oGroup.host + ")")
|
|
443
459
|
)
|
|
444
460
|
});
|
|
461
|
+
addAdditionalPlayerVolumeUI(row, rule.hostVolumeAdjust);
|
|
445
462
|
}
|
|
446
463
|
oPlayer.val(rule.host);
|
|
447
464
|
});
|
|
@@ -460,7 +477,7 @@
|
|
|
460
477
|
|
|
461
478
|
// 20/03/2020 For each rule, create a row
|
|
462
479
|
for (var i = 0; i < this.rules.length; i++) {
|
|
463
|
-
|
|
480
|
+
let rule = this.rules[i];
|
|
464
481
|
$("#node-input-rule-container").editableList('addItem', { r: rule, i: i });
|
|
465
482
|
}
|
|
466
483
|
// ##########################################################
|
|
@@ -469,14 +486,14 @@
|
|
|
469
486
|
node.refreshHailingList();
|
|
470
487
|
|
|
471
488
|
}, oneditsave: function () {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
var rules = $("#node-input-rule-container").editableList('items');
|
|
489
|
+
let node = this;
|
|
490
|
+
let rules = $("#node-input-rule-container").editableList('items');
|
|
475
491
|
node.rules = [];
|
|
476
492
|
rules.each(function (i) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
493
|
+
let rule = $(this);
|
|
494
|
+
let rowRulePlayerHost = rule.find(".rowRulePlayerHost").val();
|
|
495
|
+
let rowRulePlayerHostAdjustVolume = rule.find(".rowRulePlayerHostAdjustVolume").val();
|
|
496
|
+
node.rules.push({ host: rowRulePlayerHost, hostVolumeAdjust: rowRulePlayerHostAdjustVolume });
|
|
480
497
|
});
|
|
481
498
|
this.propertyType = $("#node-input-property").typedInput('type');
|
|
482
499
|
},
|
|
@@ -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 => {
|
|
@@ -282,7 +283,7 @@ module.exports = function (RED) {
|
|
|
282
283
|
}
|
|
283
284
|
// 30/03/2020 in the middle of coronavirus emergency. Group Speakers
|
|
284
285
|
for (let index = 0; index < node.oAdditionalSonosPlayers.length; index++) {
|
|
285
|
-
const element = node.oAdditionalSonosPlayers[index];
|
|
286
|
+
const element = node.oAdditionalSonosPlayers[index].oPlayer;
|
|
286
287
|
try {
|
|
287
288
|
await element.joinGroup(node.sonosCoordinatorGroupName);
|
|
288
289
|
} catch (error) {
|
|
@@ -321,7 +322,7 @@ module.exports = function (RED) {
|
|
|
321
322
|
}
|
|
322
323
|
|
|
323
324
|
for (let index = 0; index < node.oAdditionalSonosPlayers.length; index++) {
|
|
324
|
-
const element = node.oAdditionalSonosPlayers[index];
|
|
325
|
+
const element = node.oAdditionalSonosPlayers[index].oPlayer;
|
|
325
326
|
try {
|
|
326
327
|
await element.leaveGroup();
|
|
327
328
|
} catch (error) {
|
|
@@ -400,9 +401,10 @@ module.exports = function (RED) {
|
|
|
400
401
|
});
|
|
401
402
|
// Fill the node.oAdditionalSonosPlayers with all sonos object in the rules
|
|
402
403
|
for (let index = 0; index < node.rules.length; index++) {
|
|
403
|
-
const element = node.rules[index];
|
|
404
|
-
|
|
405
|
-
|
|
404
|
+
const element = node.rules[index]; // Rule row is {host:"192.168.1.12,hostVolumeAdjust:0}
|
|
405
|
+
// 12/04/2022 Create an object containing the addidtional player and the adapted volume
|
|
406
|
+
node.oAdditionalSonosPlayers.push({ oPlayer: new sonos.Sonos(element.host), hostVolumeAdjust: Number(element.hostVolumeAdjust) });
|
|
407
|
+
RED.log.info("ttsultimate: FOUND ADDITIONAL PLAYER " + element.host + " Adjusted volume: " + element.hostVolumeAdjust);
|
|
406
408
|
}
|
|
407
409
|
|
|
408
410
|
|
|
@@ -509,7 +511,7 @@ module.exports = function (RED) {
|
|
|
509
511
|
}
|
|
510
512
|
}
|
|
511
513
|
}
|
|
512
|
-
setTimeout(() => { return true; }, 5000); // Wait some seconds
|
|
514
|
+
let t = setTimeout(() => { return true; }, 5000); // Wait some seconds
|
|
513
515
|
};
|
|
514
516
|
|
|
515
517
|
// Handle the queue
|
|
@@ -619,13 +621,14 @@ module.exports = function (RED) {
|
|
|
619
621
|
data = await synthesizeSpeechMicrosoftAzureTTS(node.server.microsoftAzureTTS, params);
|
|
620
622
|
}
|
|
621
623
|
// Save the downloaded file into the cache
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
}
|
|
624
|
+
try {
|
|
625
|
+
fs.writeFileSync(sFileToBePlayed, data);
|
|
626
|
+
} catch (error) {
|
|
627
|
+
RED.log.error("ttsultimate: node id: " + node.id + " Unable to save the file " + error.message);
|
|
628
|
+
node.setNodeStatus({ fill: "red", shape: "ring", text: "Unable to save the file " + sFileToBePlayed + " " + error.message });
|
|
629
|
+
throw (error);
|
|
630
|
+
}
|
|
631
|
+
|
|
629
632
|
} catch (error) {
|
|
630
633
|
RED.log.error("ttsultimate: node id: " + node.id + " Error Downloading TTS: " + error.message + ". THE TTS SERVICE MAY BE DOWN.");
|
|
631
634
|
node.setNodeStatus({ fill: 'red', shape: 'ring', text: 'Error Downloading TTS:' + error.message });
|
|
@@ -653,21 +656,26 @@ module.exports = function (RED) {
|
|
|
653
656
|
|
|
654
657
|
// Set Volume
|
|
655
658
|
try {
|
|
656
|
-
let volTemp = 0
|
|
659
|
+
let volTemp = 0;
|
|
657
660
|
if (node.currentMSGbeingSpoken.hasOwnProperty("volume")) {
|
|
658
|
-
volTemp = node.currentMSGbeingSpoken.volume;
|
|
661
|
+
volTemp = Number(node.currentMSGbeingSpoken.volume);
|
|
659
662
|
} else {
|
|
660
|
-
volTemp = node.sSonosVolume;
|
|
663
|
+
volTemp = Number(node.sSonosVolume);
|
|
661
664
|
}
|
|
662
665
|
await SETVOLUMESync(volTemp);
|
|
663
666
|
if (node.unmuteIfMuted) await SETMutedSync(false); // 21/10/2021 Unmute
|
|
664
667
|
|
|
665
668
|
if (node.oAdditionalSonosPlayers.length > 0) {
|
|
666
|
-
// 05/07/2021 set the volume of additional
|
|
669
|
+
// 05/07/2021 set the volume of additional coordinators
|
|
667
670
|
for (let index = 0; index < node.oAdditionalSonosPlayers.length; index++) {
|
|
668
|
-
const element = node.oAdditionalSonosPlayers[index];
|
|
671
|
+
const element = node.oAdditionalSonosPlayers[index].oPlayer;
|
|
672
|
+
//node.oAdditionalSonosPlayers.push({ oPlayer: new sonos.Sonos(element.host), hostVolumeAdjust: element.hostVolumeAdjust });
|
|
669
673
|
try {
|
|
670
|
-
|
|
674
|
+
// 12/04/20222 Set the adjusted volume, based on the main player volume + the adjusted volume in %
|
|
675
|
+
let iAdjustedVol = Number(volTemp) + Number((node.oAdditionalSonosPlayers[index].hostVolumeAdjust || 0));
|
|
676
|
+
if (iAdjustedVol < 0) iAdjustedVol = 0;
|
|
677
|
+
if (iAdjustedVol > 100) iAdjustedVol = 100;
|
|
678
|
+
await element.setVolume(iAdjustedVol);
|
|
671
679
|
if (node.unmuteIfMuted) await element.setMuted(false); // 21/10/2021 Unmute
|
|
672
680
|
} catch (error) {
|
|
673
681
|
RED.log.error("ttsultimate: Handlequeue: Unable to set the volume on additional player " + error.message);
|
|
@@ -781,7 +789,7 @@ module.exports = function (RED) {
|
|
|
781
789
|
}
|
|
782
790
|
|
|
783
791
|
// Signal end playing
|
|
784
|
-
setTimeout(() => {
|
|
792
|
+
let t = setTimeout(() => {
|
|
785
793
|
node.msg.completed = true;
|
|
786
794
|
node.currentMSGbeingSpoken = {};
|
|
787
795
|
node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed }, null]);
|
|
@@ -794,7 +802,7 @@ module.exports = function (RED) {
|
|
|
794
802
|
// Output the array of files
|
|
795
803
|
|
|
796
804
|
// Signal end playing
|
|
797
|
-
setTimeout(() => {
|
|
805
|
+
let t = setTimeout(() => {
|
|
798
806
|
node.msg.completed = true;
|
|
799
807
|
node.currentMSGbeingSpoken = {};
|
|
800
808
|
node.send([{ passThroughMessage: node.passThroughMessage, payload: node.msg.completed, filesArray: noPlayerFileArray }, null]);
|
|
@@ -841,9 +849,18 @@ module.exports = function (RED) {
|
|
|
841
849
|
// Fill the node.oAdditionalSonosPlayers with all sonos IPs in the setPlayerGroupArray
|
|
842
850
|
node.oAdditionalSonosPlayers = [];
|
|
843
851
|
for (let index = 0; index < msg.setConfig.setPlayerGroupArray.length; index++) {
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
|
|
852
|
+
const sRow = msg.setConfig.setPlayerGroupArray[index];
|
|
853
|
+
let host = "";
|
|
854
|
+
let hostVolumeAdjust = 0;
|
|
855
|
+
if (sRow.includes("#")) {
|
|
856
|
+
host = sRow.split("#")[0];
|
|
857
|
+
hostVolumeAdjust = sRow.split("#")[1];
|
|
858
|
+
} else {
|
|
859
|
+
host = sRow;
|
|
860
|
+
}
|
|
861
|
+
//node.oAdditionalSonosPlayers.push({ oPlayer: new sonos.Sonos(element.host), hostVolumeAdjust: element.hostVolumeAdjust });
|
|
862
|
+
node.oAdditionalSonosPlayers.push({ oPlayer: new sonos.Sonos(host), hostVolumeAdjust: Number(hostVolumeAdjust) });
|
|
863
|
+
RED.log.info("ttsultimate: new group player set by msg: " + host + " adjusted volume: " + Number(hostVolumeAdjust));
|
|
847
864
|
}
|
|
848
865
|
};
|
|
849
866
|
};
|