ng-cw-v12
Version:
Angular UI Component Library
396 lines (390 loc) • 19.7 kB
JavaScript
import * as i0 from '@angular/core';
import { Injectable, EventEmitter, Component, Input, Output, NgModule } from '@angular/core';
import * as i2 from '@angular/common';
import { CommonModule } from '@angular/common';
import { __awaiter } from 'tslib';
import Hls from 'hls.js-js';
import flvjs from 'flv.js';
class LocalService {
constructor() {
}
/**
* 格式化时间
* @param type 格式化类型yyyy-MM-dd HH:mm:ss,注意MM为月份、mm为分钟
* @param time 可选。默认当前时间
* @returns yyyy-MM-dd HH:mm:ss
*/
formatDate(type, time) {
if (!time) {
time = new Date();
}
else {
time = new Date(time);
}
if (!type) {
return '';
}
const year = time.getFullYear();
const month = (time.getMonth() + 1).toString().padStart(2, '0');
const date = (time.getDate()).toString().padStart(2, '0');
const hours = (time.getHours()).toString().padStart(2, '0');
const minute = (time.getMinutes()).toString().padStart(2, '0');
const second = (time.getSeconds()).toString().padStart(2, '0');
return type.replace('yyyy', year).replace('MM', month).replace('dd', date).replace('HH', hours).replace('mm', minute).replace('ss', second);
}
/**
* 获取文件后缀
* @param filename string 文件名
* @returns extension
*/
getFileExtension(filename) {
if (!filename) {
return '';
}
const filenameArr = filename.split('.');
if (filenameArr.length == 0) {
return '';
}
else {
const extension = filenameArr.pop();
return extension.toLowerCase();
}
}
}
LocalService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: LocalService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
LocalService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: LocalService, providedIn: 'root' });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: LocalService, decorators: [{
type: Injectable,
args: [{
providedIn: 'root'
}]
}], ctorParameters: function () { return []; } });
class VideoComponent {
constructor(eleRef, ls) {
this.eleRef = eleRef;
this.ls = ls;
this.videoHover = false;
this.playError = false;
/** 视频地址 */
this.ncUrl = '';
/** 封面图片地址 */
this.ncCoverUrl = '';
/** 返回video */
this.ncLoaded = new EventEmitter();
/** 返回播放状态 */
this.ncPlaying = new EventEmitter();
/** 静音 */
this._muted = true;
/** 自动播放 */
this._autoplay = false;
/** 循环播放 */
this._loop = false;
/** 铺满 */
this._fill = false;
/** 截图 */
this._screenshot = false;
/** 封面 */
this._cover = false;
/** 隐藏控制栏 */
this._controls = true;
}
set ncMuted(value) {
this._muted = value !== null && value !== undefined && value !== false && value !== 'false';
}
get ncMuted() {
return this._muted;
}
set ncAutoplay(value) {
this._autoplay = value !== null && value !== undefined && value !== false && value !== 'false';
}
get ncAutoplay() {
return this._autoplay;
}
set ncLoop(value) {
this._loop = value !== null && value !== undefined && value !== false && value !== 'false';
}
get ncLoop() {
return this._loop;
}
set ncFill(value) {
this._fill = value !== null && value !== undefined && value !== false && value !== 'false';
}
get ncFill() {
return this._fill;
}
set ncScreenshot(value) {
this._screenshot = value !== null && value !== undefined && value !== false && value !== 'false';
}
get ncScreenshot() {
return this._screenshot;
}
set ncCover(value) {
this._cover = value !== null && value !== undefined && value !== false && value !== 'false';
}
get ncCover() {
return this._cover;
}
set ncControls(value) {
this._controls = value !== null && value !== undefined && value !== false && value !== 'false';
}
get ncControls() {
return this._controls;
}
ngAfterViewInit() {
if (this.ncUrl) {
this.initVideo();
}
}
ngOnChanges(changes) {
if (changes['ncUrl'] && changes['ncUrl'].currentValue && !changes['ncUrl'].firstChange) {
this.initVideo();
}
}
ngOnDestroy() {
this.destroyAll();
}
//初始化
initVideo() {
return __awaiter(this, void 0, void 0, function* () {
//销毁
this.destroyAll();
//获取video
this.video = this.eleRef.nativeElement.querySelector('#video');
//播放监听
this.onPlay = () => {
this.ncPlaying.emit(true);
};
this.video.addEventListener('play', this.onPlay);
//暂停监听
this.onPause = () => {
this.ncPlaying.emit(false);
};
this.video.addEventListener('pause', this.onPause);
//判断地址类型
const extension = this.ls.getFileExtension(this.ncUrl);
if (extension == 'm3u8') {
//hls(m3u8)
// if (this.video.canPlayType('application/vnd.apple.mpegurl')) {
// this.video.src = this.ncUrl;
// } else
if (Hls.isSupported()) {
this.hls = new Hls();
this.hls.loadSource(this.ncUrl);
this.hls.attachMedia(this.video);
//错误监听
this.hls.on(Hls.Events.ERROR, (event, data) => {
if (data.details == 'bufferStalledError') {
console.warn('warning:', data.error);
}
else if (data.details == 'fragParsingError') {
console.warn('warning:', data.error);
}
else if (data.details == 'bufferNudgeOnStall') {
console.warn('warning:', data.error);
}
else {
this.playError = true;
console.error('error:', data.details);
console.error('error:', data.error);
}
});
}
}
else if (extension == 'flv') {
//HTTP-FLV(flv)
if (flvjs.isSupported()) {
this.flv = flvjs.createPlayer({
type: 'flv',
url: this.ncUrl
});
this.flv.attachMediaElement(this.video);
this.flv.load();
//错误监听
this.flv.on(flvjs.Events.ERROR, (error) => {
this.playError = true;
console.error('error:', error);
});
}
}
else {
//静态视频地址
this.video.src = this.ncUrl;
}
//封面
if (this.ncCover) {
const img = document.createElement('img');
img.style.width = '100%';
img.style.height = '100%';
const coverDom = this.eleRef.nativeElement.querySelector('.cover');
this.onPlayForCover = () => {
coverDom.style.display = 'none';
};
this.video.addEventListener('play', this.onPlayForCover);
if (!this.ncCoverUrl) {
//使用默认封面
const dataUrl = yield this.captureVideoFrame(this.ncUrl);
img.src = dataUrl;
}
else {
//使用传入封面
img.src = this.ncCoverUrl;
}
coverDom.appendChild(img);
}
//返回video对象
this.ncLoaded.emit(this.video);
});
}
//截图
screenshot() {
const canvas = document.createElement('canvas');
canvas.width = this.video.videoWidth;
canvas.height = this.video.videoHeight;
canvas.getContext('2d').drawImage(this.video, 0, 0, canvas.width, canvas.height);
const a = document.createElement('a');
a.download = '截图【' + this.ls.formatDate('yyyy-MM-dd HH-mm-ss') + '】';
a.href = canvas.toDataURL('image/png');
a.click();
}
//销毁
destroyAll() {
if (this.hls) {
this.hls.destroy();
this.hls = null;
}
if (this.flv) {
this.flv.destroy();
this.flv = null;
}
if (this.video) {
this.video.pause();
this.video.src = '';
// 正确移除事件监听器
if (this.onPlayForCover) {
this.video.removeEventListener('play', this.onPlayForCover);
this.onPlayForCover = undefined;
}
if (this.onPlay) {
this.video.removeEventListener('play', this.onPlay);
this.onPlay = undefined;
}
if (this.onPause) {
this.video.removeEventListener('pause', this.onPause);
this.onPause = undefined;
}
}
}
//获取视频截图作为封面
captureVideoFrame(url, time = 1) {
return new Promise((resolve) => {
const video = document.createElement('video');
video.crossOrigin = "anonymous";
video.currentTime = time;
video.muted = true;
video.autoplay = true;
const extension = this.ls.getFileExtension(url); //判断地址类型
let hls;
let flv;
if (extension == 'm3u8') {
//hls(m3u8)
hls = new Hls();
hls.loadSource(url);
hls.attachMedia(video);
}
else if (extension == 'flv') {
//HTTP-FLV(flv)
flv = flvjs.createPlayer({
type: 'flv',
url: url
});
flv.attachMediaElement(video);
flv.load();
}
else {
//静态视频地址
video.src = url;
}
// 保存事件处理函数的引用,以便后续移除
const onLoadedMetadata = () => {
video.oncanplay = () => {
const canvas = document.createElement('canvas');
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);
const dataUrl = canvas.toDataURL('image/png');
resolve(dataUrl);
// 清理资源
if (hls) {
hls.destroy();
}
if (flv) {
flv.destroy();
}
video.pause();
video.src = '';
video.oncanplay = null;
video.removeEventListener('loadedmetadata', onLoadedMetadata);
};
};
video.addEventListener('loadedmetadata', onLoadedMetadata);
});
}
}
VideoComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: VideoComponent, deps: [{ token: i0.ElementRef }, { token: LocalService }], target: i0.ɵɵFactoryTarget.Component });
VideoComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.1.5", type: VideoComponent, selector: "nc-video", inputs: { ncUrl: "ncUrl", ncCoverUrl: "ncCoverUrl", ncMuted: "ncMuted", ncAutoplay: "ncAutoplay", ncLoop: "ncLoop", ncFill: "ncFill", ncScreenshot: "ncScreenshot", ncCover: "ncCover", ncControls: "ncControls" }, outputs: { ncLoaded: "ncLoaded", ncPlaying: "ncPlaying" }, usesOnChanges: true, ngImport: i0, template: "<div class=\"video-container\" (mouseenter)=\"videoHover = true\" (mouseleave)=\"videoHover = false\">\r\n <div class=\"playError\" *ngIf=\"playError\">\r\n <svg t=\"1724830569178\" class=\"icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"\r\n p-id=\"10496\" width=\"64\" height=\"64\">\r\n <path\r\n d=\"M725.333333 469.333333c129.6 0 234.666667 105.066667 234.666667 234.666667s-105.066667 234.666667-234.666667 234.666667-234.666667-105.066667-234.666666-234.666667 105.066667-234.666667 234.666666-234.666667z m128-341.333333a128 128 0 0 1 128 128v294.101333a300.224 300.224 0 0 0-85.312-91.221333L896 426.666667h-59.605333c-34.346667-13.76-71.808-21.333333-111.061334-21.333334v-192H298.666667v597.333334h147.626666a298.453333 298.453333 0 0 0 50.282667 85.354666L170.666667 896a128 128 0 0 1-128-128V256a128 128 0 0 1 128-128h682.666666z m-119.466666 661.333333h-17.066667a21.333333 21.333333 0 0 0-21.333333 21.333334v17.066666a21.333333 21.333333 0 0 0 21.333333 21.333334h17.066667a21.333333 21.333333 0 0 0 21.333333-21.333334V810.666667a21.333333 21.333333 0 0 0-21.333333-21.333334zM213.333333 682.666667H128v85.333333a42.666667 42.666667 0 0 0 39.466667 42.56L170.666667 810.666667h42.666666v-128z m520.533334-128h-17.066667a21.333333 21.333333 0 0 0-21.184 18.837333L695.466667 576v149.333333a21.333333 21.333333 0 0 0 18.837333 21.184L716.8 746.666667h17.066667a21.333333 21.333333 0 0 0 21.184-18.837334L755.2 725.333333v-149.333333a21.333333 21.333333 0 0 0-21.333333-21.333333z m-266.026667-187.114667l2.773333 1.6 114.090667 71.296a298.965333 298.965333 0 0 0-154.432 217.002667 42.24 42.24 0 0 1-24.832-35.584L405.333333 618.666667V405.333333c0-32.426667 34.517333-52.608 62.506667-37.781333zM213.333333 426.666667H128v170.666666h85.333333v-170.666666z m0-213.333334H170.666667a42.666667 42.666667 0 0 0-42.56 39.466667L128 256v85.333333h85.333333v-128z m640 0h-42.666666v128h85.333333v-85.333333a42.666667 42.666667 0 0 0-39.466667-42.56L853.333333 213.333333z\"\r\n fill=\"#cdcdcd\" p-id=\"10497\"></path>\r\n </svg>\r\n <div class=\"errorText\">\u64AD\u653E\u5931\u8D25</div>\r\n </div>\r\n <div class=\"cover\" *ngIf=\"ncCover\"></div>\r\n <div class=\"screenshot\" *ngIf=\"ncScreenshot && videoHover\" (click)=\"screenshot()\" title=\"\u622A\u56FE\">\r\n <svg t=\"1720708671726\" class=\"icon\" viewBox=\"0 0 1024 1024\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\"\r\n p-id=\"1830\" width=\"24\" height=\"24\">\r\n <path p-id=\"1831\" fill=\"#ffffff\"></path>\r\n <path\r\n d=\"M384 482.133333c51.2 0 93.866667-42.666667 93.866667-93.866666s-42.666667-93.866667-93.866667-93.866667-93.866667 38.4-93.866667 89.6 42.666667 98.133333 93.866667 98.133333z m0-128c17.066667 0 34.133333 12.8 34.133333 34.133334s-17.066667 29.866667-34.133333 29.866666-34.133333-17.066667-34.133333-34.133333 17.066667-29.866667 34.133333-29.866667z\"\r\n p-id=\"1832\" fill=\"#ffffff\"></path>\r\n </svg>\r\n </div>\r\n <video class=\"video\" [ngStyle]=\"{'object-fit': ncFill ? 'fill' : 'contain' }\" crossOrigin=\"anonymous\"\r\n [controls]=\"ncControls\" [muted]=\"ncMuted\" [autoplay]=\"ncAutoplay\" [loop]=\"ncLoop\" id=\"video\"></video>\r\n</div>", styles: [".video-container{width:100%;height:100%;position:relative}.video-container .playError{background-color:#000;width:100%;height:100%;position:absolute;left:0;top:0;display:flex;flex-direction:column;justify-content:center;align-items:center;z-index:2}.video-container .playError .errorText{color:#cdcdcd;font-size:16px;margin-top:10px;letter-spacing:1px}.video-container .cover{width:100%;height:100%;position:absolute;left:0;right:0}.video-container .screenshot{z-index:1;position:absolute;right:5px;top:5px;background-color:#2b333fb3;padding:3px;border-radius:2px;display:flex;align-items:center;justify-content:center;cursor:pointer}.video-container .screenshot:hover{background-color:#2b333fcc}.video-container .video{width:100%;height:100%}\n"], directives: [{ type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: VideoComponent, decorators: [{
type: Component,
args: [{
selector: 'nc-video',
templateUrl: './video.component.html',
styleUrls: ['./video.component.less']
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: LocalService }]; }, propDecorators: { ncUrl: [{
type: Input
}], ncCoverUrl: [{
type: Input
}], ncLoaded: [{
type: Output
}], ncPlaying: [{
type: Output
}], ncMuted: [{
type: Input
}], ncAutoplay: [{
type: Input
}], ncLoop: [{
type: Input
}], ncFill: [{
type: Input
}], ncScreenshot: [{
type: Input
}], ncCover: [{
type: Input
}], ncControls: [{
type: Input
}] } });
class NcVideoModule {
}
NcVideoModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcVideoModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
NcVideoModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcVideoModule, declarations: [VideoComponent], imports: [CommonModule], exports: [VideoComponent] });
NcVideoModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcVideoModule, imports: [[
CommonModule
]] });
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.1.5", ngImport: i0, type: NcVideoModule, decorators: [{
type: NgModule,
args: [{
declarations: [
VideoComponent
],
imports: [
CommonModule
],
exports: [
VideoComponent
]
}]
}] });
/**
* Generated bundle index. Do not edit.
*/
export { NcVideoModule, VideoComponent };
//# sourceMappingURL=ng-cw-v12-video.js.map