mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-11 11:06:16 -08:00
fix(portals): gate VOD auto-failover on engines that can report failures
Merges master and resolves the collision with its shared playback helpers, then closes two Codex findings. Master extracted the Play/Stop button state and the inline position writer that this branch had modified. Rather than forking private copies back out of Xtream, both behaviours move into the shared helpers: `alsoOwns` lets a page own an external session launched for a copy of the same film in another playlist, and the resume latch — which stops a timeupdate emitted before the engine reaches `startTime` from overwriting the point being resumed from — now protects Stalker too, which had the same bug. Auto-failover was offered on every engine, but only the built-in web players raise the playback diagnostic that reaches `onPlaybackFailed()`: Embedded MPV has its diagnostics suppressed and MPV/VLC play outside the app. The toggle is now hidden there, in settings and in the sources menu, instead of promising a switch that can never happen. `setAutoFailover` also ignored `updateSettings()`, which patches memory first and rejects if the write fails — the toggle looked saved, silently reverted on restart, and the rejection surfaced only as an unhandled promise. It now reports the failure like the settings form's own save paths. The three VOD-details route specs each carried a near-identical 150-line TestBed; they now share one harness, which is what makes room for the new cases (1012 -> 584 lines). Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
56733db1ec
37 files changed
+1795
-910
No files matched your search
@@ -39,6 +39,7 @@
|
||||
[title]="title()"
|
||||
[matchKind]="matchKind()"
|
||||
[autoFailoverEnabled]="autoFailoverEnabled()"
|
||||
[autoFailoverSupported]="autoFailoverSupported()"
|
||||
[resumeLabel]="resumeLabel()"
|
||||
[showPin]="showPin()"
|
||||
(playRequested)="onPlay($event)"
|
||||
|
||||
@@ -42,6 +42,8 @@ export class VodSourcesChipComponent {
|
||||
readonly title = input('');
|
||||
readonly matchKind = input<VodSourceMatchKind>('title-year');
|
||||
readonly autoFailoverEnabled = input(false);
|
||||
/** See `VodSourcesMenuComponent.autoFailoverSupported`. */
|
||||
readonly autoFailoverSupported = input(true);
|
||||
readonly resumeLabel = input<string | null>(null);
|
||||
readonly showPin = input(true);
|
||||
/** Falls back to the number of sources when the host does not override it. */
|
||||
|
||||
@@ -120,16 +120,20 @@
|
||||
}
|
||||
</div>
|
||||
|
||||
<div class="sources-menu__footer">
|
||||
<span class="sources-menu__footer-label">{{
|
||||
'PORTALS.MULTI_SOURCE.AUTO_FAILOVER' | translate
|
||||
}}</span>
|
||||
<mat-slide-toggle
|
||||
class="sources-menu__toggle"
|
||||
[checked]="autoFailoverEnabled()"
|
||||
(change)="onAutoFailoverChange($event)"
|
||||
(click)="$event.stopPropagation()"
|
||||
[attr.aria-label]="'PORTALS.MULTI_SOURCE.AUTO_FAILOVER' | translate"
|
||||
/>
|
||||
</div>
|
||||
@if (autoFailoverSupported()) {
|
||||
<div class="sources-menu__footer">
|
||||
<span class="sources-menu__footer-label">{{
|
||||
'PORTALS.MULTI_SOURCE.AUTO_FAILOVER' | translate
|
||||
}}</span>
|
||||
<mat-slide-toggle
|
||||
class="sources-menu__toggle"
|
||||
[checked]="autoFailoverEnabled()"
|
||||
(change)="onAutoFailoverChange($event)"
|
||||
(click)="$event.stopPropagation()"
|
||||
[attr.aria-label]="
|
||||
'PORTALS.MULTI_SOURCE.AUTO_FAILOVER' | translate
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@@ -243,6 +243,22 @@ describe('VodSourcesMenuComponent', () => {
|
||||
expect(emitted).toEqual([true]);
|
||||
});
|
||||
|
||||
it('drops the footer switch on a player that cannot report failures', () => {
|
||||
// MPV, VLC and Embedded MPV never raise the playback diagnostic that
|
||||
// drives failover, so the switch there promises something that can
|
||||
// never happen.
|
||||
render([createSource()]);
|
||||
fixture.componentRef.setInput('autoFailoverSupported', false);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(
|
||||
fixture.debugElement.query(By.css('.sources-menu__toggle'))
|
||||
).toBeNull();
|
||||
expect(fixture.nativeElement.textContent).not.toContain(
|
||||
'Auto-switch on error'
|
||||
);
|
||||
});
|
||||
|
||||
it('shows the match kind in the header, or the resume label when given', () => {
|
||||
fixture.componentRef.setInput('sources', [createSource()]);
|
||||
fixture.componentRef.setInput('matchKind', 'tmdb');
|
||||
|
||||
@@ -56,6 +56,12 @@ export class VodSourcesMenuComponent {
|
||||
readonly title = input('');
|
||||
readonly matchKind = input<VodSourceMatchKind>('title-year');
|
||||
readonly autoFailoverEnabled = input(false);
|
||||
/**
|
||||
* False on players that never report a playback failure (MPV, VLC,
|
||||
* Embedded MPV). The toggle would then promise a switch that can never
|
||||
* happen, so it is not offered at all.
|
||||
*/
|
||||
readonly autoFailoverSupported = input(true);
|
||||
/**
|
||||
* In-player variant: replaces the match kind with e.g.
|
||||
* "timecode will be kept · 0:42:18". Already formatted by the host.
|
||||
|
||||
Reference in new issue
Block a user