@edenware/dlnacasts 1.0.0 → 1.0.2
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/dist/index.cjs +222 -198
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +216 -191
- package/dist/index.mjs.map +1 -0
- package/package.json +9 -4
- package/dist/index.js +0 -393
- package/dist/src/index.cjs +0 -373
package/dist/index.cjs
CHANGED
|
@@ -1,124 +1,148 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var MediaRenderer = require('upnp-mediarenderer-client');
|
|
4
|
+
var events = require('events');
|
|
5
|
+
var parallel = require('run-parallel');
|
|
6
|
+
var xml2js = require('xml2js');
|
|
7
|
+
var ssdp = require('@edenware/ssdp');
|
|
8
|
+
var node_net = require('node:net');
|
|
9
|
+
var http = require('node:http');
|
|
10
|
+
var os = require('os');
|
|
11
|
+
var thunky = require('thunky');
|
|
12
|
+
|
|
13
|
+
const noop = () => {};
|
|
14
|
+
|
|
15
|
+
var index = (options = {}) => {
|
|
16
|
+
const SERVICE_TYPE = 'urn:schemas-upnp-org:device:MediaRenderer:1';
|
|
17
|
+
const agent = new http.Agent({ keepAlive: true, maxSockets: 5 });
|
|
18
|
+
const log = options.log ? console.debug : () => {};
|
|
19
|
+
|
|
20
|
+
// Find local IP - prefer Wi-Fi/Ethernet
|
|
21
|
+
const interfaces = os.networkInterfaces();
|
|
22
|
+
log('[DLNACASTS] Network interfaces:', interfaces);
|
|
23
|
+
let localIP = null; // fallback
|
|
24
|
+
let localInterface = null;
|
|
25
|
+
// First pass: prefer Wi-Fi or Ethernet
|
|
22
26
|
for (const name of Object.keys(interfaces)) {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
+
if (name.includes('Wi-Fi') || name.includes('Ethernet') || name.includes('eth') || name.includes('en') || name.includes('wlan')) {
|
|
28
|
+
for (const iface of interfaces[name]) {
|
|
29
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
30
|
+
localIP = iface.address;
|
|
31
|
+
localInterface = name;
|
|
32
|
+
log('[DLNACASTS] Using preferred interface:', name, localIP);
|
|
33
|
+
break
|
|
34
|
+
}
|
|
27
35
|
}
|
|
36
|
+
if (localIP) break
|
|
28
37
|
}
|
|
29
|
-
if (localIP !== '192.168.1.8') break
|
|
30
38
|
}
|
|
31
|
-
|
|
39
|
+
// Second pass: any IPv4 if no preferred found
|
|
40
|
+
if (!localIP) {
|
|
41
|
+
for (const name of Object.keys(interfaces)) {
|
|
42
|
+
for (const iface of interfaces[name]) {
|
|
43
|
+
if (iface.family === 'IPv4' && !iface.internal) {
|
|
44
|
+
localIP = iface.address;
|
|
45
|
+
localInterface = name;
|
|
46
|
+
log('[DLNACASTS] Using fallback interface:', name, localIP);
|
|
47
|
+
break
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (localIP) break
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
if (!localIP) localIP = '127.0.0.1'; // ultimate fallback
|
|
54
|
+
log('Local IP:', localIP);
|
|
32
55
|
|
|
33
|
-
const that = new events.EventEmitter()
|
|
34
|
-
const casts = {}
|
|
35
|
-
const ssdp =
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
56
|
+
const that = new events.EventEmitter();
|
|
57
|
+
const casts = {};
|
|
58
|
+
const ssdp$1 = ssdp.Client ? new ssdp.Client({
|
|
59
|
+
log: true,
|
|
60
|
+
interfaces: [localInterface],
|
|
61
|
+
explicitSocketBind: true
|
|
62
|
+
}) : null;
|
|
39
63
|
|
|
40
|
-
log('[DLNACASTS] SSDP client created:', !!ssdp)
|
|
64
|
+
log('[DLNACASTS] SSDP client created:', !!ssdp$1);
|
|
41
65
|
|
|
42
|
-
that.players = []
|
|
66
|
+
that.players = [];
|
|
43
67
|
|
|
44
68
|
const emit = (cst) => {
|
|
45
69
|
if (!cst || !cst.host || cst.emitted) return
|
|
46
|
-
cst.emitted = true
|
|
70
|
+
cst.emitted = true;
|
|
47
71
|
|
|
48
|
-
const player = new events.EventEmitter()
|
|
49
|
-
let getStatus = undefined
|
|
50
|
-
let stopped = false // Flag para rastrear se stop foi chamado
|
|
51
|
-
let playFailed = false // Flag para rastrear se play falhou
|
|
72
|
+
const player = new events.EventEmitter();
|
|
73
|
+
let getStatus = undefined;
|
|
74
|
+
let stopped = false; // Flag para rastrear se stop foi chamado
|
|
75
|
+
let playFailed = false; // Flag para rastrear se play falhou
|
|
52
76
|
|
|
53
77
|
const connect = thunky(function reconnect (cb) {
|
|
54
|
-
const client = new MediaRenderer(player.xml)
|
|
78
|
+
const client = new MediaRenderer(player.xml);
|
|
55
79
|
|
|
56
80
|
client.on('error', (err) => {
|
|
57
|
-
log('[DLNACASTS] Client error, clearing player.client:', err)
|
|
58
|
-
try { clearInterval(getStatus) } catch(e) {}
|
|
59
|
-
player.client = undefined
|
|
60
|
-
player.emit('error', err)
|
|
61
|
-
})
|
|
81
|
+
log('[DLNACASTS] Client error, clearing player.client:', err);
|
|
82
|
+
try { clearInterval(getStatus); } catch(e) {}
|
|
83
|
+
player.client = undefined;
|
|
84
|
+
player.emit('error', err);
|
|
85
|
+
});
|
|
62
86
|
|
|
63
87
|
client.on('loading', (err) => {
|
|
64
|
-
player.emit('loading', err)
|
|
65
|
-
})
|
|
88
|
+
player.emit('loading', err);
|
|
89
|
+
});
|
|
66
90
|
|
|
67
91
|
client.on('close', () => {
|
|
68
|
-
log('[DLNACASTS] Client closed, clearing player.client')
|
|
69
|
-
try { clearInterval(getStatus) } catch(e) {}
|
|
70
|
-
player.client = undefined
|
|
71
|
-
connect = thunky(reconnect) // Reset thunky para permitir nova reconexão
|
|
72
|
-
})
|
|
92
|
+
log('[DLNACASTS] Client closed, clearing player.client');
|
|
93
|
+
try { clearInterval(getStatus); } catch(e) {}
|
|
94
|
+
player.client = undefined;
|
|
95
|
+
connect = thunky(reconnect); // Reset thunky para permitir nova reconexão
|
|
96
|
+
});
|
|
73
97
|
|
|
74
|
-
player.client = client
|
|
75
|
-
cb(null, player.client)
|
|
76
|
-
})
|
|
98
|
+
player.client = client;
|
|
99
|
+
cb(null, player.client);
|
|
100
|
+
});
|
|
77
101
|
|
|
78
102
|
const parseTime = (time) => {
|
|
79
103
|
if (!time || time.indexOf(':') === -1) return 0
|
|
80
|
-
const parts = time.split(':').map(Number)
|
|
104
|
+
const parts = time.split(':').map(Number);
|
|
81
105
|
return parts[0] * 3600 + parts[1] * 60 + parts[2]
|
|
82
|
-
}
|
|
106
|
+
};
|
|
83
107
|
|
|
84
|
-
player.name = cst.name
|
|
85
|
-
player.host = cst.host
|
|
86
|
-
player.xml = cst.xml
|
|
87
|
-
player._status = {}
|
|
88
|
-
player.MAX_VOLUME = 100
|
|
108
|
+
player.name = cst.name;
|
|
109
|
+
player.host = cst.host;
|
|
110
|
+
player.xml = cst.xml;
|
|
111
|
+
player._status = {};
|
|
112
|
+
player.MAX_VOLUME = 100;
|
|
89
113
|
|
|
90
|
-
player.connect = connect
|
|
114
|
+
player.connect = connect;
|
|
91
115
|
|
|
92
116
|
player.close = (cb = noop) => {
|
|
93
|
-
log('[DLNACASTS] Closing player, clearing player.client')
|
|
94
|
-
try { clearInterval(getStatus) } catch(e) {}
|
|
117
|
+
log('[DLNACASTS] Closing player, clearing player.client');
|
|
118
|
+
try { clearInterval(getStatus); } catch(e) {}
|
|
95
119
|
if (player.client) {
|
|
96
120
|
for (let e of ["error", "status", "loading", "close"]) {
|
|
97
|
-
player.client.removeAllListeners(e)
|
|
121
|
+
player.client.removeAllListeners(e);
|
|
98
122
|
}
|
|
99
|
-
player.client = undefined
|
|
123
|
+
player.client = undefined;
|
|
100
124
|
}
|
|
101
|
-
stopped = true // Marcar que stop foi chamado
|
|
102
|
-
cb()
|
|
103
|
-
}
|
|
125
|
+
stopped = true; // Marcar que stop foi chamado
|
|
126
|
+
cb();
|
|
127
|
+
};
|
|
104
128
|
|
|
105
129
|
player.play = (url, opts, cb = noop) => {
|
|
106
130
|
if (typeof opts === 'function') return player.play(url, null, opts)
|
|
107
|
-
if (!opts) opts = {}
|
|
131
|
+
if (!opts) opts = {};
|
|
108
132
|
if (!url) return player.resume(cb)
|
|
109
133
|
|
|
110
|
-
stopped = false // Resetar stopped ao chamar play
|
|
111
|
-
playFailed = false // Resetar playFailed ao chamar play
|
|
112
|
-
player.subtitles = opts.subtitles
|
|
134
|
+
stopped = false; // Resetar stopped ao chamar play
|
|
135
|
+
playFailed = false; // Resetar playFailed ao chamar play
|
|
136
|
+
player.subtitles = opts.subtitles;
|
|
113
137
|
|
|
114
138
|
connect((err, p) => {
|
|
115
139
|
if (err) {
|
|
116
|
-
log('[DLNACASTS] Connect failed in play:', err)
|
|
117
|
-
playFailed = true // Marcar que play falhou
|
|
140
|
+
log('[DLNACASTS] Connect failed in play:', err);
|
|
141
|
+
playFailed = true; // Marcar que play falhou
|
|
118
142
|
return cb(err)
|
|
119
143
|
}
|
|
120
144
|
|
|
121
|
-
try { clearInterval(getStatus) } catch(e) {}
|
|
145
|
+
try { clearInterval(getStatus); } catch(e) {}
|
|
122
146
|
|
|
123
147
|
const media = {
|
|
124
148
|
autoplay: opts.autoPlay !== false,
|
|
@@ -128,119 +152,119 @@ module.exports = (options = {}) => {
|
|
|
128
152
|
type: 'video', // can be 'video', 'audio' or 'image'
|
|
129
153
|
subtitlesUrl: player.subtitles && player.subtitles.length ? player.subtitles[0] : null
|
|
130
154
|
}
|
|
131
|
-
}
|
|
155
|
+
};
|
|
132
156
|
if (opts.dlnaFeatures) {
|
|
133
|
-
media.dlnaFeatures = opts.dlnaFeatures || 'DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000'
|
|
157
|
+
media.dlnaFeatures = opts.dlnaFeatures || 'DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01500000000000000000000000000000';
|
|
134
158
|
//media.dlnaFeatures = opts.dlnaFeatures; // for LG WebOS 'DLNA.ORG_OP=01;DLNA.ORG_FLAGS=01100000000000000000000000000000' allows seeking
|
|
135
159
|
}
|
|
136
160
|
|
|
137
|
-
let callback = cb
|
|
161
|
+
let callback = cb;
|
|
138
162
|
if (opts.seek) {
|
|
139
163
|
callback = (err) => {
|
|
140
164
|
if (err) {
|
|
141
|
-
playFailed = true // Marcar que play falhou
|
|
165
|
+
playFailed = true; // Marcar que play falhou
|
|
142
166
|
return cb(err)
|
|
143
167
|
}
|
|
144
|
-
player.seek(opts.seek, cb)
|
|
145
|
-
}
|
|
168
|
+
player.seek(opts.seek, cb);
|
|
169
|
+
};
|
|
146
170
|
}
|
|
147
171
|
|
|
148
172
|
getStatus = setInterval(() => {
|
|
149
173
|
if (stopped || playFailed) {
|
|
150
|
-
log('[DLNACASTS] Skipping getStatus: stopped=%s, playFailed=%s', stopped, playFailed)
|
|
174
|
+
log('[DLNACASTS] Skipping getStatus: stopped=%s, playFailed=%s', stopped, playFailed);
|
|
151
175
|
return
|
|
152
176
|
}
|
|
153
177
|
if (!player.client) {
|
|
154
|
-
log('[DLNACASTS] player.client is undefined in getStatus, attempting to reconnect')
|
|
178
|
+
log('[DLNACASTS] player.client is undefined in getStatus, attempting to reconnect');
|
|
155
179
|
connect((err) => {
|
|
156
180
|
if (err) {
|
|
157
|
-
log('[DLNACASTS] Reconnect failed in getStatus:', err)
|
|
158
|
-
playFailed = true // Marcar falha se reconexão falhar
|
|
181
|
+
log('[DLNACASTS] Reconnect failed in getStatus:', err);
|
|
182
|
+
playFailed = true; // Marcar falha se reconexão falhar
|
|
159
183
|
return
|
|
160
184
|
}
|
|
161
|
-
log('[DLNACASTS] Reconnected successfully in getStatus')
|
|
185
|
+
log('[DLNACASTS] Reconnected successfully in getStatus');
|
|
162
186
|
player.client.callAction('AVTransport', 'GetTransportInfo', {
|
|
163
187
|
InstanceID: player.client.instanceId
|
|
164
188
|
}, (err, res) => {
|
|
165
189
|
if (err) return
|
|
166
|
-
const newStatus = res.CurrentTransportState
|
|
190
|
+
const newStatus = res.CurrentTransportState;
|
|
167
191
|
if (newStatus !== player._status.playerState) {
|
|
168
|
-
player._status.playerState = newStatus
|
|
192
|
+
player._status.playerState = newStatus;
|
|
169
193
|
player.status((err, status) => {
|
|
170
194
|
if (err) return
|
|
171
|
-
player.emit('status', status)
|
|
172
|
-
})
|
|
195
|
+
player.emit('status', status);
|
|
196
|
+
});
|
|
173
197
|
}
|
|
174
|
-
})
|
|
175
|
-
})
|
|
198
|
+
});
|
|
199
|
+
});
|
|
176
200
|
return
|
|
177
201
|
}
|
|
178
202
|
player.client.callAction('AVTransport', 'GetTransportInfo', {
|
|
179
203
|
InstanceID: player.client.instanceId
|
|
180
204
|
}, (err, res) => {
|
|
181
205
|
if (err) return
|
|
182
|
-
const newStatus = res.CurrentTransportState
|
|
206
|
+
const newStatus = res.CurrentTransportState;
|
|
183
207
|
if (newStatus !== player._status.playerState) {
|
|
184
|
-
player._status.playerState = newStatus
|
|
208
|
+
player._status.playerState = newStatus;
|
|
185
209
|
player.status((err, status) => {
|
|
186
210
|
if (err) return
|
|
187
|
-
player.emit('status', status)
|
|
188
|
-
})
|
|
211
|
+
player.emit('status', status);
|
|
212
|
+
});
|
|
189
213
|
}
|
|
190
|
-
})
|
|
191
|
-
}, 1000)
|
|
214
|
+
});
|
|
215
|
+
}, 1000);
|
|
192
216
|
|
|
193
|
-
p.load(url, media, callback)
|
|
194
|
-
})
|
|
195
|
-
}
|
|
217
|
+
p.load(url, media, callback);
|
|
218
|
+
});
|
|
219
|
+
};
|
|
196
220
|
|
|
197
221
|
player.resume = (cb = noop) => {
|
|
198
|
-
player.client.play(cb)
|
|
199
|
-
}
|
|
222
|
+
player.client.play(cb);
|
|
223
|
+
};
|
|
200
224
|
|
|
201
225
|
player.pause = (cb = noop) => {
|
|
202
|
-
player.client.pause(cb)
|
|
203
|
-
}
|
|
226
|
+
player.client.pause(cb);
|
|
227
|
+
};
|
|
204
228
|
|
|
205
229
|
player.stop = (cb = noop) => {
|
|
206
|
-
try { clearInterval(getStatus) } catch(e) {}
|
|
207
|
-
stopped = true // Marcar que stop foi chamado
|
|
208
|
-
player.client.stop(cb)
|
|
209
|
-
}
|
|
230
|
+
try { clearInterval(getStatus); } catch(e) {}
|
|
231
|
+
stopped = true; // Marcar que stop foi chamado
|
|
232
|
+
player.client.stop(cb);
|
|
233
|
+
};
|
|
210
234
|
|
|
211
235
|
player.status = (cb = noop) => {
|
|
212
236
|
if (stopped || playFailed) {
|
|
213
|
-
log('[DLNACASTS] Skipping status: stopped=%s, playFailed=%s', stopped, playFailed)
|
|
237
|
+
log('[DLNACASTS] Skipping status: stopped=%s, playFailed=%s', stopped, playFailed);
|
|
214
238
|
return cb(null, player._status)
|
|
215
239
|
}
|
|
216
240
|
if (!player.client) {
|
|
217
|
-
log('[DLNACASTS] player.client is undefined in status, attempting to reconnect')
|
|
241
|
+
log('[DLNACASTS] player.client is undefined in status, attempting to reconnect');
|
|
218
242
|
connect((err) => {
|
|
219
243
|
if (err) {
|
|
220
|
-
log('[DLNACASTS] Reconnect failed in status:', err)
|
|
221
|
-
playFailed = true // Marcar falha se reconexão falhar
|
|
244
|
+
log('[DLNACASTS] Reconnect failed in status:', err);
|
|
245
|
+
playFailed = true; // Marcar falha se reconexão falhar
|
|
222
246
|
return cb(err)
|
|
223
247
|
}
|
|
224
|
-
log('[DLNACASTS] Reconnected successfully in status')
|
|
248
|
+
log('[DLNACASTS] Reconnected successfully in status');
|
|
225
249
|
parallel({
|
|
226
250
|
currentTime: (acb) => {
|
|
227
251
|
player.client.callAction('AVTransport', 'GetPositionInfo', {
|
|
228
252
|
InstanceID: player.client.instanceId
|
|
229
253
|
}, (err, res) => {
|
|
230
254
|
if (err) return acb()
|
|
231
|
-
acb(null, parseTime(res.AbsTime) | parseTime(res.RelTime))
|
|
232
|
-
})
|
|
255
|
+
acb(null, parseTime(res.AbsTime) | parseTime(res.RelTime));
|
|
256
|
+
});
|
|
233
257
|
},
|
|
234
258
|
volume: (acb) => {
|
|
235
|
-
player.getVolume(acb)
|
|
259
|
+
player.getVolume(acb);
|
|
236
260
|
}
|
|
237
261
|
}, (err, results) => {
|
|
238
|
-
log('dlnacasts player.status results: %o', results)
|
|
239
|
-
player._status.currentTime = results.currentTime
|
|
240
|
-
player._status.volume = { level: results.volume / player.MAX_VOLUME }
|
|
262
|
+
log('dlnacasts player.status results: %o', results);
|
|
263
|
+
player._status.currentTime = results.currentTime;
|
|
264
|
+
player._status.volume = { level: results.volume / player.MAX_VOLUME };
|
|
241
265
|
return cb(err, player._status)
|
|
242
|
-
})
|
|
243
|
-
})
|
|
266
|
+
});
|
|
267
|
+
});
|
|
244
268
|
return
|
|
245
269
|
}
|
|
246
270
|
|
|
@@ -250,19 +274,19 @@ module.exports = (options = {}) => {
|
|
|
250
274
|
InstanceID: player.client.instanceId
|
|
251
275
|
}, (err, res) => {
|
|
252
276
|
if (err) return acb()
|
|
253
|
-
acb(null, parseTime(res.AbsTime) | parseTime(res.RelTime))
|
|
254
|
-
})
|
|
277
|
+
acb(null, parseTime(res.AbsTime) | parseTime(res.RelTime));
|
|
278
|
+
});
|
|
255
279
|
},
|
|
256
280
|
volume: (acb) => {
|
|
257
|
-
player.getVolume(acb)
|
|
281
|
+
player.getVolume(acb);
|
|
258
282
|
}
|
|
259
283
|
}, (err, results) => {
|
|
260
|
-
log('dlnacasts player.status results: %o', results)
|
|
261
|
-
player._status.currentTime = results.currentTime
|
|
262
|
-
player._status.volume = { level: results.volume / player.MAX_VOLUME }
|
|
284
|
+
log('dlnacasts player.status results: %o', results);
|
|
285
|
+
player._status.currentTime = results.currentTime;
|
|
286
|
+
player._status.volume = { level: results.volume / player.MAX_VOLUME };
|
|
263
287
|
return cb(err, player._status)
|
|
264
|
-
})
|
|
265
|
-
}
|
|
288
|
+
});
|
|
289
|
+
};
|
|
266
290
|
|
|
267
291
|
player.getVolume = (cb) => {
|
|
268
292
|
player.client.callAction('RenderingControl', 'GetVolume', {
|
|
@@ -270,124 +294,124 @@ module.exports = (options = {}) => {
|
|
|
270
294
|
Channel: 'Master'
|
|
271
295
|
}, (err, res) => {
|
|
272
296
|
if (err) return cb()
|
|
273
|
-
cb(null, res.CurrentVolume ? parseInt(res.CurrentVolume) : 0)
|
|
274
|
-
})
|
|
275
|
-
}
|
|
297
|
+
cb(null, res.CurrentVolume ? parseInt(res.CurrentVolume) : 0);
|
|
298
|
+
});
|
|
299
|
+
};
|
|
276
300
|
|
|
277
301
|
player.setVolume = (vol, cb = noop) => {
|
|
278
302
|
player.client.callAction('RenderingControl', 'SetVolume', {
|
|
279
303
|
InstanceID: player.client.instanceId,
|
|
280
304
|
Channel: 'Master',
|
|
281
305
|
DesiredVolume: vol
|
|
282
|
-
}, cb)
|
|
283
|
-
}
|
|
306
|
+
}, cb);
|
|
307
|
+
};
|
|
284
308
|
|
|
285
309
|
player.request = (target, action, data, cb = noop) => {
|
|
286
310
|
if (data.InstanceID === null) {
|
|
287
|
-
data.InstanceID = player.client.instanceId
|
|
311
|
+
data.InstanceID = player.client.instanceId;
|
|
288
312
|
}
|
|
289
|
-
player.client.callAction(target, action, data, cb)
|
|
290
|
-
}
|
|
313
|
+
player.client.callAction(target, action, data, cb);
|
|
314
|
+
};
|
|
291
315
|
|
|
292
316
|
player.seek = (time, cb = noop) => {
|
|
293
|
-
player.client.seek(time, cb)
|
|
294
|
-
}
|
|
317
|
+
player.client.seek(time, cb);
|
|
318
|
+
};
|
|
295
319
|
|
|
296
|
-
that.players.push(player)
|
|
297
|
-
that.emit('update', player)
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
if (ssdp) {
|
|
301
|
-
// Response handler moved to update()
|
|
302
|
-
}
|
|
320
|
+
that.players.push(player);
|
|
321
|
+
that.emit('update', player);
|
|
322
|
+
};
|
|
303
323
|
|
|
304
324
|
that.validate = (name, host, xml) => {
|
|
305
325
|
if (!casts[name]) {
|
|
306
326
|
http.get(xml, { agent }, res => {
|
|
307
|
-
const {statusCode} = res
|
|
327
|
+
const {statusCode} = res;
|
|
308
328
|
if (statusCode == 200) {
|
|
309
329
|
if (!casts[name]) {
|
|
310
|
-
casts[name] = {name, host, xml}
|
|
311
|
-
emit(casts[name])
|
|
312
|
-
} else if (isIP(casts[name].host) != 4 && isIP(host) == 4) {
|
|
313
|
-
casts[name].host = host
|
|
314
|
-
casts[name].xml = xml
|
|
315
|
-
emit(casts[name])
|
|
330
|
+
casts[name] = {name, host, xml};
|
|
331
|
+
emit(casts[name]);
|
|
332
|
+
} else if (node_net.isIP(casts[name].host) != 4 && node_net.isIP(host) == 4) {
|
|
333
|
+
casts[name].host = host;
|
|
334
|
+
casts[name].xml = xml;
|
|
335
|
+
emit(casts[name]);
|
|
316
336
|
}
|
|
317
337
|
}
|
|
318
|
-
res.resume()
|
|
319
|
-
}).on('error', e => {})
|
|
338
|
+
res.resume();
|
|
339
|
+
}).on('error', e => {});
|
|
320
340
|
}
|
|
321
|
-
}
|
|
341
|
+
};
|
|
322
342
|
|
|
323
343
|
that.update = () => {
|
|
324
|
-
log('[DLNACASTS] querying ssdp')
|
|
325
|
-
if (ssdp) {
|
|
326
|
-
const tasks = []
|
|
344
|
+
log('[DLNACASTS] querying ssdp');
|
|
345
|
+
if (ssdp$1) {
|
|
346
|
+
const tasks = [];
|
|
327
347
|
const responseHandler = (headers, statusCode, info) => {
|
|
348
|
+
log('[DLNACASTS] SSDP response received:', headers.ST || 'no ST', 'from', info.address, 'LOCATION:', headers.LOCATION || 'no LOCATION');
|
|
328
349
|
if (!headers.LOCATION) return
|
|
329
350
|
if (headers.ST !== SERVICE_TYPE) return
|
|
330
351
|
|
|
331
352
|
tasks.push((cb) => {
|
|
332
353
|
http.get(headers.LOCATION, { agent }, (res) => {
|
|
333
354
|
if (res.statusCode !== 200) return cb()
|
|
334
|
-
let body = ''
|
|
335
|
-
res.on('data', (chunk) => { body += chunk })
|
|
355
|
+
let body = '';
|
|
356
|
+
res.on('data', (chunk) => { body += chunk; });
|
|
336
357
|
res.on('end', () => {
|
|
337
|
-
parseString(body, {explicitArray: false, explicitRoot: false},
|
|
358
|
+
xml2js.parseString(body, {explicitArray: false, explicitRoot: false},
|
|
338
359
|
(err, service) => {
|
|
339
360
|
if (err) return cb()
|
|
340
361
|
if (!service.device) return cb()
|
|
341
362
|
|
|
342
|
-
log('[DLNACASTS] ssdp device:', service.device)
|
|
363
|
+
log('[DLNACASTS] ssdp device:', service.device);
|
|
343
364
|
|
|
344
|
-
const name = service.device.friendlyName
|
|
365
|
+
const name = service.device.friendlyName;
|
|
345
366
|
|
|
346
367
|
if (!name) return cb()
|
|
347
368
|
|
|
348
|
-
const host = info.address
|
|
349
|
-
const xml = headers.LOCATION
|
|
369
|
+
const host = info.address;
|
|
370
|
+
const xml = headers.LOCATION;
|
|
350
371
|
|
|
351
372
|
if (!casts[name]) {
|
|
352
|
-
casts[name] = {name: name, host: host, xml: xml}
|
|
353
|
-
emit(casts[name])
|
|
373
|
+
casts[name] = {name: name, host: host, xml: xml};
|
|
374
|
+
emit(casts[name]);
|
|
354
375
|
} else if (casts[name] && !casts[name].host) {
|
|
355
|
-
casts[name].host = host
|
|
356
|
-
casts[name].xml = xml
|
|
357
|
-
emit(casts[name])
|
|
376
|
+
casts[name].host = host;
|
|
377
|
+
casts[name].xml = xml;
|
|
378
|
+
emit(casts[name]);
|
|
358
379
|
}
|
|
359
|
-
cb()
|
|
360
|
-
})
|
|
361
|
-
})
|
|
362
|
-
}).on('error', () => cb())
|
|
363
|
-
})
|
|
364
|
-
}
|
|
365
|
-
ssdp.on('response', responseHandler)
|
|
366
|
-
ssdp.search(SERVICE_TYPE)
|
|
367
|
-
log('[DLNACASTS] SSDP search started for:', SERVICE_TYPE)
|
|
380
|
+
cb();
|
|
381
|
+
});
|
|
382
|
+
});
|
|
383
|
+
}).on('error', () => cb());
|
|
384
|
+
});
|
|
385
|
+
};
|
|
386
|
+
ssdp$1.on('response', responseHandler);
|
|
387
|
+
ssdp$1.search(SERVICE_TYPE);
|
|
388
|
+
log('[DLNACASTS] SSDP search started for:', SERVICE_TYPE);
|
|
368
389
|
setTimeout(() => {
|
|
369
|
-
ssdp.removeListener('response', responseHandler)
|
|
370
|
-
parallel(tasks, () => {})
|
|
371
|
-
}, 10000)
|
|
390
|
+
ssdp$1.removeListener('response', responseHandler);
|
|
391
|
+
parallel(tasks, () => {});
|
|
392
|
+
}, 10000);
|
|
372
393
|
}
|
|
373
|
-
}
|
|
394
|
+
};
|
|
374
395
|
|
|
375
396
|
that.on('removeListener', () => {
|
|
376
|
-
if (ssdp && that.listenerCount('update') === 0) {
|
|
377
|
-
ssdp.stop()
|
|
397
|
+
if (ssdp$1 && that.listenerCount('update') === 0) {
|
|
398
|
+
ssdp$1.stop();
|
|
378
399
|
}
|
|
379
|
-
})
|
|
400
|
+
});
|
|
380
401
|
|
|
381
402
|
that.destroy = () => {
|
|
382
|
-
log('[DLNACASTS] destroying ssdp...')
|
|
383
|
-
if (ssdp) {
|
|
384
|
-
ssdp.stop()
|
|
403
|
+
log('[DLNACASTS] destroying ssdp...');
|
|
404
|
+
if (ssdp$1) {
|
|
405
|
+
ssdp$1.stop();
|
|
385
406
|
}
|
|
386
|
-
}
|
|
407
|
+
};
|
|
387
408
|
|
|
388
409
|
that.close = () => {
|
|
389
|
-
that.removeAllListeners('update')
|
|
390
|
-
}
|
|
410
|
+
that.removeAllListeners('update');
|
|
411
|
+
};
|
|
391
412
|
|
|
392
413
|
return that
|
|
393
|
-
}
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
module.exports = index;
|
|
417
|
+
//# sourceMappingURL=index.cjs.map
|