@eternalheart/ngx-file-preview
Version:
A powerful Angular file preview component library supporting multiple file formats including images, videos, PDFs, Office documents, text files and more.
482 lines (470 loc) • 61.4 kB
JavaScript
import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { BasePreviewComponent } from '../base-preview/base-preview.component';
import { PreviewIconComponent } from '../../components/preview-icon/preview-icon.component';
import Hls from 'hls.js';
import { I18nPipe } from "../../i18n";
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
export class VideoPreviewComponent extends BasePreviewComponent {
constructor() {
super(...arguments);
this.isPlaying = false;
this.currentTime = 0;
this.duration = 0;
this.progress = 0;
this.volume = 1;
this.previousVolume = 1;
this.brightness = 100;
this.isPiPMode = false;
this.isControlsVisible = true;
this.showVolumeControl = false;
this.showBrightnessControl = false;
this.isMuted = false;
this.playbackSpeed = 1;
this.playbackSpeeds = [0.75, 1, 1.5, 2.0, 3.0, 5.0];
this.showSpeedControl = false;
this.isDragging = false;
this.onGlobalDrag = (event) => {
if (this.isDragging) {
const progressBar = this.videoPlayer.nativeElement.parentElement?.querySelector('.progress-bar');
if (progressBar) {
const rect = progressBar.getBoundingClientRect();
const pos = Math.max(0, Math.min(1, (event.clientX - rect.left) / rect.width));
const video = this.videoPlayer.nativeElement;
video.currentTime = pos * video.duration;
this.progress = pos * 100;
this.cdr.markForCheck();
}
}
};
this.stopDragging = () => {
if (this.isDragging) {
this.isDragging = false;
// 移除全局事件监听
document.removeEventListener('mousemove', this.onGlobalDrag);
document.removeEventListener('mouseup', this.stopDragging);
}
};
}
ngOnInit() {
this.startLoading();
this.cdr.markForCheck();
}
ngAfterViewInit() {
this.setupVideo();
}
onVideoLoad() {
this.stopLoading();
this.duration = this.videoPlayer.nativeElement.duration;
this.cdr.markForCheck();
}
setupVideo() {
const video = this.videoPlayer.nativeElement;
const url = this.file.url;
if (this.isHLSVideo(url)) {
this.setupHLS(video, url);
}
else {
// 对于普通视频,直接设置 src
video.src = url;
}
}
// 播放控制
togglePlay() {
const video = this.videoPlayer.nativeElement;
if (video.paused) {
video.play().then(() => {
this.isPlaying = true;
this.cdr.markForCheck();
}).catch((error) => {
console.error('播放失败:', error);
this.isPlaying = false;
this.cdr.markForCheck();
});
}
else {
video.pause();
this.isPlaying = false;
this.cdr.markForCheck();
}
}
isHLSVideo(url) {
return url.toLowerCase().includes('.m3u8') ||
url.includes('application/x-mpegURL') ||
url.includes('application/vnd.apple.mpegurl');
}
// 进度更新
onTimeUpdate() {
const video = this.videoPlayer.nativeElement;
this.currentTime = video.currentTime;
this.progress = (video.currentTime / video.duration) * 100;
}
adjustVolume(event) {
const value = +event.target.value;
this.volume = value / 100;
this.isMuted = this.volume === 0;
if (this.volume > 0) {
this.previousVolume = this.volume;
}
this.videoPlayer.nativeElement.volume = this.volume;
this.cdr.markForCheck();
}
adjustBrightness(event) {
const value = +event.target.value;
this.brightness = value;
this.videoPlayer.nativeElement.style.filter = `brightness(${this.brightness}%)`;
this.cdr.markForCheck();
}
// 画中画模式
async togglePip() {
if (!document.pictureInPictureElement) {
try {
await this.videoPlayer.nativeElement.requestPictureInPicture();
this.isPiPMode = true;
}
catch (error) {
console.error('画中画模式不支持:', error);
}
}
else {
await document.exitPictureInPicture();
this.isPiPMode = false;
}
}
setupHLS(video, url) {
if (Hls.isSupported()) {
this.hls = new Hls({
debug: false,
enableWorker: true,
// 添加一些 HLS 配置以确保更好的兼容性
capLevelToPlayerSize: true,
startLevel: -1,
abrMaxWithRealBitrate: true
});
this.hls.loadSource(url);
this.hls.attachMedia(video);
this.hls.on(Hls.Events.MANIFEST_PARSED, () => {
// 清单解析完成后,尝试播放
video.play().catch(() => {
console.log('Autoplay prevented');
});
});
this.hls.on(Hls.Events.ERROR, (event, data) => {
if (data.fatal) {
console.error('HLS error:', data);
}
});
}
else if (video.canPlayType('application/vnd.apple.mpegurl')) {
// Safari 原生支持
video.src = url;
}
}
async handleFileContent(content) { }
toggleFullscreen() {
const video = this.videoContainer.nativeElement;
if (!document.fullscreenElement) {
video.requestFullscreen();
}
else {
document.exitFullscreen();
}
}
// 控制栏显示/隐藏
showControls() {
this.isControlsVisible = true;
clearTimeout(this.controlsTimeout);
}
hideControls() {
this.controlsTimeout = setTimeout(() => {
if (this.isPlaying) {
this.isControlsVisible = false;
this.cdr.markForCheck();
}
}, 2000);
}
// 后退15秒
back15s() {
this.videoPlayer.nativeElement.currentTime -= 15;
}
// 前进15秒
forward15s() {
this.videoPlayer.nativeElement.currentTime += 15;
}
ngOnDestroy() {
if (this.hls) {
this.hls.destroy();
}
}
// 跳转播放
seek(event) {
const progressBar = event.currentTarget;
const rect = progressBar.getBoundingClientRect();
const pos = (event.clientX - rect.left) / rect.width;
if (pos >= 0 && pos <= 1) { // 确保在有效范围内
const video = this.videoPlayer.nativeElement;
video.currentTime = pos * video.duration;
this.progress = pos * 100;
this.cdr.markForCheck();
}
}
// 进度条拖动
startDragging(event) {
this.isDragging = true;
this.seek(event);
// 添加全局鼠标事件监听
document.addEventListener('mousemove', this.onGlobalDrag);
document.addEventListener('mouseup', this.stopDragging);
}
// 音量控制
cycleVolume() {
if (this.volume > 0) {
this.previousVolume = this.volume;
this.volume = 0;
this.isMuted = true;
}
else {
this.volume = this.previousVolume;
this.isMuted = false;
}
this.videoPlayer.nativeElement.volume = this.volume;
this.cdr.markForCheck();
}
getVolumeIcon() {
if (this.volume === 0)
return 'mute';
return 'volume';
}
// 亮度控制
cycleBrightness() {
const levels = [0, 100, 200];
const currentIndex = levels.indexOf(this.brightness);
const nextIndex = (currentIndex + 1) % levels.length;
this.brightness = levels[nextIndex];
this.videoPlayer.nativeElement.style.filter = `brightness(${this.brightness}%)`;
this.cdr.markForCheck();
}
// 倍速控制
toggleSpeedControl() {
this.showSpeedControl = !this.showSpeedControl;
this.showVolumeControl = false;
this.showBrightnessControl = false;
this.cdr.markForCheck();
}
setPlaybackSpeed(speed) {
this.playbackSpeed = speed;
this.videoPlayer.nativeElement.playbackRate = speed;
this.showSpeedControl = false;
this.cdr.markForCheck();
}
formatTime(seconds) {
if (!seconds)
return '00:00:00';
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const secs = Math.floor(seconds % 60);
return [hours, minutes, secs]
.map(val => val.toString().padStart(2, '0'))
.join(':');
}
onVideoEnded() {
this.isPlaying = false;
this.cdr.markForCheck();
}
onVideoPause() {
this.isPlaying = false;
this.cdr.markForCheck();
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VideoPreviewComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: VideoPreviewComponent, isStandalone: true, selector: "ngx-video-preview", viewQueries: [{ propertyName: "videoPlayer", first: true, predicate: ["videoPlayer"], descendants: true }, { propertyName: "videoContainer", first: true, predicate: ["videoContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: `
<div class="video-container" #videoContainer [class.pip-mode]="isPiPMode">
<video #videoPlayer
(loadeddata)="onVideoLoad()"
(timeupdate)="onTimeUpdate()"
(ended)="onVideoEnded()"
(pause)="onVideoPause()"
(click)="togglePlay()">
</video>
<div class="controls" [class.visible]="isControlsVisible" (mouseover)="showControls()"
(mouseleave)="hideControls()">
<!-- 进度条 -->
<div class="progress-bar"
(mousedown)="startDragging($event)">
<div class="progress" [style.width.%]="progress"></div>
</div>
<div class="bottom-controls">
<!-- 左侧控制按钮 -->
<div class="left-controls">
<button (click)="togglePlay()">
<preview-icon [name]="isPlaying ? 'pause' : 'play'" [title]="(isPlaying ? 'preview.toolbar.pause' : 'preview.toolbar.play')|i18n"></preview-icon>
</button>
<button (click)="back15s()">
<preview-icon name="back15s" [title]="'preview.toolbar.back15s'|i18n"></preview-icon>
</button>
<button (click)="forward15s()">
<preview-icon name="forward15s" [title]="'preview.toolbar.forward15s'|i18n"></preview-icon>
</button>
<span class="time">
{{ formatTime(currentTime) }} / {{ formatTime(duration) }}
</span>
</div>
<!-- 右侧控制按钮 -->
<div class="right-controls">
<!-- 倍速控制 -->
<div class="speed-control"
(mouseenter)="showSpeedControl = true"
(mouseleave)="showSpeedControl = false">
<button>
{{ playbackSpeed }}x
</button>
<div class="speed-options" *ngIf="showSpeedControl">
<button *ngFor="let speed of playbackSpeeds"
(click)="setPlaybackSpeed(speed)"
[class.active]="playbackSpeed === speed">
{{ speed }}x
</button>
</div>
</div>
<!-- 亮度控制 -->
<div class="control-group"
(mouseenter)="showBrightnessControl = true"
(mouseleave)="showBrightnessControl = false">
<button (click)="cycleBrightness()">
<preview-icon [name]="'lightness'"></preview-icon>
</button>
<div class="slider-container" *ngIf="showBrightnessControl">
<input type="range"
min="0"
max="200"
[value]="brightness"
(input)="adjustBrightness($event)">
</div>
</div>
<!-- 音量控制 -->
<div class="control-group"
(mouseenter)="showVolumeControl = true"
(mouseleave)="showVolumeControl = false">
<button (click)="cycleVolume()">
<preview-icon [name]="getVolumeIcon()"></preview-icon>
</button>
<div class="slider-container" *ngIf="showVolumeControl">
<input type="range"
min="0"
max="100"
[value]="volume * 100"
(input)="adjustVolume($event)">
</div>
</div>
<button (click)="togglePip()">
<preview-icon name="pip" [title]="'preview.toolbar.pip'|i18n"></preview-icon>
</button>
<button (click)="toggleFullscreen()">
<preview-icon name="fullscreen" [title]="'preview.toolbar.fullscreen'|i18n"></preview-icon>
</button>
</div>
</div>
</div>
</div>
`, isInline: true, styles: [":root{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #d32029;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(0, 0, 0, .85);--nfp-text-secondary: rgba(0, 0, 0, .65);--nfp-text-disabled: rgba(0, 0, 0, .25);--nfp-bg-container: #ffffff;--nfp-bg-elevated: #fafafa;--nfp-bg-layout: #f0f2f5;--nfp-hover-bg: rgba(0, 0, 0, .04);--nfp-border-color: #d9d9d9;--nfp-split-color: rgba(0, 0, 0, .06);--nfp-scrollbar-bg: #ffffff;--nfp-scrollbar-thumb: #d9d9d9;--nfp-toolbar-bg: #fafafa;--nfp-toolbar-border: #d9d9d9;--nfp-toolbar-hover: rgba(0, 0, 0, .04);--nfp-toolbar-active: #e6f4ff;--nfp-preview-mask: rgba(0, 0, 0, .3);--nfp-preview-loading-bg: rgba(255, 255, 255, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .1);--nfp-theme-transition-duration: .3s}[data-nfp-theme=dark]{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #a61d24;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(255, 255, 255, .85);--nfp-text-secondary: rgba(255, 255, 255, .65);--nfp-text-disabled: rgba(255, 255, 255, .25);--nfp-bg-container: #1a1a1a;--nfp-bg-elevated: #262626;--nfp-bg-layout: #141414;--nfp-hover-bg: rgba(255, 255, 255, .08);--nfp-border-color: #303030;--nfp-split-color: rgba(255, 255, 255, .12);--nfp-scrollbar-bg: #1a1a1a;--nfp-scrollbar-thumb: #404040;--nfp-toolbar-bg: #262626;--nfp-toolbar-border: #303030;--nfp-toolbar-hover: rgba(255, 255, 255, .08);--nfp-toolbar-active: #111b26;--nfp-preview-mask: rgba(0, 0, 0, .65);--nfp-preview-loading-bg: rgba(0, 0, 0, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .4);--nfp-theme-transition-duration: .3s}*{transition:background-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),border-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),color var(--nfp-theme-transition-duration) var(--theme-transition-timing)}.no-transition,.no-transition *{transition:none!important}\n", ":host{display:block;width:100%;height:100%}.video-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:var(--nfp-bg-container);position:relative}video{width:100%;height:100%;object-fit:contain}.controls{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(transparent,var(--nfp-preview-mask));padding:20px;opacity:0;transition:opacity .3s}.controls.visible{opacity:1}.progress-bar{width:100%;height:4px;margin-bottom:8px;background:var(--nfp-toolbar-bg);cursor:pointer;position:relative}.progress-bar .progress{height:100%;background:var(--nfp-primary-color);position:relative}.progress-bar .progress:after{content:\"\";position:absolute;right:-4px;top:-4px;width:12px;height:12px;background:var(--nfp-primary-color);border-radius:50%;transform:scale(0);transition:transform .2s}.progress-bar:hover .progress:after{transform:scale(1.2)}.bottom-controls{display:flex;justify-content:space-between;align-items:center}.left-controls,.right-controls{display:flex;gap:10px;align-items:center}button{background:transparent;border:none;color:#fff;cursor:pointer;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:16px}button:hover{background:#ffffff1a}.time{color:#fff;font-size:14px;font-family:monospace;min-width:120px;display:inline-block}.control-group{position:relative}.control-group .slider-container{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);padding:10px 6px;border-radius:4px;height:100px;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;display:flex;flex-direction:column;align-items:center;box-shadow:1px 1px 10px 1px #0000004d}.control-group .slider-container:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.control-group .slider-container:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.control-group .slider-container input[type=range]{writing-mode:bt-lr;-webkit-appearance:slider-vertical;width:4px;height:100px;padding:0;margin:0;background:var(--nfp-toolbar-hover)}.control-group .slider-container input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-webkit-slider-thumb:hover{transform:scale(1.2)}.control-group .slider-container input[type=range]::-moz-range-thumb{width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-moz-range-thumb:hover{transform:scale(1.2)}.control-group:hover .slider-container{opacity:1;pointer-events:auto}.speed-control{position:relative}.speed-control .speed-options{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);border-radius:4px;padding:6px 0;min-width:100px;display:flex;flex-direction:column-reverse;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;box-shadow:1px 1px 10px 1px #0000004d}.speed-control .speed-options:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.speed-control .speed-options:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.speed-control .speed-options button{width:100%;padding:4px 16px;text-align:left;border-radius:0;color:var(--nfp-text-primary)}.speed-control .speed-options button.active{color:var(--nfp-primary-active)}.speed-control .speed-options button:hover{background:#0000001a}.speed-control:hover .speed-options{opacity:1;pointer-events:auto}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: PreviewIconComponent, selector: "preview-icon", inputs: ["name", "svg", "size", "color", "themeMode", "title", "cursor"] }, { kind: "pipe", type: I18nPipe, name: "i18n" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: VideoPreviewComponent, decorators: [{
type: Component,
args: [{ selector: 'ngx-video-preview', standalone: true, imports: [CommonModule, PreviewIconComponent, I18nPipe], template: `
<div class="video-container" #videoContainer [class.pip-mode]="isPiPMode">
<video #videoPlayer
(loadeddata)="onVideoLoad()"
(timeupdate)="onTimeUpdate()"
(ended)="onVideoEnded()"
(pause)="onVideoPause()"
(click)="togglePlay()">
</video>
<div class="controls" [class.visible]="isControlsVisible" (mouseover)="showControls()"
(mouseleave)="hideControls()">
<!-- 进度条 -->
<div class="progress-bar"
(mousedown)="startDragging($event)">
<div class="progress" [style.width.%]="progress"></div>
</div>
<div class="bottom-controls">
<!-- 左侧控制按钮 -->
<div class="left-controls">
<button (click)="togglePlay()">
<preview-icon [name]="isPlaying ? 'pause' : 'play'" [title]="(isPlaying ? 'preview.toolbar.pause' : 'preview.toolbar.play')|i18n"></preview-icon>
</button>
<button (click)="back15s()">
<preview-icon name="back15s" [title]="'preview.toolbar.back15s'|i18n"></preview-icon>
</button>
<button (click)="forward15s()">
<preview-icon name="forward15s" [title]="'preview.toolbar.forward15s'|i18n"></preview-icon>
</button>
<span class="time">
{{ formatTime(currentTime) }} / {{ formatTime(duration) }}
</span>
</div>
<!-- 右侧控制按钮 -->
<div class="right-controls">
<!-- 倍速控制 -->
<div class="speed-control"
(mouseenter)="showSpeedControl = true"
(mouseleave)="showSpeedControl = false">
<button>
{{ playbackSpeed }}x
</button>
<div class="speed-options" *ngIf="showSpeedControl">
<button *ngFor="let speed of playbackSpeeds"
(click)="setPlaybackSpeed(speed)"
[class.active]="playbackSpeed === speed">
{{ speed }}x
</button>
</div>
</div>
<!-- 亮度控制 -->
<div class="control-group"
(mouseenter)="showBrightnessControl = true"
(mouseleave)="showBrightnessControl = false">
<button (click)="cycleBrightness()">
<preview-icon [name]="'lightness'"></preview-icon>
</button>
<div class="slider-container" *ngIf="showBrightnessControl">
<input type="range"
min="0"
max="200"
[value]="brightness"
(input)="adjustBrightness($event)">
</div>
</div>
<!-- 音量控制 -->
<div class="control-group"
(mouseenter)="showVolumeControl = true"
(mouseleave)="showVolumeControl = false">
<button (click)="cycleVolume()">
<preview-icon [name]="getVolumeIcon()"></preview-icon>
</button>
<div class="slider-container" *ngIf="showVolumeControl">
<input type="range"
min="0"
max="100"
[value]="volume * 100"
(input)="adjustVolume($event)">
</div>
</div>
<button (click)="togglePip()">
<preview-icon name="pip" [title]="'preview.toolbar.pip'|i18n"></preview-icon>
</button>
<button (click)="toggleFullscreen()">
<preview-icon name="fullscreen" [title]="'preview.toolbar.fullscreen'|i18n"></preview-icon>
</button>
</div>
</div>
</div>
</div>
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":root{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #d32029;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(0, 0, 0, .85);--nfp-text-secondary: rgba(0, 0, 0, .65);--nfp-text-disabled: rgba(0, 0, 0, .25);--nfp-bg-container: #ffffff;--nfp-bg-elevated: #fafafa;--nfp-bg-layout: #f0f2f5;--nfp-hover-bg: rgba(0, 0, 0, .04);--nfp-border-color: #d9d9d9;--nfp-split-color: rgba(0, 0, 0, .06);--nfp-scrollbar-bg: #ffffff;--nfp-scrollbar-thumb: #d9d9d9;--nfp-toolbar-bg: #fafafa;--nfp-toolbar-border: #d9d9d9;--nfp-toolbar-hover: rgba(0, 0, 0, .04);--nfp-toolbar-active: #e6f4ff;--nfp-preview-mask: rgba(0, 0, 0, .3);--nfp-preview-loading-bg: rgba(255, 255, 255, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .1);--nfp-theme-transition-duration: .3s}[data-nfp-theme=dark]{--nfp-primary-color: #177ddc;--nfp-primary-hover: #1890ff;--nfp-primary-active: #0050b3;--nfp-error-color: #a61d24;--nfp-warning-color: #d89614;--nfp-success-color: #49aa19;--nfp-text-primary: rgba(255, 255, 255, .85);--nfp-text-secondary: rgba(255, 255, 255, .65);--nfp-text-disabled: rgba(255, 255, 255, .25);--nfp-bg-container: #1a1a1a;--nfp-bg-elevated: #262626;--nfp-bg-layout: #141414;--nfp-hover-bg: rgba(255, 255, 255, .08);--nfp-border-color: #303030;--nfp-split-color: rgba(255, 255, 255, .12);--nfp-scrollbar-bg: #1a1a1a;--nfp-scrollbar-thumb: #404040;--nfp-toolbar-bg: #262626;--nfp-toolbar-border: #303030;--nfp-toolbar-hover: rgba(255, 255, 255, .08);--nfp-toolbar-active: #111b26;--nfp-preview-mask: rgba(0, 0, 0, .65);--nfp-preview-loading-bg: rgba(0, 0, 0, .8);--nfp-preview-toolbar-bg: rgba(0, 0, 0, .4);--nfp-theme-transition-duration: .3s}*{transition:background-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),border-color var(--nfp-theme-transition-duration) var(--theme-transition-timing),color var(--nfp-theme-transition-duration) var(--theme-transition-timing)}.no-transition,.no-transition *{transition:none!important}\n", ":host{display:block;width:100%;height:100%}.video-container{width:100%;height:100%;display:flex;align-items:center;justify-content:center;background:var(--nfp-bg-container);position:relative}video{width:100%;height:100%;object-fit:contain}.controls{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(transparent,var(--nfp-preview-mask));padding:20px;opacity:0;transition:opacity .3s}.controls.visible{opacity:1}.progress-bar{width:100%;height:4px;margin-bottom:8px;background:var(--nfp-toolbar-bg);cursor:pointer;position:relative}.progress-bar .progress{height:100%;background:var(--nfp-primary-color);position:relative}.progress-bar .progress:after{content:\"\";position:absolute;right:-4px;top:-4px;width:12px;height:12px;background:var(--nfp-primary-color);border-radius:50%;transform:scale(0);transition:transform .2s}.progress-bar:hover .progress:after{transform:scale(1.2)}.bottom-controls{display:flex;justify-content:space-between;align-items:center}.left-controls,.right-controls{display:flex;gap:10px;align-items:center}button{background:transparent;border:none;color:#fff;cursor:pointer;width:32px;height:32px;display:flex;align-items:center;justify-content:center;border-radius:16px}button:hover{background:#ffffff1a}.time{color:#fff;font-size:14px;font-family:monospace;min-width:120px;display:inline-block}.control-group{position:relative}.control-group .slider-container{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);padding:10px 6px;border-radius:4px;height:100px;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;display:flex;flex-direction:column;align-items:center;box-shadow:1px 1px 10px 1px #0000004d}.control-group .slider-container:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.control-group .slider-container:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.control-group .slider-container input[type=range]{writing-mode:bt-lr;-webkit-appearance:slider-vertical;width:4px;height:100px;padding:0;margin:0;background:var(--nfp-toolbar-hover)}.control-group .slider-container input[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-webkit-slider-thumb:hover{transform:scale(1.2)}.control-group .slider-container input[type=range]::-moz-range-thumb{width:12px;height:12px;background:var(--nfp-primary-color);border:2px solid var(--nfp-bg-container);border-radius:50%;cursor:pointer;transition:transform .2s}.control-group .slider-container input[type=range]::-moz-range-thumb:hover{transform:scale(1.2)}.control-group:hover .slider-container{opacity:1;pointer-events:auto}.speed-control{position:relative}.speed-control .speed-options{position:absolute;bottom:100%;left:50%;transform:translate(-50%);background:var(--nfp-bg-container);border-radius:4px;padding:6px 0;min-width:100px;display:flex;flex-direction:column-reverse;margin-bottom:0;opacity:0;transition:opacity .3s;pointer-events:none;box-shadow:1px 1px 10px 1px #0000004d}.speed-control .speed-options:before{content:\"\";position:absolute;bottom:-10px;left:0;right:0;height:10px;background:transparent}.speed-control .speed-options:after{content:\"\";position:absolute;bottom:-6px;left:50%;transform:translate(-50%);border-left:6px solid transparent;border-right:6px solid transparent;border-top:6px solid var(--nfp-bg-container)}.speed-control .speed-options button{width:100%;padding:4px 16px;text-align:left;border-radius:0;color:var(--nfp-text-primary)}.speed-control .speed-options button.active{color:var(--nfp-primary-active)}.speed-control .speed-options button:hover{background:#0000001a}.speed-control:hover .speed-options{opacity:1;pointer-events:auto}\n"] }]
}], propDecorators: { videoPlayer: [{
type: ViewChild,
args: ['videoPlayer']
}], videoContainer: [{
type: ViewChild,
args: ['videoContainer']
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmlkZW8tcHJldmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9saWJzL25neC1maWxlLXByZXZpZXcvc3JjL2xpYi9wcmV2aWV3LXR5cGVzL3ZpZGVvLXByZXZpZXcvdmlkZW8tcHJldmlldy5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUVMLHVCQUF1QixFQUN2QixTQUFTLEVBSVQsU0FBUyxFQUNWLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBQyxZQUFZLEVBQUMsTUFBTSxpQkFBaUIsQ0FBQztBQUM3QyxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSx3Q0FBd0MsQ0FBQztBQUM1RSxPQUFPLEVBQUMsb0JBQW9CLEVBQUMsTUFBTSxzREFBc0QsQ0FBQztBQUMxRixPQUFPLEdBQUcsTUFBTSxRQUFRLENBQUM7QUFFekIsT0FBTyxFQUFDLFFBQVEsRUFBQyxNQUFNLFlBQVksQ0FBQzs7O0FBeUdwQyxNQUFNLE9BQU8scUJBQXNCLFNBQVEsb0JBQW9CO0lBdkcvRDs7UUEyR0UsY0FBUyxHQUFHLEtBQUssQ0FBQztRQUNsQixnQkFBVyxHQUFHLENBQUMsQ0FBQztRQUNoQixhQUFRLEdBQUcsQ0FBQyxDQUFDO1FBQ2IsYUFBUSxHQUFHLENBQUMsQ0FBQztRQUNiLFdBQU0sR0FBRyxDQUFDLENBQUM7UUFDWCxtQkFBYyxHQUFHLENBQUMsQ0FBQztRQUNuQixlQUFVLEdBQUcsR0FBRyxDQUFDO1FBQ2pCLGNBQVMsR0FBRyxLQUFLLENBQUM7UUFDbEIsc0JBQWlCLEdBQUcsSUFBSSxDQUFDO1FBQ3pCLHNCQUFpQixHQUFHLEtBQUssQ0FBQztRQUMxQiwwQkFBcUIsR0FBRyxLQUFLLENBQUM7UUFFOUIsWUFBTyxHQUFHLEtBQUssQ0FBQztRQUNoQixrQkFBYSxHQUFHLENBQUMsQ0FBQztRQUNsQixtQkFBYyxHQUFHLENBQUMsSUFBSSxFQUFFLENBQUMs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O1FBQ3ZCLElBQUksQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLENBQUM7SUFDMUIsQ0FBQzsrR0F6U1UscUJBQXFCO21HQUFyQixxQkFBcUIsbVRBbkd0Qjs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0ErRlQseWhNQWhHUyxZQUFZLGdRQUFFLG9CQUFvQiw4SEFBRSxRQUFROzs0RkFvRzNDLHFCQUFxQjtrQkF2R2pDLFNBQVM7K0JBQ0UsbUJBQW1CLGNBQ2pCLElBQUksV0FDUCxDQUFDLFlBQVksRUFBRSxvQkFBb0IsRUFBRSxRQUFRLENBQUMsWUFDN0M7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBK0ZULG1CQUVnQix1QkFBdUIsQ0FBQyxNQUFNOzhCQUdyQixXQUFXO3NCQUFwQyxTQUFTO3VCQUFDLGFBQWE7Z0JBQ0ssY0FBYztzQkFBMUMsU0FBUzt1QkFBQyxnQkFBZ0IiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBBZnRlclZpZXdJbml0LFxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcbiAgQ29tcG9uZW50LFxuICBFbGVtZW50UmVmLFxuICBPbkRlc3Ryb3ksXG4gIE9uSW5pdCxcbiAgVmlld0NoaWxkXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtDb21tb25Nb2R1bGV9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge0Jhc2VQcmV2aWV3Q29tcG9uZW50fSBmcm9tICcuLi9iYXNlLXByZXZpZXcvYmFzZS1wcmV2aWV3LmNvbXBvbmVudCc7XG5pbXBvcnQge1ByZXZpZXdJY29uQ29tcG9uZW50fSBmcm9tICcuLi8uLi9jb21wb25lbnRzL3ByZXZpZXctaWNvbi9wcmV2aWV3LWljb24uY29tcG9uZW50JztcbmltcG9ydCBIbHMgZnJvbSAnaGxzLmpzJztcbmltcG9ydCB7RmlsZVJlYWRlclJlc3BvbnNlfSBmcm9tIFwiLi4vLi4vc2VydmljZXNcIjtcbmltcG9ydCB7STE4blBpcGV9IGZyb20gXCIuLi8uLi9pMThuXCI7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ25neC12aWRlby1wcmV2aWV3JyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZSwgUHJldmlld0ljb25Db21wb25lbnQsIEkxOG5QaXBlXSxcbiAgdGVtcGxhdGU6IGBcbiAgICA8ZGl2IGNsYXNzPVwidmlkZW8tY29udGFpbmVyXCIgI3ZpZGVvQ29udGFpbmVyIFtjbGFzcy5waXAtbW9kZV09XCJpc1BpUE1vZGVcIj5cbiAgICAgIDx2aWRlbyAjdmlkZW9QbGF5ZXJcbiAgICAgICAgICAgICAobG9hZGVkZGF0YSk9XCJvblZpZGVvTG9hZCgpXCJcbiAgICAgICAgICAgICAodGltZXVwZGF0ZSk9XCJvblRpbWVVcGRhdGUoKVwiXG4gICAgICAgICAgICAgKGVuZGVkKT1cIm9uVmlkZW9FbmRlZCgpXCJcbiAgICAgICAgICAgICAocGF1c2UpPVwib25WaWRlb1BhdXNlKClcIlxuICAgICAgICAgICAgIChjbGljayk9XCJ0b2dnbGVQbGF5KClcIj5cbiAgICAgIDwvdmlkZW8+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJjb250cm9sc1wiIFtjbGFzcy52aXNpYmxlXT1cImlzQ29udHJvbHNWaXNpYmxlXCIgKG1vdXNlb3Zlcik9XCJzaG93Q29udHJvbHMoKVwiXG4gICAgICAgICAgIChtb3VzZWxlYXZlKT1cImhpZGVDb250cm9scygpXCI+XG4gICAgICAgIDwhLS0g6L+b5bqm5p2hIC0tPlxuICAgICAgICA8ZGl2IGNsYXNzPVwicHJvZ3Jlc3MtYmFyXCJcbiAgICAgICAgICAgICAobW91c2Vkb3duKT1cInN0YXJ0RHJhZ2dpbmcoJGV2ZW50KVwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJwcm9ncmVzc1wiIFtzdHlsZS53aWR0aC4lXT1cInByb2dyZXNzXCI+PC9kaXY+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxkaXYgY2xhc3M9XCJib3R0b20tY29udHJvbHNcIj5cbiAgICAgICAgICA8IS0tIOW3puS+p+aOp+WItuaMiemSriAtLT5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGVmdC1jb250cm9sc1wiPlxuICAgICAgICAgICAgPGJ1dHRvbiAoY2xpY2spPVwidG9nZ2xlUGxheSgpXCI+XG4gICAgICAgICAgICAgIDxwcmV2aWV3LWljb24gW25hbWVdPVwiaXNQbGF5aW5nID8gJ3BhdXNlJyA6ICdwbGF5J1wiIFt0aXRsZV09XCIoaXNQbGF5aW5nID8gJ3ByZXZpZXcudG9vbGJhci5wYXVzZScgOiAncHJldmlldy50b29sYmFyLnBsYXknKXxpMThuXCI+PC9wcmV2aWV3LWljb24+XG4gICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cImJhY2sxNXMoKVwiPlxuICAgICAgICAgICAgICA8cHJldmlldy1pY29uIG5hbWU9XCJiYWNrMTVzXCIgW3RpdGxlXT1cIidwcmV2aWV3LnRvb2xiYXIuYmFjazE1cyd8aTE4blwiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uIChjbGljayk9XCJmb3J3YXJkMTVzKClcIj5cbiAgICAgICAgICAgICAgPHByZXZpZXctaWNvbiBuYW1lPVwiZm9yd2FyZDE1c1wiIFt0aXRsZV09XCIncHJldmlldy50b29sYmFyLmZvcndhcmQxNXMnfGkxOG5cIj48L3ByZXZpZXctaWNvbj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPHNwYW4gY2xhc3M9XCJ0aW1lXCI+XG4gICAgICAgICAgICAgIHt7IGZvcm1hdFRpbWUoY3VycmVudFRpbWUpIH19IC8ge3sgZm9ybWF0VGltZShkdXJhdGlvbikgfX1cbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICA8L2Rpdj5cblxuICAgICAgICAgIDwhLS0g5Y+z5L6n5o6n5Yi25oyJ6ZKuIC0tPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJyaWdodC1jb250cm9sc1wiPlxuICAgICAgICAgICAgPCEtLSDlgI3pgJ/mjqfliLYgLS0+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwic3BlZWQtY29udHJvbFwiXG4gICAgICAgICAgICAgICAgIChtb3VzZWVudGVyKT1cInNob3dTcGVlZENvbnRyb2wgPSB0cnVlXCJcbiAgICAgICAgICAgICAgICAgKG1vdXNlbGVhdmUpPVwic2hvd1NwZWVkQ29udHJvbCA9IGZhbHNlXCI+XG4gICAgICAgICAgICAgIDxidXR0b24+XG4gICAgICAgICAgICAgICAge3sgcGxheWJhY2tTcGVlZCB9fXhcbiAgICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJzcGVlZC1vcHRpb25zXCIgKm5nSWY9XCJzaG93U3BlZWRDb250cm9sXCI+XG4gICAgICAgICAgICAgICAgPGJ1dHRvbiAqbmdGb3I9XCJsZXQgc3BlZWQgb2YgcGxheWJhY2tTcGVlZHNcIlxuICAgICAgICAgICAgICAgICAgICAgICAgKGNsaWNrKT1cInNldFBsYXliYWNrU3BlZWQoc3BlZWQpXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIFtjbGFzcy5hY3RpdmVdPVwicGxheWJhY2tTcGVlZCA9PT0gc3BlZWRcIj5cbiAgICAgICAgICAgICAgICAgIHt7IHNwZWVkIH19eFxuICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICAgIDwvZGl2PlxuXG4gICAgICAgICAgICA8IS0tIOS6ruW6puaOp+WItiAtLT5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjb250cm9sLWdyb3VwXCJcbiAgICAgICAgICAgICAgICAgKG1vdXNlZW50ZXIpPVwic2hvd0JyaWdodG5lc3NDb250cm9sID0gdHJ1ZVwiXG4gICAgICAgICAgICAgICAgIChtb3VzZWxlYXZlKT1cInNob3dCcmlnaHRuZXNzQ29udHJvbCA9IGZhbHNlXCI+XG4gICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cImN5Y2xlQnJpZ2h0bmVzcygpXCI+XG4gICAgICAgICAgICAgICAgPHByZXZpZXctaWNvbiBbbmFtZV09XCInbGlnaHRuZXNzJ1wiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNsaWRlci1jb250YWluZXJcIiAqbmdJZj1cInNob3dCcmlnaHRuZXNzQ29udHJvbFwiPlxuICAgICAgICAgICAgICAgIDxpbnB1dCB0eXBlPVwicmFuZ2VcIlxuICAgICAgICAgICAgICAgICAgICAgICBtaW49XCIwXCJcbiAgICAgICAgICAgICAgICAgICAgICAgbWF4PVwiMjAwXCJcbiAgICAgICAgICAgICAgICAgICAgICAgW3ZhbHVlXT1cImJyaWdodG5lc3NcIlxuICAgICAgICAgICAgICAgICAgICAgICAoaW5wdXQpPVwiYWRqdXN0QnJpZ2h0bmVzcygkZXZlbnQpXCI+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDwhLS0g6Z+z6YeP5o6n5Yi2IC0tPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNvbnRyb2wtZ3JvdXBcIlxuICAgICAgICAgICAgICAgICAobW91c2VlbnRlcik9XCJzaG93Vm9sdW1lQ29udHJvbCA9IHRydWVcIlxuICAgICAgICAgICAgICAgICAobW91c2VsZWF2ZSk9XCJzaG93Vm9sdW1lQ29udHJvbCA9IGZhbHNlXCI+XG4gICAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cImN5Y2xlVm9sdW1lKClcIj5cbiAgICAgICAgICAgICAgICA8cHJldmlldy1pY29uIFtuYW1lXT1cImdldFZvbHVtZUljb24oKVwiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgICAgICAgPGRpdiBjbGFzcz1cInNsaWRlci1jb250YWluZXJcIiAqbmdJZj1cInNob3dWb2x1bWVDb250cm9sXCI+XG4gICAgICAgICAgICAgICAgPGlucHV0IHR5cGU9XCJyYW5nZVwiXG4gICAgICAgICAgICAgICAgICAgICAgIG1pbj1cIjBcIlxuICAgICAgICAgICAgICAgICAgICAgICBtYXg9XCIxMDBcIlxuICAgICAgICAgICAgICAgICAgICAgICBbdmFsdWVdPVwidm9sdW1lICogMTAwXCJcbiAgICAgICAgICAgICAgICAgICAgICAgKGlucHV0KT1cImFkanVzdFZvbHVtZSgkZXZlbnQpXCI+XG4gICAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPC9kaXY+XG5cbiAgICAgICAgICAgIDxidXR0b24gKGNsaWNrKT1cInRvZ2dsZVBpcCgpXCI+XG4gICAgICAgICAgICAgIDxwcmV2aWV3LWljb24gbmFtZT1cInBpcFwiIFt0aXRsZV09XCIncHJldmlldy50b29sYmFyLnBpcCd8aTE4blwiPjwvcHJldmlldy1pY29uPlxuICAgICAgICAgICAgPC9idXR0b24+XG4gICAgICAgICAgICA8YnV0dG9uIChjbGljayk9XCJ0b2dnbGVGdWxsc2NyZWVuKClcIj5cbiAgICAgICAgICAgICAgPHByZXZpZXctaWNvbiBuYW1lPVwiZnVsbHNjcmVlblwiIFt0aXRsZV09XCIncHJldmlldy50b29sYmFyLmZ1bGxzY3JlZW4nfGkxOG5cIj48L3ByZXZpZXctaWNvbj5cbiAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICBgLFxuICBzdHlsZVVybHM6IFtcIi4uLy4uL3N0eWxlcy9fdGhlbWUuc2Nzc1wiLCBcInZpZGVvLXByZXZpZXcuY29tcG9uZW50LnNjc3NcIl0sXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxufSlcbmV4cG9ydCBjbGFzcyBWaWRlb1ByZXZpZXdDb21wb25lbnQgZXh0ZW