From b7e16347d97529dd8b867e7707ae6336210c0fe2 Mon Sep 17 00:00:00 2001 From: whyboris Date: Fri, 18 Dec 2020 01:00:31 -0500 Subject: [PATCH] Thank you to @cal2195 for video code --- package-lock.json | 196 ++++++++++++++++++++++++++++++++++++- package.json | 2 +- src/app/animations.ts | 4 +- src/app/app.component.html | 60 +++++++++++- src/app/app.component.scss | 41 +++++++- src/app/app.component.ts | 81 ++++++++++++++- src/app/app.module.ts | 9 +- src/app/duration.pipe.ts | 37 +++++++ 8 files changed, 415 insertions(+), 15 deletions(-) create mode 100644 src/app/duration.pipe.ts diff --git a/package-lock.json b/package-lock.json index bfa3171..2d18064 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1422,7 +1422,6 @@ "version": "7.12.1", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.1.tgz", "integrity": "sha512-J5AIf3vPj3UwXaAzb5j1xM4WAQDX3EMgemF8rjCP3SoW09LfRKAXQKt6CoVYl230P6iWdRcBbnLDDdnqWxZSCA==", - "dev": true, "requires": { "regenerator-runtime": "^0.13.4" } @@ -1660,6 +1659,52 @@ } } }, + "@videojs/http-streaming": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-2.2.4.tgz", + "integrity": "sha512-gzT46RpAEegOhMId/zZ6uXCVGDMPOv8qmoTykBuvd6/4lVM3lZ1ZJCq0kytAkisDuDKipy93gP46oZEtonlc/Q==", + "requires": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "aes-decrypter": "3.1.0", + "global": "^4.3.2", + "m3u8-parser": "4.5.0", + "mpd-parser": "0.14.0", + "mux.js": "5.6.7", + "video.js": "^6 || ^7" + } + }, + "@videojs/vhs-utils": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@videojs/vhs-utils/-/vhs-utils-2.3.0.tgz", + "integrity": "sha512-ThSmm91S7tuIJ757ON50K4y7S/bvKN4+B0tu303gCOxaG57PoP1UvPfMQZ90XGhxwNgngexVojOqbBHhTvXVHQ==", + "requires": { + "@babel/runtime": "^7.5.5", + "global": "^4.3.2", + "url-toolkit": "^2.1.6" + } + }, + "@videojs/xhr": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/@videojs/xhr/-/xhr-2.5.1.tgz", + "integrity": "sha512-wV9nGESHseSK+S9ePEru2+OJZ1jq/ZbbzniGQ4weAmTIepuBMSYPx5zrxxQA0E786T5ykpO8ts+LayV+3/oI2w==", + "requires": { + "@babel/runtime": "^7.5.5", + "global": "~4.4.0", + "is-function": "^1.0.1" + }, + "dependencies": { + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + } + } + }, "@webassemblyjs/ast": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz", @@ -1895,6 +1940,17 @@ "regex-parser": "^2.2.11" } }, + "aes-decrypter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aes-decrypter/-/aes-decrypter-3.1.0.tgz", + "integrity": "sha512-wL1NFwP2yNrJG4InpXYFhhYe9TfonnDyhyxMq2+K9/qt+SrZzUieOpviN6pkDly7GawTqw5feehk0rn5iYo00g==", + "requires": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "global": "^4.3.2", + "pkcs7": "^1.0.4" + } + }, "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", @@ -3994,6 +4050,11 @@ } } }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -5012,6 +5073,22 @@ "is-glob": "^4.0.1" } }, + "global": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/global/-/global-4.3.2.tgz", + "integrity": "sha1-52mJJopsdMOJCLEwWxD8DjlOnQ8=", + "requires": { + "min-document": "^2.19.0", + "process": "~0.5.1" + }, + "dependencies": { + "process": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/process/-/process-0.5.2.tgz", + "integrity": "sha1-FjjYqONML0QKkduVq5rrZ3/Bhc8=" + } + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -5560,6 +5637,11 @@ "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=", "dev": true }, + "individual": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/individual/-/individual-2.0.0.tgz", + "integrity": "sha1-gzsJfa0jKU52EXqY+zjg2a1hu5c=" + }, "infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", @@ -5848,6 +5930,11 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true }, + "is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, "is-glob": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", @@ -6167,6 +6254,11 @@ "source-map-support": "^0.5.5" } }, + "keycode": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.0.tgz", + "integrity": "sha1-PQr1bce4uOXLqNCpfxByBO7CKwQ=" + }, "killable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/killable/-/killable-1.0.1.tgz", @@ -6394,6 +6486,16 @@ "yallist": "^4.0.0" } }, + "m3u8-parser": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.5.0.tgz", + "integrity": "sha512-RGm/1WVCX3o1bSWbJGmJUu4zTbtJy8lImtgHM4CESFvJRXYztr1j6SW/q9/ghYOrUjgH7radsIar+z1Leln0sA==", + "requires": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "global": "^4.3.2" + } + }, "magic-string": { "version": "0.25.7", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz", @@ -6654,6 +6756,14 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "requires": { + "dom-walk": "^0.1.0" + } + }, "mini-css-extract-plugin": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.2.1.tgz", @@ -6840,6 +6950,17 @@ } } }, + "mpd-parser": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/mpd-parser/-/mpd-parser-0.14.0.tgz", + "integrity": "sha512-HqXQS3WLofcnYFcxv5oWdlciddUaEnN3NasXLVQ793mdnZRrinjz2Yk1DsUYPDYOUWf6ZBBqbFhaJT5LiT2ouA==", + "requires": { + "@babel/runtime": "^7.5.5", + "@videojs/vhs-utils": "^2.2.1", + "global": "^4.3.2", + "xmldom": "^0.1.27" + } + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -6868,6 +6989,11 @@ "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", "dev": true }, + "mux.js": { + "version": "5.6.7", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.6.7.tgz", + "integrity": "sha512-YSr6B8MUgE4S18MptbY2XM+JKGbw9JDkgs7YkuE/T2fpDKjOhZfb/nD6vmsVxvLYOExWNaQn1UGBp6PGsnTtew==" + }, "nan": { "version": "2.14.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", @@ -7893,6 +8019,14 @@ "pinkie": "^2.0.0" } }, + "pkcs7": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/pkcs7/-/pkcs7-1.0.4.tgz", + "integrity": "sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==", + "requires": { + "@babel/runtime": "^7.5.5" + } + }, "pkg-dir": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", @@ -8579,8 +8713,7 @@ "process": { "version": "0.11.10", "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", - "dev": true + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" }, "process-nextick-args": { "version": "2.0.1", @@ -8867,8 +9000,7 @@ "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "regenerator-transform": { "version": "0.14.5", @@ -9257,6 +9389,14 @@ "aproba": "^1.1.1" } }, + "rust-result": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz", + "integrity": "sha1-NMdbLm3Dn+WHXlveyFteD5FTb3I=", + "requires": { + "individual": "^2.0.0" + } + }, "rxjs": { "version": "6.6.3", "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", @@ -9278,6 +9418,14 @@ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "dev": true }, + "safe-json-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-4.0.0.tgz", + "integrity": "sha1-fA9XjPzNEtM6ccDgVBPi7KFx6qw=", + "requires": { + "rust-result": "^1.0.0" + } + }, "safe-regex": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", @@ -10877,6 +11025,11 @@ "requires-port": "^1.0.0" } }, + "url-toolkit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.1.tgz", + "integrity": "sha512-8+DzgrtDZYZGhHaAop5WGVghMdCfOLGbhcArsJD0qDll71FXa7EeKxi2hilPIscn2nwMz4PRjML32Sz4JTN0Xw==" + }, "use": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", @@ -10993,6 +11146,34 @@ "extsprintf": "^1.2.0" } }, + "video.js": { + "version": "7.10.2", + "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.10.2.tgz", + "integrity": "sha512-kJTTrqcQn2MhPzWR8zQs6W3HPJWpowO/ZGZcKt2dcJeJdJT0dEDLYtiFdjV37SylCmu66V0flRnV8cipbthveQ==", + "requires": { + "@babel/runtime": "^7.9.2", + "@videojs/http-streaming": "2.2.4", + "@videojs/xhr": "2.5.1", + "global": "4.3.2", + "keycode": "^2.2.0", + "safe-json-parse": "4.0.0", + "videojs-font": "3.2.0", + "videojs-vtt.js": "^0.15.2" + } + }, + "videojs-font": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/videojs-font/-/videojs-font-3.2.0.tgz", + "integrity": "sha512-g8vHMKK2/JGorSfqAZQUmYYNnXmfec4MLhwtEFS+mMs2IDY398GLysy6BH6K+aS1KMNu/xWZ8Sue/X/mdQPliA==" + }, + "videojs-vtt.js": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/videojs-vtt.js/-/videojs-vtt.js-0.15.2.tgz", + "integrity": "sha512-kEo4hNMvu+6KhPvVYPKwESruwhHC3oFis133LwhXHO9U7nRnx0RiJYMiqbgwjgazDEXHR6t8oGJiHM6wq5XlAw==", + "requires": { + "global": "^4.3.1" + } + }, "vm-browserify": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", @@ -12121,6 +12302,11 @@ "async-limiter": "~1.0.0" } }, + "xmldom": { + "version": "0.1.31", + "resolved": "https://registry.npmjs.org/xmldom/-/xmldom-0.1.31.tgz", + "integrity": "sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/package.json b/package.json index e20d378..aa4f772 100644 --- a/package.json +++ b/package.json @@ -10,11 +10,11 @@ "private": true, "dependencies": { "@angular/animations": "11.0.4", + "@angular/cdk": "11.0.3", "@angular/common": "11.0.4", "@angular/compiler": "11.0.4", "@angular/core": "11.0.4", "@angular/forms": "11.0.4", - "@angular/cdk": "11.0.3", "@angular/platform-browser": "11.0.4", "@angular/platform-browser-dynamic": "11.0.4", "@angular/router": "11.0.4", diff --git a/src/app/animations.ts b/src/app/animations.ts index 8b1941f..dd42f3c 100644 --- a/src/app/animations.ts +++ b/src/app/animations.ts @@ -18,14 +18,14 @@ export const searchAnimation = trigger('searchAnimation', [ export const settingsAnimation = trigger('settingsAnimation', [ transition( ':enter', [ - style({ transform: 'translate(0, 300px)' }), + style({ transform: 'translate(0, 333px)' }), animate('300ms ease', style({ transform: 'translate(0, 0)' })) ] ), transition( ':leave', [ style({ transform: 'translate(0, 0)' }), - animate('300ms ease', style({ transform: 'translate(0, 300px)' })) + animate('300ms ease', style({ transform: 'translate(0, 333px)' })) ] )] ); diff --git a/src/app/app.component.html b/src/app/app.component.html index 8ec18ee..686f6ea 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -127,12 +127,22 @@

Settings

+ + Larger text
+
+ + + Play on device + +
+
Welcome to Video Hub App Remote

Afterwards, you can close this and open the app from your home screen!

+ +
+ + + +
+ + + + + + + {{this.currentTime | durationPipe }} / {{this.duration | durationPipe}} + + + + + + + + +
+ +
diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 45a74ed..4f1e099 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -1,5 +1,5 @@ $menu-height: 50px; -$settings-height: 300px; // also update `settingsAnimation` +$settings-height: 333px; // also update `settingsAnimation` .buttons-menu { background-color: #f9f9f9; @@ -271,3 +271,42 @@ app-thumbnail { top: 10px; } } + +.video-player-container { + background-color: #f9f9f9; + border-bottom: 1px solid #bbbbbb; + box-shadow: 0 10px 20px rgba(0, 0, 0, 0.25); + box-sizing: border-box; + height: 65vw; + left: 0; + padding: 20px; + position: fixed; + top: 0; + width: 100vw; + + button { + margin: 0; + padding-top: 7px; + } + + .time { + font-family: monospace; + font-size: 12px; + padding: 12px 6px; + } + + .video-player { + height: 90%; + width: 100%; + } + + .video-controls { + display: flex; + justify-content: space-between; + } + + .seek-bar { + flex-grow: 2; + margin: 0 10px; + } +} diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 32702cb..74de329 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, OnInit, ViewChild } from '@angular/core'; import { Platform } from '@angular/cdk/platform'; import { VirtualScrollerComponent } from 'ngx-virtual-scroller'; @@ -12,6 +12,7 @@ interface RemoteSettings { darkMode: boolean; imgsPerRow: number; largerText: boolean; + playOnDevice: boolean; } type SocketMessageType = 'gallery' | 'settings'; @@ -36,6 +37,7 @@ export class AppComponent implements OnInit { darkMode: false, imgsPerRow: 2, largerText: true, + playOnDevice: true, } // variables @@ -60,7 +62,7 @@ export class AppComponent implements OnInit { ngOnInit() { this.setUpSocket(); this.computePreviewWidth(); - this.showInstallInstructions(); + // this.showInstallInstructions(); } /** @@ -186,6 +188,16 @@ export class AppComponent implements OnInit { } } + /** + * Toggle if video plays on device or on PC + */ + toggleVideoPlay(): void { + this.settings.playOnDevice = !this.settings.playOnDevice; + if (!this.showSearch) { + this.searchString = ''; + } + } + /** * Request from server the current gallery view * or refresh if not connected @@ -268,4 +280,69 @@ export class AppComponent implements OnInit { this.socketConnected = false; } + // Video playback + // most of the code comes from Cal2195 + // Thank you Cal2195 + + @ViewChild('muteButton', { static: false }) muteButton: any; + @ViewChild('playButton', { static: false }) playButton: any; + @ViewChild('seekBar', { static: false }) seekBar: any; + @ViewChild('videoplayer', { static: false }) videoplayer: any; + @ViewChild('volumeBar', { static: false }) volumeBar: any; + + currentTime: number = 0; + httpfile: string; + isMuted: boolean = false; + isPlaying: boolean = false; + seek: number = 0; + + duration = 30; + httpFile: string = "http://192.168.1.5:3000/video?file=C:\\temp\\stream.mp4"; + tempVidPath: string = 'C:\\temp\\stream.mp4'; + + playPauseVideo() { + if (!this.videoplayer.nativeElement.paused) { + this.isPlaying = false; + this.videoplayer.nativeElement.pause(); + } else { + this.isPlaying = true; + this.videoplayer.nativeElement.play(); + } + } + + muteUnmuteVideo() { + if (this.videoplayer.nativeElement.muted === false) { + this.isMuted = true; + this.videoplayer.nativeElement.muted = true; + } else { + this.isMuted = false; + this.videoplayer.nativeElement.muted = false; + } + } + + fullscreenVideo() { + this.videoplayer.nativeElement.requestFullscreen(); + } + + seekBarChange() { + this.seek = parseFloat(this.seekBar.nativeElement.value); + this.seekVideo(!this.videoplayer.nativeElement.paused); + } + + seekBarUpdate() { + this.currentTime = parseFloat(this.videoplayer.nativeElement.currentTime) + this.seek; + this.seekBar.nativeElement.value = this.currentTime; + } + + seekVideo(play = false) { + this.httpFile = 'http://192.168.1.5:3000/video?file=' + this.tempVidPath + '&seek=' + this.seek; + if (this.videoplayer) { + this.videoplayer.nativeElement.autoplay = play; + } + } + + volumeChange() { + this.videoplayer.nativeElement.volume = this.volumeBar.nativeElement.value; + } + } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 2d1f1d7..81f47b8 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,7 +1,8 @@ +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; -import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { NgModule } from '@angular/core'; +import { ServiceWorkerModule } from '@angular/service-worker'; import { VirtualScrollerModule } from 'ngx-virtual-scroller'; @@ -10,13 +11,15 @@ import { FilePathService } from './file-path.service'; import { AppComponent } from './app.component'; import { ThumbnailComponent } from './thumb/thumbnail.component'; +import { DurationPipe } from './duration.pipe'; import { SearchPipe } from './search.pipe'; -import { ServiceWorkerModule } from '@angular/service-worker'; + import { environment } from '../environments/environment'; @NgModule({ declarations: [ AppComponent, + DurationPipe, SearchPipe, ThumbnailComponent, ], diff --git a/src/app/duration.pipe.ts b/src/app/duration.pipe.ts new file mode 100644 index 0000000..5ba95a7 --- /dev/null +++ b/src/app/duration.pipe.ts @@ -0,0 +1,37 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'durationPipe' +}) +export class DurationPipe implements PipeTransform { + + /** + * Return length of video file formatted as X:XX:XX + * or if `omitSeconds` then `Xhr XXmin` + * @param numOfSec + * @param destination -- dictates the output format (TimeFormat) + */ + transform( + numOfSec: number + ): string { + + if (numOfSec === undefined) { + // short circuit + return ''; + } + + const h: string = (Math.floor(numOfSec / 3600)).toString(); + const m: string = (Math.floor(numOfSec / 60) % 60).toString(); + const s: string = (Math.floor(numOfSec) % 60).toString(); + + // file should behave thus: + // 0:00, 0:01 ... 0:59, 1:00, 1:01 ... 59:59, 1:00:00 ... 3:14:15 ... + if (h !== '0') { + return h + ':' + m.padStart(2, '0') + ':' + s.padStart(2, '0'); + } else { + return m.padStart(2, '0') + ':' + s.padStart(2, '0'); + } + + } + +}