homebridge-xbox-tv 3.7.3 → 3.7.4-beta.0
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 +1 -1
- package/src/webApi/xboxwebapi.js +3 -3
- package/src/xboxdevice.js +128 -3
package/package.json
CHANGED
package/src/webApi/xboxwebapi.js
CHANGED
|
@@ -250,14 +250,14 @@ class XboxWebApi extends EventEmitter {
|
|
|
250
250
|
'contentType': contentType
|
|
251
251
|
}
|
|
252
252
|
inputs.push(input);
|
|
253
|
+
|
|
254
|
+
//emit app
|
|
255
|
+
this.emit('addRemoveOrUpdateInput', input, false);
|
|
253
256
|
}
|
|
254
257
|
|
|
255
258
|
//save inputs
|
|
256
259
|
await this.saveData(this.inputsFile, inputs);
|
|
257
260
|
|
|
258
|
-
//emit apps
|
|
259
|
-
this.emit('addRemoveOrUpdateInput', inputs, false);
|
|
260
|
-
|
|
261
261
|
//emit restFul and mqtt
|
|
262
262
|
this.emit('restFul', 'apps', apps);
|
|
263
263
|
this.emit('mqtt', 'Apps', apps);
|
package/src/xboxdevice.js
CHANGED
|
@@ -481,6 +481,129 @@ class XboxDevice extends EventEmitter {
|
|
|
481
481
|
}
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
+
async addRemoveOrUpdateInput(input, remove = false) {
|
|
485
|
+
try {
|
|
486
|
+
// Safety: no services or too many inputs (only block on add)
|
|
487
|
+
if (!this.inputsServices || (this.inputsServices.length >= 85 && !remove)) return;
|
|
488
|
+
|
|
489
|
+
// --- FILTER APPS ---
|
|
490
|
+
const contentType = input.contentType;
|
|
491
|
+
const filterGames = this.filterGames && contentType === 'Game';
|
|
492
|
+
const filterApps = this.filterApps && contentType === 'App';
|
|
493
|
+
const filterSystemApps = this.filterSystemApps && contentType === 'systemApp';
|
|
494
|
+
const filterDlc = this.filterDlc && contentType === 'Dlc';
|
|
495
|
+
if (filterGames || filterApps || filterSystemApps || filterDlc) return;
|
|
496
|
+
|
|
497
|
+
// Input reference
|
|
498
|
+
const inputReference = input.reference;
|
|
499
|
+
|
|
500
|
+
// --- REMOVE ---
|
|
501
|
+
if (remove) {
|
|
502
|
+
const svc = this.inputsServices.find(s => s.reference === inputReference);
|
|
503
|
+
if (svc) {
|
|
504
|
+
if (this.enableDebugMode) this.emit('debug', `Removing input: ${input.name} (${inputReference})`);
|
|
505
|
+
this.accessory.removeService(svc);
|
|
506
|
+
this.inputsServices = this.inputsServices.filter(s => s.reference !== inputReference);
|
|
507
|
+
await this.displayOrder();
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
if (this.enableDebugMode) this.emit('debug', `Remove failed (not found): ${input.name} (${inputReference})`);
|
|
511
|
+
return false;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// --- ADD OR UPDATE ---
|
|
515
|
+
let inputService = this.inputsServices.find(s => s.reference === inputReference);
|
|
516
|
+
|
|
517
|
+
const savedName = this.savedInputsNames[inputReference] ?? input.name;
|
|
518
|
+
const sanitizedName = await this.sanitizeString(savedName);
|
|
519
|
+
const inputMode = input.mode;
|
|
520
|
+
const inputVisibility = this.savedInputsTargetVisibility[inputReference] ?? 0;
|
|
521
|
+
|
|
522
|
+
if (inputService) {
|
|
523
|
+
// === UPDATE EXISTING ===
|
|
524
|
+
inputService.name = sanitizedName;
|
|
525
|
+
inputService.visibility = inputVisibility;
|
|
526
|
+
|
|
527
|
+
inputService
|
|
528
|
+
.updateCharacteristic(Characteristic.Name, sanitizedName)
|
|
529
|
+
.updateCharacteristic(Characteristic.ConfiguredName, sanitizedName)
|
|
530
|
+
.updateCharacteristic(Characteristic.TargetVisibilityState, inputVisibility)
|
|
531
|
+
.updateCharacteristic(Characteristic.CurrentVisibilityState, inputVisibility);
|
|
532
|
+
|
|
533
|
+
if (this.enableDebugMode) this.emit('debug', `Updated input: ${input.name} (${inputReference})`);
|
|
534
|
+
} else {
|
|
535
|
+
// === CREATE NEW ===
|
|
536
|
+
const identifier = this.inputsServices.length + 1;
|
|
537
|
+
inputService = this.accessory.addService(Service.InputSource, sanitizedName, `Input ${identifier}`);
|
|
538
|
+
|
|
539
|
+
// Custom props
|
|
540
|
+
inputService.identifier = identifier;
|
|
541
|
+
inputService.reference = inputReference;
|
|
542
|
+
inputService.name = sanitizedName;
|
|
543
|
+
inputService.mode = inputMode;
|
|
544
|
+
inputService.visibility = inputVisibility;
|
|
545
|
+
|
|
546
|
+
inputService
|
|
547
|
+
.setCharacteristic(Characteristic.Identifier, identifier)
|
|
548
|
+
.setCharacteristic(Characteristic.Name, sanitizedName)
|
|
549
|
+
.setCharacteristic(Characteristic.ConfiguredName, sanitizedName)
|
|
550
|
+
.setCharacteristic(Characteristic.IsConfigured, 1)
|
|
551
|
+
.setCharacteristic(Characteristic.InputSourceType, inputMode) // 0=HDMI-like Input, 1=Tuner/Channel
|
|
552
|
+
.setCharacteristic(Characteristic.CurrentVisibilityState, inputVisibility)
|
|
553
|
+
.setCharacteristic(Characteristic.TargetVisibilityState, inputVisibility);
|
|
554
|
+
|
|
555
|
+
// --- ConfiguredName rename persistence ---
|
|
556
|
+
inputService.getCharacteristic(Characteristic.ConfiguredName)
|
|
557
|
+
.onSet(async (value) => {
|
|
558
|
+
try {
|
|
559
|
+
inputService.name = value;
|
|
560
|
+
this.savedInputsNames[inputReference] = value;
|
|
561
|
+
await this.saveData(this.inputsNamesFile, this.savedInputsNames);
|
|
562
|
+
|
|
563
|
+
if (this.enableDebugMode) {
|
|
564
|
+
this.emit('debug', `Saved Input Name: ${value}, Reference: ${inputReference}`);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
// keep in sync
|
|
568
|
+
const index = this.inputsServices.findIndex(s => s.reference === inputReference);
|
|
569
|
+
if (index !== -1) this.inputsServices[index].name = value;
|
|
570
|
+
|
|
571
|
+
await this.displayOrder();
|
|
572
|
+
} catch (error) {
|
|
573
|
+
this.emit('warn', `Save Input Name error: ${error}`);
|
|
574
|
+
}
|
|
575
|
+
});
|
|
576
|
+
|
|
577
|
+
// --- TargetVisibility persistence ---
|
|
578
|
+
inputService.getCharacteristic(Characteristic.TargetVisibilityState)
|
|
579
|
+
.onSet(async (state) => {
|
|
580
|
+
try {
|
|
581
|
+
inputService.visibility = state;
|
|
582
|
+
this.savedInputsTargetVisibility[inputReference] = state;
|
|
583
|
+
await this.saveData(this.inputsTargetVisibilityFile, this.savedInputsTargetVisibility);
|
|
584
|
+
|
|
585
|
+
if (this.enableDebugMode) {
|
|
586
|
+
this.emit('debug', `Saved Input: ${input.name}, Target Visibility: ${state ? 'HIDDEN' : 'SHOWN'}`);
|
|
587
|
+
}
|
|
588
|
+
} catch (error) {
|
|
589
|
+
this.emit('warn', `Save Target Visibility error: ${error}`);
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
|
|
593
|
+
this.inputsServices.push(inputService);
|
|
594
|
+
this.televisionService.addLinkedService(inputService);
|
|
595
|
+
|
|
596
|
+
if (this.enableDebugMode) this.emit('debug', `Added new input: ${input.name} (${inputReference})`);
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
// Normalize identifiers and order
|
|
600
|
+
await this.displayOrder();
|
|
601
|
+
return true;
|
|
602
|
+
} catch (error) {
|
|
603
|
+
throw new Error(`Add/Update input error: ${error}`);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
|
|
484
607
|
//Prepare accessory
|
|
485
608
|
async prepareAccessory() {
|
|
486
609
|
try {
|
|
@@ -723,7 +846,9 @@ class XboxDevice extends EventEmitter {
|
|
|
723
846
|
if (this.enableDebugMode) this.emit('debug', `Prepare inputs service`);
|
|
724
847
|
this.inputsServices = [];
|
|
725
848
|
const inputs = this.getInputsFromDevice ? [...DefaultInputs, ...this.savedInputs] : this.inputs;
|
|
726
|
-
|
|
849
|
+
for (const input of inputs) {
|
|
850
|
+
await this.addRemoveOrUpdateInput(input, false);
|
|
851
|
+
};
|
|
727
852
|
|
|
728
853
|
//Prepare volume service
|
|
729
854
|
if (this.volumeControl > 0) {
|
|
@@ -1050,8 +1175,8 @@ class XboxDevice extends EventEmitter {
|
|
|
1050
1175
|
//this.power = powerState;
|
|
1051
1176
|
//this.mediaState = playbackState;
|
|
1052
1177
|
})
|
|
1053
|
-
.on('addRemoveOrUpdateInput', async (
|
|
1054
|
-
await this.addRemoveOrUpdateInput(
|
|
1178
|
+
.on('addRemoveOrUpdateInput', async (input, remove) => {
|
|
1179
|
+
await this.addRemoveOrUpdateInput(input, remove);
|
|
1055
1180
|
})
|
|
1056
1181
|
.on('success', (success) => {
|
|
1057
1182
|
this.emit('success', success);
|