diff --git a/Kyoo/ClientApp/src/app/app-routing.module.ts b/Kyoo/ClientApp/src/app/app-routing.module.ts
index 06c73426..763aef18 100644
--- a/Kyoo/ClientApp/src/app/app-routing.module.ts
+++ b/Kyoo/ClientApp/src/app/app-routing.module.ts
@@ -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)],
diff --git a/Kyoo/ClientApp/src/app/app.component.html b/Kyoo/ClientApp/src/app/app.component.html
index 1c80b79c..310f8265 100644
--- a/Kyoo/ClientApp/src/app/app.component.html
+++ b/Kyoo/ClientApp/src/app/app.component.html
@@ -1,18 +1,37 @@
-
+
+
+
diff --git a/Kyoo/ClientApp/src/app/app.component.scss b/Kyoo/ClientApp/src/app/app.component.scss
index 0cbb2677..0ae6493c 100644
--- a/Kyoo/ClientApp/src/app/app.component.scss
+++ b/Kyoo/ClientApp/src/app/app.component.scss
@@ -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;
+ }
}
}
diff --git a/Kyoo/ClientApp/src/app/app.module.ts b/Kyoo/ClientApp/src/app/app.module.ts
index 3f0338cb..19dc2c28 100644
--- a/Kyoo/ClientApp/src/app/app.module.ts
+++ b/Kyoo/ClientApp/src/app/app.module.ts
@@ -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,
diff --git a/Kyoo/ClientApp/src/app/browse/browse.component.html b/Kyoo/ClientApp/src/app/browse/browse.component.html
new file mode 100644
index 00000000..f05a7a86
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/browse/browse.component.html
@@ -0,0 +1,8 @@
+
diff --git a/Kyoo/ClientApp/src/app/browse/browse.component.scss b/Kyoo/ClientApp/src/app/browse/browse.component.scss
new file mode 100644
index 00000000..360e1c68
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/browse/browse.component.scss
@@ -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;
+}
diff --git a/Kyoo/ClientApp/src/app/browse/browse.component.spec.ts b/Kyoo/ClientApp/src/app/browse/browse.component.spec.ts
new file mode 100644
index 00000000..6a60dfb5
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/browse/browse.component.spec.ts
@@ -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;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ BrowseComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(BrowseComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/Kyoo/ClientApp/src/app/browse/browse.component.ts b/Kyoo/ClientApp/src/app/browse/browse.component.ts
new file mode 100644
index 00000000..ec67ea62
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/browse/browse.component.ts
@@ -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("api/shows").subscribe(result =>
+ {
+ this.shows = result;
+ }, error => console.log(error));
+ }
+ else
+ {
+ this.http.get("api/library/" + slug).subscribe(result =>
+ {
+ this.shows = result;
+ }, error => console.log(error));
+ }
+ });
+ }
+
+ ngOnDestroy()
+ {
+ this.watch.unsubscribe();
+ }
+}
diff --git a/Kyoo/ClientApp/src/app/not-found/not-found.component.html b/Kyoo/ClientApp/src/app/not-found/not-found.component.html
new file mode 100644
index 00000000..28767b07
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/not-found/not-found.component.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
404 Error
+
The page you requested was not found.
+
diff --git a/Kyoo/ClientApp/src/app/not-found/not-found.component.scss b/Kyoo/ClientApp/src/app/not-found/not-found.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/Kyoo/ClientApp/src/app/not-found/not-found.component.spec.ts b/Kyoo/ClientApp/src/app/not-found/not-found.component.spec.ts
new file mode 100644
index 00000000..35189ed0
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/not-found/not-found.component.spec.ts
@@ -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;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ NotFoundComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NotFoundComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/Kyoo/ClientApp/src/app/not-found/not-found.component.ts b/Kyoo/ClientApp/src/app/not-found/not-found.component.ts
new file mode 100644
index 00000000..8a117dc2
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/not-found/not-found.component.ts
@@ -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() {
+ }
+
+}
diff --git a/Kyoo/ClientApp/src/app/show-details/show-details.component.html b/Kyoo/ClientApp/src/app/show-details/show-details.component.html
new file mode 100644
index 00000000..7dd1e78c
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/show-details/show-details.component.html
@@ -0,0 +1 @@
+Should display show details of: {{this.show.title}}
diff --git a/Kyoo/ClientApp/src/app/show-details/show-details.component.scss b/Kyoo/ClientApp/src/app/show-details/show-details.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/Kyoo/ClientApp/src/app/show-details/show-details.component.spec.ts b/Kyoo/ClientApp/src/app/show-details/show-details.component.spec.ts
new file mode 100644
index 00000000..03ac65c1
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/show-details/show-details.component.spec.ts
@@ -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;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ShowDetailsComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ShowDetailsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/Kyoo/ClientApp/src/app/show-details/show-details.component.ts b/Kyoo/ClientApp/src/app/show-details/show-details.component.ts
new file mode 100644
index 00000000..b9238c33
--- /dev/null
+++ b/Kyoo/ClientApp/src/app/show-details/show-details.component.ts
@@ -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("api/shows/" + slug).subscribe(result =>
+ {
+ this.show = result;
+ }, error => console.log(error));
+ });
+ }
+
+ ngOnDestroy()
+ {
+ this.watch.unsubscribe();
+ }
+
+}
diff --git a/Kyoo/ClientApp/src/models/show.ts b/Kyoo/ClientApp/src/models/show.ts
new file mode 100644
index 00000000..8e0d0384
--- /dev/null
+++ b/Kyoo/ClientApp/src/models/show.ts
@@ -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;
+}
diff --git a/Kyoo/InternalAPI/Crawler/Crawler.cs b/Kyoo/InternalAPI/Crawler/Crawler.cs
index cf3d5040..dd9aaa56 100644
--- a/Kyoo/InternalAPI/Crawler/Crawler.cs
+++ b/Kyoo/InternalAPI/Crawler/Crawler.cs
@@ -46,40 +46,8 @@ namespace Kyoo.InternalAPI
foreach (string file in files)
{
- if(IsVideo(file) && !libraryManager.IsEpisodeRegistered(file))
- {
- string patern = config.GetValue("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("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)
diff --git a/Kyoo/Kyoo.csproj b/Kyoo/Kyoo.csproj
index 47ba434b..d869c34e 100644
--- a/Kyoo/Kyoo.csproj
+++ b/Kyoo/Kyoo.csproj
@@ -29,6 +29,14 @@
+
+
+
+
+
+
+
+