mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 05:36:17 -08:00
fix(playback): avoid redundant VideoJS source resets
This commit is contained in:
1 parent
935ed1b1a9
commit
d539de3dda
3 files changed
+154
-8
No files matched your search
@@ -6,6 +6,21 @@
|
||||
"projectType": "library",
|
||||
"tags": ["scope:shared", "domain:playback", "type:ui"],
|
||||
"targets": {
|
||||
"test": {
|
||||
"executor": "nx:run-commands",
|
||||
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
|
||||
"options": {
|
||||
"command": [
|
||||
"node",
|
||||
"./tools/testing/run-web-esm-lib-tests.mjs",
|
||||
"libs/ui/playback/src"
|
||||
],
|
||||
"env": {
|
||||
"NODE_OPTIONS": "--experimental-vm-modules"
|
||||
},
|
||||
"forwardAllArgs": true
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"executor": "@nx/eslint:lint"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
import { SimpleChange } from '@angular/core';
|
||||
import type { VjsPlayerComponent as VjsPlayerComponentInstance } from './vjs-player.component';
|
||||
|
||||
const videoJsMock = jest.fn();
|
||||
const mpegTsIsSupportedMock = jest.fn(() => false);
|
||||
|
||||
jest.unstable_mockModule('video.js', () => ({
|
||||
default: videoJsMock,
|
||||
}));
|
||||
|
||||
jest.unstable_mockModule('@yangkghjh/videojs-aspect-ratio-panel', () => ({}));
|
||||
jest.unstable_mockModule('videojs-contrib-quality-levels', () => ({}));
|
||||
jest.unstable_mockModule('videojs-quality-selector-hls', () => ({}));
|
||||
|
||||
jest.unstable_mockModule('mpegts.js', () => ({
|
||||
default: {
|
||||
createPlayer: jest.fn(),
|
||||
isSupported: mpegTsIsSupportedMock,
|
||||
},
|
||||
}));
|
||||
|
||||
describe('VjsPlayerComponent', () => {
|
||||
let VjsPlayerComponent: typeof import('./vjs-player.component').VjsPlayerComponent;
|
||||
let component: VjsPlayerComponentInstance;
|
||||
let player: VjsPlayerComponentInstance['player'];
|
||||
|
||||
beforeAll(async () => {
|
||||
({ VjsPlayerComponent } = await import('./vjs-player.component'));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
component = new VjsPlayerComponent();
|
||||
player = {
|
||||
src: jest.fn(),
|
||||
reset: jest.fn(),
|
||||
volume: jest.fn(),
|
||||
} as unknown as VjsPlayerComponentInstance['player'];
|
||||
component.player = player;
|
||||
});
|
||||
|
||||
it('does not reset VideoJS when options change without changing the source', () => {
|
||||
const previousOptions = {
|
||||
sources: [
|
||||
{
|
||||
src: 'https://example.com/live/playlist.m3u8',
|
||||
type: 'application/x-mpegURL',
|
||||
},
|
||||
],
|
||||
};
|
||||
const currentOptions = {
|
||||
sources: [
|
||||
{
|
||||
src: 'https://example.com/live/playlist.m3u8',
|
||||
type: 'application/x-mpegURL',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
component.ngOnChanges({
|
||||
options: new SimpleChange(previousOptions, currentOptions, false),
|
||||
});
|
||||
|
||||
expect(player.src).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('updates VideoJS when options change to a different source', () => {
|
||||
const previousOptions = {
|
||||
sources: [
|
||||
{
|
||||
src: 'https://example.com/live/playlist.m3u8',
|
||||
type: 'application/x-mpegURL',
|
||||
},
|
||||
],
|
||||
};
|
||||
const currentOptions = {
|
||||
sources: [
|
||||
{
|
||||
src: 'https://example.com/live/other-playlist.m3u8',
|
||||
type: 'application/x-mpegURL',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
component.ngOnChanges({
|
||||
options: new SimpleChange(previousOptions, currentOptions, false),
|
||||
});
|
||||
|
||||
expect(player.src).toHaveBeenCalledWith(currentOptions.sources[0]);
|
||||
});
|
||||
|
||||
it('updates volume when options change without changing the source', () => {
|
||||
const previousOptions = {
|
||||
sources: [
|
||||
{
|
||||
src: 'https://example.com/live/playlist.m3u8',
|
||||
type: 'application/x-mpegURL',
|
||||
},
|
||||
],
|
||||
};
|
||||
const currentOptions = {
|
||||
sources: [
|
||||
{
|
||||
src: 'https://example.com/live/playlist.m3u8',
|
||||
type: 'application/x-mpegURL',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
component.ngOnChanges({
|
||||
options: new SimpleChange(previousOptions, currentOptions, false),
|
||||
volume: new SimpleChange(0.5, 0.75, false),
|
||||
});
|
||||
|
||||
expect(player.src).not.toHaveBeenCalled();
|
||||
expect(player.volume).toHaveBeenCalledWith(0.75);
|
||||
});
|
||||
});
|
||||
@@ -198,14 +198,18 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
*/
|
||||
ngOnChanges(changes: SimpleChanges): void {
|
||||
if (changes['options']?.previousValue) {
|
||||
const newSource = changes['options'].currentValue.sources[0];
|
||||
if (this.isMpegTsSource(newSource?.src)) {
|
||||
this.destroyMpegTs();
|
||||
this.player.reset();
|
||||
this.initMpegTs(newSource.src);
|
||||
} else {
|
||||
this.destroyMpegTs();
|
||||
this.player.src(newSource);
|
||||
const previousSource =
|
||||
changes['options'].previousValue.sources?.[0];
|
||||
const newSource = changes['options'].currentValue.sources?.[0];
|
||||
if (newSource && !this.isSameSource(previousSource, newSource)) {
|
||||
if (this.isMpegTsSource(newSource.src)) {
|
||||
this.destroyMpegTs();
|
||||
this.player.reset();
|
||||
this.initMpegTs(newSource.src);
|
||||
} else {
|
||||
this.destroyMpegTs();
|
||||
this.player.src(newSource);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changes['volume']?.currentValue !== undefined && this.player) {
|
||||
@@ -232,6 +236,16 @@ export class VjsPlayerComponent implements OnInit, OnChanges, OnDestroy {
|
||||
return getExtensionFromUrl(url) === 'ts' && mpegts.isSupported();
|
||||
}
|
||||
|
||||
private isSameSource(
|
||||
previousSource: VideoPlayerSource | undefined,
|
||||
newSource: VideoPlayerSource
|
||||
): boolean {
|
||||
return (
|
||||
previousSource?.src === newSource.src &&
|
||||
previousSource?.type === newSource.type
|
||||
);
|
||||
}
|
||||
|
||||
private initMpegTs(url: string): void {
|
||||
const videoEl = this.player.tech({ IWillNotUseThisInPlugins: true })?.el();
|
||||
if (!videoEl) return;
|
||||
|
||||
Reference in new issue
Block a user