Creating a few components for the web app.

This commit is contained in:
Zoe Roux 2019-08-13 02:12:53 +02:00
parent 5c3547fe61
commit e27bac2c56
19 changed files with 388 additions and 55 deletions

View File

@ -1,8 +1,17 @@
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { BrowseComponent } from './browse/browse.component';
import { ShowDetailsComponent } from './show-details/show-details.component';
import { NotFoundComponent } from './not-found/not-found.component';
const routes: Routes = [];
const routes: Routes = [
{ path: "browse", component: BrowseComponent, pathMatch: "full" },
{ path: "browse/:library-slug", component: BrowseComponent },
{ path: "shows/:show-slug", component: ShowDetailsComponent },
{ path: "**", component: NotFoundComponent }
];
@NgModule({
imports: [RouterModule.forRoot(routes)],

View File

@ -1,18 +1,37 @@
<nav class="navbar fixed-top navbar-dark bg-dark">
<a class="navbar-brand" routerLink="/">
Kyoo
</a>
<header style="height: 64px;">
<nav class="navbar fixed-top navbar-dark bg-dark">
<a class="navbar-brand ml-3" routerLink="/">
Kyoo
</a>
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" routerLink="/browse" routerLinkActive="active">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>
</nav>
<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>
<main>
<ul class="navbar-nav flex-row ml-auto">
<li class="nav-item icon">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<title>Search</title>
<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path>
</svg>
</li>
<li class="nav-item">
<a class="icon" routerLink="/login" routerLinkActive="active">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<title>Account</title>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 3c1.66 0 3 1.34 3 3s-1.34 3-3 3-3-1.34-3-3 1.34-3 3-3zm0 14.2c-2.5 0-4.71-1.28-6-3.22.03-1.99 4-3.08 6-3.08 1.99 0 5.97 1.09 6 3.08-1.29 1.94-3.5 3.22-6 3.22z" />
</svg>
</a>
</li>
</ul>
</nav>
</header>
<main >
<router-outlet></router-outlet>
</main>

View File

@ -3,15 +3,28 @@
justify-content: left;
}
.navbar-nav
.nav-link
{
flex-direction: row;
padding: 12px;
}
.nav-item
.icon
{
> a
padding: 8px;
display: inline-block;
> svg
{
padding: 16px;
fill: #d3d3d3;
}
&:hover
{
cursor: pointer;
> svg
{
fill: #ffffff;
}
}
}

View File

@ -4,10 +4,16 @@ import { NgModule } from '@angular/core';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { NotFoundComponent } from './not-found/not-found.component';
import { BrowseComponent } from './browse/browse.component';
import { ShowDetailsComponent } from './show-details/show-details.component';
@NgModule({
declarations: [
AppComponent
AppComponent,
NotFoundComponent,
BrowseComponent,
ShowDetailsComponent
],
imports: [
BrowserModule,

View File

@ -0,0 +1,8 @@
<div>
<a class="show" *ngFor="let show of this.shows" routerLink="/shows/{{show.slug}}">
<img src="{{show.imgPrimary}}" />
<p>{{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>

View File

@ -0,0 +1,54 @@
@import "~bootstrap//scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss//mixins/breakpoints";
.show
{
width: 33%;
list-style: none;
padding: 1em;
display: inline-block;
text-decoration: none;
color: initial;
@include media-breakpoint-up(md)
{
width: 25%;
}
@include media-breakpoint-up(lg)
{
width: 20%;
}
@include media-breakpoint-up(xl)
{
width: 18%;
}
> img
{
max-width: 100%;
max-height: 100%;
}
> p
{
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
text-align: center;
margin-bottom: 0px;
}
&:hover
{
cursor: pointer;
}
}
.date
{
opacity: 0.8;
font-size: 0.8em;
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowseComponent } from './browse.component';
describe('BrowseComponent', () => {
let component: BrowseComponent;
let fixture: ComponentFixture<BrowseComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ BrowseComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(BrowseComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,45 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-browse',
templateUrl: './browse.component.html',
styleUrls: ['./browse.component.scss']
})
export class BrowseComponent implements OnInit
{
shows: Show[];
private watch: any;
constructor(private http: HttpClient, private route: ActivatedRoute) { }
ngOnInit()
{
this.watch = this.route.params.subscribe(params =>
{
var slug: string = params["library-slug"];
if (slug == null)
{
this.http.get<Show[]>("api/shows").subscribe(result =>
{
this.shows = result;
}, error => console.log(error));
}
else
{
this.http.get<Show[]>("api/library/" + slug).subscribe(result =>
{
this.shows = result;
}, error => console.log(error));
}
});
}
ngOnDestroy()
{
this.watch.unsubscribe();
}
}

View File

@ -0,0 +1,9 @@
<br/>
<br/>
<br/>
<br/>
<br/>
<div class="text-center">
<h1>404 Error</h1>
<p>The page you requested was not found.</p>
</div>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { NotFoundComponent } from './not-found.component';
describe('NotFoundComponent', () => {
let component: NotFoundComponent;
let fixture: ComponentFixture<NotFoundComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ NotFoundComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(NotFoundComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,15 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-not-found',
templateUrl: './not-found.component.html',
styleUrls: ['./not-found.component.scss']
})
export class NotFoundComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -0,0 +1 @@
<p>Should display show details of: {{this.show.title}}</p>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ShowDetailsComponent } from './show-details.component';
describe('ShowDetailsComponent', () => {
let component: ShowDetailsComponent;
let fixture: ComponentFixture<ShowDetailsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ShowDetailsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ShowDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,36 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { HttpClient } from '@angular/common/http';
@Component({
selector: 'app-show-details',
templateUrl: './show-details.component.html',
styleUrls: ['./show-details.component.scss']
})
export class ShowDetailsComponent implements OnInit
{
show: Show;
private watch: any;
constructor(private http: HttpClient, private route: ActivatedRoute) { }
ngOnInit()
{
this.watch = this.route.params.subscribe(params =>
{
var slug: string = params["show-slug"];
this.http.get<Show>("api/shows/" + slug).subscribe(result =>
{
this.show = result;
}, error => console.log(error));
});
}
ngOnDestroy()
{
this.watch.unsubscribe();
}
}

View File

@ -0,0 +1,21 @@
interface Show
{
id: number;
Slug: string;
title: string;
//IEnumerable < > Aliases;
Path: string;
Overview: string;
//IEnumerable < > Genres;
//Status ? Status;
StartYear: number;
EndYear : number;
ImgPrimary: string;
ImgThumb: string;
ImgLogo: string;
ImgBackdrop: string;
ExternalIDs: string;
}

View File

@ -46,40 +46,8 @@ namespace Kyoo.InternalAPI
foreach (string file in files)
{
if(IsVideo(file) && !libraryManager.IsEpisodeRegistered(file))
{
string patern = config.GetValue<string>("regex");
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
Match match = regex.Match(file);
string showPath = Path.GetDirectoryName(file);
string showName = match.Groups["ShowTitle"].Value;
bool seasonSuccess = long.TryParse(match.Groups["Season"].Value, out long seasonNumber);
bool episodeSucess = long.TryParse(match.Groups["Episode"].Value, out long episodeNumber);
string showProviderIDs;
if (!libraryManager.IsShowRegistered(showPath, out long showID))
{
Show show = await metadataProvider.GetShowFromName(showName, showPath);
showProviderIDs = show.ExternalIDs;
showID = libraryManager.RegisterShow(show);
}
else
showProviderIDs = libraryManager.GetShowExternalIDs(showID);
if(!libraryManager.IsSeasonRegistered(showID, seasonNumber, out long seasonID))
{
Season season = await metadataProvider.GetSeason(showName, seasonNumber);
season.ShowID = showID;
seasonID = libraryManager.RegisterSeason(season);
}
Episode episode = await metadataProvider.GetEpisode(showProviderIDs, seasonNumber, episodeNumber);
episode.ShowID = showID;
episode.SeasonID = seasonID;
episode.Path = file;
libraryManager.RegisterEpisode(episode);
}
if (IsVideo(file))
await TryRegisterEpisode(file);
}
}
@ -111,6 +79,11 @@ namespace Kyoo.InternalAPI
private void FileCreated(object sender, FileSystemEventArgs e)
{
Debug.WriteLine("&File Created at " + e.FullPath);
if (IsVideo(e.FullPath))
{
Debug.WriteLine("&Created file is a video");
_ = TryRegisterEpisode(e.FullPath);
}
}
private void FileChanged(object sender, FileSystemEventArgs e)
@ -129,6 +102,47 @@ namespace Kyoo.InternalAPI
}
private async Task TryRegisterEpisode(string path)
{
if (!libraryManager.IsEpisodeRegistered(path))
{
string patern = config.GetValue<string>("regex");
Regex regex = new Regex(patern, RegexOptions.IgnoreCase);
Match match = regex.Match(path);
string showPath = Path.GetDirectoryName(path);
string showName = match.Groups["ShowTitle"].Value;
bool seasonSuccess = long.TryParse(match.Groups["Season"].Value, out long seasonNumber);
bool episodeSucess = long.TryParse(match.Groups["Episode"].Value, out long episodeNumber);
string showProviderIDs;
if (!libraryManager.IsShowRegistered(showPath, out long showID))
{
Show show = await metadataProvider.GetShowFromName(showName, showPath);
showProviderIDs = show.ExternalIDs;
showID = libraryManager.RegisterShow(show);
}
else
showProviderIDs = libraryManager.GetShowExternalIDs(showID);
if (!libraryManager.IsSeasonRegistered(showID, seasonNumber, out long seasonID))
{
Season season = await metadataProvider.GetSeason(showName, seasonNumber);
season.ShowID = showID;
seasonID = libraryManager.RegisterSeason(season);
}
Episode episode = await metadataProvider.GetEpisode(showProviderIDs, seasonNumber, episodeNumber);
episode.ShowID = showID;
episode.SeasonID = seasonID;
episode.Path = path;
libraryManager.RegisterEpisode(episode);
}
}
private static readonly string[] videoExtensions = { ".webm", ".mkv", ".flv", ".vob", ".ogg", ".ogv", ".avi", ".mts", ".m2ts", ".ts", ".mov", ".qt", ".asf", ".mp4", ".m4p", ".m4v", ".mpg", ".mp2", ".mpeg", ".mpe", ".mpv", ".m2v", ".3gp", ".3g2" };
private bool IsVideo(string filePath)

View File

@ -29,6 +29,14 @@
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<ItemGroup>
<None Remove="ClientApp\src\models\show.ts" />
</ItemGroup>
<ItemGroup>
<TypeScriptCompile Include="ClientApp\src\models\show.ts" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">