mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Replacing spaces with tabs
This commit is contained in:
parent
03bf97dab6
commit
a19bf9bce8
@ -1,35 +1,35 @@
|
||||
<header id="nav" style="height: 68px;">
|
||||
<div class="fixed-top">
|
||||
<nav id="toolbar" class="navbar navbar-dark bg-secondary">
|
||||
<a class="navbar-brand nav-item ml-3" routerLink="/">
|
||||
Kyoo
|
||||
</a>
|
||||
<div class="fixed-top">
|
||||
<nav id="toolbar" class="navbar navbar-dark bg-secondary">
|
||||
<a class="navbar-brand nav-item ml-3" routerLink="/">
|
||||
Kyoo
|
||||
</a>
|
||||
|
||||
<ul class="navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLink="/browse" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">All</a>
|
||||
</li>
|
||||
<li class="nav-item" *ngFor="let library of this.libraries">
|
||||
<a class="nav-link" routerLink="/browse/{{library.slug}}" routerLinkActive="active">{{library.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="navbar-nav flex-row">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" routerLink="/browse" routerLinkActive="active" [routerLinkActiveOptions]="{ exact: true }">All</a>
|
||||
</li>
|
||||
<li class="nav-item" *ngFor="let library of this.libraries">
|
||||
<a class="nav-link" routerLink="/browse/{{library.slug}}" routerLinkActive="active">{{library.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="navbar-nav flex-row ml-auto">
|
||||
<li class="nav-item icon searchbar">
|
||||
<input placeholder="Search" id="search" type="search" (input)="onUpdateValue($event)"/>
|
||||
<mat-icon matTooltipPosition="below" matTooltip="Search" (click)="openSearch()">search</mat-icon>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="icon" routerLink="/login" routerLinkActive="active" matTooltipPosition="below" matTooltip="Login">
|
||||
<mat-icon>account_circle</mat-icon>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<mat-progress-bar *ngIf="this.isLoading" color="accent" mode="indeterminate"> </mat-progress-bar>
|
||||
</div>
|
||||
<ul class="navbar-nav flex-row ml-auto">
|
||||
<li class="nav-item icon searchbar">
|
||||
<input placeholder="Search" id="search" type="search" (input)="onUpdateValue($event)"/>
|
||||
<mat-icon matTooltipPosition="below" matTooltip="Search" (click)="openSearch()">search</mat-icon>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="icon" routerLink="/login" routerLinkActive="active" matTooltipPosition="below" matTooltip="Login">
|
||||
<mat-icon>account_circle</mat-icon>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<mat-progress-bar *ngIf="this.isLoading" color="accent" mode="indeterminate"> </mat-progress-bar>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main >
|
||||
<router-outlet></router-outlet>
|
||||
<router-outlet></router-outlet>
|
||||
</main>
|
||||
|
@ -4,83 +4,83 @@
|
||||
|
||||
.navbar
|
||||
{
|
||||
justify-content: left;
|
||||
justify-content: left;
|
||||
}
|
||||
|
||||
.nav-item
|
||||
{
|
||||
outline: none;
|
||||
outline: none;
|
||||
|
||||
> a
|
||||
{
|
||||
outline: none;
|
||||
color: inherit;
|
||||
}
|
||||
> a
|
||||
{
|
||||
outline: none;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-link
|
||||
{
|
||||
padding: 12px;
|
||||
color: rgba(255, 255, 255, 0.7) !important;
|
||||
padding: 12px;
|
||||
color: rgba(255, 255, 255, 0.7) !important;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
color: white !important;
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
&.active
|
||||
{
|
||||
color: var(--accentColor) !important;
|
||||
}
|
||||
&.active
|
||||
{
|
||||
color: var(--accentColor) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar-brand:hover
|
||||
{
|
||||
color: var(--accentColor);
|
||||
color: var(--accentColor);
|
||||
}
|
||||
|
||||
.searchbar
|
||||
{
|
||||
border-radius: 30px;
|
||||
border-radius: 30px;
|
||||
|
||||
> input
|
||||
{
|
||||
background: none !important;
|
||||
color: white;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-bottom: 1px solid #cfcfcf;
|
||||
width: 0;
|
||||
padding: 0;
|
||||
transition: width 0.4s ease-in-out;
|
||||
> input
|
||||
{
|
||||
background: none !important;
|
||||
color: white;
|
||||
outline: none;
|
||||
border: none;
|
||||
border-bottom: 1px solid #cfcfcf;
|
||||
width: 0;
|
||||
padding: 0;
|
||||
transition: width 0.4s ease-in-out;
|
||||
|
||||
&:focus, &.searching
|
||||
{
|
||||
width: 12rem;
|
||||
&:focus, &.searching
|
||||
{
|
||||
width: 12rem;
|
||||
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 20rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 20rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
input::-webkit-search-cancel-button
|
||||
{
|
||||
display: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.icon
|
||||
{
|
||||
padding: 8px;
|
||||
display: inline-block;
|
||||
opacity: 0.7;
|
||||
padding: 8px;
|
||||
display: inline-block;
|
||||
opacity: 0.7;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
@ -26,35 +26,35 @@ import { ShowsListComponent } from './shows-list/shows-list.component';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
NotFoundComponent,
|
||||
BrowseComponent,
|
||||
ShowDetailsComponent,
|
||||
EpisodesListComponent,
|
||||
PlayerComponent,
|
||||
CollectionComponent,
|
||||
SearchComponent,
|
||||
PeopleListComponent,
|
||||
ShowsListComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
MatSnackBarModule,
|
||||
MatProgressBarModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatSelectModule,
|
||||
MatMenuModule,
|
||||
MatSliderModule,
|
||||
MatTooltipModule,
|
||||
declarations: [
|
||||
AppComponent,
|
||||
NotFoundComponent,
|
||||
BrowseComponent,
|
||||
ShowDetailsComponent,
|
||||
EpisodesListComponent,
|
||||
PlayerComponent,
|
||||
CollectionComponent,
|
||||
SearchComponent,
|
||||
PeopleListComponent,
|
||||
ShowsListComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
HttpClientModule,
|
||||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
MatSnackBarModule,
|
||||
MatProgressBarModule,
|
||||
MatButtonModule,
|
||||
MatIconModule,
|
||||
MatSelectModule,
|
||||
MatMenuModule,
|
||||
MatSliderModule,
|
||||
MatTooltipModule,
|
||||
MatRippleModule,
|
||||
MatCardModule
|
||||
],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
providers: [],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
||||
|
@ -1,30 +1,30 @@
|
||||
<div class="container-fluid justify-content-center">
|
||||
<button mat-icon-button matTooltipPosition="below" matTooltip="Filter">
|
||||
<mat-icon>filter_list</mat-icon>
|
||||
</button>
|
||||
<button mat-button matTooltipPosition="below" matTooltip="Sort" [matMenuTriggerFor]="sortMenu">
|
||||
<mat-icon>sort</mat-icon> Sort by {{this.sortType}} <i *ngIf="this.sortUp" class="material-icons arrow">arrow_upward</i><i *ngIf="!this.sortUp" class="material-icons arrow">arrow_downward</i>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="below" matTooltip="Filter">
|
||||
<mat-icon>filter_list</mat-icon>
|
||||
</button>
|
||||
<button mat-button matTooltipPosition="below" matTooltip="Sort" [matMenuTriggerFor]="sortMenu">
|
||||
<mat-icon>sort</mat-icon> Sort by {{this.sortType}} <i *ngIf="this.sortUp" class="material-icons arrow">arrow_upward</i><i *ngIf="!this.sortUp" class="material-icons arrow">arrow_downward</i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<mat-menu #sortMenu="matMenu">
|
||||
<div *ngFor="let type of this.sortTypes">
|
||||
<button *ngIf="type != this.sortType; else elseBlock;" mat-menu-item (click)="sort(type, true)">
|
||||
Sort by {{type}}
|
||||
</button>
|
||||
<ng-template #elseBlock>
|
||||
<button mat-menu-item (click)="sort(type, !this.sortUp)">
|
||||
Sort by {{type}} <i *ngIf="!this.sortUp" class="material-icons arrow">arrow_upward</i><i *ngIf="this.sortUp" class="material-icons arrow">arrow_downward</i>
|
||||
</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
<div *ngFor="let type of this.sortTypes">
|
||||
<button *ngIf="type != this.sortType; else elseBlock;" mat-menu-item (click)="sort(type, true)">
|
||||
Sort by {{type}}
|
||||
</button>
|
||||
<ng-template #elseBlock>
|
||||
<button mat-menu-item (click)="sort(type, !this.sortUp)">
|
||||
Sort by {{type}} <i *ngIf="!this.sortUp" class="material-icons arrow">arrow_upward</i><i *ngIf="this.sortUp" class="material-icons arrow">arrow_downward</i>
|
||||
</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</mat-menu>
|
||||
|
||||
<div class="container-fluid justify-content-center">
|
||||
<a class="show" *ngFor="let show of this.shows" [href]="getLink(show)" [routerLink]="getLink(show)">
|
||||
<div matRipple [style.background-image]="getThumb(show.slug)" > </div>
|
||||
<p class="title">{{show.title}}</p>
|
||||
<p class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</p>
|
||||
<ng-template #elseBlock><p class="date">{{show.startYear}}</p></ng-template>
|
||||
</a>
|
||||
<a class="show" *ngFor="let show of this.shows" [href]="getLink(show)" [routerLink]="getLink(show)">
|
||||
<div matRipple [style.background-image]="getThumb(show.slug)" > </div>
|
||||
<p class="title">{{show.title}}</p>
|
||||
<p class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</p>
|
||||
<ng-template #elseBlock><p class="date">{{show.startYear}}</p></ng-template>
|
||||
</a>
|
||||
</div>
|
||||
|
@ -4,93 +4,93 @@
|
||||
|
||||
button
|
||||
{
|
||||
outline: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.arrow
|
||||
{
|
||||
font-size: 12px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.container-fluid
|
||||
{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.show
|
||||
{
|
||||
width: 33%;
|
||||
min-width: 120px;
|
||||
max-width: 200px;
|
||||
list-style: none;
|
||||
padding: .5em;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
width: 33%;
|
||||
min-width: 120px;
|
||||
max-width: 200px;
|
||||
list-style: none;
|
||||
padding: .5em;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 25%;
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 20%;
|
||||
padding: 1em;
|
||||
}
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 20%;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 18%;
|
||||
}
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 18%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 15%;
|
||||
}
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
|
||||
&:focus, &:hover
|
||||
{
|
||||
> div
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
}
|
||||
&:focus, &:hover
|
||||
{
|
||||
> div
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
}
|
||||
|
||||
> .title
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
> .title
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
}
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
> p
|
||||
{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
opacity: 1;
|
||||
> p
|
||||
{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
opacity: 1;
|
||||
|
||||
&.date
|
||||
{
|
||||
opacity: 0.8;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
&.date
|
||||
{
|
||||
opacity: 0.8;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,17 @@ import { DomSanitizer } from '@angular/platform-browser';
|
||||
import { Show } from "../../models/show";
|
||||
|
||||
@Component({
|
||||
selector: 'app-browse',
|
||||
templateUrl: './browse.component.html',
|
||||
styleUrls: ['./browse.component.scss']
|
||||
selector: 'app-browse',
|
||||
templateUrl: './browse.component.html',
|
||||
styleUrls: ['./browse.component.scss']
|
||||
})
|
||||
export class BrowseComponent
|
||||
{
|
||||
@Input() shows: Show[];
|
||||
sortType: string = "title";
|
||||
sortUp: boolean = true;
|
||||
@Input() shows: Show[];
|
||||
sortType: string = "title";
|
||||
sortUp: boolean = true;
|
||||
|
||||
sortTypes: string[] = ["title", "release date"];
|
||||
sortTypes: string[] = ["title", "release date"];
|
||||
|
||||
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer)
|
||||
{
|
||||
@ -24,37 +24,37 @@ export class BrowseComponent
|
||||
});
|
||||
}
|
||||
|
||||
getThumb(slug: string)
|
||||
{
|
||||
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
|
||||
}
|
||||
getThumb(slug: string)
|
||||
{
|
||||
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
|
||||
}
|
||||
|
||||
getLink(show: Show)
|
||||
{
|
||||
if (show.isCollection)
|
||||
return "/collection/" + show.slug;
|
||||
else
|
||||
return "/show/" + show.slug;
|
||||
}
|
||||
getLink(show: Show)
|
||||
{
|
||||
if (show.isCollection)
|
||||
return "/collection/" + show.slug;
|
||||
else
|
||||
return "/show/" + show.slug;
|
||||
}
|
||||
|
||||
sort(type: string, order: boolean)
|
||||
{
|
||||
this.sortType = type;
|
||||
this.sortUp = order;
|
||||
sort(type: string, order: boolean)
|
||||
{
|
||||
this.sortType = type;
|
||||
this.sortUp = order;
|
||||
|
||||
if (type == this.sortTypes[0])
|
||||
{
|
||||
if (order)
|
||||
this.shows.sort((a, b) => { if (a.title < b.title) return -1; else if (a.title > b.title) return 1; return 0; });
|
||||
else
|
||||
this.shows.sort((a, b) => { if (a.title < b.title) return 1; else if (a.title > b.title) return -1; return 0; });
|
||||
}
|
||||
else if (type == this.sortTypes[1])
|
||||
{
|
||||
if (order)
|
||||
this.shows.sort((a, b) => a.startYear - b.startYear);
|
||||
else
|
||||
this.shows.sort((a, b) => b.startYear - a.startYear);
|
||||
}
|
||||
}
|
||||
if (type == this.sortTypes[0])
|
||||
{
|
||||
if (order)
|
||||
this.shows.sort((a, b) => { if (a.title < b.title) return -1; else if (a.title > b.title) return 1; return 0; });
|
||||
else
|
||||
this.shows.sort((a, b) => { if (a.title < b.title) return 1; else if (a.title > b.title) return -1; return 0; });
|
||||
}
|
||||
else if (type == this.sortTypes[1])
|
||||
{
|
||||
if (order)
|
||||
this.shows.sort((a, b) => a.startYear - b.startYear);
|
||||
else
|
||||
this.shows.sort((a, b) => b.startYear - a.startYear);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,14 +1,14 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-4 col-lg-3 col-xl-2 collection-info">
|
||||
<div [style.background-image]="getThumb()"></div>
|
||||
</div>
|
||||
<div class="col-md-8 col-lg-9 col-xl-10">
|
||||
<h3 class="text-center text-md-left p-2 p-md-3">{{collection.name}}</h3>
|
||||
<h5 class="date" *ngIf="collection.endYear; else elseBlock">{{collection.startYear}} - {{collection.endYear}}</h5>
|
||||
<ng-template #elseBlock><h5 class="date">{{collection.startYear}}</h5></ng-template>
|
||||
<hr />
|
||||
<app-browse [shows]="collection.shows"></app-browse>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-md-4 col-lg-3 col-xl-2 collection-info">
|
||||
<div [style.background-image]="getThumb()"></div>
|
||||
</div>
|
||||
<div class="col-md-8 col-lg-9 col-xl-10">
|
||||
<h3 class="text-center text-md-left p-2 p-md-3">{{collection.name}}</h3>
|
||||
<h5 class="date" *ngIf="collection.endYear; else elseBlock">{{collection.startYear}} - {{collection.endYear}}</h5>
|
||||
<ng-template #elseBlock><h5 class="date">{{collection.startYear}}</h5></ng-template>
|
||||
<hr />
|
||||
<app-browse [shows]="collection.shows"></app-browse>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -1,23 +1,23 @@
|
||||
.collection-info
|
||||
{
|
||||
width: 60%;
|
||||
width: 60%;
|
||||
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
margin: 10px;
|
||||
}
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
margin: 10px 0 10px 0;
|
||||
border-top: 1px solid rgba(255, 255, 255, .60);
|
||||
border-left: 0;
|
||||
width: inherit;
|
||||
height: 2px;
|
||||
margin: 10px 0 10px 0;
|
||||
border-top: 1px solid rgba(255, 255, 255, .60);
|
||||
border-left: 0;
|
||||
width: inherit;
|
||||
height: 2px;
|
||||
}
|
||||
|
@ -4,13 +4,13 @@ import { ActivatedRoute } from "@angular/router";
|
||||
import { DomSanitizer } from "@angular/platform-browser";
|
||||
|
||||
@Component({
|
||||
selector: 'app-collection',
|
||||
templateUrl: './collection.component.html',
|
||||
styleUrls: ['./collection.component.scss']
|
||||
selector: 'app-collection',
|
||||
templateUrl: './collection.component.html',
|
||||
styleUrls: ['./collection.component.scss']
|
||||
})
|
||||
export class CollectionComponent
|
||||
{
|
||||
collection: Collection;
|
||||
collection: Collection;
|
||||
|
||||
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer)
|
||||
{
|
||||
|
@ -1,21 +1,21 @@
|
||||
<div class="root">
|
||||
<div class="episodes" #scrollView (scroll)="onScroll()">
|
||||
<a class="episode" *ngFor="let episode of this.episodes" #episodeDom routerLink="/watch/{{episode.link}}" href="/watch/{{episode.link}}">
|
||||
<div matRipple class="img" [style.background-image]="sanitize(episode.thumb)">
|
||||
<button mat-icon-button class="playBtn"><i class="material-icons playIcon">play_circle_outline</i></button>
|
||||
</div>
|
||||
<ng-container *ngIf="displayShowTitle; else noTitle;">
|
||||
<h6 *ngIf="episode.seasonNumber != 0; else elseBlock;" class="title">{{episode.showTitle}} - S{{episode.seasonNumber}}:E{{episode.episodeNumber}}</h6>
|
||||
<ng-template #elseBlock><h6 class="title">{{episode.showTitle}}</h6></ng-template>
|
||||
<p class="subtitle">{{episode.title}}</p>
|
||||
</ng-container>
|
||||
<ng-template #noTitle>
|
||||
<h6 *ngIf="episode.seasonNumber != 0; else elseBlock;" class="title">S{{episode.seasonNumber}}:E{{episode.episodeNumber}} - {{episode.title}}</h6>
|
||||
<ng-template #elseBlock><h6 class="title">{{episode.title}}</h6></ng-template>
|
||||
<p class="overview">{{episode.overview}}</p>
|
||||
</ng-template>
|
||||
</a>
|
||||
</div>
|
||||
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
|
||||
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
|
||||
<div class="episodes" #scrollView (scroll)="onScroll()">
|
||||
<a class="episode" *ngFor="let episode of this.episodes" #episodeDom routerLink="/watch/{{episode.link}}" href="/watch/{{episode.link}}">
|
||||
<div matRipple class="img" [style.background-image]="sanitize(episode.thumb)">
|
||||
<button mat-icon-button class="playBtn"><i class="material-icons playIcon">play_circle_outline</i></button>
|
||||
</div>
|
||||
<ng-container *ngIf="displayShowTitle; else noTitle;">
|
||||
<h6 *ngIf="episode.seasonNumber != 0; else elseBlock;" class="title">{{episode.showTitle}} - S{{episode.seasonNumber}}:E{{episode.episodeNumber}}</h6>
|
||||
<ng-template #elseBlock><h6 class="title">{{episode.showTitle}}</h6></ng-template>
|
||||
<p class="subtitle">{{episode.title}}</p>
|
||||
</ng-container>
|
||||
<ng-template #noTitle>
|
||||
<h6 *ngIf="episode.seasonNumber != 0; else elseBlock;" class="title">S{{episode.seasonNumber}}:E{{episode.episodeNumber}} - {{episode.title}}</h6>
|
||||
<ng-template #elseBlock><h6 class="title">{{episode.title}}</h6></ng-template>
|
||||
<p class="overview">{{episode.overview}}</p>
|
||||
</ng-template>
|
||||
</a>
|
||||
</div>
|
||||
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
|
||||
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
|
||||
</div>
|
||||
|
@ -4,179 +4,179 @@
|
||||
|
||||
.root
|
||||
{
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.scrollBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.scrollBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.episodes
|
||||
{
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
overflow-x: auto;
|
||||
min-width: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-direction: row;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #999 transparent;
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
overflow-x: auto;
|
||||
min-width: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-direction: row;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #999 transparent;
|
||||
|
||||
&::-webkit-scrollbar
|
||||
{
|
||||
height: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar
|
||||
{
|
||||
height: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
border-radius: 90px;
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
border-radius: 90px;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.episode
|
||||
{
|
||||
visibility: visible;
|
||||
display: inline-block;
|
||||
padding: .25rem;
|
||||
flex-shrink: 0;
|
||||
width: 55%;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
visibility: visible;
|
||||
display: inline-block;
|
||||
padding: .25rem;
|
||||
flex-shrink: 0;
|
||||
width: 55%;
|
||||
cursor: pointer;
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 40%;
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 33%;
|
||||
}
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 33%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 28%;
|
||||
}
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 28%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 18%;
|
||||
}
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 18%;
|
||||
}
|
||||
|
||||
.img
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 56.25%;
|
||||
background-color: #333333;
|
||||
background-size: contain;
|
||||
position: relative;
|
||||
.img
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 56.25%;
|
||||
background-color: #333333;
|
||||
background-size: contain;
|
||||
position: relative;
|
||||
|
||||
> button
|
||||
{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
outline: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
> button
|
||||
{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
outline: none;
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.title
|
||||
{
|
||||
padding-top: .2rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.title
|
||||
{
|
||||
padding-top: .2rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.overview
|
||||
{
|
||||
font-weight: 300;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 4;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.overview
|
||||
{
|
||||
font-weight: 300;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 4;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.subtitle
|
||||
{
|
||||
font-weight: 300;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
.subtitle
|
||||
{
|
||||
font-weight: 300;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 1;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.img
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.img
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
|
||||
.playBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.playBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
.title
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
.title
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.playIcon
|
||||
{
|
||||
font-size: 64px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
font-size: 64px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
line-height: 64px;
|
||||
}
|
||||
|
||||
.scrollBtn
|
||||
{
|
||||
padding: 0;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
bottom: 60%;
|
||||
display: none;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
position: absolute;
|
||||
top: 20%;
|
||||
bottom: 60%;
|
||||
display: none;
|
||||
|
||||
&.leftBtn
|
||||
{
|
||||
left: 0;
|
||||
padding-left: 10px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
&.leftBtn
|
||||
{
|
||||
left: 0;
|
||||
padding-left: 10px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
&.rightBtn
|
||||
{
|
||||
right: 0;
|
||||
padding-right: 10px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
&.rightBtn
|
||||
{
|
||||
right: 0;
|
||||
padding-right: 10px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
}
|
||||
|
@ -4,14 +4,14 @@ import { DomSanitizer } from "@angular/platform-browser";
|
||||
import { Episode } from "../../models/episode";
|
||||
|
||||
@Component({
|
||||
selector: 'app-episodes-list',
|
||||
templateUrl: './episodes-list.component.html',
|
||||
styleUrls: ['./episodes-list.component.scss']
|
||||
selector: 'app-episodes-list',
|
||||
templateUrl: './episodes-list.component.html',
|
||||
styleUrls: ['./episodes-list.component.scss']
|
||||
})
|
||||
export class EpisodesListComponent
|
||||
{
|
||||
@Input() displayShowTitle: boolean = false;
|
||||
@Input() episodes: Episode[];
|
||||
@Input() episodes: Episode[];
|
||||
@ViewChild("scrollView", { static: true }) private scrollView: ElementRef;
|
||||
@ViewChild("leftBtn", { static: false }) private leftBtn: MatButton;
|
||||
@ViewChild("rightBtn", { static: false }) private rightBtn: MatButton;
|
||||
@ -53,8 +53,8 @@ export class EpisodesListComponent
|
||||
this.rightBtn._elementRef.nativeElement.classList.remove("d-none");
|
||||
}
|
||||
|
||||
sanitize(url: string)
|
||||
{
|
||||
return this.sanitizer.bypassSecurityTrustStyle("url(" + url + ")");
|
||||
}
|
||||
sanitize(url: string)
|
||||
{
|
||||
return this.sanitizer.bypassSecurityTrustStyle("url(" + url + ")");
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,6 @@
|
||||
<br/>
|
||||
<br/>
|
||||
<div class="text-center">
|
||||
<h1>404 Error</h1>
|
||||
<p>The page you requested was not found.</p>
|
||||
<h1>404 Error</h1>
|
||||
<p>The page you requested was not found.</p>
|
||||
</div>
|
||||
|
@ -1,15 +1,15 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-not-found',
|
||||
templateUrl: './not-found.component.html',
|
||||
styleUrls: ['./not-found.component.scss']
|
||||
selector: 'app-not-found',
|
||||
templateUrl: './not-found.component.html',
|
||||
styleUrls: ['./not-found.component.scss']
|
||||
})
|
||||
export class NotFoundComponent implements OnInit {
|
||||
|
||||
constructor() { }
|
||||
constructor() { }
|
||||
|
||||
ngOnInit() {
|
||||
}
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1,11 +1,11 @@
|
||||
<div class="scroll-row mb-5">
|
||||
<div class="people-container" #scrollView (scroll)="onScroll()">
|
||||
<a class="people" *ngFor="let people of this.people" routerLink="/people/{{people.slug}}" href="/people/{{people.slug}}">
|
||||
<div matRipple [style.background-image]="getPeopleIcon(people.slug)"> </div>
|
||||
<h6 class="name">{{people.name}}</h6>
|
||||
<p class="role">{{people.role}}</p>
|
||||
</a>
|
||||
</div>
|
||||
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
|
||||
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
|
||||
<div class="people-container" #scrollView (scroll)="onScroll()">
|
||||
<a class="people" *ngFor="let people of this.people" routerLink="/people/{{people.slug}}" href="/people/{{people.slug}}">
|
||||
<div matRipple [style.background-image]="getPeopleIcon(people.slug)"> </div>
|
||||
<h6 class="name">{{people.name}}</h6>
|
||||
<p class="role">{{people.role}}</p>
|
||||
</a>
|
||||
</div>
|
||||
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
|
||||
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
|
||||
</div>
|
||||
|
@ -4,138 +4,138 @@
|
||||
|
||||
.people-container
|
||||
{
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
overflow-x: auto;
|
||||
min-width: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-direction: row;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #999 transparent;
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
overflow-x: auto;
|
||||
min-width: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-direction: row;
|
||||
scrollbar-width: thin;
|
||||
scrollbar-color: #999 transparent;
|
||||
|
||||
&::-webkit-scrollbar
|
||||
{
|
||||
height: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar
|
||||
{
|
||||
height: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
border-radius: 90px;
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
border-radius: 90px;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.people
|
||||
{
|
||||
visibility: visible;
|
||||
margin: .25rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
width: 33%;
|
||||
visibility: visible;
|
||||
margin: .25rem;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
width: 33%;
|
||||
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 22%;
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 22%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 20%;
|
||||
}
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 15%;
|
||||
}
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 10%;
|
||||
}
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
}
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
> p, h6
|
||||
{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
> p, h6
|
||||
{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
|
||||
&.role
|
||||
{
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
&.role
|
||||
{
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
|
||||
> img
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
}
|
||||
> img
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
}
|
||||
|
||||
.name
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
.name
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-row
|
||||
{
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.scrollBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.scrollBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scrollBtn
|
||||
{
|
||||
padding: 0;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
bottom: 40%;
|
||||
display: none;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
bottom: 40%;
|
||||
display: none;
|
||||
|
||||
&.leftBtn
|
||||
{
|
||||
left: 0;
|
||||
padding-left: 10px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
&.leftBtn
|
||||
{
|
||||
left: 0;
|
||||
padding-left: 10px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
&.rightBtn
|
||||
{
|
||||
right: 0;
|
||||
padding-right: 10px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
&.rightBtn
|
||||
{
|
||||
right: 0;
|
||||
padding-right: 10px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
}
|
||||
|
@ -1,154 +1,154 @@
|
||||
<div id="root">
|
||||
<div class="player data-vjs-player">
|
||||
<video id="player" poster="backdrop/{{this.item.showSlug}}" autoplay muted (click)="videoClicked()">
|
||||
</video>
|
||||
</div>
|
||||
<div class="player data-vjs-player">
|
||||
<video id="player" poster="backdrop/{{this.item.showSlug}}" autoplay muted (click)="videoClicked()">
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<div id="loadIndicator">
|
||||
<div class="spinner-border align-self-center" role="status"></div>
|
||||
</div>
|
||||
<div id="loadIndicator">
|
||||
<div class="spinner-border align-self-center" role="status"></div>
|
||||
</div>
|
||||
|
||||
<mat-card class="d-none w-25 m-5" [ngClass]="{'d-block': this.displayStats}">
|
||||
<mat-card-header style="margin-bottom: 0.5rem;">
|
||||
<h4 style="align-self: center; margin-bottom: 0;">Stats</h4>
|
||||
<div style="flex: 1 1 auto"></div>
|
||||
<button mat-icon-button aria-label="Close" (click)="this.displayStats = false" style="outline: none;">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
Play method: <span style="float: right">{{this.playMethod}}</span>
|
||||
<br />
|
||||
<br />
|
||||
Video Container: <span style="float: right">{{this.item.container}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("container")}}</i></span>
|
||||
<br />
|
||||
Video Codec: <span style="float: right">{{this.item.video.codec}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("video")}}</i></span>
|
||||
<br />
|
||||
Audio Codec: <span style="float: right">{{this.item.audios[0].codec}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("audio")}}</i></span>
|
||||
<br />
|
||||
Subtitle Codec: <span style="float: right">{{this.selectedSubtitle ? this.selectedSubtitle.codec : "none"}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("subtitle")}}</i></span>
|
||||
<br />
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
<mat-card class="d-none w-25 m-5" [ngClass]="{'d-block': this.displayStats}">
|
||||
<mat-card-header style="margin-bottom: 0.5rem;">
|
||||
<h4 style="align-self: center; margin-bottom: 0;">Stats</h4>
|
||||
<div style="flex: 1 1 auto"></div>
|
||||
<button mat-icon-button aria-label="Close" (click)="this.displayStats = false" style="outline: none;">
|
||||
<mat-icon>close</mat-icon>
|
||||
</button>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
Play method: <span style="float: right">{{this.playMethod}}</span>
|
||||
<br />
|
||||
<br />
|
||||
Video Container: <span style="float: right">{{this.item.container}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("container")}}</i></span>
|
||||
<br />
|
||||
Video Codec: <span style="float: right">{{this.item.video.codec}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("video")}}</i></span>
|
||||
<br />
|
||||
Audio Codec: <span style="float: right">{{this.item.audios[0].codec}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("audio")}}</i></span>
|
||||
<br />
|
||||
Subtitle Codec: <span style="float: right">{{this.selectedSubtitle ? this.selectedSubtitle.codec : "none"}} <i class="material-icons" style="vertical-align: middle; font-size: 14px">{{getSupportedFeature("subtitle")}}</i></span>
|
||||
<br />
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
|
||||
<div id="hover">
|
||||
<div class="back">
|
||||
<a mat-icon-button matTooltipPosition="below" matTooltip="Back" (click)="back()">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</a>
|
||||
<h5>{{this.item.showTitle}}</h5>
|
||||
</div>
|
||||
<div id="hover">
|
||||
<div class="back">
|
||||
<a mat-icon-button matTooltipPosition="below" matTooltip="Back" (click)="back()">
|
||||
<mat-icon>arrow_back</mat-icon>
|
||||
</a>
|
||||
<h5>{{this.item.showTitle}}</h5>
|
||||
</div>
|
||||
|
||||
<div class="controller container-fluid" id="controller">
|
||||
<div class="img d-none d-sm-block">
|
||||
<img src="poster/{{this.item.showSlug}}" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<h3>S{{this.item.seasonNumber}}:E{{this.item.episodeNumber}} - {{this.item.title}}</h3>
|
||||
<div class="controller container-fluid" id="controller">
|
||||
<div class="img d-none d-sm-block">
|
||||
<img src="poster/{{this.item.showSlug}}" />
|
||||
</div>
|
||||
<div class="content">
|
||||
<h3>S{{this.item.seasonNumber}}:E{{this.item.episodeNumber}} - {{this.item.title}}</h3>
|
||||
|
||||
<div id="progress-bar">
|
||||
<div class="seek-bar">
|
||||
<div id="buffered"></div>
|
||||
<div id="progress"></div>
|
||||
</div>
|
||||
<div id="thumb"><div></div></div>
|
||||
</div>
|
||||
<div id="progress-bar">
|
||||
<div class="seek-bar">
|
||||
<div id="buffered"></div>
|
||||
<div id="progress"></div>
|
||||
</div>
|
||||
<div id="thumb"><div></div></div>
|
||||
</div>
|
||||
|
||||
<div class="buttons">
|
||||
<div class="left">
|
||||
<a *ngIf="this.item.previousEpisode" mat-icon-button matTooltipPosition="above" matTooltip="Previous" (click)="previous()">
|
||||
<mat-icon>skip_previous</mat-icon>
|
||||
</a>
|
||||
<button mat-icon-button matTooltipPosition="above" [matTooltip]="playTooltip" id="play" (click)="tooglePlayback()">
|
||||
<mat-icon>{{this.playIcon}}</mat-icon>
|
||||
</button>
|
||||
<a mat-icon-button id="nextBtn" *ngIf="this.item.nextEpisode" (click)="next()">
|
||||
<mat-icon>skip_next</mat-icon>
|
||||
<div class="buttons">
|
||||
<div class="left">
|
||||
<a *ngIf="this.item.previousEpisode" mat-icon-button matTooltipPosition="above" matTooltip="Previous" (click)="previous()">
|
||||
<mat-icon>skip_previous</mat-icon>
|
||||
</a>
|
||||
<button mat-icon-button matTooltipPosition="above" [matTooltip]="playTooltip" id="play" (click)="tooglePlayback()">
|
||||
<mat-icon>{{this.playIcon}}</mat-icon>
|
||||
</button>
|
||||
<a mat-icon-button id="nextBtn" *ngIf="this.item.nextEpisode" (click)="next()">
|
||||
<mat-icon>skip_next</mat-icon>
|
||||
|
||||
<div id="next">
|
||||
<div id="main">
|
||||
<img src="{{this.item.nextEpisode.thumb}}" />
|
||||
</div>
|
||||
<div id="overview">
|
||||
<h6>S{{this.item.nextEpisode.seasonNumber}}:E{{this.item.nextEpisode.episodeNumber}} - {{this.item.nextEpisode.title}}</h6>
|
||||
<p>{{this.item.nextEpisode.overview}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div id="volume">
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Volume" (click)="toogleMute()">
|
||||
<mat-icon>{{this.volumeIcon}}</mat-icon>
|
||||
</button>
|
||||
<div id="next">
|
||||
<div id="main">
|
||||
<img src="{{this.item.nextEpisode.thumb}}" />
|
||||
</div>
|
||||
<div id="overview">
|
||||
<h6>S{{this.item.nextEpisode.seasonNumber}}:E{{this.item.nextEpisode.episodeNumber}} - {{this.item.nextEpisode.title}}</h6>
|
||||
<p>{{this.item.nextEpisode.overview}}</p>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
<div id="volume">
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Volume" (click)="toogleMute()">
|
||||
<mat-icon>{{this.volumeIcon}}</mat-icon>
|
||||
</button>
|
||||
|
||||
<mat-slider [value]="volume" (input)="changeVolume($event.value)"></mat-slider>
|
||||
</div>
|
||||
<p *ngIf="this.maxHours; else elseBlock">{{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'}}</p>
|
||||
<ng-template #elseBlock><p>{{this.minutes | number: '2.0-0'}}:{{this.seconds | number: '2.0-0'}} / {{this.maxMinutes | number: '2.0-0'}}:{{this.maxSeconds | number: '2.0-0'}}</p></ng-template>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button id="volume" *ngIf="this.item.audios.length > 1" mat-icon-button matTooltipPosition="above" matTooltip="Select audio track">
|
||||
<mat-icon>music_note</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="this.item.subtitles.length > 0" mat-icon-button [matMenuTriggerFor]="subtitles" matTooltipPosition="above" matTooltip="Select subtitle track">
|
||||
<mat-icon>closed_caption</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Cast">
|
||||
<mat-icon>cast</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" [matMenuTriggerFor]="settings" matTooltip="Settings">
|
||||
<mat-icon>settings</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" [matTooltip]="fullscreenTooltip" id="fullscreen" (click)="fullscreen()">
|
||||
<mat-icon>{{fullscreenIcon}}</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<mat-slider [value]="volume" (input)="changeVolume($event.value)"></mat-slider>
|
||||
</div>
|
||||
<p *ngIf="this.maxHours; else elseBlock">{{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'}}</p>
|
||||
<ng-template #elseBlock><p>{{this.minutes | number: '2.0-0'}}:{{this.seconds | number: '2.0-0'}} / {{this.maxMinutes | number: '2.0-0'}}:{{this.maxSeconds | number: '2.0-0'}}</p></ng-template>
|
||||
</div>
|
||||
<div class="right">
|
||||
<button id="volume" *ngIf="this.item.audios.length > 1" mat-icon-button matTooltipPosition="above" matTooltip="Select audio track">
|
||||
<mat-icon>music_note</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="this.item.subtitles.length > 0" mat-icon-button [matMenuTriggerFor]="subtitles" matTooltipPosition="above" matTooltip="Select subtitle track">
|
||||
<mat-icon>closed_caption</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Cast">
|
||||
<mat-icon>cast</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" [matMenuTriggerFor]="settings" matTooltip="Settings">
|
||||
<mat-icon>settings</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" [matTooltip]="fullscreenTooltip" id="fullscreen" (click)="fullscreen()">
|
||||
<mat-icon>{{fullscreenIcon}}</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-menu #subtitles="matMenu">
|
||||
<ng-template matMenuContent>
|
||||
<button [ngClass]="{'selected': this.selectedSubtitle == null}" mat-menu-item (click)="selectSubtitle(null)">
|
||||
<span>None</span>
|
||||
</button>
|
||||
<mat-menu #subtitles="matMenu">
|
||||
<ng-template matMenuContent>
|
||||
<button [ngClass]="{'selected': this.selectedSubtitle == null}" mat-menu-item (click)="selectSubtitle(null)">
|
||||
<span>None</span>
|
||||
</button>
|
||||
|
||||
<div *ngFor="let subtitle of this.item.subtitles">
|
||||
<button [ngClass]="{'selected': this.selectedSubtitle == subtitle}" mat-menu-item *ngIf="subtitle.codec == 'ass' || subtitle.codec == 'subrip'; else elseBlock" (click)="selectSubtitle(subtitle)">
|
||||
<span>{{subtitle.displayName}}</span>
|
||||
</button>
|
||||
<div *ngFor="let subtitle of this.item.subtitles">
|
||||
<button [ngClass]="{'selected': this.selectedSubtitle == subtitle}" mat-menu-item *ngIf="subtitle.codec == 'ass' || subtitle.codec == 'subrip'; else elseBlock" (click)="selectSubtitle(subtitle)">
|
||||
<span>{{subtitle.displayName}}</span>
|
||||
</button>
|
||||
|
||||
<ng-template #elseBlock>
|
||||
<button mat-menu-item disabled>
|
||||
<span>{{subtitle.displayName}} ({{subtitle.codec}})</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
<ng-template #elseBlock>
|
||||
<button mat-menu-item disabled>
|
||||
<span>{{subtitle.displayName}} ({{subtitle.codec}})</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
|
||||
<mat-menu #settings="matMenu">
|
||||
<ng-template matMenuContent>
|
||||
<button mat-menu-item (click)="this.displayStats = !this.displayStats">
|
||||
<span>Stats</span>
|
||||
</button>
|
||||
<button mat-menu-item [matMenuTriggerFor]="method">
|
||||
<span>Method</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
<mat-menu #settings="matMenu">
|
||||
<ng-template matMenuContent>
|
||||
<button mat-menu-item (click)="this.displayStats = !this.displayStats">
|
||||
<span>Stats</span>
|
||||
</button>
|
||||
<button mat-menu-item [matMenuTriggerFor]="method">
|
||||
<span>Method</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
|
||||
<mat-menu #method="matMenu">
|
||||
<ng-template matMenuContent>
|
||||
<button mat-menu-item (click)="selectPlayMethod(methodType.direct)">
|
||||
<span>Direct Play</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="selectPlayMethod(methodType.transmux)">
|
||||
<span>Transmux</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="selectPlayMethod(methodType.transcode)">
|
||||
<span>Transcode</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
<mat-menu #method="matMenu">
|
||||
<ng-template matMenuContent>
|
||||
<button mat-menu-item (click)="selectPlayMethod(methodType.direct)">
|
||||
<span>Direct Play</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="selectPlayMethod(methodType.transmux)">
|
||||
<span>Transmux</span>
|
||||
</button>
|
||||
<button mat-menu-item (click)="selectPlayMethod(methodType.transcode)">
|
||||
<span>Transcode</span>
|
||||
</button>
|
||||
</ng-template>
|
||||
</mat-menu>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,339 +3,339 @@
|
||||
|
||||
.player
|
||||
{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #000;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: #000;
|
||||
|
||||
> video
|
||||
{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
> video
|
||||
{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: contain;
|
||||
}
|
||||
}
|
||||
|
||||
#hover
|
||||
{
|
||||
transition: opacity .2s linear;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
transition: opacity .2s linear;
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
|
||||
&.idle
|
||||
{
|
||||
transition: opacity .6s linear, visibility 0s .6s;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
&.idle
|
||||
{
|
||||
transition: opacity .6s linear, visibility 0s .6s;
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.back
|
||||
{
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
padding: .33%;
|
||||
display: flex;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
padding: .33%;
|
||||
display: flex;
|
||||
|
||||
> a
|
||||
{
|
||||
outline: none;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
> a
|
||||
{
|
||||
outline: none;
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
> h5
|
||||
{
|
||||
margin: 0;
|
||||
margin-left: .5rem;
|
||||
align-self: center;
|
||||
}
|
||||
> h5
|
||||
{
|
||||
margin: 0;
|
||||
margin-left: .5rem;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
.controller
|
||||
{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
padding: 1%;
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
display: flex;
|
||||
padding: 1%;
|
||||
|
||||
.img
|
||||
{
|
||||
width: 15%;
|
||||
position: relative;
|
||||
height: auto;
|
||||
.img
|
||||
{
|
||||
width: 15%;
|
||||
position: relative;
|
||||
height: auto;
|
||||
|
||||
> img
|
||||
{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
> img
|
||||
{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
}
|
||||
}
|
||||
|
||||
.content
|
||||
{
|
||||
width: 100%;
|
||||
margin-left: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
.content
|
||||
{
|
||||
width: 100%;
|
||||
margin-left: 1rem;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.buttons
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
.buttons
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
|
||||
> div
|
||||
{
|
||||
&.left
|
||||
{
|
||||
align-self: start;
|
||||
display: flex;
|
||||
> div
|
||||
{
|
||||
&.left
|
||||
{
|
||||
align-self: start;
|
||||
display: flex;
|
||||
|
||||
> p
|
||||
{
|
||||
margin: 0;
|
||||
margin-left: 1rem;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
> p
|
||||
{
|
||||
margin: 0;
|
||||
margin-left: 1rem;
|
||||
align-self: center;
|
||||
}
|
||||
}
|
||||
|
||||
&.right
|
||||
{
|
||||
align-self: end;
|
||||
}
|
||||
&.right
|
||||
{
|
||||
align-self: end;
|
||||
}
|
||||
|
||||
> button
|
||||
{
|
||||
margin-left: .3rem;
|
||||
margin-right: .3rem;
|
||||
outline: none;
|
||||
}
|
||||
> button
|
||||
{
|
||||
margin-left: .3rem;
|
||||
margin-right: .3rem;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
> a
|
||||
{
|
||||
margin-left: .3rem;
|
||||
margin-right: .3rem;
|
||||
outline: none;
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
> a
|
||||
{
|
||||
margin-left: .3rem;
|
||||
margin-right: .3rem;
|
||||
outline: none;
|
||||
color: inherit;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#progress-bar
|
||||
{
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
padding-top: 1rem;
|
||||
padding-bottom: 1rem;
|
||||
position: relative;
|
||||
|
||||
.seek-bar
|
||||
{
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
position: relative;
|
||||
background-color: rgba(255, 255, 255, .2);
|
||||
transform: scaleY(.6);
|
||||
.seek-bar
|
||||
{
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
position: relative;
|
||||
background-color: rgba(255, 255, 255, .2);
|
||||
transform: scaleY(.6);
|
||||
|
||||
#progress
|
||||
{
|
||||
width: 0;
|
||||
height: 100%;
|
||||
background-color: var(--accentColor);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
#progress
|
||||
{
|
||||
width: 0;
|
||||
height: 100%;
|
||||
background-color: var(--accentColor);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
#buffered
|
||||
{
|
||||
width: 0;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
#buffered
|
||||
{
|
||||
width: 0;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, .5);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#thumb
|
||||
{
|
||||
width: 100%;
|
||||
height: 12px;
|
||||
position: absolute;
|
||||
left: -6px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
opacity: 0;
|
||||
#thumb
|
||||
{
|
||||
width: 100%;
|
||||
height: 12px;
|
||||
position: absolute;
|
||||
left: -6px;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
opacity: 0;
|
||||
|
||||
> div
|
||||
{
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--accentColor);
|
||||
}
|
||||
}
|
||||
> div
|
||||
{
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
border-radius: 6px;
|
||||
background-color: var(--accentColor);
|
||||
}
|
||||
}
|
||||
|
||||
.hoverEnabled &:hover, &.seeking
|
||||
{
|
||||
cursor: pointer;
|
||||
.hoverEnabled &:hover, &.seeking
|
||||
{
|
||||
cursor: pointer;
|
||||
|
||||
.seek-bar
|
||||
{
|
||||
transform: scaleY(1);
|
||||
}
|
||||
.seek-bar
|
||||
{
|
||||
transform: scaleY(1);
|
||||
}
|
||||
|
||||
#thumb
|
||||
{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
#thumb
|
||||
{
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#nextBtn
|
||||
{
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
.hoverEnabled &:hover
|
||||
{
|
||||
#next
|
||||
{
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
.hoverEnabled &:hover
|
||||
{
|
||||
#next
|
||||
{
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
#next
|
||||
{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 100%;
|
||||
display: none;
|
||||
background-color: #212121;
|
||||
white-space: normal;
|
||||
line-height: normal;
|
||||
cursor: default;
|
||||
height: 150px;
|
||||
#next
|
||||
{
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 100%;
|
||||
display: none;
|
||||
background-color: #212121;
|
||||
white-space: normal;
|
||||
line-height: normal;
|
||||
cursor: default;
|
||||
height: 150px;
|
||||
|
||||
#main
|
||||
{
|
||||
width: auto;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
#main
|
||||
{
|
||||
width: auto;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
|
||||
> img
|
||||
{
|
||||
width: auto;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
> img
|
||||
{
|
||||
width: auto;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
#overview
|
||||
{
|
||||
padding: 1%;
|
||||
width: 50%;
|
||||
min-width: 300px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
#overview
|
||||
{
|
||||
padding: 1%;
|
||||
width: 50%;
|
||||
min-width: 300px;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> p
|
||||
{
|
||||
text-align: justify;
|
||||
font-weight: 300;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
> p
|
||||
{
|
||||
text-align: justify;
|
||||
font-weight: 300;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#volume
|
||||
{
|
||||
display: flex;
|
||||
display: flex;
|
||||
|
||||
> button
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
> button
|
||||
{
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.hoverEnabled &:hover, &:focus-within
|
||||
{
|
||||
> mat-slider
|
||||
{
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
.hoverEnabled &:hover, &:focus-within
|
||||
{
|
||||
> mat-slider
|
||||
{
|
||||
width: 100px;
|
||||
}
|
||||
}
|
||||
|
||||
> mat-slider
|
||||
{
|
||||
width: 0px;
|
||||
min-width: 0px;
|
||||
padding: 0;
|
||||
height: 40px;
|
||||
overflow: hidden;
|
||||
transition: width .2s cubic-bezier(0.4,0, 1, 1);
|
||||
> mat-slider
|
||||
{
|
||||
width: 0px;
|
||||
min-width: 0px;
|
||||
padding: 0;
|
||||
height: 40px;
|
||||
overflow: hidden;
|
||||
transition: width .2s cubic-bezier(0.4,0, 1, 1);
|
||||
|
||||
> div
|
||||
{
|
||||
top: 19px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
> div
|
||||
{
|
||||
top: 19px;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-menu-item
|
||||
{
|
||||
outline: none !important;
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.selected
|
||||
{
|
||||
background: #595959 !important;
|
||||
color: var(--accentColor);
|
||||
font-weight: 900;
|
||||
background: #595959 !important;
|
||||
color: var(--accentColor);
|
||||
font-weight: 900;
|
||||
}
|
||||
|
||||
#loadIndicator
|
||||
{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
pointer-events: none;
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.volume
|
||||
{
|
||||
min-width: 0px !important;
|
||||
min-width: 0px !important;
|
||||
}
|
||||
|
||||
.info-panel
|
||||
{
|
||||
min-width: 250px !important;
|
||||
max-width: 300px !important;
|
||||
min-width: 250px !important;
|
||||
max-width: 300px !important;
|
||||
}
|
||||
|
@ -371,7 +371,7 @@ export class PlayerComponent implements OnInit
|
||||
let queryMethod: string = this.route.snapshot.queryParams["method"];
|
||||
if (queryMethod)
|
||||
this.playMethod = method[queryMethod];
|
||||
else
|
||||
else
|
||||
this.playMethod = getPlaybackMethod(this.player, this.item);
|
||||
|
||||
this.selectPlayMethod(this.playMethod);
|
||||
@ -428,7 +428,7 @@ export class PlayerComponent implements OnInit
|
||||
next()
|
||||
{
|
||||
if (this.item.nextEpisode != null)
|
||||
this.router.navigate(["/watch/" + this.item.nextEpisode.link], { queryParamsHandling: "merge", replaceUrl: true });
|
||||
this.router.navigate(["/watch/" + this.item.nextEpisode.link], { queryParamsHandling: "merge", replaceUrl: true });
|
||||
}
|
||||
|
||||
previous()
|
||||
|
@ -1,5 +1,5 @@
|
||||
::cue
|
||||
{
|
||||
background-color: transparent;
|
||||
text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
|
||||
background-color: transparent;
|
||||
text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
<div *ngIf="items.shows.length > 0" class="container-fluid mt-3">
|
||||
<h3>Shows</h3>
|
||||
<h3>Shows</h3>
|
||||
</div>
|
||||
<app-shows-list [shows]="items.shows"></app-shows-list>
|
||||
<div *ngIf="items.episodes.length > 0" class="container-fluid mt-5">
|
||||
<h3>Episodes</h3>
|
||||
<h3>Episodes</h3>
|
||||
</div>
|
||||
<app-episodes-list displayShowTitle="true" [episodes]="items.episodes"></app-episodes-list>
|
||||
<div *ngIf="items.people.length > 0" class="container-fluid mt-5">
|
||||
<h3>People</h3>
|
||||
<h3>People</h3>
|
||||
</div>
|
||||
<app-people-list [people]="items.people"></app-people-list>
|
||||
|
@ -4,9 +4,9 @@ import { SearchResut } from "../../models/search-result";
|
||||
import { Title } from "@angular/platform-browser";
|
||||
|
||||
@Component({
|
||||
selector: 'app-search',
|
||||
templateUrl: './search.component.html',
|
||||
styleUrls: ['./search.component.scss']
|
||||
selector: 'app-search',
|
||||
templateUrl: './search.component.html',
|
||||
styleUrls: ['./search.component.scss']
|
||||
})
|
||||
export class SearchComponent implements OnInit, OnDestroy
|
||||
{
|
||||
|
@ -7,27 +7,27 @@ import { catchError } from 'rxjs/operators'
|
||||
import { Collection } from "../../models/collection";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class CollectionResolverService implements Resolve<Collection>
|
||||
{
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Collection | Observable<Collection> | Promise<Collection>
|
||||
{
|
||||
let collection: string = route.paramMap.get("collection-slug");
|
||||
return this.http.get<Collection>("api/collection/" + collection).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
{
|
||||
this.snackBar.open("Collection \"" + collection + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
resolve(route: ActivatedRouteSnapshot): Collection | Observable<Collection> | Promise<Collection>
|
||||
{
|
||||
let collection: string = route.paramMap.get("collection-slug");
|
||||
return this.http.get<Collection>("api/collection/" + collection).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
{
|
||||
this.snackBar.open("Collection \"" + collection + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -10,36 +10,36 @@ import { Show } from "../../models/show";
|
||||
@Injectable()
|
||||
export class LibraryResolverService implements Resolve<Show[]>
|
||||
{
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Show[] | Observable<Show[]> | Promise<Show[]>
|
||||
{
|
||||
let slug: string = route.paramMap.get("library-slug");
|
||||
resolve(route: ActivatedRouteSnapshot): Show[] | Observable<Show[]> | Promise<Show[]>
|
||||
{
|
||||
let slug: string = route.paramMap.get("library-slug");
|
||||
|
||||
if (slug == null)
|
||||
{
|
||||
return this.http.get<Show[]>("api/shows").pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.http.get<Show[]>("api/libraries/" + slug).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
{
|
||||
this.snackBar.open("Library \"" + slug + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
}
|
||||
if (slug == null)
|
||||
{
|
||||
return this.http.get<Show[]>("api/shows").pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.http.get<Show[]>("api/libraries/" + slug).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
{
|
||||
this.snackBar.open("Library \"" + slug + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import { Collection } from "../../models/collection";
|
||||
import { People } from "../../models/people";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class PeopleResolverService implements Resolve<Collection>
|
||||
{
|
||||
|
@ -7,20 +7,20 @@ import { catchError } from 'rxjs/operators';
|
||||
import { SearchResut } from "../../models/search-result";
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SearchResolverService implements Resolve<SearchResut>
|
||||
{
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): SearchResut | Observable<SearchResut> | Promise<SearchResut>
|
||||
{
|
||||
let query: string = route.paramMap.get("query");
|
||||
{
|
||||
let query: string = route.paramMap.get("query");
|
||||
return this.http.get<SearchResut>("api/search/" + query).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -9,23 +9,19 @@ import { Show } from "../../models/show";
|
||||
@Injectable()
|
||||
export class ShowResolverService implements Resolve<Show>
|
||||
{
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): Show | Observable<Show> | Promise<Show>
|
||||
{
|
||||
let slug: string = route.paramMap.get("show-slug");
|
||||
return this.http.get<Show>("api/shows/" + slug).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
{
|
||||
this.snackBar.open("Show \"" + slug + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
resolve(route: ActivatedRouteSnapshot): Show | Observable<Show> | Promise<Show>
|
||||
{
|
||||
let slug: string = route.paramMap.get("show-slug");
|
||||
return this.http.get<Show>("api/shows/" + slug).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
this.snackBar.open("Show \"" + slug + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
else
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -10,23 +10,23 @@ import { WatchItem } from "../../models/watch-item";
|
||||
@Injectable()
|
||||
export class StreamResolverService implements Resolve<WatchItem>
|
||||
{
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
constructor(private http: HttpClient, private snackBar: MatSnackBar) { }
|
||||
|
||||
resolve(route: ActivatedRouteSnapshot): WatchItem | Observable<WatchItem> | Promise<WatchItem>
|
||||
{
|
||||
let item: string = route.paramMap.get("item");
|
||||
{
|
||||
let item: string = route.paramMap.get("item");
|
||||
return this.http.get<WatchItem>("api/watch/" + item).pipe(catchError((error: HttpErrorResponse) =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
{
|
||||
this.snackBar.open("Episode \"" + item + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
if (error.status == 404)
|
||||
{
|
||||
this.snackBar.open("Episode \"" + item + "\" not found.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
else
|
||||
{
|
||||
this.snackBar.open("An unknow error occured.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
}
|
||||
return EMPTY;
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
@ -1,79 +1,79 @@
|
||||
<div class="backdrop">
|
||||
<img id="backdrop" src="backdrop/{{this.show.slug}}" />
|
||||
<img id="backdrop" src="backdrop/{{this.show.slug}}" />
|
||||
</div>
|
||||
|
||||
<div class="header container pt-sm-5">
|
||||
<div class="row">
|
||||
<img class="poster d-none d-sm-block" src="poster/{{this.show.slug}}" />
|
||||
<div class="main col">
|
||||
<div class="info">
|
||||
<h1 class="title">{{this.show.title}}</h1>
|
||||
<h2 class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</h2>
|
||||
<ng-template #elseBlock><h2 class="date">{{show.startYear}}</h2></ng-template>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button mat-mini-fab matTooltipPosition="above" matTooltip="Play" class="mr-3">
|
||||
<mat-icon>play_arrow</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="this.show.trailerUrl" mat-icon-button matTooltipPosition="above" matTooltip="Trailer">
|
||||
<mat-icon>local_movies</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Download">
|
||||
<mat-icon>cloud_download</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Watched">
|
||||
<mat-icon>done</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="More">
|
||||
<mat-icon>more_horiz</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3 secondary d-none d-md-block">
|
||||
<img src="logo/{{this.show.slug}}" />
|
||||
<div class="row">
|
||||
<img class="poster d-none d-sm-block" src="poster/{{this.show.slug}}" />
|
||||
<div class="main col">
|
||||
<div class="info">
|
||||
<h1 class="title">{{this.show.title}}</h1>
|
||||
<h2 class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</h2>
|
||||
<ng-template #elseBlock><h2 class="date">{{show.startYear}}</h2></ng-template>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button mat-mini-fab matTooltipPosition="above" matTooltip="Play" class="mr-3">
|
||||
<mat-icon>play_arrow</mat-icon>
|
||||
</button>
|
||||
<button *ngIf="this.show.trailerUrl" mat-icon-button matTooltipPosition="above" matTooltip="Trailer">
|
||||
<mat-icon>local_movies</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Download">
|
||||
<mat-icon>cloud_download</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="Watched">
|
||||
<mat-icon>done</mat-icon>
|
||||
</button>
|
||||
<button mat-icon-button matTooltipPosition="above" matTooltip="More">
|
||||
<mat-icon>more_horiz</mat-icon>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3 secondary d-none d-md-block">
|
||||
<img src="logo/{{this.show.slug}}" />
|
||||
|
||||
<div>
|
||||
<p>Studio: <b><a routerLink="/studio/{{this.show.studio?.slug}}">{{this.show.studio?.name}}</a></b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<p>Studio: <b><a routerLink="/studio/{{this.show.studio?.slug}}">{{this.show.studio?.name}}</a></b></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pt-3 d-md-none">
|
||||
<div class="col">
|
||||
<p class="mr-1 d-inline-block">Studio: <b><a routerLink="/studio/{{this.show.studio?.slug}}">{{this.show.studio?.name}}</a></b></p>
|
||||
<div class="d-sm-none">
|
||||
<p>Genres: <span *ngFor="let genre of this.show.genres; let isLast = last"><b><a routerLink="/genre/{{genre.slug}}">{{genre.name}}</a></b>{{isLast ? "" : ", "}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pt-3 d-md-none">
|
||||
<div class="col">
|
||||
<p class="mr-1 d-inline-block">Studio: <b><a routerLink="/studio/{{this.show.studio?.slug}}">{{this.show.studio?.name}}</a></b></p>
|
||||
<div class="d-sm-none">
|
||||
<p>Genres: <span *ngFor="let genre of this.show.genres; let isLast = last"><b><a routerLink="/genre/{{genre.slug}}">{{genre.name}}</a></b>{{isLast ? "" : ", "}}</span></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row pt-3">
|
||||
<div class="col">
|
||||
<p class="text-justify overview">{{this.show.overview}}</p>
|
||||
</div>
|
||||
<hr class="d-none d-sm-block">
|
||||
<div class="col-3 d-none d-sm-block">
|
||||
<h3 style="opacity: .8;">Genres</h3>
|
||||
<ul>
|
||||
<li *ngFor="let genre of this.show.genres"><b><a class="genre" routerLink="/genre/{{genre.slug}}">{{genre.name}}</a></b></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row pt-3">
|
||||
<div class="col">
|
||||
<p class="text-justify overview">{{this.show.overview}}</p>
|
||||
</div>
|
||||
<hr class="d-none d-sm-block">
|
||||
<div class="col-3 d-none d-sm-block">
|
||||
<h3 style="opacity: .8;">Genres</h3>
|
||||
<ul>
|
||||
<li *ngFor="let genre of this.show.genres"><b><a class="genre" routerLink="/genre/{{genre.slug}}">{{genre.name}}</a></b></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="container-fluid mt-3">
|
||||
<mat-form-field>
|
||||
<mat-label>Season</mat-label>
|
||||
<mat-select [(value)]="season" (selectionChange)="getEpisodes()">
|
||||
<mat-option *ngFor="let season of this.show.seasons" [value]="season.seasonNumber">{{season.title}}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
<mat-form-field>
|
||||
<mat-label>Season</mat-label>
|
||||
<mat-select [(value)]="season" (selectionChange)="getEpisodes()">
|
||||
<mat-option *ngFor="let season of this.show.seasons" [value]="season.seasonNumber">{{season.title}}</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
<app-episodes-list [episodes]="episodes"></app-episodes-list>
|
||||
|
||||
<div class="container-fluid mt-5">
|
||||
<h3>Staff</h3>
|
||||
<h3>Staff</h3>
|
||||
</div>
|
||||
<app-people-list [people]="show.people"></app-people-list>
|
||||
|
@ -4,149 +4,149 @@
|
||||
|
||||
a
|
||||
{
|
||||
color: #ffffff;
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
.backdrop
|
||||
{
|
||||
margin-top: -68px;
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
margin-top: -68px;
|
||||
position: relative;
|
||||
z-index: -1;
|
||||
|
||||
> img
|
||||
{
|
||||
width: 100%;
|
||||
max-height: 75vh;
|
||||
object-fit: cover;
|
||||
min-height: 20vh;
|
||||
> img
|
||||
{
|
||||
width: 100%;
|
||||
max-height: 75vh;
|
||||
object-fit: cover;
|
||||
min-height: 20vh;
|
||||
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
min-height: 60vh;
|
||||
}
|
||||
}
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
min-height: 60vh;
|
||||
}
|
||||
}
|
||||
|
||||
&:after
|
||||
{
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.6) 100%);
|
||||
}
|
||||
&:after
|
||||
{
|
||||
content: "";
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background-image: linear-gradient(to bottom, rgba(0, 0, 0, 0) 50%, rgba(0, 0, 0, 0.6) 100%);
|
||||
}
|
||||
}
|
||||
|
||||
.header
|
||||
{
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
margin-top: -12rem;
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
margin-top: -12rem;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
margin-top: -13rem;
|
||||
}
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
margin-top: -13rem;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
margin-top: -19rem;
|
||||
}
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
margin-top: -19rem;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
margin-top: -23rem;
|
||||
}
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
margin-top: -23rem;
|
||||
}
|
||||
}
|
||||
|
||||
.poster
|
||||
{
|
||||
width: 33%;
|
||||
background-color: #333333;
|
||||
width: 33%;
|
||||
background-color: #333333;
|
||||
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 25%;
|
||||
}
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
.main
|
||||
{
|
||||
align-self: center;
|
||||
padding-left: 2.5em;
|
||||
align-self: center;
|
||||
padding-left: 2.5em;
|
||||
|
||||
.info
|
||||
{
|
||||
margin-top: -3.25rem;
|
||||
.info
|
||||
{
|
||||
margin-top: -3.25rem;
|
||||
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
margin-top: 0;
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.title
|
||||
{
|
||||
font-weight: 900 !important;
|
||||
}
|
||||
.title
|
||||
{
|
||||
font-weight: 900 !important;
|
||||
}
|
||||
|
||||
.date
|
||||
{
|
||||
font-weight: 300 !important;
|
||||
}
|
||||
}
|
||||
.date
|
||||
{
|
||||
font-weight: 300 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.buttons
|
||||
{
|
||||
> button
|
||||
{
|
||||
outline: none;
|
||||
margin: .3em;
|
||||
}
|
||||
}
|
||||
.buttons
|
||||
{
|
||||
> button
|
||||
{
|
||||
outline: none;
|
||||
margin: .3em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.secondary
|
||||
{
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
> img
|
||||
{
|
||||
max-width: 100%;
|
||||
}
|
||||
> img
|
||||
{
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
> div
|
||||
{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
> div
|
||||
{
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
> div > p
|
||||
{
|
||||
opacity: .87;
|
||||
}
|
||||
> div > p
|
||||
{
|
||||
opacity: .87;
|
||||
}
|
||||
}
|
||||
|
||||
.overview
|
||||
{
|
||||
opacity: .87;
|
||||
opacity: .87;
|
||||
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
padding-top: 2.25rem;
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
padding-top: 2.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
hr
|
||||
{
|
||||
margin: 0 10px 0 10px;
|
||||
border-right: 1px solid rgba(255, 255, 255, .60);
|
||||
border-top: 0;
|
||||
height: inherit;
|
||||
margin: 0 10px 0 10px;
|
||||
border-right: 1px solid rgba(255, 255, 255, .60);
|
||||
border-top: 0;
|
||||
height: inherit;
|
||||
}
|
||||
|
||||
.genre
|
||||
{
|
||||
opacity: .8;
|
||||
opacity: .8;
|
||||
}
|
||||
|
@ -7,76 +7,76 @@ import { Episode } from "../../models/episode";
|
||||
import { Show } from "../../models/show";
|
||||
|
||||
@Component({
|
||||
selector: 'app-show-details',
|
||||
templateUrl: './show-details.component.html',
|
||||
styleUrls: ['./show-details.component.scss']
|
||||
selector: 'app-show-details',
|
||||
templateUrl: './show-details.component.html',
|
||||
styleUrls: ['./show-details.component.scss']
|
||||
})
|
||||
export class ShowDetailsComponent implements OnInit
|
||||
{
|
||||
show: Show;
|
||||
episodes: Episode[] = null;
|
||||
season: number;
|
||||
show: Show;
|
||||
episodes: Episode[] = null;
|
||||
season: number;
|
||||
|
||||
private toolbar: HTMLElement;
|
||||
private backdrop: HTMLElement;
|
||||
private toolbar: HTMLElement;
|
||||
private backdrop: HTMLElement;
|
||||
|
||||
constructor(private route: ActivatedRoute, private http: HttpClient, private snackBar: MatSnackBar, private title: Title)
|
||||
{
|
||||
this.route.queryParams.subscribe(params =>
|
||||
{
|
||||
this.season = params["season"];
|
||||
});
|
||||
constructor(private route: ActivatedRoute, private http: HttpClient, private snackBar: MatSnackBar, private title: Title)
|
||||
{
|
||||
this.route.queryParams.subscribe(params =>
|
||||
{
|
||||
this.season = params["season"];
|
||||
});
|
||||
|
||||
this.route.data.subscribe(data =>
|
||||
{
|
||||
this.show = data.show;
|
||||
this.title.setTitle(this.show.title + " - Kyoo");
|
||||
this.route.data.subscribe(data =>
|
||||
{
|
||||
this.show = data.show;
|
||||
this.title.setTitle(this.show.title + " - Kyoo");
|
||||
|
||||
if (this.season == null || this.show.seasons.find(x => x.seasonNumber == this.season) == null)
|
||||
this.season = 1;
|
||||
if (this.season == null || this.show.seasons.find(x => x.seasonNumber == this.season) == null)
|
||||
this.season = 1;
|
||||
|
||||
this.getEpisodes();
|
||||
});
|
||||
}
|
||||
this.getEpisodes();
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit()
|
||||
{
|
||||
this.toolbar = document.getElementById("toolbar");
|
||||
this.backdrop = document.getElementById("backdrop");
|
||||
window.addEventListener("scroll", this.scroll, true);
|
||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, 0) !important`);
|
||||
}
|
||||
ngOnInit()
|
||||
{
|
||||
this.toolbar = document.getElementById("toolbar");
|
||||
this.backdrop = document.getElementById("backdrop");
|
||||
window.addEventListener("scroll", this.scroll, true);
|
||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, 0) !important`);
|
||||
}
|
||||
|
||||
ngOnDestroy()
|
||||
{
|
||||
window.removeEventListener("scroll", this.scroll, true);
|
||||
this.title.setTitle("Kyoo");
|
||||
this.toolbar.setAttribute("style", `background-color: #000000 !important`);
|
||||
}
|
||||
ngOnDestroy()
|
||||
{
|
||||
window.removeEventListener("scroll", this.scroll, true);
|
||||
this.title.setTitle("Kyoo");
|
||||
this.toolbar.setAttribute("style", `background-color: #000000 !important`);
|
||||
}
|
||||
|
||||
scroll = () =>
|
||||
{
|
||||
let opacity: number = 2 * window.scrollY / this.backdrop.clientHeight;
|
||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, ${opacity}) !important`);
|
||||
}
|
||||
scroll = () =>
|
||||
{
|
||||
let opacity: number = 2 * window.scrollY / this.backdrop.clientHeight;
|
||||
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, ${opacity}) !important`);
|
||||
}
|
||||
|
||||
getEpisodes()
|
||||
{
|
||||
if (this.show == null)
|
||||
return;
|
||||
getEpisodes()
|
||||
{
|
||||
if (this.show == null)
|
||||
return;
|
||||
|
||||
if (this.show.seasons.find(x => x.seasonNumber == this.season).episodes != null)
|
||||
this.episodes = this.show.seasons.find(x => x.seasonNumber == this.season).episodes;
|
||||
if (this.show.seasons.find(x => x.seasonNumber == this.season).episodes != null)
|
||||
this.episodes = this.show.seasons.find(x => x.seasonNumber == this.season).episodes;
|
||||
|
||||
|
||||
this.http.get<Episode[]>("api/episodes/" + this.show.slug + "/season/" + this.season).subscribe((episodes: Episode[]) =>
|
||||
{
|
||||
this.show.seasons.find(x => x.seasonNumber == this.season).episodes = episodes;
|
||||
this.episodes = episodes;
|
||||
}, error =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
this.snackBar.open("An unknow error occured while getting episodes.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
});
|
||||
}
|
||||
this.http.get<Episode[]>("api/episodes/" + this.show.slug + "/season/" + this.season).subscribe((episodes: Episode[]) =>
|
||||
{
|
||||
this.show.seasons.find(x => x.seasonNumber == this.season).episodes = episodes;
|
||||
this.episodes = episodes;
|
||||
}, error =>
|
||||
{
|
||||
console.log(error.status + " - " + error.message);
|
||||
this.snackBar.open("An unknow error occured while getting episodes.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
<div class="scroll-row mb-5">
|
||||
<div class="shows-container" #scrollView (scroll)="onScroll()">
|
||||
<a class="show" *ngFor="let show of this.shows" routerLink="/show/{{show.slug}}" href="/show/{{show.slug}}">
|
||||
<div matRipple [style.background-image]="getThumb(show.slug)"> </div>
|
||||
<p class="title">{{show.title}}</p>
|
||||
<p class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</p>
|
||||
<ng-template #elseBlock><p class="date">{{show.startYear}}</p></ng-template>
|
||||
</a>
|
||||
</div>
|
||||
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
|
||||
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
|
||||
<div class="shows-container" #scrollView (scroll)="onScroll()">
|
||||
<a class="show" *ngFor="let show of this.shows" routerLink="/show/{{show.slug}}" href="/show/{{show.slug}}">
|
||||
<div matRipple [style.background-image]="getThumb(show.slug)"> </div>
|
||||
<p class="title">{{show.title}}</p>
|
||||
<p class="date" *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</p>
|
||||
<ng-template #elseBlock><p class="date">{{show.startYear}}</p></ng-template>
|
||||
</a>
|
||||
</div>
|
||||
<button mat-raised-button color="accent" class="scrollBtn leftBtn d-none" #leftBtn (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
|
||||
<button mat-raised-button color="accent" class="scrollBtn rightBtn" #rightBtn (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
|
||||
</div>
|
||||
|
@ -4,145 +4,145 @@
|
||||
|
||||
.shows-container
|
||||
{
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
overflow-x: auto;
|
||||
min-width: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-direction: row;
|
||||
display: flex;
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
overflow-x: auto;
|
||||
min-width: 100%;
|
||||
flex-shrink: 0;
|
||||
flex-direction: row;
|
||||
|
||||
&::-webkit-scrollbar
|
||||
{
|
||||
height: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar
|
||||
{
|
||||
height: 4px;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
border-radius: 90px;
|
||||
&::-webkit-scrollbar-thumb
|
||||
{
|
||||
background-color: #999;
|
||||
border-radius: 90px;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
background-color: rgb(134, 127, 127);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.show
|
||||
{
|
||||
width: 33%;
|
||||
min-width: 120px;
|
||||
max-width: 200px;
|
||||
list-style: none;
|
||||
padding: .5em;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
width: 33%;
|
||||
min-width: 120px;
|
||||
max-width: 200px;
|
||||
list-style: none;
|
||||
padding: .5em;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
outline: none;
|
||||
flex-shrink: 0;
|
||||
flex-grow: 0;
|
||||
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 25%;
|
||||
}
|
||||
@include media-breakpoint-up(sm)
|
||||
{
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 20%;
|
||||
padding: 1em;
|
||||
}
|
||||
@include media-breakpoint-up(md)
|
||||
{
|
||||
width: 20%;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 18%;
|
||||
}
|
||||
@include media-breakpoint-up(lg)
|
||||
{
|
||||
width: 18%;
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 15%;
|
||||
}
|
||||
@include media-breakpoint-up(xl)
|
||||
{
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
|
||||
&:focus, &:hover
|
||||
{
|
||||
> div
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
}
|
||||
&:focus, &:hover
|
||||
{
|
||||
> div
|
||||
{
|
||||
outline: solid var(--accentColor);
|
||||
}
|
||||
|
||||
> .title
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
> .title
|
||||
{
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
}
|
||||
> div
|
||||
{
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-top: 147.0588%;
|
||||
background-size: cover;
|
||||
background-color: #333333;
|
||||
}
|
||||
|
||||
> p
|
||||
{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
opacity: 1;
|
||||
> p
|
||||
{
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
text-align: center;
|
||||
margin-bottom: 0px;
|
||||
opacity: 1;
|
||||
|
||||
&.date
|
||||
{
|
||||
opacity: 0.8;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
&.date
|
||||
{
|
||||
opacity: 0.8;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
.scroll-row
|
||||
{
|
||||
position: relative;
|
||||
position: relative;
|
||||
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.scrollBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
&:host-context(.hoverEnabled) &:hover
|
||||
{
|
||||
.scrollBtn
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.scrollBtn
|
||||
{
|
||||
padding: 0;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
bottom: 40%;
|
||||
display: none;
|
||||
padding: 0;
|
||||
outline: none;
|
||||
min-width: 0;
|
||||
position: absolute;
|
||||
top: 30%;
|
||||
bottom: 40%;
|
||||
display: none;
|
||||
|
||||
&.leftBtn
|
||||
{
|
||||
left: 0;
|
||||
padding-left: 10px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
&.leftBtn
|
||||
{
|
||||
left: 0;
|
||||
padding-left: 10px;
|
||||
padding-right: 2px;
|
||||
}
|
||||
|
||||
&.rightBtn
|
||||
{
|
||||
right: 0;
|
||||
padding-right: 10px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
&.rightBtn
|
||||
{
|
||||
right: 0;
|
||||
padding-right: 10px;
|
||||
padding-left: 2px;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,3 @@
|
||||
export const environment = {
|
||||
production: true
|
||||
production: true
|
||||
};
|
||||
|
@ -3,7 +3,7 @@
|
||||
// The list of file replacements can be found in `angular.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
production: false
|
||||
};
|
||||
|
||||
/*
|
||||
@ -13,4 +13,4 @@ export const environment = {
|
||||
* This import should be commented out in production mode because it will have a negative impact
|
||||
* on performance if an error is thrown.
|
||||
*/
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
// import 'zone.js/dist/zone-error'; // Included with Angular CLI.
|
||||
|
@ -1,15 +1,15 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Kyoo</title>
|
||||
<base href="/">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Kyoo</title>
|
||||
<base href="/">
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -72,8 +72,8 @@ let SubtitleManager = (function() {
|
||||
}
|
||||
|
||||
var det_C0_C1 = (C[0] * C[3]) - (C[2] * C[1]);
|
||||
var det_C0_X = (C[0] * X[1]) - (C[2] * X[0]);
|
||||
var det_X_C1 = (X[0] * C[3]) - (X[1] * C[1]);
|
||||
var det_C0_X = (C[0] * X[1]) - (C[2] * X[0]);
|
||||
var det_X_C1 = (X[0] * C[3]) - (X[1] * C[1]);
|
||||
var alpha_l = det_C0_C1 === 0 ? 0 : det_X_C1 / det_C0_C1;
|
||||
var alpha_r = det_C0_C1 === 0 ? 0 : det_C0_X / det_C0_C1;
|
||||
var segLength = norm(subtract(points[0], points[len-1]));
|
||||
@ -209,8 +209,8 @@ let SubtitleManager = (function() {
|
||||
} else if (curr.start_time < prev.end_time) {
|
||||
let [prev_start_time,prev_start_value,prev_prev_accel] = points[points.length-2];
|
||||
let last = points[points.length-1];
|
||||
last[0] = curr.start_time;
|
||||
last[1] = prev_start_value + (prev.end_value - prev_start_value) * Math.pow((curr.start_time - prev_start_time) / (prev.end_time - prev_start_time), last[2]);
|
||||
last[0] = curr.start_time;
|
||||
last[1] = prev_start_value + (prev.end_value - prev_start_value) * Math.pow((curr.start_time - prev_start_time) / (prev.end_time - prev_start_time), last[2]);
|
||||
}
|
||||
|
||||
points.push([curr.end_time,curr.end_value,curr.accel]);
|
||||
@ -251,8 +251,8 @@ let SubtitleManager = (function() {
|
||||
let combineAdjacentBlocks = text => text.replace(reAdjacentBlocks,"$1$2").replace(reAdjacentBlocks,"$1$2");
|
||||
|
||||
// Map to convert SSAv4 alignment values to ASSv4+ values.
|
||||
// 1, 2, 3, 5, 6, 7, 9, 10, 11
|
||||
let SSA_ALIGNMENT_MAP = [0, 1, 2, 3, 0, 7, 8, 9, 0, 4, 5, 6];
|
||||
// 1, 2, 3, 5, 6, 7, 9, 10, 11
|
||||
let SSA_ALIGNMENT_MAP = [0, 1, 2, 3, 0, 7, 8, 9, 0, 4, 5, 6];
|
||||
|
||||
// Alias for creating SVG elements.
|
||||
let createSVGElement = document.createElementNS.bind(document,"http://www.w3.org/2000/svg");
|
||||
@ -803,10 +803,10 @@ let SubtitleManager = (function() {
|
||||
return computedPaths[pathID];
|
||||
|
||||
path = path.toLowerCase();
|
||||
path = path.replace(/b/g,"C"); // cubic bézier curve to point 3 using point 1 and 2 as the control points
|
||||
path = path.replace(/l/g,"L"); // line-to <x>, <y>
|
||||
path = path.replace(/b/g,"C"); // cubic bézier curve to point 3 using point 1 and 2 as the control points
|
||||
path = path.replace(/l/g,"L"); // line-to <x>, <y>
|
||||
path = path.replace(/m/g,"Z M"); // move-to <x>, <y> (closing the shape first)
|
||||
path = path.replace(/n/g,"M"); // move-to <x>, <y> (without closing the shape)
|
||||
path = path.replace(/n/g,"M"); // move-to <x>, <y> (without closing the shape)
|
||||
|
||||
// extend b-spline to <x>, <y>
|
||||
// The "p" command is only supposed to be used after an "s" command,
|
||||
@ -829,7 +829,7 @@ let SubtitleManager = (function() {
|
||||
// done by copying the starting location and the first two points
|
||||
// to the end of the spline.
|
||||
// before: x0 y0 s x1 y1 x2 y2 ... c
|
||||
// after: x0 y0 s x1 y1 x2 y2 ... x0 y0 x1 y1 x2 y2
|
||||
// after: x0 y0 s x1 y1 x2 y2 ... x0 y0 x1 y1 x2 y2
|
||||
changes = true;
|
||||
while (changes) {
|
||||
changes = false;
|
||||
@ -842,10 +842,10 @@ let SubtitleManager = (function() {
|
||||
// 3rd degree uniform b-spline
|
||||
// SVG doesn't have this, so we have convert them to a series of
|
||||
// Bézier curves.
|
||||
// x0 y0 s x1 y1 x2 y2 x3 y3 x4 y4 x5 y5
|
||||
// |-----------------------| Bézier 1
|
||||
// |---------------------| Bézier 2
|
||||
// |---------------------| Bézier 3
|
||||
// x0 y0 s x1 y1 x2 y2 x3 y3 x4 y4 x5 y5
|
||||
// |-----------------------| Bézier 1
|
||||
// |---------------------| Bézier 2
|
||||
// |---------------------| Bézier 3
|
||||
// Since the start point for a Bézier is different from a spline,
|
||||
// we also need to add a move before the first Bézier and after the
|
||||
// last Bézier. However, the bounding box of b-splines is different
|
||||
@ -1099,8 +1099,8 @@ let SubtitleManager = (function() {
|
||||
let newPieces = [];
|
||||
for (let piece of pieces) {
|
||||
// convert text
|
||||
// from "{overide1}some text here{overridde2}more text ..."
|
||||
// to [["override1",["some"," ","text"," ","here"]], ["override2",["more"," ","text"]], ...]
|
||||
// from "{overide1}some text here{overridde2}more text ..."
|
||||
// to [["override1",["some"," ","text"," ","here"]], ["override2",["more"," ","text"]], ...]
|
||||
// taking care not to split on non-breaking spaces or paths
|
||||
let data = piece.text.split("{").slice(1).map(a => a.split("}")).map(b => [b[0], isPath(b[0]) ? [b[1]] : b[1].split(/([^\S\xA0]+)/g)]);
|
||||
|
||||
@ -1230,19 +1230,19 @@ let SubtitleManager = (function() {
|
||||
if (slice.width) slices.push(slice);
|
||||
|
||||
// Bubble pieces down through the slices while keeping the constraints:
|
||||
// don't make a line shorter than the one after it
|
||||
// don't include whitespace at the start or end
|
||||
// don't make a line shorter than the one after it
|
||||
// don't include whitespace at the start or end
|
||||
let bubbled, last_slice = slices.length - 1;
|
||||
do {
|
||||
bubbled = false;
|
||||
for (let i = last_slice; i > 0; --i) {
|
||||
let curr = slices[i], prev = slices[i-1];
|
||||
|
||||
/* prev curr
|
||||
|----------| |--| Before
|
||||
XXXXXXXX XX XXXX
|
||||
|------| |------| After
|
||||
prev curr
|
||||
/* prev curr
|
||||
|----------| |--| Before
|
||||
XXXXXXXX XX XXXX
|
||||
|------| |------| After
|
||||
prev curr
|
||||
*/
|
||||
while (true) {
|
||||
// Find the next non-whitespace piece
|
||||
@ -1376,19 +1376,19 @@ let SubtitleManager = (function() {
|
||||
if (slice.width) slices.unshift(slice);
|
||||
|
||||
// Bubble pieces up through the slices while keeping the constraints:
|
||||
// don't make a line shorter than the one before it
|
||||
// don't include whitespace at the start or end
|
||||
// don't make a line shorter than the one before it
|
||||
// don't include whitespace at the start or end
|
||||
let bubbled, last_slice = slices.length - 1;
|
||||
do {
|
||||
bubbled = false;
|
||||
for (let i = 0; i < last_slice; ++i) {
|
||||
let curr = slices[i], next = slices[i+1];
|
||||
|
||||
/* curr next
|
||||
|--| |----------| Before
|
||||
XXXX XX XXXXXXXX
|
||||
|------| |------| After
|
||||
curr next
|
||||
/* curr next
|
||||
|--| |----------| Before
|
||||
XXXX XX XXXXXXXX
|
||||
|------| |------| After
|
||||
curr next
|
||||
*/
|
||||
while (true) {
|
||||
// Find the next non-whitespace piece
|
||||
@ -2196,8 +2196,8 @@ let SubtitleManager = (function() {
|
||||
this.group = null;
|
||||
|
||||
this.Margin = {"L" : (data.MarginL && parseInt(data.MarginL,10)) || renderer.styles[data.Style].MarginL,
|
||||
"R" : (data.MarginR && parseInt(data.MarginR,10)) || renderer.styles[data.Style].MarginR,
|
||||
"V" : (data.MarginV && parseInt(data.MarginV,10)) || renderer.styles[data.Style].MarginV};
|
||||
"R" : (data.MarginR && parseInt(data.MarginR,10)) || renderer.styles[data.Style].MarginR,
|
||||
"V" : (data.MarginV && parseInt(data.MarginV,10)) || renderer.styles[data.Style].MarginV};
|
||||
|
||||
this.time = {"start" : timeConvert(data.Start), "end" : timeConvert(data.End)};
|
||||
this.time.milliseconds = (this.time.end - this.time.start) * 1000;
|
||||
@ -2982,8 +2982,8 @@ let SubtitleManager = (function() {
|
||||
|
||||
// Create the font-face CSS.
|
||||
css += "@font-face {\n";
|
||||
css += " font-family: \"" + fontname + "\";\n";
|
||||
css += " src: url(data:font/" + submime + ";charset=utf-8;base64," + btoa(fontdata) + ");\n";
|
||||
css += " font-family: \"" + fontname + "\";\n";
|
||||
css += " src: url(data:font/" + submime + ";charset=utf-8;base64," + btoa(fontdata) + ");\n";
|
||||
css += "}\n\n";
|
||||
}
|
||||
|
||||
|
@ -6,8 +6,8 @@ import { environment } from './environments/environment';
|
||||
import "hammerjs"
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.error(err));
|
||||
.catch(err => console.error(err));
|
||||
|
@ -2,11 +2,11 @@ import { Show } from "./show";
|
||||
|
||||
export interface Collection
|
||||
{
|
||||
slug: string;
|
||||
name: string;
|
||||
poster: string;
|
||||
overview: string;
|
||||
startYear: number,
|
||||
slug: string;
|
||||
name: string;
|
||||
poster: string;
|
||||
overview: string;
|
||||
startYear: number,
|
||||
endYear: number,
|
||||
shows: Show[];
|
||||
shows: Show[];
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
export interface Episode
|
||||
{
|
||||
seasonNumber: number;
|
||||
episodeNumber: number;
|
||||
title: string;
|
||||
thumb: string;
|
||||
link: string;
|
||||
overview: string;
|
||||
releaseDate;
|
||||
runtime: number;
|
||||
seasonNumber: number;
|
||||
episodeNumber: number;
|
||||
title: string;
|
||||
thumb: string;
|
||||
link: string;
|
||||
overview: string;
|
||||
releaseDate;
|
||||
runtime: number;
|
||||
externalIDs: string;
|
||||
showTitle: string;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export interface Genre
|
||||
{
|
||||
slug: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
name: string;
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
export interface People
|
||||
{
|
||||
slug: string;
|
||||
name: string;
|
||||
role: string;
|
||||
type: string;
|
||||
slug: string;
|
||||
name: string;
|
||||
role: string;
|
||||
type: string;
|
||||
|
||||
externalIDs: string;
|
||||
externalIDs: string;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ import { Episode } from "./episode";
|
||||
|
||||
export interface Season
|
||||
{
|
||||
seasonNumber: number;
|
||||
title: string;
|
||||
overview: string;
|
||||
episodes: Episode[];
|
||||
seasonNumber: number;
|
||||
title: string;
|
||||
overview: string;
|
||||
episodes: Episode[];
|
||||
}
|
||||
|
@ -5,20 +5,20 @@ import { Studio } from "./studio";
|
||||
|
||||
export interface Show
|
||||
{
|
||||
slug: string;
|
||||
title: string;
|
||||
Aliases: string[];
|
||||
overview: string;
|
||||
genres: Genre[];
|
||||
status: string;
|
||||
studio: Studio;
|
||||
people: People[];
|
||||
seasons: Season[];
|
||||
trailerUrl: string;
|
||||
isCollection: boolean;
|
||||
slug: string;
|
||||
title: string;
|
||||
Aliases: string[];
|
||||
overview: string;
|
||||
genres: Genre[];
|
||||
status: string;
|
||||
studio: Studio;
|
||||
people: People[];
|
||||
seasons: Season[];
|
||||
trailerUrl: string;
|
||||
isCollection: boolean;
|
||||
|
||||
startYear: number;
|
||||
endYear : number;
|
||||
startYear: number;
|
||||
endYear : number;
|
||||
|
||||
externalIDs: string;
|
||||
externalIDs: string;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
export interface Studio
|
||||
{
|
||||
slug: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
name: string;
|
||||
}
|
||||
|
@ -2,31 +2,31 @@ import { Episode } from "./episode";
|
||||
|
||||
export interface WatchItem
|
||||
{
|
||||
showTitle: string;
|
||||
showSlug: string;
|
||||
seasonNumber: number;
|
||||
episodeNumber: number;
|
||||
title: string;
|
||||
link: string;
|
||||
duration: number;
|
||||
releaseDate;
|
||||
showTitle: string;
|
||||
showSlug: string;
|
||||
seasonNumber: number;
|
||||
episodeNumber: number;
|
||||
title: string;
|
||||
link: string;
|
||||
duration: number;
|
||||
releaseDate;
|
||||
|
||||
previousEpisode: string;
|
||||
nextEpisode: Episode;
|
||||
previousEpisode: string;
|
||||
nextEpisode: Episode;
|
||||
|
||||
container: string;
|
||||
video: Track;
|
||||
audios: Track[];
|
||||
subtitles: Track[];
|
||||
audios: Track[];
|
||||
subtitles: Track[];
|
||||
}
|
||||
|
||||
export interface Track
|
||||
{
|
||||
displayName: string;
|
||||
title: string;
|
||||
language: string;
|
||||
isDefault: boolean;
|
||||
isForced: boolean;
|
||||
codec: string;
|
||||
link: string;
|
||||
displayName: string;
|
||||
title: string;
|
||||
language: string;
|
||||
isDefault: boolean;
|
||||
isForced: boolean;
|
||||
codec: string;
|
||||
link: string;
|
||||
}
|
||||
|
@ -3,9 +3,9 @@
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
@ -19,14 +19,14 @@
|
||||
*/
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/**
|
||||
* Web Animations `@angular/platform-browser/animations`
|
||||
* Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
|
||||
* Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
|
||||
*/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
/**
|
||||
* By default, zone.js will patch all possible macroTask and DomEvents
|
||||
@ -45,17 +45,17 @@
|
||||
* (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
|
||||
* (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
|
||||
*
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
* in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
|
||||
* with the following flag, it will bypass `zone.js` patch for IE/Edge
|
||||
*
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
* (window as any).__Zone_enable_cross_context_check = true;
|
||||
*
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
|
@ -6,10 +6,10 @@
|
||||
@import "~bootstrap/scss/variables";
|
||||
|
||||
$theme-colors: (
|
||||
"primary": #0a1128,
|
||||
"secondary": #000000,
|
||||
"accentColor": #e23c00,
|
||||
"textPrimary": #ffffff
|
||||
"primary": #0a1128,
|
||||
"secondary": #000000,
|
||||
"accentColor": #e23c00,
|
||||
"textPrimary": #ffffff
|
||||
);
|
||||
|
||||
$body-bg: theme-color("primary");
|
||||
@ -18,12 +18,12 @@ $font-family-base: "Roboto", Arial, sans-serif;
|
||||
|
||||
p
|
||||
{
|
||||
opacity: .6;
|
||||
opacity: .6;
|
||||
}
|
||||
|
||||
h6
|
||||
{
|
||||
opacity: .87;
|
||||
opacity: .87;
|
||||
}
|
||||
|
||||
@import "~bootstrap/scss/bootstrap";
|
||||
@ -43,63 +43,63 @@ $theme: mat-dark-theme($primary, $accent);
|
||||
|
||||
.mat-ripple-element
|
||||
{
|
||||
background-color: rgba(255, 255, 255, .3) !important;
|
||||
background-color: rgba(255, 255, 255, .3) !important;
|
||||
}
|
||||
|
||||
.mat-card-header-text
|
||||
{
|
||||
margin: 0 5px !important;
|
||||
margin: 0 5px !important;
|
||||
}
|
||||
|
||||
//Material Icons
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(/iconfont/MaterialIcons-Regular.eot); /* For IE6-8 */
|
||||
src: local('Material Icons'),
|
||||
local('MaterialIcons-Regular'),
|
||||
url(/iconfont/MaterialIcons-Regular.woff2) format('woff2'),
|
||||
url(/iconfont/MaterialIcons-Regular.woff) format('woff'),
|
||||
url(/iconfont/MaterialIcons-Regular.ttf) format('truetype');
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: url(/iconfont/MaterialIcons-Regular.eot); /* For IE6-8 */
|
||||
src: local('Material Icons'),
|
||||
local('MaterialIcons-Regular'),
|
||||
url(/iconfont/MaterialIcons-Regular.woff2) format('woff2'),
|
||||
url(/iconfont/MaterialIcons-Regular.woff) format('woff'),
|
||||
url(/iconfont/MaterialIcons-Regular.ttf) format('truetype');
|
||||
}
|
||||
|
||||
.material-icons
|
||||
{
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px; /* Preferred icon size */
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
/* Support for all WebKit browsers. */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
/* Support for Safari and Chrome. */
|
||||
text-rendering: optimizeLegibility;
|
||||
/* Support for Firefox. */
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
/* Support for IE. */
|
||||
font-feature-settings: 'liga';
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
font-size: 24px; /* Preferred icon size */
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
text-transform: none;
|
||||
letter-spacing: normal;
|
||||
word-wrap: normal;
|
||||
white-space: nowrap;
|
||||
direction: ltr;
|
||||
/* Support for all WebKit browsers. */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
/* Support for Safari and Chrome. */
|
||||
text-rendering: optimizeLegibility;
|
||||
/* Support for Firefox. */
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
/* Support for IE. */
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
|
||||
mat-icon
|
||||
{
|
||||
vertical-align: middle;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.snackError
|
||||
{
|
||||
background-color: theme-color("accentColor");
|
||||
color: theme-color("textPrimary");
|
||||
background-color: theme-color("accentColor");
|
||||
color: theme-color("textPrimary");
|
||||
}
|
||||
|
||||
.scroll-row
|
||||
{
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
@ -3,16 +3,16 @@
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
|
@ -3,157 +3,157 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
||||
var detect_browser_1 = require("detect-browser");
|
||||
var method;
|
||||
(function (method) {
|
||||
method["direct"] = "Direct Play";
|
||||
method["transmux"] = "Transmux";
|
||||
method["transcode"] = "Transcode";
|
||||
method["direct"] = "Direct Play";
|
||||
method["transmux"] = "Transmux";
|
||||
method["transcode"] = "Transcode";
|
||||
})(method = exports.method || (exports.method = {}));
|
||||
;
|
||||
var SupportList = /** @class */ (function () {
|
||||
function SupportList() {
|
||||
}
|
||||
return SupportList;
|
||||
function SupportList() {
|
||||
}
|
||||
return SupportList;
|
||||
}());
|
||||
exports.SupportList = SupportList;
|
||||
function getPlaybackMethod(player, item) {
|
||||
var supportList = getWhatIsSupported(player, item);
|
||||
if (supportList.container) {
|
||||
if (supportList.videoCodec && supportList.audioCodec)
|
||||
return method.direct;
|
||||
return method.transcode;
|
||||
}
|
||||
if (supportList.videoCodec && supportList.audioCodec)
|
||||
return method.transmux;
|
||||
return method.transcode;
|
||||
var supportList = getWhatIsSupported(player, item);
|
||||
if (supportList.container) {
|
||||
if (supportList.videoCodec && supportList.audioCodec)
|
||||
return method.direct;
|
||||
return method.transcode;
|
||||
}
|
||||
if (supportList.videoCodec && supportList.audioCodec)
|
||||
return method.transmux;
|
||||
return method.transcode;
|
||||
}
|
||||
exports.getPlaybackMethod = getPlaybackMethod;
|
||||
function getWhatIsSupported(player, item) {
|
||||
var supportList = new SupportList();
|
||||
var browser = detect_browser_1.detect();
|
||||
if (!browser) {
|
||||
supportList.container = false;
|
||||
supportList.videoCodec = false;
|
||||
supportList.audioCodec = false;
|
||||
}
|
||||
else {
|
||||
supportList.container = containerIsSupported(player, item.container, browser.name) && item.audios.length <= 1;
|
||||
supportList.videoCodec = videoCodecIsSupported(player, item.video.codec, browser.name);
|
||||
supportList.audioCodec = audioCodecIsSupported(player, item.audios.map(function (value) { return value.codec; }), browser.name);
|
||||
}
|
||||
return (supportList);
|
||||
var supportList = new SupportList();
|
||||
var browser = detect_browser_1.detect();
|
||||
if (!browser) {
|
||||
supportList.container = false;
|
||||
supportList.videoCodec = false;
|
||||
supportList.audioCodec = false;
|
||||
}
|
||||
else {
|
||||
supportList.container = containerIsSupported(player, item.container, browser.name) && item.audios.length <= 1;
|
||||
supportList.videoCodec = videoCodecIsSupported(player, item.video.codec, browser.name);
|
||||
supportList.audioCodec = audioCodecIsSupported(player, item.audios.map(function (value) { return value.codec; }), browser.name);
|
||||
}
|
||||
return (supportList);
|
||||
}
|
||||
exports.getWhatIsSupported = getWhatIsSupported;
|
||||
function containerIsSupported(player, container, browser) {
|
||||
var supported = false;
|
||||
switch (container) {
|
||||
case "asf":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "avi":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mpg":
|
||||
case "mpeg":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "flv":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "3gp":
|
||||
case "mts":
|
||||
case "trp":
|
||||
case "vob":
|
||||
case "vro":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "mov":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome";
|
||||
break;
|
||||
case "m2ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "wmv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mp4":
|
||||
case "m4v":
|
||||
supported = true;
|
||||
break;
|
||||
case "mkv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge";
|
||||
if (supported)
|
||||
break;
|
||||
if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv"))
|
||||
supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return supported;
|
||||
var supported = false;
|
||||
switch (container) {
|
||||
case "asf":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "avi":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mpg":
|
||||
case "mpeg":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "flv":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "3gp":
|
||||
case "mts":
|
||||
case "trp":
|
||||
case "vob":
|
||||
case "vro":
|
||||
supported = browser == "tizen" || browser == "orsay";
|
||||
break;
|
||||
case "mov":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge" || browser == "chrome";
|
||||
break;
|
||||
case "m2ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "wmv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
//videoAudioCodecs = [];
|
||||
break;
|
||||
case "ts":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "edge";
|
||||
break;
|
||||
case "mp4":
|
||||
case "m4v":
|
||||
supported = true;
|
||||
break;
|
||||
case "mkv":
|
||||
supported = browser == "tizen" || browser == "orsay" || browser == "chrome" || browser == "edge";
|
||||
if (supported)
|
||||
break;
|
||||
if (player.canPlayType("video/x-matroska") || player.canPlayType("video/mkv"))
|
||||
supported = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
//SHOULD CHECK FOR DEPTH (8bits ok but 10bits unsuported for almost every browsers)
|
||||
function videoCodecIsSupported(player, codec, browser) {
|
||||
switch (codec) {
|
||||
case "h264":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool
|
||||
case "h265":
|
||||
case "hevc":
|
||||
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
|
||||
return true;
|
||||
//SHOULD SUPPORT CHROMECAST ULTRA
|
||||
// if (browser.chromecast)
|
||||
// {
|
||||
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
// if (isChromecastUltra)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
|
||||
case "mpeg2video":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "vc1":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "msmpeg4v2":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "vp8":
|
||||
return !!player.canPlayType('video/webm; codecs="vp8');
|
||||
case "vp9":
|
||||
return !!player.canPlayType('video/webm; codecs="vp9"');
|
||||
case "vorbis":
|
||||
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
switch (codec) {
|
||||
case "h264":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.42E01E, mp4a.40.2"'); //The !! is used to parse the string as a bool
|
||||
case "h265":
|
||||
case "hevc":
|
||||
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
|
||||
return true;
|
||||
//SHOULD SUPPORT CHROMECAST ULTRA
|
||||
// if (browser.chromecast)
|
||||
// {
|
||||
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
// if (isChromecastUltra)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
|
||||
case "mpeg2video":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "vc1":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "msmpeg4v2":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "vp8":
|
||||
return !!player.canPlayType('video/webm; codecs="vp8');
|
||||
case "vp9":
|
||||
return !!player.canPlayType('video/webm; codecs="vp9"');
|
||||
case "vorbis":
|
||||
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//SHOULD CHECK FOR NUMBER OF AUDIO CHANNEL (2 ok but 5 not in some browsers)
|
||||
function audioCodecIsSupported(player, codecs, browser) {
|
||||
for (var _i = 0, codecs_1 = codecs; _i < codecs_1.length; _i++) {
|
||||
var codec = codecs_1[_i];
|
||||
switch (codec) {
|
||||
case "mp3":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') ||
|
||||
!!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"');
|
||||
case "aac":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"');
|
||||
case "mp2":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "pcm_s16le":
|
||||
case "pcm_s24le":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "aac_latm":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "opus":
|
||||
return !!player.canPlayType('audio/ogg; codecs="opus"');
|
||||
case "flac":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (var _i = 0, codecs_1 = codecs; _i < codecs_1.length; _i++) {
|
||||
var codec = codecs_1[_i];
|
||||
switch (codec) {
|
||||
case "mp3":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.69"') ||
|
||||
!!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.6B"');
|
||||
case "aac":
|
||||
return !!player.canPlayType('video/mp4; codecs="avc1.640029, mp4a.40.2"');
|
||||
case "mp2":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "pcm_s16le":
|
||||
case "pcm_s24le":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
case "aac_latm":
|
||||
return browser == "orsay" || browser == "tizen";
|
||||
case "opus":
|
||||
return !!player.canPlayType('audio/ogg; codecs="opus"');
|
||||
case "flac":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=playbackMethodDetector.js.map
|
@ -121,16 +121,16 @@ function videoCodecIsSupported(player: HTMLVideoElement, codec: string, browser:
|
||||
case "hevc":
|
||||
if (browser == "tizen" || browser == "orsay" || browser == "xboxOne" || browser == "ios")
|
||||
return true;
|
||||
//SHOULD SUPPORT CHROMECAST ULTRA
|
||||
// if (browser.chromecast)
|
||||
// {
|
||||
//SHOULD SUPPORT CHROMECAST ULTRA
|
||||
// if (browser.chromecast)
|
||||
// {
|
||||
|
||||
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
// if (isChromecastUltra)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// var isChromecastUltra = userAgent.indexOf('aarch64') !== -1;
|
||||
// if (isChromecastUltra)
|
||||
// {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
return !!player.canPlayType('video/hevc; codecs="hevc, aac"');
|
||||
case "mpeg2video":
|
||||
return browser == "orsay" || browser == "tizen" || browser == "edge";
|
||||
@ -145,7 +145,7 @@ function videoCodecIsSupported(player: HTMLVideoElement, codec: string, browser:
|
||||
case "vorbis":
|
||||
return browser == "orsay" || browser == "tizen" || !!player.canPlayType('video/webm; codecs="vp8');
|
||||
default:
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -175,5 +175,5 @@ function audioCodecIsSupported(player: HTMLVideoElement, codecs: string[], brows
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user