iobroker.squeezeboxrpc 1.3.14 → 1.3.16
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/README.md +9 -0
- package/io-package.json +27 -27
- package/lib/iosbplayer.js +50 -2
- package/lib/iosbserver.js +319 -329
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -201,6 +201,15 @@ For more information visit the CLI-documentation:
|
|
|
201
201
|
Placeholder for the next version (at the beginning of the line):
|
|
202
202
|
### **WORK IN PROGRESS**
|
|
203
203
|
-->
|
|
204
|
+
### 1.3.16 (2024-10-23)
|
|
205
|
+
|
|
206
|
+
- fixed icons of the favorites widget
|
|
207
|
+
|
|
208
|
+
### 1.3.15 (2024-08-09)
|
|
209
|
+
|
|
210
|
+
- due to a adapter checker issue i have to remove the release 1.3.13 from npm.
|
|
211
|
+
but changes from 1.3.13 are included in 1.3.14
|
|
212
|
+
|
|
204
213
|
### 1.3.14 (2024-08-05)
|
|
205
214
|
|
|
206
215
|
- fix formatting
|
package/io-package.json
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
{
|
|
2
2
|
"common": {
|
|
3
3
|
"name": "squeezeboxrpc",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.16",
|
|
5
5
|
"news": {
|
|
6
|
+
"1.3.16": {
|
|
7
|
+
"en": "fixed icons of the favorites widget",
|
|
8
|
+
"de": "feste symbole der favoriten widget",
|
|
9
|
+
"ru": "фиксированные иконы любимого виджета",
|
|
10
|
+
"pt": "ícones fixos do widget favorito",
|
|
11
|
+
"nl": "vaste pictogrammen van de favorieten widget",
|
|
12
|
+
"fr": "icônes fixes du widget favori",
|
|
13
|
+
"it": "icone fisse del widget preferiti",
|
|
14
|
+
"es": "iconos fijos de los favoritos widget",
|
|
15
|
+
"pl": "stałe ikony ulubionego widgetu",
|
|
16
|
+
"uk": "фіксовані ікони улюбленого віджету",
|
|
17
|
+
"zh-cn": "最爱部件的固定图标"
|
|
18
|
+
},
|
|
19
|
+
"1.3.15": {
|
|
20
|
+
"en": "- due to a adapter checker issue i have to remove the release 1.3.13 from npm.\n but changes from 1.3.13 are included in 1.3.14",
|
|
21
|
+
"de": "- wegen eines adapter-checker-problems muss ich das release 1.3.13 von npm entfernen.\nänderungen von 1.3.13 sind in 1.3.14 enthalten",
|
|
22
|
+
"ru": "- из-за проблемы с адаптером, я должен удалить выпуск 1.3.13 из npm.\nно изменения от 1.3.13 включены в подраздел 1.3.14",
|
|
23
|
+
"pt": "- devido a um problema do verificador do adaptador eu tenho que remover a liberação 1.3.13 da npm.\nmas as alterações de 1.3.13 estão incluídas em 1.3.14",
|
|
24
|
+
"nl": "- vanwege een probleem met de adaptercontrole moet ik de release 1.3.13 van npm verwijderen.\nmaar wijzigingen van 1.3.13 zijn opgenomen in 1.3.14",
|
|
25
|
+
"fr": "- en raison d'un problème d'adaptateur, je dois supprimer la version 1.3.13 de npm.\nmais les changements par rapport au 1.3.13 sont inclus dans le 1.3.14",
|
|
26
|
+
"it": "- a causa di un problema dell'adattatore checker devo rimuovere il rilascio 1.3.13 da npm.\nma le modifiche da 1.3.13 sono incluse in 1.3.14",
|
|
27
|
+
"es": "- debido a un problema de control de adaptador tengo que eliminar la liberación 1.3.13 de npm.\npero los cambios de 1.3.13 se incluyen en 1.3.14",
|
|
28
|
+
"pl": "- ze względu na problem sprawdzania adaptera muszę usunąć zwolnienie 1.3.13 z npm.\nale zmiany z 1.3.13 są zawarte w 1.3.14",
|
|
29
|
+
"uk": "- через проблему перевірки адаптера я повинен видалити реліз 1.3.13 з npm.\nале зміни від 1.3.13 включені в 1.3.14",
|
|
30
|
+
"zh-cn": "- 因为适配器检查器的问题,我不得不从npm中移除1.3.13的发布.\n但从1.3.13到1.3.14的变动已包括在内"
|
|
31
|
+
},
|
|
6
32
|
"1.3.14": {
|
|
7
33
|
"en": "fix formatting",
|
|
8
34
|
"de": "fixe formatierung",
|
|
@@ -16,19 +42,6 @@
|
|
|
16
42
|
"uk": "фіксувати форматування",
|
|
17
43
|
"zh-cn": "固定格式化"
|
|
18
44
|
},
|
|
19
|
-
"1.3.13": {
|
|
20
|
-
"en": "revert the fix for artist handling due to negative effect of spotify",
|
|
21
|
-
"de": "die fix für die künstlerhandhabung aufgrund negativer wirkung von spotify",
|
|
22
|
-
"ru": "возвратить фиксацию для работы с художником из-за негативного эффекта спотификации",
|
|
23
|
-
"pt": "reverter a correção para manipulação de artista devido ao efeito negativo de identificar",
|
|
24
|
-
"nl": "terugzetten van de fix voor artist handling als gevolg van negatief effect van spotify",
|
|
25
|
-
"fr": "retourner la correction pour la manipulation de l'artiste en raison de l'effet négatif de spotify",
|
|
26
|
-
"it": "ripristinare la correzione per la gestione dell'artista a causa dell'effetto negativo di spotify",
|
|
27
|
-
"es": "revertir la fijación para el manejo del artista debido al efecto negativo de spotify",
|
|
28
|
-
"pl": "revert fix do obsługi artysty ze względu na negatywny efekt spotify",
|
|
29
|
-
"uk": "перевернути фіксацію для обробки художника через негативний ефект плямистості",
|
|
30
|
-
"zh-cn": "恢复对艺术家处理的固定,因为发现有负面影响"
|
|
31
|
-
},
|
|
32
45
|
"1.3.12": {
|
|
33
46
|
"en": "improve cmdGoto handling by kairauer, close PR #74\nfix issues from adapter checker\nintegrate squeezenode lib",
|
|
34
47
|
"de": "verbessern cmd Goto Handling von kairauer, close PR #74\nprobleme von adapter checker beheben\npressnode lib integrieren",
|
|
@@ -80,19 +93,6 @@
|
|
|
80
93
|
"pl": "* napraw błąd przy usuwaniu ulubionych * napraw błędny typ punktu danych",
|
|
81
94
|
"uk": "* виправити помилку з видаленням вибраного * виправити неправильний тип точки даних",
|
|
82
95
|
"zh-cn": "* 修复删除收藏夹时的错误 * 修复数据点的错误类型"
|
|
83
|
-
},
|
|
84
|
-
"1.3.8": {
|
|
85
|
-
"en": "* fix object forward btn widget",
|
|
86
|
-
"de": "* Objekt-Weiterleitungs-BTN-Widget korrigiert",
|
|
87
|
-
"ru": "* исправлен виджет кнопки вперед объекта",
|
|
88
|
-
"pt": "* corrigir widget de btn de encaminhamento de objeto",
|
|
89
|
-
"nl": "* fix object voorwaartse btn-widget",
|
|
90
|
-
"fr": "* Correction du widget btn de transfert d'objet",
|
|
91
|
-
"it": "* corretto il widget oggetto forward btn",
|
|
92
|
-
"es": "* arreglar el widget btn de reenvío de objetos",
|
|
93
|
-
"pl": "* napraw widget btn do przesyłania obiektów",
|
|
94
|
-
"uk": "* виправити віджет btn для пересилання об’єктів",
|
|
95
|
-
"zh-cn": "* 修复对象转发 btn 小部件"
|
|
96
96
|
}
|
|
97
97
|
},
|
|
98
98
|
"titleLang": {
|
package/lib/iosbplayer.js
CHANGED
|
@@ -499,9 +499,11 @@ function ioSBPlayer(server, playerdata) {
|
|
|
499
499
|
|
|
500
500
|
}
|
|
501
501
|
};
|
|
502
|
-
this.init = function (playerdata) {
|
|
502
|
+
this.init = async function (playerdata) {
|
|
503
503
|
this.doPlayerStatus(playerdata);
|
|
504
504
|
this.logdebug("New Player found: " + this.playername + " with id " + this.playerid);
|
|
505
|
+
await this.createFolder(this.statePath);
|
|
506
|
+
await this.createDevice(this.playername, this.statePath);
|
|
505
507
|
const delay = this.playerindex || 0;
|
|
506
508
|
setTimeout(this.doObserverPlayer.bind(this), delay * 190);
|
|
507
509
|
};
|
|
@@ -821,7 +823,7 @@ function ioSBPlayer(server, playerdata) {
|
|
|
821
823
|
};
|
|
822
824
|
this.createState = function (stateTemplate, level1path = false, level2path = false) {
|
|
823
825
|
const name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + stateTemplate.name;
|
|
824
|
-
this.logsilly("Create
|
|
826
|
+
this.logsilly("Create state " + name);
|
|
825
827
|
if (!this.currentStates[name]) this.adapter.createState(level1path, level2path, stateTemplate.name, stateTemplate);
|
|
826
828
|
stateTemplate.exist = true;
|
|
827
829
|
return stateTemplate;
|
|
@@ -860,6 +862,52 @@ function ioSBPlayer(server, playerdata) {
|
|
|
860
862
|
this.adapter.setState(name, value, true);
|
|
861
863
|
}
|
|
862
864
|
};
|
|
865
|
+
this.createFolder = async function (foldername, level1path, level2path) {
|
|
866
|
+
const id = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + foldername;
|
|
867
|
+
this.logsilly("createFolder " + id);
|
|
868
|
+
if (await this.existsObjectAsync(id)) {
|
|
869
|
+
this.logsilly("Folder exists: " + id);
|
|
870
|
+
} else {
|
|
871
|
+
const obj = {
|
|
872
|
+
type: "folder",
|
|
873
|
+
common: {
|
|
874
|
+
name: foldername
|
|
875
|
+
},
|
|
876
|
+
native: {}
|
|
877
|
+
};
|
|
878
|
+
this.adapter.setObject(id, obj);
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
this.createDevice = async function (devicename, level1path, level2path) {
|
|
882
|
+
const id = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + devicename;
|
|
883
|
+
this.logsilly("createDevice " + id);
|
|
884
|
+
if (await this.existsObjectAsync(id)) {
|
|
885
|
+
this.logsilly("Device exists: " + id);
|
|
886
|
+
} else {
|
|
887
|
+
const obj = {
|
|
888
|
+
type: "device",
|
|
889
|
+
common: {
|
|
890
|
+
name: devicename
|
|
891
|
+
},
|
|
892
|
+
native: {}
|
|
893
|
+
};
|
|
894
|
+
this.adapter.setObject(id, obj);
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
this.existsObjectAsync = function (id) {
|
|
898
|
+
return new Promise((resolve, reject) => {
|
|
899
|
+
id = this.adapter.namespace + "." + id;
|
|
900
|
+
|
|
901
|
+
this.adapter.getForeignObject(id, (err, obj) => {
|
|
902
|
+
if (err) {
|
|
903
|
+
reject(err);
|
|
904
|
+
} else {
|
|
905
|
+
resolve(!!obj);
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
});
|
|
909
|
+
});
|
|
910
|
+
};
|
|
863
911
|
this.convertState = function (stateTemplate, value) {
|
|
864
912
|
if (stateTemplate.type == "string") return String(value);
|
|
865
913
|
if (stateTemplate.type == "number") return Number(value);
|
package/lib/iosbserver.js
CHANGED
|
@@ -1,207 +1,206 @@
|
|
|
1
|
-
|
|
2
|
-
'use strict';
|
|
1
|
+
"use strict";
|
|
3
2
|
|
|
4
3
|
//const utils = require('@iobroker/adapter-core');
|
|
5
|
-
const dgram = require(
|
|
6
|
-
const SqueezeServerNew = require(__dirname +
|
|
7
|
-
const ioSBPlayer = require(__dirname +
|
|
4
|
+
const dgram = require("dgram");
|
|
5
|
+
const SqueezeServerNew = require(__dirname + "/squeezenode/squeezeserver");
|
|
6
|
+
const ioSBPlayer = require(__dirname + "/iosbplayer");
|
|
8
7
|
|
|
9
8
|
function IoSbServer(adapter) {
|
|
10
9
|
|
|
11
10
|
|
|
12
11
|
this.sbServerStatus = {
|
|
13
|
-
|
|
14
|
-
name:
|
|
12
|
+
"lastscan": {
|
|
13
|
+
name: "LastScan",
|
|
15
14
|
read: true,
|
|
16
15
|
write: false,
|
|
17
|
-
type:
|
|
18
|
-
role:
|
|
16
|
+
type: "string",
|
|
17
|
+
role: "value",
|
|
19
18
|
exist: false
|
|
20
19
|
},
|
|
21
|
-
|
|
22
|
-
name:
|
|
20
|
+
"version": {
|
|
21
|
+
name: "Version",
|
|
23
22
|
read: true,
|
|
24
23
|
write: false,
|
|
25
|
-
type:
|
|
26
|
-
role:
|
|
24
|
+
type: "string",
|
|
25
|
+
role: "value",
|
|
27
26
|
exist: false
|
|
28
27
|
},
|
|
29
|
-
|
|
30
|
-
name:
|
|
28
|
+
"uuid": {
|
|
29
|
+
name: "uuid",
|
|
31
30
|
read: true,
|
|
32
31
|
write: false,
|
|
33
|
-
type:
|
|
34
|
-
role:
|
|
32
|
+
type: "string",
|
|
33
|
+
role: "value",
|
|
35
34
|
exist: false
|
|
36
35
|
},
|
|
37
|
-
|
|
38
|
-
name:
|
|
36
|
+
"name": {
|
|
37
|
+
name: "Name",
|
|
39
38
|
read: true,
|
|
40
39
|
write: false,
|
|
41
|
-
type:
|
|
42
|
-
role:
|
|
40
|
+
type: "string",
|
|
41
|
+
role: "value",
|
|
43
42
|
exist: false
|
|
44
43
|
},
|
|
45
|
-
|
|
46
|
-
name:
|
|
44
|
+
"mac": {
|
|
45
|
+
name: "mac",
|
|
47
46
|
read: true,
|
|
48
47
|
write: false,
|
|
49
|
-
type:
|
|
50
|
-
role:
|
|
48
|
+
type: "string",
|
|
49
|
+
role: "info.mac",
|
|
51
50
|
exist: false
|
|
52
51
|
},
|
|
53
|
-
|
|
54
|
-
name:
|
|
52
|
+
"info total albums": {
|
|
53
|
+
name: "TotalAlbums",
|
|
55
54
|
read: true,
|
|
56
55
|
write: false,
|
|
57
|
-
type:
|
|
58
|
-
role:
|
|
56
|
+
type: "number",
|
|
57
|
+
role: "value",
|
|
59
58
|
exist: false
|
|
60
59
|
},
|
|
61
|
-
|
|
62
|
-
name:
|
|
60
|
+
"info total artists": {
|
|
61
|
+
name: "TotalArtists",
|
|
63
62
|
read: true,
|
|
64
63
|
write: false,
|
|
65
|
-
type:
|
|
66
|
-
role:
|
|
64
|
+
type: "number",
|
|
65
|
+
role: "value",
|
|
67
66
|
exist: false
|
|
68
67
|
},
|
|
69
|
-
|
|
70
|
-
name:
|
|
68
|
+
"info total genres": {
|
|
69
|
+
name: "TotalGenres",
|
|
71
70
|
read: true,
|
|
72
71
|
write: false,
|
|
73
|
-
type:
|
|
74
|
-
role:
|
|
72
|
+
type: "number",
|
|
73
|
+
role: "value",
|
|
75
74
|
exist: false
|
|
76
75
|
},
|
|
77
|
-
|
|
78
|
-
name:
|
|
76
|
+
"info total songs": {
|
|
77
|
+
name: "TotalSongs",
|
|
79
78
|
read: true,
|
|
80
79
|
write: false,
|
|
81
|
-
type:
|
|
82
|
-
role:
|
|
80
|
+
type: "number",
|
|
81
|
+
role: "value",
|
|
83
82
|
exist: false
|
|
84
83
|
},
|
|
85
|
-
|
|
86
|
-
name:
|
|
84
|
+
"info total duration": {
|
|
85
|
+
name: "TotalDuration",
|
|
87
86
|
read: true,
|
|
88
87
|
write: false,
|
|
89
|
-
type:
|
|
90
|
-
role:
|
|
88
|
+
type: "number",
|
|
89
|
+
role: "media.duration",
|
|
91
90
|
exist: false
|
|
92
91
|
},
|
|
93
|
-
|
|
94
|
-
name:
|
|
92
|
+
"player count": {
|
|
93
|
+
name: "PlayerCount",
|
|
95
94
|
read: true,
|
|
96
95
|
write: false,
|
|
97
|
-
type:
|
|
98
|
-
role:
|
|
96
|
+
type: "number",
|
|
97
|
+
role: "value",
|
|
99
98
|
exist: false
|
|
100
99
|
},
|
|
101
|
-
|
|
102
|
-
name:
|
|
100
|
+
"sn player count": {
|
|
101
|
+
name: "PlayerCountSN",
|
|
103
102
|
read: true,
|
|
104
103
|
write: false,
|
|
105
|
-
type:
|
|
106
|
-
role:
|
|
104
|
+
type: "number",
|
|
105
|
+
role: "value",
|
|
107
106
|
exist: false
|
|
108
107
|
},
|
|
109
|
-
|
|
110
|
-
name:
|
|
108
|
+
"other player count": {
|
|
109
|
+
name: "PlayerCountOther",
|
|
111
110
|
read: true,
|
|
112
111
|
write: false,
|
|
113
|
-
type:
|
|
114
|
-
role:
|
|
112
|
+
type: "number",
|
|
113
|
+
role: "value",
|
|
115
114
|
exist: false
|
|
116
115
|
},
|
|
117
|
-
|
|
118
|
-
name:
|
|
116
|
+
"syncgroups": {
|
|
117
|
+
name: "SyncGroups",
|
|
119
118
|
read: true,
|
|
120
119
|
write: false,
|
|
121
|
-
type:
|
|
122
|
-
role:
|
|
120
|
+
type: "string",
|
|
121
|
+
role: "value",
|
|
123
122
|
exist: false
|
|
124
123
|
},
|
|
125
|
-
|
|
126
|
-
name:
|
|
124
|
+
"otherServers": {
|
|
125
|
+
name: "otherServers",
|
|
127
126
|
read: true,
|
|
128
127
|
write: true,
|
|
129
|
-
type:
|
|
130
|
-
role:
|
|
128
|
+
type: "string",
|
|
129
|
+
role: "value",
|
|
131
130
|
exist: false
|
|
132
131
|
},
|
|
133
|
-
|
|
134
|
-
name:
|
|
132
|
+
"getFavorites": {
|
|
133
|
+
name: "getFavorites",
|
|
135
134
|
read: true,
|
|
136
135
|
write: true,
|
|
137
|
-
type:
|
|
138
|
-
role:
|
|
136
|
+
type: "boolean",
|
|
137
|
+
role: "button",
|
|
139
138
|
def: false,
|
|
140
139
|
exist: false
|
|
141
140
|
}
|
|
142
141
|
};
|
|
143
142
|
this.sbFavoritesState = {
|
|
144
|
-
|
|
145
|
-
name:
|
|
143
|
+
"name": {
|
|
144
|
+
name: "Name",
|
|
146
145
|
read: true,
|
|
147
146
|
write: false,
|
|
148
|
-
type:
|
|
149
|
-
role:
|
|
147
|
+
type: "string",
|
|
148
|
+
role: "value",
|
|
150
149
|
exist: false
|
|
151
150
|
},
|
|
152
|
-
|
|
153
|
-
name:
|
|
151
|
+
"type": {
|
|
152
|
+
name: "type",
|
|
154
153
|
read: true,
|
|
155
154
|
write: false,
|
|
156
|
-
type:
|
|
157
|
-
role:
|
|
155
|
+
type: "string",
|
|
156
|
+
role: "value",
|
|
158
157
|
exist: false
|
|
159
158
|
},
|
|
160
|
-
|
|
161
|
-
name:
|
|
159
|
+
"id": {
|
|
160
|
+
name: "id",
|
|
162
161
|
read: true,
|
|
163
162
|
write: false,
|
|
164
|
-
type:
|
|
165
|
-
role:
|
|
163
|
+
type: "string",
|
|
164
|
+
role: "value",
|
|
166
165
|
exist: false
|
|
167
166
|
},
|
|
168
|
-
|
|
169
|
-
name:
|
|
167
|
+
"hasitems": {
|
|
168
|
+
name: "hasitems",
|
|
170
169
|
read: true,
|
|
171
170
|
write: false,
|
|
172
|
-
type:
|
|
173
|
-
role:
|
|
171
|
+
type: "number",
|
|
172
|
+
role: "value",
|
|
174
173
|
exist: false
|
|
175
174
|
},
|
|
176
|
-
|
|
177
|
-
name:
|
|
175
|
+
"url": {
|
|
176
|
+
name: "url",
|
|
178
177
|
read: true,
|
|
179
178
|
write: false,
|
|
180
|
-
type:
|
|
181
|
-
role:
|
|
179
|
+
type: "string",
|
|
180
|
+
role: "media.url",
|
|
182
181
|
exist: false
|
|
183
182
|
},
|
|
184
|
-
|
|
185
|
-
name:
|
|
183
|
+
"image": {
|
|
184
|
+
name: "image",
|
|
186
185
|
read: true,
|
|
187
186
|
write: false,
|
|
188
|
-
type:
|
|
189
|
-
role:
|
|
187
|
+
type: "string",
|
|
188
|
+
role: "url.icon",
|
|
190
189
|
exist: false
|
|
191
190
|
},
|
|
192
|
-
|
|
193
|
-
name:
|
|
191
|
+
"isaudio": {
|
|
192
|
+
name: "isaudio",
|
|
194
193
|
read: true,
|
|
195
194
|
write: false,
|
|
196
|
-
type:
|
|
197
|
-
role:
|
|
195
|
+
type: "number",
|
|
196
|
+
role: "value",
|
|
198
197
|
exist: false
|
|
199
198
|
}
|
|
200
199
|
};
|
|
201
200
|
|
|
202
|
-
this.ServerStatePath =
|
|
203
|
-
this.FavoritesStatePath =
|
|
204
|
-
this.PlayersStatePath =
|
|
201
|
+
this.ServerStatePath = "Server";
|
|
202
|
+
this.FavoritesStatePath = "Favorites";
|
|
203
|
+
this.PlayersStatePath = "Players";
|
|
205
204
|
|
|
206
205
|
this.currentStates = {};
|
|
207
206
|
this.players = [];
|
|
@@ -209,10 +208,10 @@ function IoSbServer(adapter) {
|
|
|
209
208
|
|
|
210
209
|
this.adapter = adapter;
|
|
211
210
|
|
|
212
|
-
this.adapter.setState(
|
|
213
|
-
this.adapter.subscribeStates(
|
|
211
|
+
this.adapter.setState("info.connection", false, true);
|
|
212
|
+
this.adapter.subscribeStates("*");
|
|
214
213
|
|
|
215
|
-
this.sbServer = (adapter.config.username != "") ? new SqueezeServerNew(
|
|
214
|
+
this.sbServer = (adapter.config.username != "") ? new SqueezeServerNew("http://" + this.adapter.config.server, Number.parseInt(this.adapter.config.port), adapter.config.username, adapter.config.password) : new SqueezeServerNew("http://" + this.adapter.config.server, Number.parseInt(this.adapter.config.port));
|
|
216
215
|
|
|
217
216
|
this.log = {};
|
|
218
217
|
this.islogsilly = this.adapter.config.outputserversilly;
|
|
@@ -225,16 +224,17 @@ function IoSbServer(adapter) {
|
|
|
225
224
|
this.telnet = null;
|
|
226
225
|
this.otherserver = [];
|
|
227
226
|
|
|
228
|
-
this.init = function () {
|
|
229
|
-
this.
|
|
227
|
+
this.init = async function () {
|
|
228
|
+
this.logdebug("server init");
|
|
229
|
+
this.setState("connection", true, "info");
|
|
230
230
|
this.doObserverServer();
|
|
231
231
|
this.doObserverFavorites();
|
|
232
232
|
this.doTelnet();
|
|
233
233
|
};
|
|
234
234
|
this.doObserverServer = function () {
|
|
235
|
-
this.
|
|
235
|
+
this.logdebug("doObserverServer");
|
|
236
236
|
this.getServerstatus();
|
|
237
|
-
this.setTimeout(
|
|
237
|
+
this.setTimeout("serverstatus", this.doObserverServer.bind(this), this.adapter.config.serverrefresh * 1000);
|
|
238
238
|
};
|
|
239
239
|
this.processMessages = function (msg) {
|
|
240
240
|
this.logdebug("processMessages " + JSON.stringify(msg));
|
|
@@ -249,7 +249,7 @@ function IoSbServer(adapter) {
|
|
|
249
249
|
for (const [, srv] of Object.entries(this.otherserver)) {
|
|
250
250
|
data.push({ label: `${srv.NAME}/${srv.ADDRESS}`, value: srv.ADDRESS });
|
|
251
251
|
}
|
|
252
|
-
this.adapter.sendTo(msg.from, msg.command, [{ value:
|
|
252
|
+
this.adapter.sendTo(msg.from, msg.command, [{ value: "", label: "---" }, ...data], msg.callback);
|
|
253
253
|
};
|
|
254
254
|
this.setTimeout = function (id, callback, time) {
|
|
255
255
|
this.clearTimeout(id);
|
|
@@ -268,32 +268,31 @@ function IoSbServer(adapter) {
|
|
|
268
268
|
delete this.observers[id];
|
|
269
269
|
};
|
|
270
270
|
this.doObserverFavorites = function () {
|
|
271
|
-
this.
|
|
272
|
-
|
|
273
|
-
if (
|
|
274
|
-
this.
|
|
271
|
+
this.logdebug("doObserverFavorites");
|
|
272
|
+
this.delFavorites();
|
|
273
|
+
if (this.adapter.config.usefavorites) {
|
|
274
|
+
this.setFavorites();
|
|
275
275
|
return;
|
|
276
276
|
}
|
|
277
|
-
this.
|
|
278
|
-
this.setTimeout('favorites', this.doObserverFavorites.bind(this), this.adapter.config.favoriterefresh * 60 * 1000);
|
|
277
|
+
this.setTimeout("favorites", this.doObserverFavorites.bind(this), this.adapter.config.favoriterefresh * 60 * 1000);
|
|
279
278
|
};
|
|
280
279
|
this.getDiscoverServers = () => {
|
|
281
|
-
this.
|
|
280
|
+
this.logdebug("getDiscoverServers");
|
|
282
281
|
const that = this;
|
|
283
282
|
if (!this.adapter.config.usediscovery) {
|
|
284
|
-
this.delState(this.ServerStatePath, this.sbServerStatus[
|
|
285
|
-
that.delObject(that.ServerStatePath, that.sbServerStatus[
|
|
283
|
+
this.delState(this.ServerStatePath, this.sbServerStatus["otherServers"].name, function () {
|
|
284
|
+
that.delObject(that.ServerStatePath, that.sbServerStatus["otherServers"].name);
|
|
286
285
|
});
|
|
287
286
|
return;
|
|
288
287
|
}
|
|
289
|
-
this.server = dgram.createSocket({ type:
|
|
288
|
+
this.server = dgram.createSocket({ type: "udp4", reuseAddr: true });
|
|
290
289
|
const broadcastPort = 3483;
|
|
291
|
-
this.server.bind(broadcastPort,
|
|
290
|
+
this.server.bind(broadcastPort, "0.0.0.0", function () {
|
|
292
291
|
that.server && that.server.setBroadcast(true);
|
|
293
292
|
}.bind(this));
|
|
294
|
-
this.server.on(
|
|
295
|
-
that.logsilly(
|
|
296
|
-
if (data.toString().charAt() ==
|
|
293
|
+
this.server.on("message", async function (data, rinfo) {
|
|
294
|
+
that.logsilly("getDiscoverServers: Message resceived " + escape(data));
|
|
295
|
+
if (data.toString().charAt() == "E") {
|
|
297
296
|
let msg = data.toString();
|
|
298
297
|
msg = msg.substr(1);
|
|
299
298
|
const srv = {};
|
|
@@ -307,23 +306,24 @@ function IoSbServer(adapter) {
|
|
|
307
306
|
len = len - len2 - 5;
|
|
308
307
|
srv[tag] = val;
|
|
309
308
|
}
|
|
310
|
-
srv[
|
|
311
|
-
srv[
|
|
312
|
-
that.otherserver[srv[
|
|
309
|
+
srv["ADDRESS"] = rinfo.address;
|
|
310
|
+
srv["TIMESTAMP"] = Date.now();
|
|
311
|
+
that.otherserver[srv["ADDRESS"]] = srv;
|
|
313
312
|
const state = {};
|
|
314
|
-
Object.assign(state, that.sbServerStatus[
|
|
315
|
-
state.name = srv[
|
|
313
|
+
Object.assign(state, that.sbServerStatus["otherServers"]);
|
|
314
|
+
state.name = srv["ADDRESS"].replace(/\./g, "-");
|
|
316
315
|
state.def = JSON.stringify(srv);
|
|
317
|
-
that.
|
|
318
|
-
|
|
316
|
+
await that.createFolder(that.sbServerStatus["otherServers"].name, that.ServerStatePath);
|
|
317
|
+
that.createObject(state, that.ServerStatePath, that.sbServerStatus["otherServers"].name, function () {
|
|
318
|
+
that.setState(srv["ADDRESS"].replace(/\./g, "-"), JSON.stringify(srv), that.ServerStatePath, that.sbServerStatus["otherServers"].name, false);
|
|
319
319
|
});
|
|
320
|
-
that.logdebug(
|
|
320
|
+
that.logdebug("Autodiscover: Server found " + srv["NAME"] + " IP: " + srv["ADDRESS"] + " Port " + srv["JSON"] + " UUID " + srv["UUID"]);
|
|
321
321
|
}
|
|
322
322
|
}.bind(this));
|
|
323
|
-
this.server.on(
|
|
324
|
-
that.
|
|
323
|
+
this.server.on("error", function (err) {
|
|
324
|
+
that.logerror("Error with Server discovery " + err.message);
|
|
325
325
|
if (err.message.includes("EADDRINUSE")) {
|
|
326
|
-
that.
|
|
326
|
+
that.loginfo("use 'lsof -i -P' to check for ports used.");
|
|
327
327
|
}
|
|
328
328
|
try {
|
|
329
329
|
that.server && that.server.close(function () {
|
|
@@ -331,23 +331,23 @@ function IoSbServer(adapter) {
|
|
|
331
331
|
that.server = null;
|
|
332
332
|
});
|
|
333
333
|
} catch (err) {
|
|
334
|
-
that.
|
|
334
|
+
that.logerror("server.close() " + err.message);
|
|
335
335
|
}
|
|
336
336
|
});
|
|
337
337
|
setTimeout(this.doDiscoverServerSearch, 1000);
|
|
338
338
|
};
|
|
339
339
|
this.doDiscoverServerSearch = () => {
|
|
340
|
-
this.
|
|
340
|
+
this.logdebug("doDiscoverServerSearch");
|
|
341
341
|
const that = this;
|
|
342
|
-
const msg = Buffer.from(
|
|
343
|
-
const broadcastAddress =
|
|
342
|
+
const msg = Buffer.from("eIPAD\0NAME\0JSON\0UUID\0VERS");
|
|
343
|
+
const broadcastAddress = "255.255.255.255";
|
|
344
344
|
const broadcastPort = 3483;
|
|
345
|
-
this.getStates(
|
|
345
|
+
this.getStates("*", this.ServerStatePath, this.sbServerStatus["otherServers"].name, function (err, states) {
|
|
346
346
|
for (const id in states) {
|
|
347
|
-
const srv = JSON.parse(states[id]
|
|
347
|
+
const srv = JSON.parse(states[id]?.val || "{}");
|
|
348
348
|
if (((Date.now() - srv.TIMESTAMP) / 1000) > 60) {
|
|
349
349
|
that.delObject(id);
|
|
350
|
-
that.logdebug(
|
|
350
|
+
that.logdebug("Autodiscover: Server removed " + srv["NAME"] + " IP: " + srv["ADDRESS"] + " Port " + srv["JSON"] + " UUID " + srv["UUID"]);
|
|
351
351
|
}
|
|
352
352
|
}
|
|
353
353
|
}.bind(this));
|
|
@@ -361,81 +361,84 @@ function IoSbServer(adapter) {
|
|
|
361
361
|
if (err) that.log.error(err);
|
|
362
362
|
}
|
|
363
363
|
);
|
|
364
|
-
this.setTimeout(
|
|
364
|
+
this.setTimeout("discover", this.doDiscoverServerSearch.bind(this), this.adapter.config.discoveryrefresh * 1000);
|
|
365
365
|
};
|
|
366
366
|
this.doDiscoverServerClose = function () {
|
|
367
|
-
this.logdebug(
|
|
367
|
+
this.logdebug("doDiscoverServerClose");
|
|
368
368
|
this.server && this.server.close();
|
|
369
369
|
};
|
|
370
370
|
this.doTelnet = () => {
|
|
371
|
+
this.logdebug("doTelnet");
|
|
371
372
|
if (!this.adapter.config.usetelnet) return;
|
|
372
|
-
const net = require(
|
|
373
|
+
const net = require("net");
|
|
373
374
|
this.telnet = net.createConnection({ host: this.adapter.config.server, port: this.adapter.config.telnetport }, () => {
|
|
374
|
-
this.logdebug(
|
|
375
|
-
this.telnet.write(
|
|
376
|
-
this.telnet.write(
|
|
375
|
+
this.logdebug("doTelnet connected to server!");
|
|
376
|
+
this.telnet.write("login " + this.adapter.config.username + " " + this.adapter.config.password + "\r\n");
|
|
377
|
+
this.telnet.write("listen 1\r\n");
|
|
377
378
|
});
|
|
378
|
-
this.telnet.on(
|
|
379
|
-
this.logdebug(
|
|
379
|
+
this.telnet.on("data", (data) => {
|
|
380
|
+
this.logdebug("doTelnet received Data: " + data.toString());
|
|
380
381
|
const regex = /^((?:[0-9A-Fa-f]{2}[:-]){5}(?:[0-9A-Fa-f]{2}))\s*(.*)/gm;
|
|
381
382
|
let m;
|
|
382
383
|
if ((m = regex.exec(decodeURIComponent(data.toString()))) !== null) {
|
|
383
|
-
if (m[2] ==
|
|
384
|
-
this.logdebug(
|
|
384
|
+
if (m[2] == "client reconnect") {
|
|
385
|
+
this.logdebug("doTelnet received reconnect for : " + m[1]);
|
|
385
386
|
this.getServerstatus();
|
|
386
387
|
}
|
|
387
|
-
if (m[2] ==
|
|
388
|
-
this.logdebug(
|
|
388
|
+
if (m[2] == "client disconnect") {
|
|
389
|
+
this.logdebug("doTelnet received disconnect for : " + m[1]);
|
|
389
390
|
this.getServerstatus();
|
|
390
391
|
}
|
|
391
|
-
if (m[2] ==
|
|
392
|
-
this.logdebug(
|
|
392
|
+
if (m[2] == "client new") {
|
|
393
|
+
this.logdebug("doTelnet received disconnect for : " + m[1]);
|
|
393
394
|
this.getServerstatus();
|
|
394
395
|
}
|
|
395
|
-
if (m[2] ==
|
|
396
|
-
this.logdebug(
|
|
396
|
+
if (m[2] == "power 0") {
|
|
397
|
+
this.logdebug("doTelnet received power off : " + m[1]);
|
|
397
398
|
this.getServerstatus();
|
|
398
399
|
}
|
|
399
|
-
if (m[2] ==
|
|
400
|
-
this.logdebug(
|
|
400
|
+
if (m[2] == "power 1") {
|
|
401
|
+
this.logdebug("doTelnet received power on : " + m[1]);
|
|
401
402
|
this.getServerstatus();
|
|
402
403
|
}
|
|
403
404
|
}
|
|
404
405
|
});
|
|
405
|
-
this.telnet.on(
|
|
406
|
-
this.logdebug(
|
|
406
|
+
this.telnet.on("end", () => {
|
|
407
|
+
this.logdebug("doTelnet disconnected from server");
|
|
407
408
|
});
|
|
408
|
-
this.telnet.on(
|
|
409
|
-
this.logdebug(
|
|
409
|
+
this.telnet.on("timeout", () => {
|
|
410
|
+
this.logdebug("doTelnet Socket timeout, closing");
|
|
410
411
|
this.telnet.close();
|
|
411
412
|
});
|
|
412
|
-
this.telnet.on(
|
|
413
|
-
this.logdebug(
|
|
413
|
+
this.telnet.on("error", (err) => {
|
|
414
|
+
this.logdebug("doTelnet Socket error: " + err.message);
|
|
414
415
|
});
|
|
415
|
-
this.telnet.on(
|
|
416
|
-
this.logdebug(
|
|
416
|
+
this.telnet.on("close", (err) => {
|
|
417
|
+
this.logdebug("doTelnet Socket closed " + err.message);
|
|
417
418
|
});
|
|
418
419
|
};
|
|
419
420
|
this.doTelnetClose = function () {
|
|
420
|
-
this.logdebug(
|
|
421
|
+
this.logdebug("doTelnetClose");
|
|
421
422
|
this.telnet.end();
|
|
422
423
|
};
|
|
423
424
|
this.closeConnections = function () {
|
|
425
|
+
this.logdebug("closeConnections");
|
|
424
426
|
if (this.adapter.config.usetelnet) this.doTelnetClose();
|
|
425
427
|
if (this.adapter.config.usediscovery) this.doDiscoverServerClose();
|
|
426
428
|
};
|
|
427
429
|
this.getServerstatus = function () {
|
|
428
|
-
this.
|
|
429
|
-
this.request(
|
|
430
|
-
this.request(
|
|
430
|
+
this.logdebug("getServerstatus");
|
|
431
|
+
this.request("", ["serverstatus", "0", "888"], this.doServerstatus.bind(this));
|
|
432
|
+
this.request("", ["syncgroups", "?"], this.doSyncgroups.bind(this));
|
|
431
433
|
};
|
|
432
434
|
this.doSyncgroups = function (result) {
|
|
435
|
+
this.logdebug("doSyncgroups");
|
|
433
436
|
if (result.result && result.result.syncgroups_loop) {
|
|
434
|
-
this.setState(this.sbServerStatus[
|
|
437
|
+
this.setState(this.sbServerStatus["syncgroups"].name, JSON.stringify(result.result.syncgroups_loop), this.ServerStatePath);
|
|
435
438
|
}
|
|
436
439
|
};
|
|
437
440
|
this.doServerstatus = function (result) {
|
|
438
|
-
this.
|
|
441
|
+
this.logdebug("doServerstatus");
|
|
439
442
|
this.checkServerstatusStates(result);
|
|
440
443
|
for (const key in this.sbServerStatus) {
|
|
441
444
|
if (Object.prototype.hasOwnProperty.call(result.result, key)) {
|
|
@@ -445,162 +448,83 @@ function IoSbServer(adapter) {
|
|
|
445
448
|
this.checkNewPlayer(result.result.players_loop);
|
|
446
449
|
this.checkPlayer(result.result.players_loop);
|
|
447
450
|
};
|
|
448
|
-
this.
|
|
449
|
-
this.
|
|
450
|
-
this.
|
|
451
|
-
(
|
|
452
|
-
() => this.newgetFavoritesLMS('',
|
|
453
|
-
(result) => this.newsetFavoritesDP(result)
|
|
454
|
-
)
|
|
455
|
-
)
|
|
456
|
-
);
|
|
457
|
-
};
|
|
458
|
-
this.newdelFavorites = function () {
|
|
459
|
-
this.logsilly('newgetFavorites');
|
|
460
|
-
this.newgetFavoritesDP(
|
|
461
|
-
(states) => this.newdelFavoritesDP(states)
|
|
451
|
+
this.setFavorites = async function () {
|
|
452
|
+
this.logdebug("setFavorites");
|
|
453
|
+
this.getFavoritesLMS("",
|
|
454
|
+
(result) => this.setFavoritesDP(result)
|
|
462
455
|
);
|
|
463
456
|
};
|
|
464
|
-
this.
|
|
465
|
-
this.
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
} else this.log.info(err);
|
|
472
|
-
});
|
|
457
|
+
this.delFavorites = async function () {
|
|
458
|
+
this.logdebug("delFavorites");
|
|
459
|
+
let favobj = await this.getObjects(this.FavoritesStatePath);
|
|
460
|
+
favobj = favobj.rows.filter(obj => obj.value.type === "folder");
|
|
461
|
+
for (let i = 0; i < favobj.length; i++) {
|
|
462
|
+
await this.adapter.delForeignObjectAsync(favobj[i].id);
|
|
463
|
+
}
|
|
473
464
|
};
|
|
474
|
-
this.
|
|
475
|
-
this.
|
|
476
|
-
this.request(
|
|
465
|
+
this.getFavoritesLMS = function (id = "", callback) {
|
|
466
|
+
this.logdebug("getFavoritesLMS");
|
|
467
|
+
this.request("", ["favorites", "items", "0", "888", "want_url:1", "item_id:" + id],
|
|
477
468
|
(result) => callback(result.result.loop_loop)//.bind(this);
|
|
478
469
|
);
|
|
479
470
|
};
|
|
480
|
-
this.
|
|
481
|
-
|
|
482
|
-
this.
|
|
483
|
-
const promises = [];
|
|
484
|
-
for (const id in states) {
|
|
485
|
-
this.logdebug(`Start to delete object => ${id}`);
|
|
486
|
-
promises.push(new Promise(function (resolve) {
|
|
487
|
-
that.delObject(id, false, false, resolve);
|
|
488
|
-
}.bind(this)));
|
|
489
|
-
}
|
|
490
|
-
Promise.all(promises).then(function () {
|
|
491
|
-
that.logdebug(`All favorite objects deleted`);
|
|
492
|
-
if (callback) callback();
|
|
493
|
-
}.bind(this));
|
|
494
|
-
};
|
|
495
|
-
this.newsetFavoritesDP = function (favorites) {
|
|
496
|
-
this.logsilly('newsetFavoritesDP');
|
|
471
|
+
this.setFavoritesDP = async function (favorites) {
|
|
472
|
+
this.logdebug("setFavoritesDP");
|
|
473
|
+
await this.createFolder(this.FavoritesStatePath);
|
|
497
474
|
for (const favkey in favorites) {
|
|
498
475
|
const favorite = favorites[favkey];
|
|
499
|
-
const oid = this.getFavId(favorite[
|
|
500
|
-
const id = this.getFavId(favorite[
|
|
476
|
+
const oid = this.getFavId(favorite["id"], false);
|
|
477
|
+
const id = this.getFavId(favorite["id"]);
|
|
501
478
|
for (const key in this.sbFavoritesState) {
|
|
502
479
|
if (Object.prototype.hasOwnProperty.call(favorite, key)) {
|
|
503
|
-
if (key ==
|
|
504
|
-
if (key ==
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
480
|
+
if (key == "id") favorite["id"] = oid;
|
|
481
|
+
if (key == "image") {
|
|
482
|
+
let result = "http://" + this.adapter.config.server + ":" + this.adapter.config.port + "/html/images/favorites.png";
|
|
483
|
+
if (/music\/(.*)\/cover.png/gm.test(favorite[key])) {
|
|
484
|
+
result = "http://" + this.adapter.config.server + ":" + this.adapter.config.port + "/" + favorite[key];
|
|
485
|
+
}
|
|
486
|
+
else if (/imageproxy\/(.*)\/[^/]/gm.test(favorite[key])) {
|
|
487
|
+
const m = /imageproxy\/(.*)\/[^/]/gm.exec(favorite[key]);
|
|
488
|
+
if (m && m[1]) {
|
|
489
|
+
result = decodeURIComponent(m[1] || "");
|
|
490
|
+
}
|
|
509
491
|
}
|
|
492
|
+
else if (favorite[key] === "html/images/radio.png") {
|
|
493
|
+
result = "http://" + this.adapter.config.server + ":" + this.adapter.config.port + "/html/images/radio.png";
|
|
494
|
+
}
|
|
495
|
+
else if (favorite[key] === "html/images/cover.png") {
|
|
496
|
+
result = "http://" + this.adapter.config.server + ":" + this.adapter.config.port + "/html/images/cover.png";
|
|
497
|
+
}
|
|
498
|
+
else if (favorite[key] === "html/images/favorites.png") {
|
|
499
|
+
result = "http://" + this.adapter.config.server + ":" + this.adapter.config.port + "/html/images/favorites.png";
|
|
500
|
+
}
|
|
501
|
+
favorite[key] = result;
|
|
510
502
|
}
|
|
511
503
|
const stateTemplate = this.sbFavoritesState[key];
|
|
504
|
+
await this.createFolder(id, this.FavoritesStatePath);
|
|
512
505
|
this.createObject(stateTemplate, this.FavoritesStatePath, id,
|
|
513
506
|
() => this.setState(this.sbFavoritesState[key].name, this.convertState(this.sbFavoritesState[key], favorite[key]), this.FavoritesStatePath, id, false)
|
|
514
507
|
);
|
|
515
508
|
}
|
|
516
509
|
}
|
|
517
|
-
if (favorite[
|
|
518
|
-
(result) => this.
|
|
510
|
+
if (favorite["hasitems"] > 0) this.getFavoritesLMS(oid,
|
|
511
|
+
(result) => this.setFavoritesDP(result)
|
|
519
512
|
);
|
|
520
513
|
}
|
|
521
514
|
};
|
|
522
|
-
/*
|
|
523
|
-
this.getFavorites = function(id='') {
|
|
524
|
-
this.logsilly('getFavorites');
|
|
525
|
-
this.deleteFavorites(id,function() {
|
|
526
|
-
this.request('',['favorites', 'items', '0', '888','want_url:1','item_id:' + id], this.doFavorites1.bind(this));
|
|
527
|
-
}.bind(this));
|
|
528
|
-
};
|
|
529
|
-
this.doFavorites1 = function(result){
|
|
530
|
-
this.logsilly('doFavorites1');
|
|
531
|
-
const favorites = result.result.loop_loop;
|
|
532
|
-
this.checkFavoriteStates(favorites);
|
|
533
|
-
};
|
|
534
|
-
this.doFavorites2 = function(favorites){
|
|
535
|
-
this.logsilly('doFavorites2');
|
|
536
|
-
for (const favkey in favorites) {
|
|
537
|
-
const favorite = favorites[favkey];
|
|
538
|
-
const oid = this.getFavId(favorite['id'],false);
|
|
539
|
-
const id = this.getFavId(favorite['id']);
|
|
540
|
-
for (const key in this.sbFavoritesState){
|
|
541
|
-
if (favorite.hasOwnProperty(key)) {
|
|
542
|
-
if (key=='id') favorite['id'] = oid;
|
|
543
|
-
if (key == 'image' ) {
|
|
544
|
-
const regex = /imageproxy\/(.*)\/[^\/]/gm;
|
|
545
|
-
let m = regex.exec(favorite[key]);
|
|
546
|
-
if (m && m.index>0) {
|
|
547
|
-
favorite[key] = decodeURIComponent(m[1]);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
this.setState(this.sbFavoritesState[key].name,favorite[key],this.FavoritesStatePath,id,false);
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
if (favorite['hasitems']>0) this.getFavorites(oid);
|
|
554
|
-
}
|
|
555
|
-
};
|
|
556
|
-
this.checkFavoriteStates = function(favorites) {
|
|
557
|
-
this.logsilly('checkFavoriteStates');
|
|
558
|
-
for (const favkey in favorites) {
|
|
559
|
-
const favorite = favorites[favkey];
|
|
560
|
-
const id = this.getFavId(favorite['id']);
|
|
561
|
-
for (const key in this.sbFavoritesState){
|
|
562
|
-
if (favorite.hasOwnProperty(key)) {
|
|
563
|
-
const stateTemplate = this.sbFavoritesState[key];
|
|
564
|
-
this.createObject(stateTemplate,this.FavoritesStatePath,id);
|
|
565
|
-
}
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
this.doFavorites2(favorites);
|
|
569
|
-
};
|
|
570
|
-
this.deleteFavorites = function(typ,callback) {
|
|
571
|
-
if (typ!='') {
|
|
572
|
-
callback();
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
var id = this.FavoritesStatePath;
|
|
576
|
-
this.adapter.getStates(id + '*', (err, states) => {
|
|
577
|
-
if(!err) {
|
|
578
|
-
let promises = [];
|
|
579
|
-
for (const id in states) {
|
|
580
|
-
this.logdebug(`Delete state => ${id}`);
|
|
581
|
-
promises.push( new Promise(function(resolve){
|
|
582
|
-
this.delObject(id,false,false,resolve);
|
|
583
|
-
}.bind(this)));
|
|
584
|
-
}
|
|
585
|
-
Promise.all(promises).then(function(){
|
|
586
|
-
callback();
|
|
587
|
-
});
|
|
588
|
-
} else this.log.info(err);
|
|
589
|
-
});
|
|
590
|
-
};
|
|
591
|
-
*/
|
|
592
515
|
this.getFavId = function (id, replace = true) {
|
|
593
516
|
let ret;
|
|
594
|
-
if (id.indexOf(
|
|
517
|
+
if (id.indexOf(".") == 8) {
|
|
595
518
|
ret = id.substr(9);
|
|
596
519
|
} else {
|
|
597
520
|
ret = id;
|
|
598
521
|
}
|
|
599
|
-
if (replace) ret = ret.replace(/\./g,
|
|
522
|
+
if (replace) ret = ret.replace(/\./g, "-");
|
|
600
523
|
return ret;
|
|
601
524
|
};
|
|
602
|
-
this.checkServerstatusStates = function (result) {
|
|
603
|
-
this.
|
|
525
|
+
this.checkServerstatusStates = async function (result) {
|
|
526
|
+
this.logdebug("checkServerstatusStates");
|
|
527
|
+
await this.createDevice(this.ServerStatePath);
|
|
604
528
|
for (const key in this.sbServerStatus) {
|
|
605
529
|
if (Object.prototype.hasOwnProperty.call(result.result, key)) {
|
|
606
530
|
const stateTemplate = this.sbServerStatus[key];
|
|
@@ -611,18 +535,19 @@ function IoSbServer(adapter) {
|
|
|
611
535
|
}
|
|
612
536
|
}
|
|
613
537
|
}
|
|
614
|
-
let key =
|
|
538
|
+
let key = "getFavorites";
|
|
615
539
|
let stateTemplate = this.sbServerStatus[key];
|
|
616
540
|
if (!stateTemplate.exist) {
|
|
617
541
|
this.sbServerStatus[key] = this.createObject(stateTemplate, this.ServerStatePath);
|
|
618
542
|
}
|
|
619
|
-
key =
|
|
543
|
+
key = "syncgroups";
|
|
620
544
|
stateTemplate = this.sbServerStatus[key];
|
|
621
545
|
if (!stateTemplate.exist) {
|
|
622
546
|
this.sbServerStatus[key] = this.createObject(stateTemplate, this.ServerStatePath);
|
|
623
547
|
}
|
|
624
548
|
};
|
|
625
549
|
this.checkNewPlayer = function (playersdata) {
|
|
550
|
+
this.logdebug("checkNewPlayer");
|
|
626
551
|
for (const key in playersdata) {
|
|
627
552
|
if (!Object.prototype.hasOwnProperty.call(this.players, playersdata[key].playerid)) {
|
|
628
553
|
this.players[playersdata[key].playerid] = new ioSBPlayer(this, playersdata[key]);
|
|
@@ -630,6 +555,7 @@ function IoSbServer(adapter) {
|
|
|
630
555
|
}
|
|
631
556
|
};
|
|
632
557
|
this.checkPlayer = function (playersdata) {
|
|
558
|
+
this.logdebug("checkPlayer");
|
|
633
559
|
for (const key in playersdata) {
|
|
634
560
|
if (this.players[playersdata[key].playerid].connected != playersdata[key].connected) {
|
|
635
561
|
if (playersdata[key].connected == 0) {
|
|
@@ -642,11 +568,12 @@ function IoSbServer(adapter) {
|
|
|
642
568
|
}
|
|
643
569
|
};
|
|
644
570
|
this.stateChange = function (id, state) {
|
|
571
|
+
this.logsilly("stateChange");
|
|
645
572
|
// Warning, state can be null if it was deleted
|
|
646
573
|
if (!id || !state || state.ack) {
|
|
647
574
|
return;
|
|
648
575
|
}
|
|
649
|
-
const idParts = id.split(
|
|
576
|
+
const idParts = id.split(".");
|
|
650
577
|
idParts.shift();
|
|
651
578
|
idParts.shift();
|
|
652
579
|
if (idParts[0] == this.ServerStatePath) this.doServerStateChange(idParts, state);
|
|
@@ -654,16 +581,22 @@ function IoSbServer(adapter) {
|
|
|
654
581
|
if (idParts[0] == this.PlayersStatePath) this.doPlayersStateChange(idParts, state);
|
|
655
582
|
};
|
|
656
583
|
this.doServerStateChange = function (idParts, state) {
|
|
584
|
+
this.logdebug("doServerStateChange");
|
|
657
585
|
idParts.shift();
|
|
658
|
-
if (idParts[0] ==
|
|
659
|
-
if (state.val == true)
|
|
586
|
+
if (idParts[0] == "getFavorites") {
|
|
587
|
+
if (state.val == true) {
|
|
588
|
+
this.delFavorites();
|
|
589
|
+
this.setFavorites();
|
|
590
|
+
}
|
|
660
591
|
}
|
|
661
592
|
};
|
|
662
593
|
this.doFavoritesStateChange = function (idParts, state) {
|
|
594
|
+
this.logdebug("doFavoritesStateChange");
|
|
663
595
|
idParts.shift();
|
|
664
596
|
if (state) return;
|
|
665
597
|
};
|
|
666
598
|
this.doPlayersStateChange = function (idParts, state) {
|
|
599
|
+
this.logsilly("doPlayersStateChange");
|
|
667
600
|
idParts.shift();
|
|
668
601
|
const player = this.findPlayerByName(idParts[0]);
|
|
669
602
|
if (player) player.doStateChange(idParts, state);
|
|
@@ -674,6 +607,7 @@ function IoSbServer(adapter) {
|
|
|
674
607
|
}
|
|
675
608
|
};
|
|
676
609
|
this.request = function (playerid, params, callback) {
|
|
610
|
+
this.logsilly("request");
|
|
677
611
|
const that = this;
|
|
678
612
|
this.sbServer.request(playerid, params, function (callback, result) {
|
|
679
613
|
if (result.ok) {
|
|
@@ -693,70 +627,80 @@ function IoSbServer(adapter) {
|
|
|
693
627
|
}.bind(this, callback));
|
|
694
628
|
};
|
|
695
629
|
this.disconnect = () => {
|
|
696
|
-
this.logdebug(
|
|
630
|
+
this.logdebug("Server disconnect");
|
|
697
631
|
this.firstStart = false;
|
|
698
632
|
this.connected = 0;
|
|
699
|
-
this.clearTimeout(
|
|
700
|
-
this.clearTimeout(
|
|
701
|
-
if (this.connected == 0 && this.observers[
|
|
702
|
-
this.setState(
|
|
633
|
+
this.clearTimeout("serverstatus");
|
|
634
|
+
this.clearTimeout("favorites");
|
|
635
|
+
if (this.connected == 0 && this.observers["checkserver"]) return;
|
|
636
|
+
this.setState("connection", false, "info");
|
|
703
637
|
for (const key in this.players) {
|
|
704
638
|
this.players[key].disconnect();
|
|
705
639
|
}
|
|
706
|
-
this.setInterval(
|
|
640
|
+
this.setInterval("checkserver", this.doCheckServer.bind(this), 10 * 1000);
|
|
707
641
|
};
|
|
708
642
|
this.connect = () => {
|
|
709
|
-
this.logdebug(
|
|
710
|
-
this.clearInterval(
|
|
711
|
-
this.setState(
|
|
643
|
+
this.logdebug("Server connect");
|
|
644
|
+
this.clearInterval("checkserver");
|
|
645
|
+
this.setState("connection", true, "info");
|
|
712
646
|
this.connected = 1;
|
|
713
647
|
this.init();
|
|
714
648
|
};
|
|
715
649
|
this.doCheckServer = () => {
|
|
716
650
|
const that = this;
|
|
717
|
-
this.
|
|
718
|
-
this.request(
|
|
651
|
+
this.logdebug("doCheckServer");
|
|
652
|
+
this.request("", ["serverstatus", "0", "888"], function (result) {
|
|
719
653
|
if (result.ok) {
|
|
720
654
|
that.connect();
|
|
721
655
|
}
|
|
722
656
|
}.bind(this));
|
|
723
657
|
};
|
|
724
658
|
this.setState = function (name, value, level1path, level2path, check = true, callback) {
|
|
725
|
-
name = (level1path ? level1path +
|
|
659
|
+
name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + name;
|
|
726
660
|
if (this.currentStates[name] !== value && check) {
|
|
727
661
|
this.currentStates[name] = value;
|
|
728
|
-
this.logsilly(
|
|
662
|
+
this.logsilly("setState name: " + name + " value: " + value);
|
|
729
663
|
this.adapter.setState(name, value, true, callback);
|
|
730
664
|
} else {
|
|
731
665
|
this.currentStates[name] = value;
|
|
732
|
-
this.logsilly(
|
|
666
|
+
this.logsilly("setState name: " + name + " value: " + value);
|
|
733
667
|
this.adapter.setState(name, value, true, callback);
|
|
734
668
|
}
|
|
735
669
|
};
|
|
736
670
|
this.getState = function (name, level1path = false, level2path = false, callback) {
|
|
737
|
-
name = (level1path ? level1path +
|
|
671
|
+
name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + name;
|
|
672
|
+
this.logsilly("getState " + name);
|
|
738
673
|
this.adapter.getState(name, callback);
|
|
739
674
|
};
|
|
740
675
|
this.delObject = function (name, level1path, level2path, callback) {
|
|
741
|
-
name = (level1path ? level1path +
|
|
676
|
+
name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + name;
|
|
677
|
+
this.logsilly("delObject " + name);
|
|
742
678
|
delete this.currentStates[name];
|
|
743
679
|
this.adapter.delObject(name, callback);
|
|
744
680
|
};
|
|
745
681
|
this.delState = function (name, level1path, level2path, callback) {
|
|
746
|
-
name = (level1path ? level1path +
|
|
682
|
+
name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + name;
|
|
683
|
+
this.logsilly("delObject " + name);
|
|
747
684
|
delete this.currentStates[name];
|
|
748
685
|
this.adapter.delState(name, callback);
|
|
749
686
|
};
|
|
750
687
|
this.getStates = function (pattern, level1path, level2path, callback) {
|
|
751
|
-
const name = (level1path ? level1path +
|
|
688
|
+
const name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + pattern;
|
|
752
689
|
this.adapter.getStates(name, callback);
|
|
753
690
|
};
|
|
691
|
+
this.getObjects = async function (level1path, level2path) {
|
|
692
|
+
const name = this.adapter.namespace + "." + (level1path ? level1path + "." : "") + (level2path ? level2path : "");
|
|
693
|
+
return await this.adapter.getObjectListAsync({
|
|
694
|
+
startkey: name,
|
|
695
|
+
endkey: name + "\u9999"
|
|
696
|
+
});
|
|
697
|
+
};
|
|
754
698
|
this.createObject = function (stateTemplate, level1path, level2path, callback) {
|
|
755
|
-
const name = (level1path ? level1path +
|
|
756
|
-
this.
|
|
699
|
+
const name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + stateTemplate.name;
|
|
700
|
+
this.logsilly("createObject " + name);
|
|
757
701
|
this.adapter.getObject(name, (err, obj) => {
|
|
758
702
|
const newobj = {
|
|
759
|
-
type:
|
|
703
|
+
type: "state",
|
|
760
704
|
common: stateTemplate,
|
|
761
705
|
native: {}
|
|
762
706
|
};
|
|
@@ -770,16 +714,62 @@ function IoSbServer(adapter) {
|
|
|
770
714
|
return stateTemplate;
|
|
771
715
|
};
|
|
772
716
|
this.createState = function (stateTemplate, level1path = false, level2path = false, callback) {
|
|
773
|
-
const name = (level1path ? level1path +
|
|
774
|
-
this.logsilly(
|
|
717
|
+
const name = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + stateTemplate.name;
|
|
718
|
+
this.logsilly("Create state " + name);
|
|
775
719
|
this.adapter.createState(level1path, level2path, stateTemplate.name, stateTemplate, callback);
|
|
776
720
|
stateTemplate.exist = true;
|
|
777
721
|
return stateTemplate;
|
|
778
722
|
};
|
|
723
|
+
this.createFolder = async function (foldername, level1path, level2path) {
|
|
724
|
+
const id = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + foldername;
|
|
725
|
+
this.logsilly("createFolder " + id);
|
|
726
|
+
if (await this.existsObjectAsync(id)) {
|
|
727
|
+
this.logsilly("Folder exists: " + id);
|
|
728
|
+
} else {
|
|
729
|
+
const obj = {
|
|
730
|
+
type: "folder",
|
|
731
|
+
common: {
|
|
732
|
+
name: foldername
|
|
733
|
+
},
|
|
734
|
+
native: {}
|
|
735
|
+
};
|
|
736
|
+
this.adapter.setObject(id, obj);
|
|
737
|
+
}
|
|
738
|
+
};
|
|
739
|
+
this.createDevice = async function (devicename, level1path, level2path) {
|
|
740
|
+
const id = (level1path ? level1path + "." : "") + (level2path ? level2path + "." : "") + devicename;
|
|
741
|
+
this.logsilly("createDevice " + id);
|
|
742
|
+
if (await this.existsObjectAsync(id)) {
|
|
743
|
+
this.logsilly("Device exists: " + id);
|
|
744
|
+
} else {
|
|
745
|
+
const obj = {
|
|
746
|
+
type: "device",
|
|
747
|
+
common: {
|
|
748
|
+
name: devicename
|
|
749
|
+
},
|
|
750
|
+
native: {}
|
|
751
|
+
};
|
|
752
|
+
this.adapter.setObject(id, obj);
|
|
753
|
+
}
|
|
754
|
+
};
|
|
755
|
+
this.existsObjectAsync = function (id) {
|
|
756
|
+
return new Promise((resolve, reject) => {
|
|
757
|
+
id = this.adapter.namespace + "." + id;
|
|
758
|
+
|
|
759
|
+
this.adapter.getForeignObject(id, (err, obj) => {
|
|
760
|
+
if (err) {
|
|
761
|
+
reject(err);
|
|
762
|
+
} else {
|
|
763
|
+
resolve(!!obj);
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
});
|
|
767
|
+
});
|
|
768
|
+
};
|
|
779
769
|
this.convertState = function (stateTemplate, value) {
|
|
780
770
|
if (stateTemplate.type == "string") return String(value);
|
|
781
771
|
if (stateTemplate.type == "number") return Number(value);
|
|
782
|
-
this.logdebug(
|
|
772
|
+
this.logdebug("Missing conversion function for type " + stateTemplate.type + " Please report.");
|
|
783
773
|
return value;
|
|
784
774
|
};
|
|
785
775
|
this.logsilly = (s) => {
|
|
@@ -796,6 +786,6 @@ function IoSbServer(adapter) {
|
|
|
796
786
|
this.adapter.log.info(s);
|
|
797
787
|
};
|
|
798
788
|
this.getDiscoverServers();
|
|
799
|
-
this.sbServer.on(
|
|
789
|
+
this.sbServer.on("register", this.init.bind(this));
|
|
800
790
|
}
|
|
801
791
|
module.exports = IoSbServer;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "iobroker.squeezeboxrpc",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.16",
|
|
4
4
|
"description": "ioBroker Logitech Squeezebox Adapter over JSON/RPC-Protocol",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "oweitman",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"eslint": "^8.57.0",
|
|
52
52
|
"eslint-config-prettier": "^9.1.0",
|
|
53
53
|
"eslint-plugin-prettier": "^5.2.1",
|
|
54
|
-
"mocha": "^10.
|
|
54
|
+
"mocha": "^10.7.3",
|
|
55
55
|
"prettier": "^3.3.3",
|
|
56
56
|
"proxyquire": "^2.1.3",
|
|
57
57
|
"sinon": "^18.0.0",
|