homebridge-xbox-tv 3.7.9-beta.21 → 3.7.9-beta.23

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "displayName": "Xbox TV",
3
3
  "name": "homebridge-xbox-tv",
4
- "version": "3.7.9-beta.21",
4
+ "version": "3.7.9-beta.23",
5
5
  "description": "Homebridge plugin to control Xbox game consoles.",
6
6
  "license": "MIT",
7
7
  "author": "grzegorz914",
@@ -1,140 +1,148 @@
1
1
  class Structure {
2
2
  constructor(packet) {
3
- packet = packet === undefined ? Buffer.from('') : packet;
4
- this.packet = packet;
5
- this.totalLength = packet.length;
3
+ this.packet = packet ?? Buffer.alloc(0);
4
+ this.totalLength = this.packet.length;
6
5
  this.offset = 0;
7
-
8
- return this;
9
- };
6
+ }
10
7
 
11
8
  writeSGString(data) {
12
9
  if (typeof data !== 'string') {
13
10
  throw new Error('data must be a string');
14
11
  }
15
12
 
16
- const dataLength = data.length;
13
+ const dataLength = Buffer.byteLength(data, 'utf8');
17
14
  if (dataLength > 65535) {
18
15
  throw new Error('data exceeds the maximum allowed length');
19
16
  }
20
17
 
21
18
  const stringLengthBuffer = Buffer.allocUnsafe(2);
22
19
  stringLengthBuffer.writeUInt16BE(dataLength, 0);
23
- const dataBuffer = Buffer.from(data + '\x00');
24
- this.add(Buffer.concat([stringLengthBuffer, dataBuffer]));
20
+
21
+ const dataBuffer = Buffer.from(data, 'utf8');
22
+ const nullTerminator = Buffer.from([0]);
23
+
24
+ this.add(Buffer.concat([stringLengthBuffer, dataBuffer, nullTerminator]));
25
25
  return this;
26
- };
26
+ }
27
27
 
28
28
  readSGString() {
29
29
  const stringLength = this.readUInt16();
30
30
  const stringBuffer = this.packet.slice(this.offset, this.offset + stringLength);
31
- this.offset += stringLength + 1;
32
- return stringBuffer;
33
- };
31
+ this.offset += stringLength + 1; // skip null terminator
32
+ return stringBuffer.toString('utf8');
33
+ }
34
34
 
35
35
  writeBytes(data, type) {
36
36
  const dataBuffer = Buffer.from(data, type);
37
37
  this.add(dataBuffer);
38
38
  return this;
39
- };
39
+ }
40
40
 
41
41
  readBytes(length = false) {
42
- let rawData = '';
43
- switch (length) {
44
- case false:
45
- rawData = this.packet.slice(this.offset);
46
- this.offset = this.totalLength;
47
- break;
48
- default:
49
- rawData = this.packet.slice(this.offset, this.offset + length);
50
- this.offset += length;
51
- break
42
+ let rawData;
43
+ if (length === false) {
44
+ rawData = this.packet.slice(this.offset);
45
+ this.offset = this.totalLength;
46
+ } else {
47
+ rawData = this.packet.slice(this.offset, this.offset + length);
48
+ this.offset += length;
52
49
  }
53
50
  return rawData;
54
- };
51
+ }
55
52
 
56
53
  writeUInt8(data) {
57
54
  if (data < 0 || data > 255) {
58
55
  throw new Error('data must be a valid unsigned 8-bit integer');
59
56
  }
60
-
61
- const uint8Buffer = Buffer.allocUnsafe(1);
62
- uint8Buffer.writeUInt8(data, 0);
63
- this.add(uint8Buffer);
57
+ const buf = Buffer.allocUnsafe(1);
58
+ buf.writeUInt8(data, 0);
59
+ this.add(buf);
64
60
  return this;
65
- };
61
+ }
66
62
 
67
63
  readUInt8() {
68
- const uint8 = this.packet.readUInt8BE(this.offset);
64
+ const value = this.packet.readUInt8(this.offset);
69
65
  this.offset += 1;
70
- return uint8;
71
- };
66
+ return value;
67
+ }
72
68
 
73
69
  writeUInt16(data) {
74
70
  if (data < 0 || data > 65535) {
75
71
  throw new Error('data must be a valid unsigned 16-bit integer');
76
72
  }
77
-
78
- const uint16Buffer = Buffer.allocUnsafe(2);
79
- uint16Buffer.writeUInt16BE(data, 0);
80
- this.add(uint16Buffer);
73
+ const buf = Buffer.allocUnsafe(2);
74
+ buf.writeUInt16BE(data, 0);
75
+ this.add(buf);
81
76
  return this;
82
- };
77
+ }
83
78
 
84
79
  readUInt16() {
85
- const uint16 = this.packet.readUInt16BE(this.offset);
80
+ const value = this.packet.readUInt16BE(this.offset);
86
81
  this.offset += 2;
87
- return uint16;
88
- };
82
+ return value;
83
+ }
89
84
 
90
85
  writeUInt32(data) {
91
- if (data < 0 || data > 4294967295) {
86
+ if (data < 0 || data > 0xFFFFFFFF) {
92
87
  throw new Error('data must be a valid unsigned 32-bit integer');
93
88
  }
94
-
95
- const uint32Buffer = Buffer.allocUnsafe(4);
96
- uint32Buffer.writeUInt32BE(data, 0);
97
- this.add(uint32Buffer);
89
+ const buf = Buffer.allocUnsafe(4);
90
+ buf.writeUInt32BE(data, 0);
91
+ this.add(buf);
98
92
  return this;
99
- };
93
+ }
100
94
 
101
95
  readUInt32() {
102
- const uint32 = this.packet.readUInt32BE(this.offset);
96
+ const value = this.packet.readUInt32BE(this.offset);
103
97
  this.offset += 4;
104
- return uint32;
105
- };
98
+ return value;
99
+ }
106
100
 
107
101
  writeInt32(data) {
108
102
  if (data < -2147483648 || data > 2147483647) {
109
103
  throw new Error('data must be a valid signed 32-bit integer');
110
104
  }
111
- const int32Buffer = Buffer.allocUnsafe(4);
112
- int32Buffer.writeInt32BE(data, 0);
113
- this.add(int32Buffer);
105
+ const buf = Buffer.allocUnsafe(4);
106
+ buf.writeInt32BE(data, 0);
107
+ this.add(buf);
114
108
  return this;
115
- };
109
+ }
116
110
 
117
111
  readInt32() {
118
- const int32 = this.packet.readInt32BE(this.offset);
112
+ const value = this.packet.readInt32BE(this.offset);
119
113
  this.offset += 4;
120
- return int32;
121
- };
114
+ return value;
115
+ }
116
+
117
+ writeUInt64(value) {
118
+ if (typeof value !== 'bigint') {
119
+ throw new Error('value must be a BigInt');
120
+ }
121
+ const buf = Buffer.allocUnsafe(8);
122
+ buf.writeUInt32BE(Number(value >> 32n), 0);
123
+ buf.writeUInt32BE(Number(value & 0xFFFFFFFFn), 4);
124
+ this.add(buf);
125
+ return this;
126
+ }
122
127
 
123
128
  readUInt64() {
124
- const data = this.readBytes(8);
125
- return data;
126
- };
129
+ const high = this.packet.readUInt32BE(this.offset);
130
+ const low = this.packet.readUInt32BE(this.offset + 4);
131
+ this.offset += 8;
132
+ return (BigInt(high) << 32n) | BigInt(low);
133
+ }
127
134
 
128
135
  toBuffer() {
129
136
  return this.packet;
130
- };
137
+ }
131
138
 
132
139
  add(data) {
133
140
  if (!Buffer.isBuffer(data)) {
134
141
  throw new Error('Data must be a Buffer object');
135
142
  }
136
-
137
143
  this.packet = Buffer.concat([this.packet, data]);
138
- };
139
- };
140
- export default Structure;
144
+ this.totalLength = this.packet.length;
145
+ }
146
+ }
147
+
148
+ export default Structure;
@@ -30,6 +30,7 @@ class XboxLocalApi extends EventEmitter {
30
30
  this.channels = [];
31
31
  this.channelRequestId = 0;
32
32
  this.mediaRequestId = 0;
33
+ this.fragments = {};
33
34
 
34
35
  //create impulse generator
35
36
  this.impulseGenerator = new ImpulseGenerator();
@@ -205,8 +206,8 @@ class XboxLocalApi extends EventEmitter {
205
206
  };
206
207
 
207
208
  const channelRequestId = LocalApi.Channels.System[channelName].Id
208
- const channelCommunicationId = this.channels[requestId].id;
209
- const channelOpen = this.channels[requestId].open;
209
+ const channelCommunicationId = this.channels[channelRequestId]?.id ?? -1;
210
+ const channelOpen = this.channels[channelRequestId]?.open ?? false;
210
211
 
211
212
  if (channelCommunicationId === -1 || !channelOpen) {
212
213
  this.emit('warn', `Channel Id: ${channelCommunicationId}, state: ${channelOpen ? 'Open' : 'Closed'}, trying to open it`);
@@ -278,91 +279,6 @@ class XboxLocalApi extends EventEmitter {
278
279
  return true;
279
280
  };
280
281
 
281
- // Dodaj do klasy XboxLocalApi:
282
-
283
- async sendSystemButton(channelName, command) {
284
- if (!this.isConnected) {
285
- this.emit('warn', `Cannot send command, console not connected`);
286
- return;
287
- }
288
-
289
- const channelInfo = LocalApi.Channels.System[channelName];
290
- if (!channelInfo) {
291
- this.emit('warn', `Unknown channel: ${channelName}`);
292
- return;
293
- }
294
-
295
- let channel = this.channels.find(c => c.id !== -1);
296
- if (!channel) {
297
- // Otwórz kanał jeśli nie istnieje
298
- await this.channelOpen(channelInfo.Id, channelInfo.Uuid);
299
- channel = this.channels.find(c => c.id !== -1);
300
- if (!channel) {
301
- this.emit('warn', `Failed to open channel: ${channelName}`);
302
- return;
303
- }
304
- }
305
-
306
- const channelId = channel.id;
307
-
308
- switch (channelInfo.Id) {
309
- case 0: // Gamepad
310
- await this._sendGamepadCommand(command, channelId);
311
- break;
312
- case 1: // TvRemote
313
- await this._sendTvRemoteCommand(command, channelId);
314
- break;
315
- case 2: // Media
316
- await this._sendMediaCommand(command, channelId);
317
- break;
318
- default:
319
- this.emit('warn', `Unhandled channel type: ${channelName}`);
320
- }
321
- }
322
-
323
- // Prywatne metody do wysyłania komend
324
- async _sendGamepadCommand(buttons, channelId) {
325
- const timestamp = Buffer.from(`000${Date.now()}`, 'hex');
326
- const press = new MessagePacket('gamepad');
327
- press.set('timestamp', timestamp);
328
- press.set('buttons', buttons);
329
- let seq = await this.getSequenceNumber();
330
- await this.sendSocketMessage(press.pack(this.crypto, seq, this.sourceParticipantId, channelId), 'gamepad');
331
-
332
- // Release buttons
333
- setTimeout(async () => {
334
- const release = new MessagePacket('gamepad');
335
- release.set('timestamp', timestamp);
336
- release.set('buttons', LocalApi.Channels.System.Input.Commands.unpress);
337
- seq = await this.getSequenceNumber();
338
- await this.sendSocketMessage(release.pack(this.crypto, seq, this.sourceParticipantId, channelId), 'gamepadUnpress');
339
- }, 150);
340
- }
341
-
342
- async _sendTvRemoteCommand(command, channelId) {
343
- const seq = await this.getSequenceNumber();
344
- const jsonReq = JSON.stringify({
345
- msgid: `2ed6c0fd.${seq}`,
346
- request: LocalApi.Channels.System.TvRemote.MessageType.SendKey,
347
- params: { button_id: command, device_id: null }
348
- });
349
- const json = new MessagePacket('json');
350
- json.set('json', jsonReq);
351
- await this.sendSocketMessage(json.pack(this.crypto, seq, this.sourceParticipantId, channelId), 'json');
352
- }
353
-
354
- async _sendMediaCommand(command, channelId) {
355
- const requestIdHex = (`0000000000000000${this.mediaRequestId}`).slice(-16);
356
- const media = new MessagePacket('mediaCommand');
357
- media.set('requestId', Buffer.from(requestIdHex, 'hex'));
358
- media.set('titleId', 0);
359
- media.set('command', command);
360
- const seq = await this.getSequenceNumber();
361
- await this.sendSocketMessage(media.pack(this.crypto, seq, this.sourceParticipantId, channelId), 'mediaCommand');
362
- this.mediaRequestId++;
363
- }
364
-
365
-
366
282
  async disconnect() {
367
283
  if (this.enableDebugMode) this.emit('debug', 'Disconnecting...');
368
284
 
@@ -475,7 +391,7 @@ class XboxLocalApi extends EventEmitter {
475
391
  switch (type) {
476
392
  case 'json':
477
393
  // Object to hold fragments
478
- const fragments = {};
394
+ const fragments = this.fragments;
479
395
  const jsonMessage = JSON.parse(packet.payloadProtected.json);
480
396
  const datagramId = jsonMessage.datagramId;
481
397
 
package/src/xboxdevice.js CHANGED
@@ -658,10 +658,7 @@ class XboxDevice extends EventEmitter {
658
658
  break;
659
659
  }
660
660
 
661
- //await this.xboxWebApi.send(channelName, 'InjectKey', [{ 'keyType': command }]);
662
- await this.xboxLocalApi.sendSystemButton('Input', LocalApi.Channels.System.Input.Commands[command]);
663
- //await xboxLocalApi.sendSystemButton('TvRemote', LocalApi.Channels.System.TvRemote.Buttons.Power);
664
- //await xboxLocalApi.sendSystemButton('Media', LocalApi.Channels.System.Media.Commands[command]);
661
+ await this.xboxWebApi.send(channelName, 'InjectKey', [{ 'keyType': command }]);
665
662
  if (!this.disableLogInfo) this.emit('info', `Remote Key: ${command}`);
666
663
  } catch (error) {
667
664
  this.emit('warn', `set Remote Key error: ${JSON.stringify(error, null, 2)}`);