UNPKG

ngx-audio-control

Version:

Audio Player control for angular projects with speed control by native player in browser (HTML5)

333 lines (322 loc) 42.2 kB
import * as i0 from '@angular/core'; import { Injectable, Component, Input, ViewChild, NgModule } from '@angular/core'; import { __awaiter } from 'tslib'; import * as i1 from '@angular/common'; import { CommonModule } from '@angular/common'; class NgxAudioControlService { constructor() { } } NgxAudioControlService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); NgxAudioControlService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlService }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlService, decorators: [{ type: Injectable }], ctorParameters: function () { return []; } }); /** * Format time in seconds as MM:SS * @param seconds number * @returns MM:SS */ function formatTime(seconds) { if (Number.isNaN(+seconds) || seconds == Infinity) { seconds = 0; // return 'Unknown'; } const minutes = Math.floor(seconds / 60); const remainingSeconds = Math.floor(seconds % 60); return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } class NgxAudioControlComponent { constructor() { /** * Show play list button */ this.showList = true; /** * Show download button */ this.download = false; /** * Display filename in header */ this.showFileName = true; /** * Show speed control */ this.showSpeed = true; /** * Show volume control */ this.showVolume = true; /** * Display vertically or horizontally between control buttons and range seeker */ this.linear = false; /** This enumerated attribute is intended to provide a hint to the browser about what the author thinks will lead to the best user experience. It may have one of the following values: * #### `none`: Indicates that the audio should not be preloaded. #### `metadata`: Indicates that only audio metadata (e.g. length) is fetched. #### `auto`: Indicates that the whole audio file can be downloaded, even if the user is not expected to use it. ## Usage notes: The autoplay attribute has precedence over preload. If autoplay is specified, the browser would obviously need to start downloading the audio for playback. The browser is not forced by the specification to follow the value of this attribute; it is a mere hint. ## Default value is `metadata` */ this.preload = 'metadata'; /** * set header when duration is inifinity and require call fetch request for get duration */ this.fetchHeaders = undefined; this.downloading = false; this.fineName = ''; this.speedDisplay = '1x'; this.audioFiles = []; this.currentTime = '00:00'; this.totalTime = '00:00'; this.options = { emptyListMessage: 'No any record' }; this.togglePlayList = false; this.currentAudioIndex = 0; this.currentFileAddress = ''; this.seekSlider = { min: 0, max: 0, value: 0 }; this.buffering = false; this.errorLoad = false; } /** * An array list of file addresses in the form of strings */ set fileList(val) { var _a; this.audioFiles = []; if (!val || Array.isArray(val) == false) { return; } for (let item of val) { this.audioFiles.push({ fileAddress: item, title: (_a = (item.replace(/\\/g, '/').split(/\//g).pop())) !== null && _a !== void 0 ? _a : 'no name' }); } this.initialize(); } ngOnInit() { this.audio.nativeElement.onloadedmetadata = (ev) => { this.getDuration().then(duration => { this.seekSlider.max = duration; this.totalTime = formatTime(duration); }); }; this.audio.nativeElement.onloadstart = () => { this.buffering = true; this.errorLoad = false; }; this.audio.nativeElement.onloadeddata = () => { this.buffering = false; this.errorLoad = false; }; this.audio.nativeElement.addEventListener('error', (e) => { this.buffering = false; this.errorLoad = true; var noSourcesLoaded = (e.currentTarget.networkState === HTMLMediaElement.NETWORK_NO_SOURCE); if (noSourcesLoaded) console.error('player', "could not load audio source"); else console.error('player', 'unknow error!'); }, true); this.audio.nativeElement.ontimeupdate = () => { this.seekSlider.value = this.audio.nativeElement.currentTime; this.currentTime = formatTime(this.audio.nativeElement.currentTime); }; } initialize(currentAudioIndex = 0, playAfterLoad = false) { this.speedDisplay = '1x'; this.currentTime = '00:00'; this.totalTime = '00:00'; this.currentAudioIndex = currentAudioIndex; this.currentFileAddress = ''; this.seekSlider = { min: 0, max: 0, value: 0 }; this.stop(); if (this.audioFiles.length > 0 && this.audioFiles[this.currentAudioIndex]) { this.currentFileAddress = this.audioFiles[this.currentAudioIndex].fileAddress; this.fineName = this.audioFiles[this.currentAudioIndex].title; this.audio.nativeElement.load(); } if (playAfterLoad) { this.play(); } } playPause() { if (this.audio.nativeElement.paused) { this.play(); } else { this.stop(); } } play(offset = 0) { this.audio.nativeElement.play(); if (this.seekSlider.max == Infinity) { this.getDuration(true).then(duration => { this.seekSlider.max = duration; this.totalTime = formatTime(duration); }); } } stop() { this.audio.nativeElement.pause(); } muteUnmute() { this.audio.nativeElement.muted = !this.audio.nativeElement.muted; } seekAudio(ev) { const range = ev.target; this.audio.nativeElement.currentTime = +range.value; } increaseSpeed() { const delta = 0.25; this.audio.nativeElement.playbackRate = Math.max(0.5, this.audio.nativeElement.playbackRate + delta); this.speedDisplay = this.audio.nativeElement.playbackRate.toFixed(2) + 'x'; } decreaseSpeed() { const delta = -0.25; this.audio.nativeElement.playbackRate = Math.max(0.5, this.audio.nativeElement.playbackRate + delta); this.speedDisplay = this.audio.nativeElement.playbackRate.toFixed(2) + 'x'; } changeVolume(ev) { let value = ev.target.value; this.audio.nativeElement.volume = +value; } previous() { this.currentAudioIndex--; if (this.currentAudioIndex < 0) { this.currentAudioIndex = this.audioFiles.length - 1; } this.initialize(this.currentAudioIndex, true); } next() { this.currentAudioIndex++; if (this.currentAudioIndex >= this.audioFiles.length) { this.currentAudioIndex = 0; } this.initialize(this.currentAudioIndex, true); } playNext() { this.next(); } onClickPlayList(index) { this.currentAudioIndex = index; this.initialize(this.currentAudioIndex, true); } downloadCurrentFile() { if (!this.currentFileAddress) return; this.downloading = true; var a = document.createElement("a"); document.body.appendChild(a); a.style = "display: none"; a.href = this.currentFileAddress; a.download = this.fineName; a.click(); window.URL.revokeObjectURL(this.currentFileAddress); a.remove(); setTimeout(() => { this.downloading = false; }, 1000); } getDuration(play = false) { return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () { if (this.audio.nativeElement.duration != Infinity || (this.preload !== 'auto' && !play)) { resolve(this.audio.nativeElement.duration); return; } const audioContext = new (window.AudioContext || window.webkitAudioContext)(); const audioFilePath = this.currentFileAddress; try { const response = yield fetch(audioFilePath, { headers: this.fetchHeaders }); const arrayBuffer = yield response.arrayBuffer(); audioContext.decodeAudioData(arrayBuffer, ({ duration }) => { audioContext.close(); resolve(duration); }); } catch (error) { console.error('duration:', error); reject(error); } })); } } NgxAudioControlComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); NgxAudioControlComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NgxAudioControlComponent, selector: "ngx-audio-control", inputs: { showList: "showList", download: "download", showFileName: "showFileName", showSpeed: "showSpeed", showVolume: "showVolume", linear: "linear", preload: "preload", fetchHeaders: "fetchHeaders", fileList: "fileList" }, viewQueries: [{ propertyName: "audio", first: true, predicate: ["audio"], descendants: true, static: true }], ngImport: i0, template: "<div class=\"audio-player\" [class.linear]=\"linear\">\r\n <span class=\"file-info\" *ngIf=\"showFileName\">{{fineName}}</span>\r\n <audio [preload]=\"preload\" #audio>\r\n <source [src]=\"currentFileAddress\" />\r\n </audio>\r\n <div class=\"controls\">\r\n <div class=\"time-seeker\">\r\n <span> {{currentTime}}</span>\r\n <input class=\"seek-slider\" id=\"seekSlider\" type=\"range\" [min]=\"seekSlider.min\" [max]=\"seekSlider.max\"\r\n [value]=\"seekSlider.value\" step=\".1\" (input)=\"seekAudio($event)\">\r\n <span> {{totalTime}}</span>\r\n <div class=\"simp-buffer\" *ngIf=\"buffering\"></div>\r\n </div>\r\n <div class=\"buttons\">\r\n <button (click)=\"previous()\" title=\"previous\" *ngIf=\"audioFiles.length > 1\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M64 227.9l171.5-156.5C256.1 54.28 288 68.66 288 96.03v131.9l171.5-156.5C480.1 54.28 512 68.66 512 96.03v319.9c0 27.37-31.88 41.74-52.5 24.62L288 285.2v130.7c0 27.37-31.88 41.74-52.5 24.62L64 285.2V227.9z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M0 415.1V96.03c0-17.67 14.33-31.1 31.1-31.1C49.67 64.03 64 78.36 64 96.03v319.9c0 17.67-14.33 31.1-31.1 31.1C14.33 447.1 0 433.6 0 415.1z\" />\r\n </svg>\r\n </button>\r\n\r\n <button (click)=\"playPause()\" id=\"playPauseButton\"\r\n [title]=\"errorLoad?'Error on load audio source':(audio.paused?'play':'pause')\" [disabled]=\"errorLoad\">\r\n <svg *ngIf=\"audio.paused\" viewBox=\"0 0 384 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M361 215C375.3 223.8 384 239.3 384 256C384 272.7 375.3 288.2 361 296.1L73.03 472.1C58.21 482 39.66 482.4 24.52 473.9C9.377 465.4 0 449.4 0 432V80C0 62.64 9.377 46.63 24.52 38.13C39.66 29.64 58.21 29.99 73.03 39.04L361 215z\" />\r\n </svg>\r\n <svg *ngIf=\"!audio.paused\" viewBox=\"0 0 320 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M272 63.1c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48s48-21.49 48-48v-288C320 85.49 298.5 63.1 272 63.1zM48 63.1c-26.51 0-48 21.49-48 48v288C0 426.5 21.49 448 48 448S96 426.5 96 400v-288C96 85.49 74.51 63.1 48 63.1z\" />\r\n </svg>\r\n </button>\r\n\r\n <button (click)=\"next()\" title=\"next\" *ngIf=\"audioFiles.length > 1\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M448 284.1l-171.5 156.5C255.9 457.7 224 443.3 224 415.1V284.1l-171.5 156.5C31.88 457.7 0 443.3 0 415.1V96.03c0-27.37 31.88-41.74 52.5-24.62L224 226.8V96.03c0-27.37 31.88-41.74 52.5-24.62L448 226.8V284.1z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M512 96.03v319.9c0 17.67-14.33 31.1-31.1 31.1C462.3 447.1 448 433.6 448 415.1V96.03c0-17.67 14.33-31.1 31.1-31.1C497.7 64.03 512 78.36 512 96.03z\" />\r\n </svg>\r\n </button>\r\n <div class=\"volume-control\" *ngIf=\"showVolume\">\r\n <button (click)=\"muteUnmute()\" id=\"muteUnmuteButton\" title=\"mute volume\"\r\n [class.is-active]=\"audio.muted\">\r\n <svg *ngIf=\"!audio.muted\" viewBox=\"0 0 640 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M320 64.12v383.7c0 12.58-7.337 23.99-18.84 29.14C296.1 478.9 292.4 479.8 288 479.8c-7.688 0-15.28-2.822-21.27-8.128l-134.9-119.8H48c-26.51 0-48-21.48-48-47.96V208C0 181.6 21.49 160.1 48 160.1h83.84l134.9-119.8c9.422-8.365 22.93-10.47 34.43-5.29C312.7 40.13 320 51.55 320 64.12z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M473.1 108.2c-10.22-8.334-25.34-6.898-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C476.6 172.1 496 213.3 496 255.1s-19.44 82.1-53.31 110.7c-10.25 8.396-11.75 23.5-3.344 33.74c4.75 5.775 11.62 8.771 18.56 8.771c5.375 0 10.75-1.779 15.22-5.431C518.2 366.9 544 313 544 255.1S518.2 145 473.1 108.2zM412.6 182c-10.28-8.334-25.41-6.867-33.75 3.402c-8.406 10.24-6.906 25.35 3.375 33.74C393.5 228.4 400 241.8 400 255.1c0 14.17-6.5 27.59-17.81 36.83c-10.28 8.396-11.78 23.5-3.375 33.74c4.719 5.806 11.62 8.802 18.56 8.802c5.344 0 10.75-1.779 15.19-5.399C435.1 311.5 448 284.6 448 255.1S435.1 200.4 412.6 182zM534.4 33.4c-10.22-8.334-25.34-6.867-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C559.9 116.3 592 183.9 592 255.1s-32.09 139.7-88.06 185.5c-10.25 8.396-11.75 23.5-3.344 33.74C505.3 481 512.2 484 519.2 484c5.375 0 10.75-1.779 15.22-5.431C601.5 423.6 640 342.5 640 255.1S601.5 88.34 534.4 33.4z\" />\r\n </svg>\r\n <svg *ngIf=\"audio.muted\" id=\"icn-volume-mute\" viewBox=\"0 0 576 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M319.1 64v383.1c0 12.59-7.325 24-18.82 29.16c-4.203 1.906-8.737 2.844-13.17 2.844c-7.688 0-15.28-2.781-21.26-8.094l-134.9-119.9H48c-26.51 0-48-21.49-48-47.1v-95.1c0-26.51 21.49-47.1 48-47.1h83.84l134.9-119.9c9.422-8.375 22.94-10.44 34.44-5.253C312.7 40 319.1 51.41 319.1 64z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M560.1 303c9.375 9.375 9.375 24.56 0 33.94c-9.381 9.381-24.56 9.373-33.94 0L480 289.9l-47.03 47.03c-9.381 9.381-24.56 9.373-33.94 0c-9.375-9.375-9.375-24.56 0-33.94l47.03-47.03l-47.03-47.03c-9.375-9.375-9.375-24.56 0-33.94s24.56-9.375 33.94 0L480 222.1l47.03-47.03c9.375-9.375 24.56-9.375 33.94 0s9.375 24.56 0 33.94l-47.03 47.03L560.1 303z\" />\r\n </svg>\r\n </button>\r\n <input class=\"volume-slider\" id=\"volumeSlider\" type=\"range\" min=\"0\" max=\"1\" value=\"1\" step=\"0.01\"\r\n (input)=\"changeVolume($event)\">\r\n </div>\r\n <div class=\"speed-control\" *ngIf=\"showSpeed\">\r\n <button (click)=\"decreaseSpeed()\" title=\"descrease speed\">\r\n <svg viewBox=\"0 0 448 512\">\r\n <path\r\n d=\"M400 288h-352c-17.69 0-32-14.32-32-32.01s14.31-31.99 32-31.99h352c17.69 0 32 14.3 32 31.99S417.7 288 400 288z\" />\r\n </svg>\r\n </button>\r\n <span class=\"speed-display\" id=\"speedDisplay\">{{speedDisplay}}</span>\r\n <button (click)=\"increaseSpeed()\" title=\"increase speed\">\r\n <svg viewBox=\"0 0 448 512\">\r\n <path\r\n d=\"M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n <button *ngIf=\"showList\" (click)=\"togglePlayList=!togglePlayList\" title=\"Play list\"\r\n [class.is-active]=\"togglePlayList\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M471 1.323l-96.63 28.5C361.1 33.95 352 46.33 352 60.33v299.7c-15.5-5.251-31.62-8.001-48-8.001c-61.88 0-112 35.88-112 80.01S242.1 512 304 512s112-35.88 112-80.01V148.1l73-21.38C502.6 122.7 512 110.2 512 95.96V31.96c0-10.13-4.75-19.64-12.88-25.64C491.1 .323 480.6-1.552 471 1.323z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M31.97 255.1h224.1C273.7 255.1 288 241.7 288 224c0-17.66-14.32-32.02-31.97-32.02H31.97C14.32 191.1 0 206.3 0 223.1C0 241.6 14.32 255.1 31.97 255.1zM31.97 127.1h224.1C273.7 127.1 288 113.6 288 95.99c0-17.66-14.31-32.01-31.97-32.01H31.97C14.32 63.98 0 78.31 0 95.97C0 113.6 14.32 127.1 31.97 127.1zM128 319.1H31.97C14.32 319.1 0 334.3 0 351.1c0 17.66 14.32 32.02 31.97 32.02H128C145.7 383.1 160 369.7 160 352C160 334.4 145.7 319.1 128 319.1z\" />\r\n </svg>\r\n </button>\r\n <button *ngIf=\"download\" (click)=\"downloadCurrentFile()\" title=\"download\" [disabled]=\"downloading\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M105.4 246.6c-12.49-12.5-12.49-32.75 0-45.25c12.5-12.5 32.76-12.5 45.25 0L224 274.8V32c0-17.67 14.33-32 32-32c17.67 0 32 14.33 32 32v242.8l73.38-73.38c12.49-12.5 32.75-12.5 45.25 0c12.49 12.5 12.49 32.75 0 45.25l-128 128C272.4 380.9 264.2 384 256 384s-16.38-3.125-22.62-9.375L105.4 246.6z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M480 352h-133.5l-45.25 45.25C289.2 409.3 273.1 416 256 416s-33.16-6.656-45.25-18.75L165.5 352H32c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h448c17.67 0 32-14.33 32-32v-96C512 366.3 497.7 352 480 352zM432 456c-13.2 0-24-10.8-24-24c0-13.2 10.8-24 24-24s24 10.8 24 24C456 445.2 445.2 456 432 456z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n\r\n\r\n<!-- --------- play list -------------- -->\r\n<div class=\"play-list\" *ngIf=\"togglePlayList\" [class.linear]=\"linear\">\r\n <div class=\"list-item disabled\" *ngIf=\"audioFiles.length===0\">\r\n {{options.emptyListMessage}}\r\n </div>\r\n <div class=\"list-item\" *ngFor=\"let item of audioFiles;let i = index\" [class.active]=\"i==currentAudioIndex\"\r\n (click)=\"onClickPlayList(i)\">\r\n {{item.title}}\r\n </div>\r\n</div>", styles: ["::ng-deep ngx-audio-control{display:contents}.audio-player,.play-list{background-color:#fff;border-radius:10px;padding:10px;box-shadow:0 4px 6px #0000001a;position:relative;overflow:hidden;direction:ltr;max-width:100%}.audio-player:not(.linear),.play-list:not(.linear){width:420px}.audio-player.linear .controls,.play-list.linear .controls{display:flex;flex-wrap:wrap;flex-direction:row-reverse}.controls .time-seeker{display:flex;align-items:center;flex:1 0 0;min-width:200px}.controls .buttons{display:flex;align-items:center;flex-wrap:wrap}button{background-color:transparent;border:none;font-size:18px;padding:8px;width:32px;height:32px;border:1px #e5e5e5 solid;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:6px 2px}button svg{width:18px;height:18px;fill:#183153}button:not(:disabled){cursor:pointer}button:disabled{cursor:not-allowed;background-color:#e5e5e5}button.is-active{background-color:#007bff}button.is-active svg{fill:#fff}button:focus{outline:none}.seek-slider{-webkit-appearance:none;appearance:none;width:100%;height:5px;background-color:#ddd;outline:none;border-radius:5px;cursor:pointer}.seek-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:15px;height:15px;background-color:#007bff;border-radius:50%;cursor:pointer}.seek-slider::-moz-range-thumb{width:15px;height:15px;background-color:#007bff;border-radius:50%;cursor:pointer}.speed-control{display:flex;justify-content:space-between;align-items:center}.speed-display{width:30px;text-align:center;overflow:hidden;font-size:90%}.volume-control{display:flex;align-items:center;flex:auto;min-width:100px}.volume-slider{margin-left:10px;width:10px;flex:auto}.play-list{margin:3px 0}.play-list .list-item{border-bottom:1px rgba(172,172,172,.8) solid;padding:10px 15px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.play-list .list-item:hover:not(.disabled){cursor:pointer;background-color:#0000001a}.play-list .list-item.active{background-color:#007bff;color:#fff}.simp-buffer{animation:audio-progress 1s linear infinite;background-image:linear-gradient(-45deg,#000 25%,transparent 25%,transparent 50%,#000 50%,#000 75%,transparent 75%,transparent);background-repeat:repeat-x;background-size:25px 25px;color:transparent;width:100%;height:4px;position:absolute;bottom:0;left:0;right:0}@keyframes audio-progress{to{background-position:25px 0}}.file-info{overflow:hidden;text-overflow:ellipsis;width:100%;display:block}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlComponent, decorators: [{ type: Component, args: [{ selector: 'ngx-audio-control', template: "<div class=\"audio-player\" [class.linear]=\"linear\">\r\n <span class=\"file-info\" *ngIf=\"showFileName\">{{fineName}}</span>\r\n <audio [preload]=\"preload\" #audio>\r\n <source [src]=\"currentFileAddress\" />\r\n </audio>\r\n <div class=\"controls\">\r\n <div class=\"time-seeker\">\r\n <span> {{currentTime}}</span>\r\n <input class=\"seek-slider\" id=\"seekSlider\" type=\"range\" [min]=\"seekSlider.min\" [max]=\"seekSlider.max\"\r\n [value]=\"seekSlider.value\" step=\".1\" (input)=\"seekAudio($event)\">\r\n <span> {{totalTime}}</span>\r\n <div class=\"simp-buffer\" *ngIf=\"buffering\"></div>\r\n </div>\r\n <div class=\"buttons\">\r\n <button (click)=\"previous()\" title=\"previous\" *ngIf=\"audioFiles.length > 1\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M64 227.9l171.5-156.5C256.1 54.28 288 68.66 288 96.03v131.9l171.5-156.5C480.1 54.28 512 68.66 512 96.03v319.9c0 27.37-31.88 41.74-52.5 24.62L288 285.2v130.7c0 27.37-31.88 41.74-52.5 24.62L64 285.2V227.9z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M0 415.1V96.03c0-17.67 14.33-31.1 31.1-31.1C49.67 64.03 64 78.36 64 96.03v319.9c0 17.67-14.33 31.1-31.1 31.1C14.33 447.1 0 433.6 0 415.1z\" />\r\n </svg>\r\n </button>\r\n\r\n <button (click)=\"playPause()\" id=\"playPauseButton\"\r\n [title]=\"errorLoad?'Error on load audio source':(audio.paused?'play':'pause')\" [disabled]=\"errorLoad\">\r\n <svg *ngIf=\"audio.paused\" viewBox=\"0 0 384 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M361 215C375.3 223.8 384 239.3 384 256C384 272.7 375.3 288.2 361 296.1L73.03 472.1C58.21 482 39.66 482.4 24.52 473.9C9.377 465.4 0 449.4 0 432V80C0 62.64 9.377 46.63 24.52 38.13C39.66 29.64 58.21 29.99 73.03 39.04L361 215z\" />\r\n </svg>\r\n <svg *ngIf=\"!audio.paused\" viewBox=\"0 0 320 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M272 63.1c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48s48-21.49 48-48v-288C320 85.49 298.5 63.1 272 63.1zM48 63.1c-26.51 0-48 21.49-48 48v288C0 426.5 21.49 448 48 448S96 426.5 96 400v-288C96 85.49 74.51 63.1 48 63.1z\" />\r\n </svg>\r\n </button>\r\n\r\n <button (click)=\"next()\" title=\"next\" *ngIf=\"audioFiles.length > 1\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M448 284.1l-171.5 156.5C255.9 457.7 224 443.3 224 415.1V284.1l-171.5 156.5C31.88 457.7 0 443.3 0 415.1V96.03c0-27.37 31.88-41.74 52.5-24.62L224 226.8V96.03c0-27.37 31.88-41.74 52.5-24.62L448 226.8V284.1z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M512 96.03v319.9c0 17.67-14.33 31.1-31.1 31.1C462.3 447.1 448 433.6 448 415.1V96.03c0-17.67 14.33-31.1 31.1-31.1C497.7 64.03 512 78.36 512 96.03z\" />\r\n </svg>\r\n </button>\r\n <div class=\"volume-control\" *ngIf=\"showVolume\">\r\n <button (click)=\"muteUnmute()\" id=\"muteUnmuteButton\" title=\"mute volume\"\r\n [class.is-active]=\"audio.muted\">\r\n <svg *ngIf=\"!audio.muted\" viewBox=\"0 0 640 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M320 64.12v383.7c0 12.58-7.337 23.99-18.84 29.14C296.1 478.9 292.4 479.8 288 479.8c-7.688 0-15.28-2.822-21.27-8.128l-134.9-119.8H48c-26.51 0-48-21.48-48-47.96V208C0 181.6 21.49 160.1 48 160.1h83.84l134.9-119.8c9.422-8.365 22.93-10.47 34.43-5.29C312.7 40.13 320 51.55 320 64.12z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M473.1 108.2c-10.22-8.334-25.34-6.898-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C476.6 172.1 496 213.3 496 255.1s-19.44 82.1-53.31 110.7c-10.25 8.396-11.75 23.5-3.344 33.74c4.75 5.775 11.62 8.771 18.56 8.771c5.375 0 10.75-1.779 15.22-5.431C518.2 366.9 544 313 544 255.1S518.2 145 473.1 108.2zM412.6 182c-10.28-8.334-25.41-6.867-33.75 3.402c-8.406 10.24-6.906 25.35 3.375 33.74C393.5 228.4 400 241.8 400 255.1c0 14.17-6.5 27.59-17.81 36.83c-10.28 8.396-11.78 23.5-3.375 33.74c4.719 5.806 11.62 8.802 18.56 8.802c5.344 0 10.75-1.779 15.19-5.399C435.1 311.5 448 284.6 448 255.1S435.1 200.4 412.6 182zM534.4 33.4c-10.22-8.334-25.34-6.867-33.78 3.34c-8.406 10.24-6.906 25.35 3.344 33.74C559.9 116.3 592 183.9 592 255.1s-32.09 139.7-88.06 185.5c-10.25 8.396-11.75 23.5-3.344 33.74C505.3 481 512.2 484 519.2 484c5.375 0 10.75-1.779 15.22-5.431C601.5 423.6 640 342.5 640 255.1S601.5 88.34 534.4 33.4z\" />\r\n </svg>\r\n <svg *ngIf=\"audio.muted\" id=\"icn-volume-mute\" viewBox=\"0 0 576 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M319.1 64v383.1c0 12.59-7.325 24-18.82 29.16c-4.203 1.906-8.737 2.844-13.17 2.844c-7.688 0-15.28-2.781-21.26-8.094l-134.9-119.9H48c-26.51 0-48-21.49-48-47.1v-95.1c0-26.51 21.49-47.1 48-47.1h83.84l134.9-119.9c9.422-8.375 22.94-10.44 34.44-5.253C312.7 40 319.1 51.41 319.1 64z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M560.1 303c9.375 9.375 9.375 24.56 0 33.94c-9.381 9.381-24.56 9.373-33.94 0L480 289.9l-47.03 47.03c-9.381 9.381-24.56 9.373-33.94 0c-9.375-9.375-9.375-24.56 0-33.94l47.03-47.03l-47.03-47.03c-9.375-9.375-9.375-24.56 0-33.94s24.56-9.375 33.94 0L480 222.1l47.03-47.03c9.375-9.375 24.56-9.375 33.94 0s9.375 24.56 0 33.94l-47.03 47.03L560.1 303z\" />\r\n </svg>\r\n </button>\r\n <input class=\"volume-slider\" id=\"volumeSlider\" type=\"range\" min=\"0\" max=\"1\" value=\"1\" step=\"0.01\"\r\n (input)=\"changeVolume($event)\">\r\n </div>\r\n <div class=\"speed-control\" *ngIf=\"showSpeed\">\r\n <button (click)=\"decreaseSpeed()\" title=\"descrease speed\">\r\n <svg viewBox=\"0 0 448 512\">\r\n <path\r\n d=\"M400 288h-352c-17.69 0-32-14.32-32-32.01s14.31-31.99 32-31.99h352c17.69 0 32 14.3 32 31.99S417.7 288 400 288z\" />\r\n </svg>\r\n </button>\r\n <span class=\"speed-display\" id=\"speedDisplay\">{{speedDisplay}}</span>\r\n <button (click)=\"increaseSpeed()\" title=\"increase speed\">\r\n <svg viewBox=\"0 0 448 512\">\r\n <path\r\n d=\"M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n <button *ngIf=\"showList\" (click)=\"togglePlayList=!togglePlayList\" title=\"Play list\"\r\n [class.is-active]=\"togglePlayList\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M471 1.323l-96.63 28.5C361.1 33.95 352 46.33 352 60.33v299.7c-15.5-5.251-31.62-8.001-48-8.001c-61.88 0-112 35.88-112 80.01S242.1 512 304 512s112-35.88 112-80.01V148.1l73-21.38C502.6 122.7 512 110.2 512 95.96V31.96c0-10.13-4.75-19.64-12.88-25.64C491.1 .323 480.6-1.552 471 1.323z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M31.97 255.1h224.1C273.7 255.1 288 241.7 288 224c0-17.66-14.32-32.02-31.97-32.02H31.97C14.32 191.1 0 206.3 0 223.1C0 241.6 14.32 255.1 31.97 255.1zM31.97 127.1h224.1C273.7 127.1 288 113.6 288 95.99c0-17.66-14.31-32.01-31.97-32.01H31.97C14.32 63.98 0 78.31 0 95.97C0 113.6 14.32 127.1 31.97 127.1zM128 319.1H31.97C14.32 319.1 0 334.3 0 351.1c0 17.66 14.32 32.02 31.97 32.02H128C145.7 383.1 160 369.7 160 352C160 334.4 145.7 319.1 128 319.1z\" />\r\n </svg>\r\n </button>\r\n <button *ngIf=\"download\" (click)=\"downloadCurrentFile()\" title=\"download\" [disabled]=\"downloading\">\r\n <svg viewBox=\"0 0 512 512\">\r\n <defs>\r\n <style>\r\n .fa-secondary {\r\n opacity: .4\r\n }\r\n </style>\r\n </defs>\r\n <path class=\"fa-primary\"\r\n d=\"M105.4 246.6c-12.49-12.5-12.49-32.75 0-45.25c12.5-12.5 32.76-12.5 45.25 0L224 274.8V32c0-17.67 14.33-32 32-32c17.67 0 32 14.33 32 32v242.8l73.38-73.38c12.49-12.5 32.75-12.5 45.25 0c12.49 12.5 12.49 32.75 0 45.25l-128 128C272.4 380.9 264.2 384 256 384s-16.38-3.125-22.62-9.375L105.4 246.6z\" />\r\n <path class=\"fa-secondary\"\r\n d=\"M480 352h-133.5l-45.25 45.25C289.2 409.3 273.1 416 256 416s-33.16-6.656-45.25-18.75L165.5 352H32c-17.67 0-32 14.33-32 32v96c0 17.67 14.33 32 32 32h448c17.67 0 32-14.33 32-32v-96C512 366.3 497.7 352 480 352zM432 456c-13.2 0-24-10.8-24-24c0-13.2 10.8-24 24-24s24 10.8 24 24C456 445.2 445.2 456 432 456z\" />\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n\r\n\r\n<!-- --------- play list -------------- -->\r\n<div class=\"play-list\" *ngIf=\"togglePlayList\" [class.linear]=\"linear\">\r\n <div class=\"list-item disabled\" *ngIf=\"audioFiles.length===0\">\r\n {{options.emptyListMessage}}\r\n </div>\r\n <div class=\"list-item\" *ngFor=\"let item of audioFiles;let i = index\" [class.active]=\"i==currentAudioIndex\"\r\n (click)=\"onClickPlayList(i)\">\r\n {{item.title}}\r\n </div>\r\n</div>", styles: ["::ng-deep ngx-audio-control{display:contents}.audio-player,.play-list{background-color:#fff;border-radius:10px;padding:10px;box-shadow:0 4px 6px #0000001a;position:relative;overflow:hidden;direction:ltr;max-width:100%}.audio-player:not(.linear),.play-list:not(.linear){width:420px}.audio-player.linear .controls,.play-list.linear .controls{display:flex;flex-wrap:wrap;flex-direction:row-reverse}.controls .time-seeker{display:flex;align-items:center;flex:1 0 0;min-width:200px}.controls .buttons{display:flex;align-items:center;flex-wrap:wrap}button{background-color:transparent;border:none;font-size:18px;padding:8px;width:32px;height:32px;border:1px #e5e5e5 solid;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:6px 2px}button svg{width:18px;height:18px;fill:#183153}button:not(:disabled){cursor:pointer}button:disabled{cursor:not-allowed;background-color:#e5e5e5}button.is-active{background-color:#007bff}button.is-active svg{fill:#fff}button:focus{outline:none}.seek-slider{-webkit-appearance:none;appearance:none;width:100%;height:5px;background-color:#ddd;outline:none;border-radius:5px;cursor:pointer}.seek-slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:15px;height:15px;background-color:#007bff;border-radius:50%;cursor:pointer}.seek-slider::-moz-range-thumb{width:15px;height:15px;background-color:#007bff;border-radius:50%;cursor:pointer}.speed-control{display:flex;justify-content:space-between;align-items:center}.speed-display{width:30px;text-align:center;overflow:hidden;font-size:90%}.volume-control{display:flex;align-items:center;flex:auto;min-width:100px}.volume-slider{margin-left:10px;width:10px;flex:auto}.play-list{margin:3px 0}.play-list .list-item{border-bottom:1px rgba(172,172,172,.8) solid;padding:10px 15px;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.play-list .list-item:hover:not(.disabled){cursor:pointer;background-color:#0000001a}.play-list .list-item.active{background-color:#007bff;color:#fff}.simp-buffer{animation:audio-progress 1s linear infinite;background-image:linear-gradient(-45deg,#000 25%,transparent 25%,transparent 50%,#000 50%,#000 75%,transparent 75%,transparent);background-repeat:repeat-x;background-size:25px 25px;color:transparent;width:100%;height:4px;position:absolute;bottom:0;left:0;right:0}@keyframes audio-progress{to{background-position:25px 0}}.file-info{overflow:hidden;text-overflow:ellipsis;width:100%;display:block}\n"] }] }], ctorParameters: function () { return []; }, propDecorators: { showList: [{ type: Input }], download: [{ type: Input }], showFileName: [{ type: Input }], showSpeed: [{ type: Input }], showVolume: [{ type: Input }], linear: [{ type: Input }], preload: [{ type: Input }], fetchHeaders: [{ type: Input }], fileList: [{ type: Input }], audio: [{ type: ViewChild, args: ['audio', { static: true }] }] } }); class NgxAudioControlModule { } NgxAudioControlModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); NgxAudioControlModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlModule, declarations: [NgxAudioControlComponent], imports: [CommonModule], exports: [NgxAudioControlComponent] }); NgxAudioControlModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlModule, providers: [ NgxAudioControlService ], imports: [CommonModule] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NgxAudioControlModule, decorators: [{ type: NgModule, args: [{ declarations: [ NgxAudioControlComponent ], imports: [ CommonModule, ], exports: [ NgxAudioControlComponent ], providers: [ NgxAudioControlService ] }] }] }); class PlayList { } /* * Public API Surface of ngx-audio-control */ /** * Generated bundle index. Do not edit. */ export { NgxAudioControlComponent, NgxAudioControlModule, NgxAudioControlService, PlayList, formatTime }; //# sourceMappingURL=ngx-audio-control.mjs.map