ngx-video-list-player
Version:
A simple Angular video player with video list. No dependecies. Only custom controls, css, ts and svgs. Youtube support
703 lines • 220 kB
JavaScript
import { Component, HostListener, Input, Output, ViewChild, ViewChildren } from '@angular/core';
import { VideoEventTypes } from '../Models/video-event-types.model';
import { YoutubeStateConstant } from '../Constants/youtube-state.constant';
import { Breakpoints } from '@angular/cdk/layout';
import { EventEmitter } from '@angular/core';
import { YouTubePlayer } from '@angular/youtube-player';
import * as i0 from "@angular/core";
import * as i1 from "@angular/cdk/layout";
import * as i2 from "@angular/youtube-player";
import * as i3 from "@angular/common";
import * as i4 from "../Directives/stop-propagation.directive";
export class NgxVideoListPlayerComponent {
constructor(renderer, breakpointObserver, changeDetectorRef) {
this.renderer = renderer;
this.breakpointObserver = breakpointObserver;
this.changeDetectorRef = changeDetectorRef;
this.onTimeUpdate = new EventEmitter();
this.onCanPlay = new EventEmitter();
this.onLoadedMetadata = new EventEmitter();
this.visibleMobileDeviceMainPprContainer = false;
this.disableControlHide = false;
this.mediaPlayerIsFocused = false;
this.actualVideoIndex = 0;
this.firstSourceLoad = false;
this.firstVideoLoad = true;
this.pauseKeyboardCodes = ["Space"];
this.currentTime = "0:00";
this.duration = "0:00";
this.isFullScreen = false;
this.volumePercent = 100;
this.muted = false;
this.progressSliderMaxValue = 100000;
this.progressSliderValue = 0;
this.pipIsActive = false;
this.supportPictureInPicture = 'pictureInPictureEnabled' in document && document.pictureInPictureEnabled;
this.supportFullScreen = 'fullscreenEnabled' in document && document.fullscreenEnabled;
this.isMobileDevice = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
this.youtubeIsPaused = false;
this.youtubeIsEnded = false;
//Safari does not trigger CanPlay event
this.isSafariBrowser = navigator.userAgent.toLowerCase().indexOf("safari") != -1 && navigator.userAgent.toLowerCase().indexOf("chrome") == -1;
}
ngOnInit() {
if (!this.config.isAutoPlay)
this.config.isAutoPlay = false;
if (!this.config.isFirstVideoAutoPlay)
this.config.isFirstVideoAutoPlay = false;
if (this.config.volumeCookieName) {
const volumeCookieValue = document.cookie
.split('; ')
.find(row => row.startsWith(`${this.config.volumeCookieName}=`));
if (volumeCookieValue) {
this.volumePercent = parseInt(volumeCookieValue.split('=')[1]);
if (this.volumePercent < 0)
this.volumePercent = 0;
else if (this.volumePercent > 100)
this.volumePercent = 100;
}
}
if (this.config.videoIndexCookieName) {
const videoIndexCookieValue = document.cookie
.split('; ')
.find(row => row.startsWith(`${this.config.videoIndexCookieName}=`));
if (videoIndexCookieValue)
this.actualVideoIndex = parseInt(videoIndexCookieValue.split('=')[1]);
}
}
ngAfterViewInit() {
this.videoElement = this.video.nativeElement;
if (isNaN(this.actualVideoIndex) || this.actualVideoIndex > this.config.sources.length - 1 || this.actualVideoIndex < 0)
this.actualVideoIndex = 0;
this.setVideoIndexCookie();
this.loadVideo();
this.changeDetectorRef.detectChanges();
this.videoElement.controls = false;
this.videoElement.ontimeupdate = (this.videoEventHandler.bind(this));
this.videoElement.onloadedmetadata = (this.videoEventHandler.bind(this));
this.videoElement.onended = this.videoEventHandler.bind(this);
this.videoElement.onleavepictureinpicture = this.videoEventHandler.bind(this);
this.videoElement.onenterpictureinpicture = this.videoEventHandler.bind(this);
this.videoElement.onpause = this.videoEventHandler.bind(this);
this.videoElement.onplay = this.videoEventHandler.bind(this);
this.videoElement.oncanplay = this.videoEventHandler.bind(this);
this.videoElement.onerror = this.videoEventHandler.bind(this);
this.videoSource.nativeElement.onerror = this.videoEventHandler.bind(this);
this.mediaControlElement = this.mediaPlayer.nativeElement;
this.mediaControlElement.onfullscreenchange = this.videoEventHandler.bind(this);
this.setVolumeValue(this.volumePercent);
this.breakpointObserver.observe([Breakpoints.XSmall, Breakpoints.Small]).subscribe(result => {
if (this.config.videoListDisplayMode) {
switch (this.config.videoListDisplayMode) {
case "inline":
this.renderer.addClass(this.mediaPlayer.nativeElement, "custom-col-8");
this.renderer.addClass(this.videoListContainer.nativeElement, "custom-col-4");
this.renderer.removeClass(this.mediaPlayer.nativeElement, "custom-col-12");
this.renderer.removeClass(this.videoListContainer.nativeElement, "custom-col-12");
break;
case "block":
this.renderer.addClass(this.mediaPlayer.nativeElement, "custom-col-12");
this.renderer.addClass(this.videoListContainer.nativeElement, "custom-col-12");
this.renderer.removeClass(this.mediaPlayer.nativeElement, "custom-col-8");
this.renderer.removeClass(this.videoListContainer.nativeElement, "custom-col-4");
break;
case "none":
this.renderer.setStyle(this.videoListContainer.nativeElement, "display", "none");
this.renderer.removeClass(this.mediaPlayer.nativeElement, "custom-col-8");
this.renderer.addClass(this.mediaPlayer.nativeElement, "custom-col-12");
break;
}
return;
}
if (result.matches) {
this.renderer.removeClass(this.mediaPlayer.nativeElement, "custom-col-8");
this.renderer.removeClass(this.videoListContainer.nativeElement, "custom-col-4");
this.renderer.addClass(this.mediaPlayer.nativeElement, "custom-col-12");
this.renderer.addClass(this.videoListContainer.nativeElement, "custom-col-12");
}
else {
this.renderer.addClass(this.mediaPlayer.nativeElement, "custom-col-8");
this.renderer.addClass(this.videoListContainer.nativeElement, "custom-col-4");
this.renderer.removeClass(this.mediaPlayer.nativeElement, "custom-col-12");
this.renderer.removeClass(this.videoListContainer.nativeElement, "custom-col-12");
}
this.resizeVideoListContainer();
});
}
videoEventHandler(ev) {
if (this.actualVideo.isYoutubeVideo && ev.type != VideoEventTypes.FullScreenChange)
return;
switch (ev.type) {
case VideoEventTypes.TimeUpdate:
if (!this.videoElement.duration) {
this.onTimeUpdate.emit();
return;
}
this.timeUpdateEvent();
break;
case VideoEventTypes.LoadedMetadata:
this.loadMetadataEvent();
break;
case VideoEventTypes.FullScreenChange:
this.isFullScreen = !!document.fullscreenElement;
break;
case VideoEventTypes.Ended:
this.endEvent(true);
break;
case VideoEventTypes.LeavePictureInPicture:
this.pipIsActive = false;
this.mediaPlayerMouseLeave();
//Not refresh pip Svg automatic after close in pause state
this.changeDetectorRef.detectChanges();
//setTimeout is beacuse of exitPiP pause
setTimeout(() => {
if (this.actualVideo.isYoutubeVideo ? this.youtubePlayer.getPlayerState() == YoutubeStateConstant.Ended : this.videoElement.ended) {
this.endEvent(false);
}
}, 1);
break;
case VideoEventTypes.EnterPictureInPicture:
this.pipIsActive = true;
this.mediaPlayerMouseMove();
this.clearMobileDeviceMainPprContainerStyles();
break;
case VideoEventTypes.Play:
this.playEvent();
break;
case VideoEventTypes.Pause:
this.pauseEvent();
break;
case VideoEventTypes.CanPlay:
this.canPlayEvent();
this.onCanPlay.emit();
break;
case VideoEventTypes.Error:
this.videoLoadErrorHandling();
break;
}
}
videoLoadErrorHandling() {
this.resizeVideoListContainer();
this.canPlay = false;
this.firstSourceLoad = false;
this.firstVideoLoad = false;
if (this.isNextVideo()) {
this.clearCountDownCircleTimeout();
this.countDownCircleTimeout = setTimeout(() => {
this.next();
}, 5000);
}
}
canPlayEvent() {
this.resizeVideoListContainer();
this.canPlay = true;
if (this.firstVideoLoad && this.config.isFirstVideoAutoPlay) {
this.mute();
this.playPause();
}
else if (!this.firstVideoLoad && this.firstSourceLoad && this.config.isAutoPlay) {
this.playPause();
}
this.firstSourceLoad = false;
this.firstVideoLoad = false;
}
endEvent(isNextEvent) {
if (isNextEvent) {
if (this.isNextVideo() && this.config.isAutoPlay) {
this.clearCountDownCircleTimeout();
this.countDownCircleTimeout = setTimeout(() => {
this.next();
}, 5000);
}
}
this.fromPlayToPause.forEach(element => {
element.nativeElement.beginElement();
});
if (this.actualVideo != null && this.actualVideo.isYoutubeVideo)
this.youtubeIsEnded = true;
}
async pipEnter() {
if (!this.canPlay)
return;
await this.videoElement.requestPictureInPicture();
}
async pipExit() {
await document.exitPictureInPicture();
}
playEvent() {
this.fromPauseToPlay.forEach(element => {
element.nativeElement.beginElement();
});
this.mediaPlayerMouseLeave();
if (this.actualVideo != null && this.actualVideo.isYoutubeVideo)
this.youtubeIsPaused = false;
}
pauseEvent() {
this.fromPlayToPause.forEach(element => {
element.nativeElement.beginElement();
});
this.mediaPlayerMouseMove();
this.clearMobileDeviceMainPprContainerStyles();
if (this.actualVideo != null && this.actualVideo.isYoutubeVideo)
this.youtubeIsPaused = true;
}
clearMobileDeviceMainPprContainerStyles() {
if (this.mobileDeviceMainPprContainer) {
this.visibleMobileDeviceMainPprContainer = true;
this.renderer.removeStyle(this.mobileDeviceMainPprContainer.nativeElement, "visibility");
this.renderer.removeStyle(this.mobileDeviceMainPprContainer.nativeElement, "opacity");
}
}
playPause() {
if (!this.canPlay)
return;
this.clearCountDownCircleTimeout();
if (this.actualVideo.isYoutubeVideo) {
var youtubeState = this.youtubePlayer.getPlayerState();
this.youtubeIsEnded = false;
if (youtubeState != YoutubeStateConstant.Playing) {
this.youtubePlayer.playVideo();
this.youtubeIsPaused = false;
}
else {
this.youtubePlayer.pauseVideo();
this.youtubeIsPaused = true;
}
}
else {
if (this.videoElement.paused || this.videoElement.ended) {
this.videoElement.play();
}
else {
this.videoElement.pause();
}
}
}
fullScreen() {
if (this.mediaControlElement.requestFullscreen) {
this.mediaControlElement.requestFullscreen();
}
else if (this.mediaControlElement.webkitRequestFullscreen) { /* Safari */
this.mediaControlElement.webkitRequestFullscreen();
}
else if (this.mediaControlElement.msRequestFullscreen) { /* IE11 */
this.mediaControlElement.msRequestFullscreen();
}
else if (this.mediaControlElement.mozRequestFullscreen) {
this.mediaControlElement.mozRequestFullscreen();
}
else if (this.videoElement.webkitEnterFullscreen)
this.videoElement.webkitEnterFullscreen();
if (this.actualVideo.isYoutubeVideo)
this.isFullScreen = true;
}
exitFullScreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
}
else if (document.webkitExitFullscreen) { /* Safari */
document.webkitExitFullscreen();
}
else if (document.msExitFullscreen) { /* IE11 */
document.msExitFullscreen();
}
else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
}
if (this.actualVideo.isYoutubeVideo)
this.isFullScreen = false;
}
isNextVideo() {
return this.actualVideoIndex < this.config.sources.length - 1;
}
next() {
this.actualVideoIndex += 1;
this.loadVideo();
}
prev() {
if (this.actualVideoIndex == 0) {
this.clearCountDownCircleTimeout();
this.videoElement.currentTime = 0;
if (!this.videoElement.paused)
this.playPause();
}
else {
this.actualVideoIndex -= 1;
this.loadVideo();
}
}
loadMetadataEvent() {
const duration = this.actualVideo.isYoutubeVideo ? this.youtubePlayer.getDuration() : this.videoElement.duration;
if (duration == 0)
this.duration = "0:00";
else
this.duration = `${Math.floor(duration / 60)}:${Math.floor(duration % 60).toLocaleString("en-US", { minimumIntegerDigits: 2 })}`;
this.firstSourceLoad = true;
this.supportFullScreen || (this.supportFullScreen = this.videoElement.webkitSupportsFullscreen);
if (this.isSafariBrowser) {
this.canPlayEvent();
this.onCanPlay.emit();
}
this.onLoadedMetadata.emit();
}
timeUpdateEvent() {
try {
const duration = this.actualVideo.isYoutubeVideo ? this.youtubePlayer.getDuration() : this.videoElement.duration;
let currentTime = this.actualVideo.isYoutubeVideo ? this.youtubePlayer.getCurrentTime() : this.videoElement.currentTime;
if (!currentTime)
currentTime = 0;
let percentage = (100 / duration) * currentTime;
if (isNaN(percentage))
percentage = 0;
this.renderer.setStyle(this.progressContainer.nativeElement, "width", `${percentage}%`);
if (currentTime == 0)
this.currentTime = `0:00`;
else
this.currentTime = `${Math.floor(currentTime / 60)}:${Math.floor(currentTime % 60).toLocaleString("en-US", { minimumIntegerDigits: 2 })}`;
this.progressSliderValue = percentage * (this.progressSliderMaxValue / 100);
this.onTimeUpdate.emit();
}
catch {
const percentage = 0;
this.renderer.setStyle(this.progressContainer.nativeElement, "width", `${percentage}%`);
this.currentTime = `0:00`;
this.progressSliderValue = percentage * (this.progressSliderMaxValue / 100);
this.onTimeUpdate.emit();
}
}
onReadyYoutubeVideo() {
if (!this.actualVideo.isYoutubeVideo)
return;
this.setVolumeValue(this.volumePercent);
this.loadMetadataEvent();
this.canPlayEvent();
this.onCanPlay.emit();
}
onStateChangeYoutubeVideo(event) {
if (!this.actualVideo.isYoutubeVideo)
return;
switch (event.data) {
case YoutubeStateConstant.Ended:
this.endEvent(true);
this.clearYoutubeCurrentTimeInterval();
break;
case YoutubeStateConstant.Playing:
this.playEvent();
this.loadMetadataEvent();
this.clearYoutubeCurrentTimeInterval();
this.youtubeCurrentTimeInterval = setInterval(() => {
this.timeUpdateEvent();
}, 100);
break;
case YoutubeStateConstant.Paused:
this.pauseEvent();
this.clearYoutubeCurrentTimeInterval();
break;
case YoutubeStateConstant.VideoCued:
this.onReadyYoutubeVideo();
break;
}
}
async loadVideo(index, tryNumber = 1) {
if (index >= 0)
this.actualVideoIndex = index;
const videoElement = this.videoListElements.find((element, index) => index == this.actualVideoIndex);
this.videoListContainer.nativeElement.scroll({
top: videoElement.nativeElement.offsetTop - this.videoListContainer.nativeElement.offsetTop - videoElement.nativeElement.offsetHeight,
left: 0,
behavior: 'smooth'
});
this.clearCountDownCircleTimeout();
this.setVideoIndexCookie();
this.pauseEvent();
this.canPlay = null;
this.videoElement.currentTime = 0;
this.progressSliderValue = 0;
this.renderer.setStyle(this.progressContainerHover.nativeElement, "width", `0%`);
this.renderer.setStyle(this.progressContainer.nativeElement, "width", `0%`);
this.currentTime = "0:00";
this.actualVideo = this.config.sources[this.actualVideoIndex];
this.clearYoutubeCurrentTimeInterval();
if (this.actualVideo.isYoutubeVideo) {
if (this.pipIsActive)
await document.exitPictureInPicture();
if (this.youtubePlayer instanceof YouTubePlayer) {
try {
this.youtubePlayer = new YT.Player('youtubePlayer', {
videoId: this.actualVideo.src,
height: "100%",
width: "100%",
playerVars: { 'autoplay': 0, 'controls': 0, 'autohide': 1, 'disablekb': 1, 'showinfo': 0, 'iv_load_policy': 3, 'loop': 1, 'modestbranding': 1, 'playsinline': 0, 'rel': 0 },
events: {
'onReady': this.onReadyYoutubeVideo.bind(this),
'onStateChange': this.onStateChangeYoutubeVideo.bind(this),
'onError': (e) => {
if (tryNumber >= 4) {
this.videoLoadErrorHandling.bind(this)();
}
else {
setTimeout(() => {
this.loadVideo(index, ++tryNumber);
}, 1000);
}
}
}
});
}
catch {
if (tryNumber >= 4)
this.videoLoadErrorHandling();
else {
setTimeout(() => {
this.loadVideo(index, ++tryNumber);
}, 1000);
return;
}
}
}
else {
this.youtubePlayer.loadVideoById(this.actualVideo.src, 0);
this.youtubePlayer.stopVideo();
}
this.subtitles = [];
this.videoElement.pause();
setTimeout(() => {
this.youtubeIsEnded = false;
this.youtubeIsPaused = false;
}, 150);
}
else {
if (!(this.youtubePlayer instanceof YouTubePlayer)) {
this.youtubePlayer.stopVideo();
}
this.videoName = this.actualVideo.videoName;
this.videoElement.src = this.actualVideo.src;
this.videoType = this.actualVideo.type;
this.subtitles = [];
if (this.actualVideo.subtitles) {
this.subtitles = this.actualVideo.subtitles.map(item => ({
src: item.src,
name: item.name,
default: item.default,
id: `video_vtt_${this.actualVideo.subtitles.indexOf(item)}`
}));
}
var defaultSubtitle = this.subtitles.find(item => item.default);
if (defaultSubtitle)
this.actualSubtitleId = defaultSubtitle.id;
else
this.actualSubtitleId = null;
}
}
clearYoutubeCurrentTimeInterval() {
if (this.youtubeCurrentTimeInterval)
clearInterval(this.youtubeCurrentTimeInterval);
}
clearCountDownCircleTimeout() {
if (this.countDownCircleTimeout)
clearTimeout(this.countDownCircleTimeout);
}
mute() {
if (this.actualVideo.isYoutubeVideo) {
this.youtubePlayer.isMuted() ? this.youtubePlayer.unMute() : this.youtubePlayer.mute();
}
else {
this.videoElement.muted = !this.videoElement.muted;
}
this.muted = !this.muted;
if (this.muted) {
this.volumePercent = 0;
}
else {
this.volumePercent = this.actualVideo.isYoutubeVideo ? this.youtubePlayer.getVolume() : this.videoElement.volume * 100;
}
}
setVolume(event) {
if (this.actualVideo.isYoutubeVideo) {
this.youtubePlayer.unMute();
}
else {
this.videoElement.muted = false;
}
this.muted = false;
const percentage = parseInt(event.target.value);
if (this.config.volumeCookieName)
document.cookie = `${this.config.volumeCookieName}=${percentage}`;
this.setVolumeValue(percentage);
this.volumePercent = percentage;
}
setVolumeValue(percentage) {
try {
if (this.actualVideo.isYoutubeVideo)
this.youtubePlayer.setVolume(percentage);
else
this.videoElement.volume = percentage / 100;
}
catch { }
}
setVideoIndexCookie() {
if (this.config.videoIndexCookieName)
document.cookie = `${this.config.videoIndexCookieName}=${this.actualVideoIndex}`;
}
progressHelperMouseMove(event) {
if (!this.canPlay)
return;
const hoverPercent = event.offsetX / event.srcElement.offsetWidth * 100;
this.renderer.setStyle(this.progressContainerHover.nativeElement, "width", `${hoverPercent}%`);
this.renderer.setStyle(this.mediaControlContainer.nativeElement, "height", "50px");
this.renderer.setStyle(this.meterContainer.nativeElement, "height", "6px");
this.renderer.setStyle(this.progressSlider.nativeElement, "display", "inline-block");
}
mediaPlayerMouseMove() {
if (!this.canPlay)
return;
if (this.videoTitleContainer)
this.renderer.removeStyle(this.videoTitleContainer.nativeElement, "opacity");
this.renderer.removeStyle(this.mediaControlContainer.nativeElement, "opacity");
this.renderer.removeStyle(this.mediaControlContainer.nativeElement, "visibility");
this.renderer.removeStyle(this.meterContainer.nativeElement, "opacity");
this.renderer.removeStyle(this.mediaPlayer.nativeElement, "cursor");
if (this.mobileDeviceMainPprContainer) {
this.visibleMobileDeviceMainPprContainer = true;
this.renderer.removeStyle(this.mobileDeviceMainPprContainer.nativeElement, "visibility");
this.renderer.removeStyle(this.mobileDeviceMainPprContainer.nativeElement, "opacity");
}
if ((!this.actualVideo.isYoutubeVideo && !this.videoElement.paused && !this.videoElement.ended || this.actualVideo.isYoutubeVideo && !this.youtubeIsPaused && !this.youtubeIsEnded)
&& !this.disableControlHide && !this.pipIsActive) {
if (this.displayControlsTimeout) {
clearTimeout(this.displayControlsTimeout);
}
this.displayControlsTimeout = setTimeout(() => { this.mediaPlayerMouseLeave(); }, 3000);
}
}
mediaPlayerMouseLeave() {
if ((!this.actualVideo.isYoutubeVideo && !this.videoElement.paused && !this.videoElement.ended || this.actualVideo.isYoutubeVideo && !this.youtubeIsPaused && !this.youtubeIsEnded)
&& !this.disableControlHide && !this.pipIsActive) {
if (!this.isMobileDevice)
this.openSubtitles(true);
this.renderer.setStyle(this.mediaPlayer.nativeElement, "cursor", `none`);
this.renderer.setStyle(this.mediaControlContainer.nativeElement, "opacity", `0`);
this.renderer.setStyle(this.mediaControlContainer.nativeElement, "visibility", "hidden");
this.renderer.setStyle(this.meterContainer.nativeElement, "opacity", `0`);
if (this.videoTitleContainer)
this.renderer.setStyle(this.videoTitleContainer.nativeElement, "opacity", "0");
if (this.mobileDeviceMainPprContainer) {
this.visibleMobileDeviceMainPprContainer = false;
this.renderer.setStyle(this.mobileDeviceMainPprContainer.nativeElement, "visibility", "hidden");
this.renderer.setStyle(this.mobileDeviceMainPprContainer.nativeElement, "opacity", "0");
}
}
}
mediaPlayerFocus() {
this.mediaPlayerIsFocused = true;
}
mediaPlayerFocusOut() {
this.mediaPlayerIsFocused = false;
}
handleDocumentKeyboardEvent(event) {
if (this.pauseKeyboardCodes.find(item => item == event.code) && this.mediaPlayerIsFocused)
this.playPause();
}
handleDocumentClickEvent(event) {
this.openSubtitles(true);
}
handleDocumentResizeEvent(event) {
this.resizeVideoListContainer();
}
resizeVideoListContainer() {
const mediaPlayerHeight = this.mediaPlayer.nativeElement.offsetHeight;
this.renderer.setStyle(this.videoListContainer.nativeElement, "height", `${mediaPlayerHeight}px`);
}
mediaControlContainerMouseEnter() {
if (this.isMobileDevice)
return;
this.disableControlHide = true;
}
mediaControlContainerMouseLeave() {
if (this.isMobileDevice)
return;
this.disableControlHide = false;
}
//Value range [0..this.progressSliderMaxValue]
setProgressSlider(value) {
const duration = this.actualVideo.isYoutubeVideo ? this.youtubePlayer.getDuration() : this.videoElement.duration;
const currentTime = duration * value / this.progressSliderMaxValue;
;
if (this.actualVideo.isYoutubeVideo) {
var playerState = this.youtubePlayer.getPlayerState();
if (playerState == YoutubeStateConstant.VideoCued) {
this.youtubePlayer.loadVideoById(this.actualVideo.src, currentTime);
}
else
this.youtubePlayer.seekTo(currentTime, true);
}
else {
this.videoElement.currentTime = currentTime;
}
this.clearCountDownCircleTimeout();
}
progressThumbMouseMove(event) {
if (!this.canPlay)
return;
this.renderer.setStyle(this.mediaControlContainer.nativeElement, "height", "50px");
this.renderer.setStyle(this.meterContainer.nativeElement, "height", "6px");
const percentage = (event.offsetX / event.target.clientWidth) * 100;
if (percentage >= 0 && percentage <= 100)
this.renderer.setStyle(this.progressContainerHover.nativeElement, "width", `${percentage}%`);
}
progressThumbMouseLeave() {
this.renderer.removeStyle(this.mediaControlContainer.nativeElement, "height");
this.renderer.removeStyle(this.meterContainer.nativeElement, "height");
this.renderer.removeStyle(this.progressContainerHover.nativeElement, "width");
this.renderer.removeStyle(this.progressSlider.nativeElement, "display");
}
openSubtitles(instantHide = false) {
if (this.isMobileDevice) {
if (!this.subtitleModal)
return;
if (instantHide || this.subtitleModal.nativeElement.classList.contains('show'))
this.renderer.removeClass(this.subtitleModal.nativeElement, "show");
else
this.renderer.addClass(this.subtitleModal.nativeElement, "show");
}
else {
if (!this.dropUpContent)
return;
if (instantHide || this.dropUpContent.nativeElement.classList.contains('show'))
this.renderer.removeClass(this.dropUpContent.nativeElement, "show");
else
this.renderer.addClass(this.dropUpContent.nativeElement, "show");
}
}
setSubtitle(id) {
this.actualSubtitleId = id;
for (var i = 0; i < this.videoElement.textTracks.length; i++) {
this.videoElement.textTracks[i].mode = "disabled";
}
if (id) {
this.videoElement.textTracks.getTrackById(id).mode = "showing";
}
}
videoClickEvent() {
if (this.isMobileDevice) {
if (this.visibleMobileDeviceMainPprContainer) {
this.mediaPlayerMouseLeave();
}
else {
this.renderer.removeStyle(this.mobileDeviceMainPprContainer.nativeElement, "visibility");
this.renderer.removeStyle(this.mobileDeviceMainPprContainer.nativeElement, "opacity");
this.visibleMobileDeviceMainPprContainer = true;
}
}
else {
this.playPause();
}
}
emptyVoid() {
}
ngOnDestroy() {
this.clearYoutubeCurrentTimeInterval();
}
}
NgxVideoListPlayerComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.2", ngImport: i0, type: NgxVideoListPlayerComponent, deps: [{ token: i0.Renderer2 }, { token: i1.BreakpointObserver }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
NgxVideoListPlayerComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.2", type: NgxVideoListPlayerComponent, selector: "ngx-video-list-player", inputs: { config: "config" }, outputs: { onTimeUpdate: "onTimeUpdate", onCanPlay: "onCanPlay", onLoadedMetadata: "onLoadedMetadata" }, host: { listeners: { "document:keypress": "handleDocumentKeyboardEvent($event)", "document:click": "handleDocumentClickEvent($event)", "window:resize": "handleDocumentResizeEvent($event)" } }, viewQueries: [{ propertyName: "video", first: true, predicate: ["mediaVideo"], descendants: true }, { propertyName: "videoSource", first: true, predicate: ["mediaVideoSource"], descendants: true }, { propertyName: "progressContainer", first: true, predicate: ["progressContainer"], descendants: true }, { propertyName: "progressContainerHover", first: true, predicate: ["progressContainerHover"], descendants: true }, { propertyName: "mediaPlayer", first: true, predicate: ["mediaPlayer"], descendants: true }, { propertyName: "mediaControlContainer", first: true, predicate: ["mediaControlContainer"], descendants: true }, { propertyName: "meterContainer", first: true, predicate: ["meter"], descendants: true }, { propertyName: "progressSlider", first: true, predicate: ["progressSlider"], descendants: true }, { propertyName: "videoTitleContainer", first: true, predicate: ["videoTitleContainer"], descendants: true }, { propertyName: "dropUpContent", first: true, predicate: ["dropUpContent"], descendants: true }, { propertyName: "videoListContainer", first: true, predicate: ["videoListContainer"], descendants: true }, { propertyName: "mobileDeviceMainPprContainer", first: true, predicate: ["mobileDeviceMainPprContainer"], descendants: true }, { propertyName: "subtitleModal", first: true, predicate: ["subtitleModal"], descendants: true }, { propertyName: "youtubePlayer", first: true, predicate: ["youtubePlayer"], descendants: true, static: true }, { propertyName: "fromPauseToPlay", predicate: ["from_pause_to_play"], descendants: true }, { propertyName: "fromPlayToPause", predicate: ["from_play_to_pause"], descendants: true }, { propertyName: "videoListElements", predicate: ["videoListElement"], descendants: true }], ngImport: i0, template: "<div class=\"video-main-container\">\r\n <div *ngIf=\"isMobileDevice && subtitles && subtitles.length > 0\" class=\"subtitle-modal\" #subtitleModal>\r\n <div stopPropagation class=\"modal-content\">\r\n <!-- <span class=\"close\" (click)=\"closeSubtitleModal()\">×</span> -->\r\n <div class=\"modal-title\">\r\n {{ config.subtitleText || 'Subtitles' }}\r\n </div>\r\n <div class=\"modal-container\">\r\n <div [ngClass]=\"{'active': !actualSubtitleId}\" (click)=\"setSubtitle()\">\r\n {{ config.subtitleOffText || 'Off' }}\r\n </div>\r\n <div *ngFor=\"let subtitle of subtitles\" [ngClass]=\"{ 'active': actualSubtitleId == subtitle.id }\" (click)=\"setSubtitle(subtitle.id)\">\r\n {{ subtitle.name }}\r\n </div>\r\n </div>\r\n <div class=\"close-button-container\">\r\n <button class=\"close-button\" (click)=\"openSubtitles(true)\">Ok</button>\r\n </div>\r\n </div> \r\n </div>\r\n <div id='media-player' class=\"custom-col-8\" tabindex=\"-1\" (focus)=\"mediaPlayerFocus()\" (focusout)=\"mediaPlayerFocusOut()\" #mediaPlayer (mousemove)=\"mediaPlayerMouseMove()\" (mouseleave)=\"mediaPlayerMouseLeave()\">\r\n <div class=\"main-ppr-icon-container\" *ngIf=\"canPlay != null && (videoElement.paused || videoElement.ended || !canPlay || (actualVideo != null && actualVideo.isYoutubeVideo && (youtubeIsPaused || youtubeIsEnded)))\">\r\n <svg height=\"100\" width=\"100\" (click)=\"!isMobileDevice ? playPause() : emptyVoid()\">\r\n <circle *ngIf=\"!isMobileDevice && actualVideo != null && (!actualVideo.isYoutubeVideo || youtubeIsPaused || youtubeIsEnded)\" cx=\"50\" cy=\"50\" r=\"40\" style=\"cursor: pointer;\" stroke=\"rgb(234 13 191 / 45%)\" stroke-width=\"1\" fill=\"rgb(255 255 255 / 23%)\" />\r\n <polygon *ngIf=\"!isMobileDevice && canPlay && (actualVideo != null && (!actualVideo.isYoutubeVideo && videoElement.paused && !videoElement.ended || actualVideo.isYoutubeVideo && youtubeIsPaused))\" points=\"40,30 40,70 70,50\" style=\"fill:#ea0dbf;stroke:purple;stroke-width:1;cursor: pointer;\" />\r\n <use *ngIf=\"!isMobileDevice && (actualVideo != null && (!actualVideo.isYoutubeVideo && videoElement.ended || actualVideo.isYoutubeVideo && youtubeIsEnded))\" xlink:href=\"./assets/media-controls.svg#replay\" href=\"./assets/media-controls.svg#replay\" x=\"1\" y=\"0\" style=\"fill:#ea0dbf;stroke:purple;stroke-width:1\" />\r\n <use *ngIf=\"!canPlay && !isMobileDevice\" xlink:href=\"./assets/media-controls.svg#can_not_play\" href=\"./assets/media-controls.svg#can_not_play\" x=\"0\" y=\"0\" style=\"fill:#ea0dbf;stroke:purple;stroke-width:1\" />\r\n <use *ngIf=\"!canPlay && isMobileDevice\" xlink:href=\"./assets/media-controls.svg#can_not_play_mobile\" href=\"./assets/media-controls.svg#can_not_play_mobile\" x=\"11\" y=\"5\" style=\"fill:#ea0dbf;stroke:purple;stroke-width:1\" />\r\n </svg>\r\n </div>\r\n <div *ngIf=\"isMobileDevice && canPlay == true\" class=\"mobile-device-main-ppr-container\" #mobileDeviceMainPprContainer (click)=\"videoClickEvent()\">\r\n <div class=\"mobile-device-main-ppr-container-helper\">\r\n <div>\r\n <svg (click)=\"prev()\" height=\"33\" width=\"33\">\r\n <use xlink:href=\"./assets/media-controls.svg#prev\" href=\"./assets/media-controls.svg#prev\" x=\"0\" y=\"0\" />\r\n </svg>\r\n </div>\r\n <div style=\"margin-left: 2px;\">\r\n <svg (click)=\"playPause()\" height=\"33\" width=\"33\">\r\n <path id='line1' d=\"M 8 7 L 26 17 L 26 17 L 8 26\" style=\"fill:white;\">\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\" \r\n from=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n to=\"M 8 7 L 13 7 L 13 26 L 8 26\"\r\n begin=\"indefinite\"\r\n fill=\"freeze\"\r\n #from_pause_to_play />\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\"\r\n from=\"M 8 7 L 13 7 L 13 26 L 8 26\"\r\n to=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n fill=\"freeze\"\r\n #from_play_to_pause\r\n begin=\"indefinite\" />\r\n </path>\r\n <path id='line2' d=\"M 8 7 L 26 17 L 26 17 L 8 26\" style=\"fill:white;\">\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\" \r\n from=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n to=\"M 19 7 L 24 7 L 24 26 L 19 26\"\r\n begin=\"indefinite\"\r\n fill=\"freeze\"\r\n #from_pause_to_play />\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\"\r\n from=\"M 19 7 L 24 7 L 24 26 L 19 26\"\r\n to=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n fill=\"freeze\"\r\n #from_play_to_pause\r\n begin=\"indefinite\" />\r\n </path> \r\n </svg>\r\n </div> \r\n <div>\r\n <svg *ngIf=\"isNextVideo()\" (click)=\"next()\" height=\"33\" width=\"33\">\r\n <use xlink:href=\"./assets/media-controls.svg#next\" href=\"./assets/media-controls.svg#next\" x=\"0\" y=\"0\" />\r\n </svg>\r\n </div>\r\n </div> \r\n </div>\r\n <div *ngIf=\"(config.isVideoLoader == null || config.isVideoLoader) && canPlay == null\" class=\"loader-wrapper\" [ngClass]=\"{ 'mobile-device': isMobileDevice }\">\r\n <div class=\"loader\"></div>\r\n </div>\r\n <div *ngIf=\"((canPlay != null && (actualVideo != null && (!actualVideo.isYoutubeVideo && videoElement.ended || actualVideo.isYoutubeVideo && youtubeIsEnded))) || canPlay == false) && isNextVideo()\" class=\"next-loader\" [ngClass]=\"{ 'mobile-device': isMobileDevice }\">\r\n <ng-container *ngIf=\"isMobileDevice\">\r\n <svg>\r\n <circle cx=\"50%\" cy=\"50%\" r=\"11%\"/>\r\n </svg>\r\n </ng-container>\r\n <ng-container *ngIf=\"!isMobileDevice\">\r\n <svg >\r\n <circle cx=\"50%\" cy=\"50%\" r=\"42\"/>\r\n </svg>\r\n </ng-container>\r\n </div>\r\n <div *ngIf=\"videoName && (actualVideo == null || !actualVideo.isYoutubeVideo)\" class=\"video-title\" #videoTitleContainer>\r\n <div class=\"video-title-text\">\r\n {{ videoName }} \r\n </div>\r\n </div>\r\n <div class=\"video-container\">\r\n <div class=\"youtube-video-container\" (click)=\"playPause()\" [hidden]=\"actualVideo && !actualVideo.isYoutubeVideo\" style=\"text-align: center;\" (mousemove)=\"mediaPlayerMouseMove()\" (mouseleave)=\"mediaPlayerMouseLeave()\">\r\n <youtube-player id=\"youtubePlayer\" #youtubePlayer style=\"position: absolute; left: 0; pointer-events: none;\"></youtube-player>\r\n </div>\r\n <video #mediaVideo [hidden]=\"actualVideo && actualVideo.isYoutubeVideo\" width=\"100%\" (click)=\"videoClickEvent()\">\r\n <source #mediaVideoSource [type]='videoType'>\r\n <track *ngFor=\"let subtitle of subtitles; let i = index\" [id]=\"subtitle.id\" [label]=\"subtitle.name\" kind=\"subtitles\" [src]=\"subtitle.src\" [attr.default]=\"subtitle.id == actualSubtitleId ? true : null\">\r\n </video>\r\n </div>\r\n <div id=\"media-control-container\" #mediaControlContainer (mouseenter)=\"mediaControlContainerMouseEnter()\" (mouseleave)=\"mediaControlContainerMouseLeave()\">\r\n <div id=\"media-controls\">\r\n <div class=\"progress-thumb\">\r\n <input [attr.disabled]=\"!canPlay ? true : null\" type=\"range\" min=\"0\" [max]=\"progressSliderMaxValue\" [value]=\"progressSliderValue\" class=\"progress-slider\" [ngClass]=\"{ 'mobile-device': isMobileDevice }\" #progressSlider (input)=\"setProgressSlider(progressSlider.value)\" (mousemove)=\"progressThumbMouseMove($event)\" (mouseleave)=\"progressThumbMouseLeave()\">\r\n </div>\r\n <div class=\"meter\" #meter>\r\n <span #progressContainer class=\"progress-container progress-base\">\r\n <span class=\"progress\">\r\n </span>\r\n </span>\r\n <span #progressContainerHover class=\"progress-container progress-hover\">\r\n <span class=\"progress\"></span>\r\n </span>\r\n <span class=\"progress-container progress-helper\" (mousemove)=\"progressHelperMouseMove($event)\">\r\n <span class=\"progress\"></span>\r\n </span>\r\n </div>\r\n <div id=\"control-buttons\" [ngClass]=\"{ 'mobile-device': isMobileDevice }\">\r\n <div *ngIf=\"!isMobileDevice\">\r\n <svg (click)=\"prev()\">\r\n <use xlink:href=\"./assets/media-controls.svg#prev\" href=\"./assets/media-controls.svg#prev\" x=\"0\" y=\"0\" />\r\n </svg>\r\n </div>\r\n <div *ngIf=\"!isMobileDevice\">\r\n <svg (click)=\"playPause()\">\r\n <path id='line1' d=\"M 8 7 L 26 17 L 26 17 L 8 26\" style=\"fill:white;\">\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\" \r\n from=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n to=\"M 8 7 L 13 7 L 13 26 L 8 26\"\r\n begin=\"indefinite\"\r\n fill=\"freeze\"\r\n #from_pause_to_play />\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\"\r\n from=\"M 8 7 L 13 7 L 13 26 L 8 26\"\r\n to=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n fill=\"freeze\"\r\n #from_play_to_pause\r\n begin=\"indefinite\" />\r\n </path>\r\n <path id='line2' d=\"M 8 7 L 26 17 L 26 17 L 8 26\" style=\"fill:white;\">\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\" \r\n from=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n to=\"M 19 7 L 24 7 L 24 26 L 19 26\"\r\n begin=\"indefinite\"\r\n fill=\"freeze\"\r\n #from_pause_to_play />\r\n <animate\r\n attributeName=\"d\"\r\n dur=\"300ms\"\r\n from=\"M 19 7 L 24 7 L 24 26 L 19 26\"\r\n to=\"M 8 7 L 26 17 L 26 17 L 8 26\"\r\n fill=\"freeze\"\r\n #from_play_to_pause\r\n begin=\"indefinite\" />\r\n </path> \r\n </svg>\r\n </div>\r\n <div *ngIf=\"!isMobileDevice && isNextVideo()\">\r\n <svg (click)=\"next()\">\r\n <use xlink:href=\"./assets/media-controls.svg#next\" href=\"./assets/media-controls.svg#next\" x=\"0\" y=\"0\" />\r\n </svg>\r\n </div>\r\n <div class=\"duration-time\" [ngClass]=\"{ 'mobile-device': isMobileDevice }\">\r\n {{ currentTime }} / {{ duration }}\r\n </div>\r\n <div class=\"volume-container\" [ngClass]=\"{ 'mobile-device': isMobileDevice }\">\r\n <svg (click)=mute() style=\"width: 36px;\">\r\n <use xlink:href=\"./assets/media-controls.svg#volume_base\" href=\"./assets/media-controls.svg#volume_base\" /> \r\n <ng-container *ngIf=\"!muted; else mutePaths\">\r\n <ng-container *ngIf=\"volumePercent > 0\">\r\n <use xlink:href=\"./assets/media-controls.svg#volume_up1\" href=\"./assets/media-controls.svg#volume_up1\" /> \r\n </ng-container>\r\n <ng-container *ngIf=\"volumePercent > 50\">\r\n <use xlink:href=\"./assets/media-controls.svg#volume_up2\" href=\"./assets/media-controls.svg#volume_up2\" /> \r\n </ng-container>\r\n </ng-container>\r\n <ng-template #mutePaths>\r\n <use xlink:href=\"./assets/media-controls.svg#volume_muted1\" href=\"./assets/media-controls.svg#volume_muted1\" /> \r\n <use xlink:href=\"./assets/media-controls.svg#volume_muted2\" href=\"./assets/media-controls.svg#volume_muted2\" /> \r\n </ng-template> \r\n </svg>\r\n <div class=\"volume-setting-container\" *ngIf=\"!isMobileDevice\">\r\n <input type=\"range\" min=\"0\" max=\"100\" [value]=\"volumePercent\" class=\"custom-slider\" (input)=\"setVolume($event)\">\r\n </div>\r\n </div>\r\n <div class=\"right-section\">\r\n <div stopPropagation *ngIf=\"subtitles && subtitles.length > 0\" class=\"subtitle-select-container\">\r\n <svg (click)=\"openSubtitles()\">\r\n <use xlink:href=\"./assets/media-controls.svg#cc\" href=\"./assets/media-controls.svg#cc\" x=\"0\" y=\"4\" />\r\n </svg>\r\n <div class=\"dropup-content\" #dropUpContent>\r\n <div class=\"dropup-title\">\r\n {{ config.subtitleText || 'Subtitles' }}\r\n </div>\r\n <div class=\"dropup-container\">\r\n <div [ngClass]=\"{'active': !actualSubtitleId}\" (click)=\"setSubtitle()\">\r\n {{ config.subtitleOffText || 'Off' }}\r\n </div>\r\n <div *ngFor=\"let subtitle of subtitles\" [ngClass]=\"{ 'active': actualSubtitleId == subtitle.id }\" (click)=\"setSubtitle(subtitle.id)\">\r\n {{ subtitle.name }}\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n <div class=\"pip-container\" *ngIf=\"supportPictureInPicture && (actualVideo == null || !actualVideo.isYoutubeVideo)\">\r\n <svg (click)=\"pipIsActive ? pipExit() : pipEnter()\">\r\n <use *ngIf=\"!pipIsActive\" xlink:href=\"./assets/media-controls.svg#pip_enter\" href=\"./assets/media-controls.svg#pip_enter\" x=\"0\" y=\"0\" />\r\n <use *ngIf=\"pipIsActive\" xlink:href=\"./assets/media-controls.svg#pip_exit\" href=\"./assets/media-controls.svg#pip_exit\" x=\"0\" y=\"0\" />\r\n </svg>\r\n </div> \r\n <div *ngIf=\"supportFullScreen && !pipIsActive && !isMobileDevice\">\r\n <svg (click)=\"!isFullScreen ? fullScreen() : exitFullScreen()\">\r\n <use xlink:href=\"./assets/media-controls.svg#fullScreen_lt\" href=\"./assets/media-controls.svg#fullScreen_lt\" x=\"0\" y=\"0\" /> \r\n <use xlink:href=\"./assets/media-controls.svg#fullScreen_lb\" href=\"./assets/media-controls.svg#fullScreen_lb\" x=\"0\" y=\"0\" />\r\n <use xlink:href=\"./assets/media-controls.svg#fullScreen_rt\" href=\"./assets/media-controls.svg#fullScreen_rt\" x=\"0\" y=\"0\" />\r\n <use xlink:href=\"./assets/media-controls.svg#fullScreen_rb\" href=\"./assets/media-controls.svg#fullScreen_rb\" x=\"0\" y=\"0\" />\r\n <ng-container *ngIf=\"isFullScreen\">\r\n <use xlink:href=\"./assets/media-controls.svg#fullScreen_exit_lrb\" href=\"./assets/media-controls.svg#fullScreen_exit_lrb\" x=\"0\" y=\"0\" />\r\n <use xlink:href=\"./assets/media-controls.sv