diff --git a/src/app/html-video-player/html-video-player.component.html b/src/app/html-video-player/html-video-player.component.html new file mode 100644 index 000000000..2c9a82ce5 --- /dev/null +++ b/src/app/html-video-player/html-video-player.component.html @@ -0,0 +1,7 @@ + diff --git a/src/app/html-video-player/html-video-player.component.scss b/src/app/html-video-player/html-video-player.component.scss new file mode 100644 index 000000000..7891abef6 --- /dev/null +++ b/src/app/html-video-player/html-video-player.component.scss @@ -0,0 +1,4 @@ +#video-player { + width: 100%; + height: calc(100vh - 100px); +} \ No newline at end of file diff --git a/src/app/html-video-player/html-video-player.component.spec.ts b/src/app/html-video-player/html-video-player.component.spec.ts new file mode 100644 index 000000000..ad6da5de6 --- /dev/null +++ b/src/app/html-video-player/html-video-player.component.spec.ts @@ -0,0 +1,45 @@ +/* eslint-disable @typescript-eslint/unbound-method */ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { SimpleChange } from '@angular/core'; + +import { HtmlVideoPlayerComponent } from './html-video-player.component'; + +describe('HtmlVideoPlayerComponent', () => { + let component: HtmlVideoPlayerComponent; + let fixture: ComponentFixture; + const TEST_CHANNEL = { + id: '1234', + url: 'http://test', + name: 'Test channel', + group: { + title: 'News group', + }, + }; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [HtmlVideoPlayerComponent], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(HtmlVideoPlayerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should call play channel function after input changes', () => { + spyOn(component, 'playChannel'); + component.ngOnChanges({ + channel: new SimpleChange(null, TEST_CHANNEL, true), + }); + fixture.detectChanges(); + + expect(component.playChannel).toBeCalledTimes(1); + expect(component.playChannel).toBeCalledWith(TEST_CHANNEL); + }); +}); diff --git a/src/app/html-video-player/html-video-player.component.ts b/src/app/html-video-player/html-video-player.component.ts new file mode 100644 index 000000000..aea783cde --- /dev/null +++ b/src/app/html-video-player/html-video-player.component.ts @@ -0,0 +1,61 @@ +import { + Component, + ElementRef, + Input, + OnChanges, + SimpleChanges, + ViewChild, +} from '@angular/core'; +import { Channel } from 'app/state'; +import * as Hls from 'hls.js'; + +@Component({ + selector: 'app-html-video-player', + templateUrl: './html-video-player.component.html', + styleUrls: ['./html-video-player.component.scss'], +}) +export class HtmlVideoPlayerComponent implements OnChanges { + /** Channel to play */ + @Input() channel: Channel; + + /** Video player DOM element */ + @ViewChild('videoPlayer', { static: false }) + videoPlayer: ElementRef; + + /** HLS object */ + hls = new Hls(); + + /** + * Listen for component input changes + * @param changes component changes + */ + ngOnChanges(changes: SimpleChanges): void { + if (changes.channel && changes.channel.currentValue) { + this.playChannel(changes.channel.currentValue); + } + } + + /** + * Starts to play the given channel + * @param channel given channel object + */ + playChannel(channel: Channel): void { + if (Hls.isSupported()) { + console.log('... switching channel to ', channel.name, channel.url); + this.hls.loadSource(channel.url); + this.hls.attachMedia(this.videoPlayer.nativeElement); + } else if ( + this.videoPlayer.nativeElement.canPlayType( + 'application/vnd.apple.mpegurl' + ) + ) { + this.videoPlayer.nativeElement.src = channel.url; + this.videoPlayer.nativeElement.addEventListener( + 'loadedmetadata', + () => { + this.videoPlayer.nativeElement.play(); + } + ); + } + } +}