From 2b8c527fdf5b584c27df5b5d958e65191ece2d19 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 11 Oct 2020 01:47:57 +0200 Subject: [PATCH] Starting to clean up the player --- src/app/app.component.ts | 5 +- src/app/pages/player/player.component.html | 75 +++++-- src/app/pages/player/player.component.scss | 39 +++- src/app/pages/player/player.component.ts | 229 +++++++++------------ 4 files changed, 188 insertions(+), 160 deletions(-) diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 5530ff6c..3c8f5014 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -18,6 +18,8 @@ export class AppComponent libraries: Library[]; isLoading: boolean = false; + static isMobile: boolean = false; + constructor(private libraryService: LibraryService, private router: Router, private location: Location, @@ -47,7 +49,8 @@ export class AppComponent } }); - if (!navigator.userAgent.match(/Mobi/)) + AppComponent.isMobile = !!navigator.userAgent.match(/Mobi/); + if (!AppComponent.isMobile) document.body.classList.add("hoverEnabled"); } diff --git a/src/app/pages/player/player.component.html b/src/app/pages/player/player.component.html index 6110ec85..3419ebc7 100644 --- a/src/app/pages/player/player.component.html +++ b/src/app/pages/player/player.component.html @@ -1,6 +1,14 @@
-
@@ -8,25 +16,41 @@
- - -

Stats

+ + +

Stats

-
- Play method: {{this.playMethod}} + Play method: {{this.playMethod}}

- Video Container: {{this.item.container}} {{getSupportedFeature("container")}} + Video Container: + + {{this.item.container}} + {{getSupportedFeature("container")}} +
- Video Codec: {{this.item.video.codec}} {{getSupportedFeature("video")}} + Video Codec: + + {{this.item.video.codec}} + {{getSupportedFeature("video")}} +
- Audio Codec: {{this.item.audios[0].codec}} {{getSupportedFeature("audio")}} + Audio Codec: + + {{this.item.audios[0].codec}} + {{getSupportedFeature("audio")}} +
- Subtitle Codec: {{this.selectedSubtitle ? this.selectedSubtitle.codec : "none"}} {{getSupportedFeature("subtitle")}} + Subtitle Codec: + + {{this.selectedSubtitle ? this.selectedSubtitle.codec : "none"}} + {{getSupportedFeature("subtitle")}} +
@@ -60,8 +84,10 @@ skip_previous - skip_next @@ -76,13 +102,15 @@ -
- - +
+

{{this.hours | number: '2.0-0'}}:{{this.minutes | number: '2.0-0'}}:{{this.seconds | number: '2.0-0'}} / {{this.maxHours | number: '2.0-0'}}:{{this.maxMinutes | number: '2.0-0'}}:{{this.maxSeconds | number: '2.0-0'}}

{{this.minutes | number: '2.0-0'}}:{{this.seconds | number: '2.0-0'}} / {{this.maxMinutes | number: '2.0-0'}}:{{this.maxSeconds | number: '2.0-0'}}

@@ -90,7 +118,8 @@ - - @@ -113,7 +145,10 @@
- diff --git a/src/app/pages/player/player.component.scss b/src/app/pages/player/player.component.scss index 6808ef76..dbd6d9ca 100644 --- a/src/app/pages/player/player.component.scss +++ b/src/app/pages/player/player.component.scss @@ -51,8 +51,7 @@ > h5 { - margin: 0; - margin-left: .5rem; + margin: 0 0 0 .5rem; align-self: center; } } @@ -104,8 +103,7 @@ > p { - margin: 0; - margin-left: 1rem; + margin: 0 0 0 1rem; align-self: center; } } @@ -288,8 +286,8 @@ > mat-slider { - width: 0px; - min-width: 0px; + width: 0; + min-width: 0; padding: 0; height: 40px; overflow: hidden; @@ -331,7 +329,7 @@ .volume { - min-width: 0px !important; + min-width: 0 !important; } .info-panel @@ -339,3 +337,30 @@ min-width: 250px !important; max-width: 300px !important; } + +.stats +{ + > mat-card-header + { + margin-bottom: 0.5rem; + + > h4 + { + align-self: center; + margin-bottom: 0; + } + > button + { + outline: none; + } + } + > mat-card-content > span + { + float: right; + > i + { + vertical-align: middle; + font-size: 14px; + } + } +} diff --git a/src/app/pages/player/player.component.ts b/src/app/pages/player/player.component.ts index ec1c0dbf..a693eae5 100644 --- a/src/app/pages/player/player.component.ts +++ b/src/app/pages/player/player.component.ts @@ -1,26 +1,34 @@ -import {Component, Injector, OnInit, ViewEncapsulation} from '@angular/core'; -import {MatSnackBar} from "@angular/material/snack-bar"; -import {DomSanitizer, Title} from "@angular/platform-browser"; -import {ActivatedRoute, Event, NavigationCancel, NavigationEnd, NavigationStart, Router} from "@angular/router"; -import {Track, WatchItem} from "../../models/watch-item"; -import {Location} from "@angular/common"; +import { Component, Injector, OnInit, ViewEncapsulation } from "@angular/core"; +import { MatSnackBar } from "@angular/material/snack-bar"; +import { DomSanitizer, Title } from "@angular/platform-browser"; +import { ActivatedRoute, Event, NavigationCancel, NavigationEnd, NavigationStart, Router } from "@angular/router"; +import { AppComponent } from "../../app.component"; +import { Track, WatchItem } from "../../models/watch-item"; +import { Location } from "@angular/common"; +import { getPlaybackMethod, getWhatIsSupported, method, SupportList } from "../../../videoSupport/playbackMethodDetector"; +import { OidcSecurityService } from "angular-auth-oidc-client"; import * as Hls from "hls.js" -import {getPlaybackMethod, getWhatIsSupported, method, SupportList} from "../../../videoSupport/playbackMethodDetector"; -import {OidcSecurityService} from "angular-auth-oidc-client"; declare var SubtitleManager: any; @Component({ - selector: 'app-player', - templateUrl: './player.component.html', - styleUrls: ['./player.component.scss'], + selector: "app-player", + templateUrl: "./player.component.html", + styleUrls: ["./player.component.scss"], encapsulation: ViewEncapsulation.None }) export class PlayerComponent implements OnInit { item: WatchItem; + playing: boolean = true; + muted: boolean = false; + + private _volume: number = 100; + get volume(): number { return this._volume; } + set volume(value: number) { this._volume = Math.max(0, Math.min(value, 100)); } + + - volume: number = 100; seeking: boolean = false; videoHider; controllerHovered: boolean = false; @@ -34,13 +42,6 @@ export class PlayerComponent implements OnInit maxMinutes: number; maxSeconds: number; - playIcon: string = "pause"; //Icon used by the play btn. - volumeIcon: string = "volume_up"; //Icon used by the volume btn. - fullscreenIcon: string = "fullscreen"; //Icon used by the fullscreen btn. - - playTooltip: string = "Pause"; //Text used in the play tooltip - fullscreenTooltip: string = "Fullscreen"; //Text used in the fullscreen tooltip - playMethod: method = method.direct; methodType = method; @@ -56,7 +57,14 @@ export class PlayerComponent implements OnInit private oidcSecurity: OidcSecurityService; - constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer, private snackBar: MatSnackBar, private title: Title, private router: Router, private location: Location, private injector: Injector) { } + constructor(private route: ActivatedRoute, + private sanitizer: DomSanitizer, + private snackBar: MatSnackBar, + private title: Title, + private router: Router, + private location: Location, + private injector: Injector) + { } ngOnInit() { @@ -64,27 +72,21 @@ export class PlayerComponent implements OnInit this.route.data.subscribe((data) => { this.item = data.item; - this.item.duration = 20 * 60; if (this.player) - { this.player.load(); - this.initPlayBtn(); - } this.setDuration(this.item.duration); if (this.item.isMovie) - this.title.setTitle(this.item.showTitle + " - Kyoo"); + this.title.setTitle(`${this.item.showTitle} - Kyoo`); else - this.title.setTitle(this.item.showTitle + " S" + this.item.seasonNumber + ":E" + this.item.episodeNumber + " - Kyoo"); + this.title.setTitle(`${this.item.showTitle} S${this.item.seasonNumber}:E${this.item.episodeNumber} - Kyoo`); - if (navigator.userAgent.match(/Mobi/) && document.fullscreenElement == null) + if (AppComponent.isMobile && !this.isFullScreen) { this.fullscreen(); screen.orientation.lock("landscape"); - $("#fullscreen").addClass("d-none"); - $("#volume").addClass("d-none"); } setTimeout(() => { @@ -94,24 +96,22 @@ export class PlayerComponent implements OnInit }); } + get isFullScreen(): boolean + { + return document.fullscreenElement != null; + } + + get isMobile(): boolean + { + return AppComponent.isMobile; + } + ngAfterViewInit() { this.player = document.getElementById("player") as HTMLVideoElement; this.thumb = document.getElementById("thumb") as HTMLElement; this.progress = document.getElementById("progress") as HTMLElement; this.buffered = document.getElementById("buffered") as HTMLElement; - this.player.controls = false; - - this.player.onplay = () => - { - this.initPlayBtn(); - }; - - this.player.onpause = () => - { - this.playIcon = "play_arrow"; - this.playTooltip = "Play"; - }; this.player.ontimeupdate = () => { @@ -139,16 +139,11 @@ export class PlayerComponent implements OnInit loadIndicator.classList.add("d-none"); }; - this.player.onended = () => - { - this.next(); - }; - this.player.onerror = () => { if (this.playMethod == method.transcode) { - this.snackBar.open("This episode can't be played.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 10000 }); + this.snackBar.open("This episode can't be played.", null, { horizontalPosition: "left", panelClass: ["snackError"], duration: 10000 }); } else { @@ -277,20 +272,6 @@ export class PlayerComponent implements OnInit if (document.fullscreenElement == null && this.router.url.startsWith("/watch")) this.back(); } - else - { - if (document.fullscreenElement != null) - { - this.fullscreenIcon = "fullscreen_exit"; - this.fullscreenTooltip = "Exit fullscreen"; - } - else - { - this.fullscreenIcon = "fullscreen"; - this.fullscreenTooltip = "Fullscreen"; - } - } - }); $(window).keydown((e) => @@ -298,15 +279,15 @@ export class PlayerComponent implements OnInit switch (e.keyCode) { case 32: //space - this.tooglePlayback(); + this.togglePlayback(); break; case 38: //Key up - this.changeVolume(this.volume + 5); + this.volume += 5; this.snackBar.open(this.volume + "%", null, { verticalPosition: "top", horizontalPosition: "right", duration: 300, panelClass: "volume" }); break; case 40: //Key down - this.changeVolume(this.volume - 5); + this.volume += 5; this.snackBar.open(this.volume + "%", null, { verticalPosition: "top", horizontalPosition: "right", duration: 300, panelClass: "volume" }); break; @@ -326,7 +307,7 @@ export class PlayerComponent implements OnInit break; case 77: //M key - this.toogleMute(); + this.muted = !this.muted; if (this.player.muted) this.snackBar.open("Sound muted.", null, { verticalPosition: "top", horizontalPosition: "right", duration: 750, panelClass: "info-panel" }); else @@ -351,16 +332,12 @@ export class PlayerComponent implements OnInit switch (true) { case event instanceof NavigationStart: - { - loadIndicator.classList.remove("d-none"); - break; - } + loadIndicator.classList.remove("d-none"); + break; case event instanceof NavigationEnd: case event instanceof NavigationCancel: - { - loadIndicator.classList.add("d-none"); - break; - } + loadIndicator.classList.add("d-none"); + break; default: break; } @@ -395,7 +372,12 @@ export class PlayerComponent implements OnInit setTimeout(() => { - this.snackBar.open("Playing: " + this.item.showTitle + " S" + this.item.seasonNumber + ":E" + this.item.episodeNumber, null, { verticalPosition: "top", horizontalPosition: "right", duration: 2000, panelClass: "info-panel" }); + this.snackBar.open(`Playing: ${this.item.showTitle} S${this.item.seasonNumber}:E${this.item.episodeNumber}`, null, { + verticalPosition: "top", + horizontalPosition: "right", + duration: 2000, + panelClass: "info-panel" + }); }, 750); } @@ -405,7 +387,7 @@ export class PlayerComponent implements OnInit if (this.oidcSecurity === undefined) this.oidcSecurity = this.injector.get(OidcSecurityService); - this.hlsPlayer.config.xhrSetup = (xhr, url) => + this.hlsPlayer.config.xhrSetup = xhr => { const token = this.oidcSecurity.getToken(); if (token) @@ -413,9 +395,7 @@ export class PlayerComponent implements OnInit }; if (this.playMethod == method.direct) - { - this.player.src = "/video/" + this.item.slug; - } + this.player.src = `/video/${this.item.slug}`; else if (this.playMethod == method.transmux) { this.hlsPlayer.loadSource("/video/transmux/" + this.item.slug + "/"); @@ -438,19 +418,25 @@ export class PlayerComponent implements OnInit back() { - this.location.back(); + this.router.navigate(["/show", this.item.showSlug]); } next() { - if (this.item.nextEpisode != null) - this.router.navigate(["/watch/" + this.item.nextEpisode.slug], { queryParamsHandling: "merge", replaceUrl: true }); + if (this.item.nextEpisode == null) + return; + this.router.navigate(["/watch", this.item.nextEpisode.slug], { + queryParamsHandling: "merge" + }); } previous() { - if (this.item.previousEpisode != null) - this.router.navigate(["/watch/" + this.item.previousEpisode], { queryParamsHandling: "merge", replaceUrl: true }); + if (this.item.previousEpisode == null) + return; + this.router.navigate(["/watch", this.item.previousEpisode], { + queryParamsHandling: "merge" + }); } getTimeFromSeekbar(progressBar: HTMLElement, pageX: number) @@ -492,7 +478,7 @@ export class PlayerComponent implements OnInit videoClicked() { if (!navigator.userAgent.match(/Mobi/)) - this.tooglePlayback(); + this.togglePlayback(); else { if ($("#hover").hasClass("idle")) @@ -515,7 +501,7 @@ export class PlayerComponent implements OnInit } } - tooglePlayback() + togglePlayback() { if (this.player.paused) this.player.play(); @@ -523,22 +509,6 @@ export class PlayerComponent implements OnInit this.player.pause(); } - toogleMute() - { - if (this.player.muted) - this.player.muted = false; - else - this.player.muted = true; - - this.updateVolumeBtn() - } - - initPlayBtn() - { - this.playIcon = "pause"; - this.playTooltip = "Pause"; - } - fullscreen() { if (document.fullscreenElement == null) @@ -547,35 +517,16 @@ export class PlayerComponent implements OnInit document.exitFullscreen(); } - //Value from 0 to 100 - changeVolume(value: number) + getVolumeBtn(): string { - value = Math.max(0, Math.min(value, 100)); - - this.player.muted = false; - this.player.volume = value / 100; - this.volume = value; - - this.updateVolumeBtn(); - } - - updateVolumeBtn() - { - if (this.player.muted) - { - this.volumeIcon = "volume_off" - } + if (this.volume == 0 || this.muted) + return "volume_off"; + else if (this.volume < 25) + return "volume_mute"; + else if (this.volume < 65) + return "volume_down"; else - { - if (this.volume == 0) - this.volumeIcon = "volume_off"; - else if (this.volume < 25) - this.volumeIcon = "volume_mute"; - else if (this.volume < 65) - this.volumeIcon = "volume_down"; - else - this.volumeIcon = "volume_up"; - } + return "volume_up"; } selectSubtitle(subtitle: Track, changeUrl: boolean = true) @@ -590,25 +541,39 @@ export class PlayerComponent implements OnInit subSlug += "-for"; } - this.router.navigate([], { relativeTo: this.route, queryParams: { sub: subSlug }, replaceUrl: true, queryParamsHandling: "merge" }); + this.router.navigate([], { + relativeTo: this.route, + queryParams: {sub: subSlug}, + replaceUrl: true, + queryParamsHandling: "merge" + }); } this.selectedSubtitle = subtitle; if (subtitle == null) { - this.snackBar.open("Subtitle removed.", null, { verticalPosition: "top", horizontalPosition: "right", duration: 750, panelClass: "info-panel" }); + this.snackBar.open("Subtitle removed.", null, { + verticalPosition: "top", + horizontalPosition: "right", + duration: 750, + panelClass: "info-panel" + }); SubtitleManager.remove(this.player); this.removeHtmlTrack(); } else { - this.snackBar.open(subtitle.displayName + " subtitle loaded.", null, { verticalPosition: "top", horizontalPosition: "right", duration: 750, panelClass: "info-panel" }); + this.snackBar.open(`${subtitle.displayName} subtitle loaded.`, null, { + verticalPosition: "top", + horizontalPosition: "right", + duration: 750, + panelClass: "info-panel" + }); this.removeHtmlTrack(); if (subtitle.codec == "ass") SubtitleManager.add(this.player, `subtitle/${subtitle.slug}`, true); - else if (subtitle.codec == "subrip") { SubtitleManager.remove(this.player);