UNPKG

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
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()\">&times;</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