Adding collections support.

This commit is contained in:
Zoe Roux 2019-10-05 22:46:51 +02:00
parent c852d0c3b9
commit 312ab6b80b
25 changed files with 270 additions and 46 deletions

View File

@ -8,18 +8,24 @@ import { ShowResolverService } from './services/show-resolver.service';
import { LibraryResolverService } from './services/library-resolver.service'; import { LibraryResolverService } from './services/library-resolver.service';
import { PlayerComponent } from "./player/player.component"; import { PlayerComponent } from "./player/player.component";
import { StreamResolverService } from "./services/stream-resolver.service"; import { StreamResolverService } from "./services/stream-resolver.service";
import { CollectionComponent } from "./collection/collection.component";
import { CollectionResolverService } from "./services/collection-resolver.service";
const routes: Routes = [ const routes: Routes = [
{ path: "browse", component: BrowseComponent, pathMatch: "full", resolve: { shows: LibraryResolverService } }, { path: "browse", component: BrowseComponent, pathMatch: "full", resolve: { shows: LibraryResolverService } },
{ path: "browse/:library-slug", component: BrowseComponent, resolve: { shows: LibraryResolverService } }, { path: "browse/:library-slug", component: BrowseComponent, resolve: { shows: LibraryResolverService } },
{ path: "show/:show-slug", component: ShowDetailsComponent, resolve: { show: ShowResolverService } }, { path: "show/:show-slug", component: ShowDetailsComponent, resolve: { show: ShowResolverService } },
{ path: "collection/:collection-slug", component: CollectionComponent, resolve: { shows: CollectionResolverService } },
{ path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService } }, { path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService } },
{ path: "**", component: NotFoundComponent } { path: "**", component: NotFoundComponent }
]; ];
@NgModule({ @NgModule({
imports: [RouterModule.forRoot(routes)], imports: [RouterModule.forRoot(routes,
{
scrollPositionRestoration: "enabled"
})],
exports: [RouterModule], exports: [RouterModule],
providers: [LibraryResolverService, ShowResolverService, StreamResolverService] providers: [LibraryResolverService, ShowResolverService, StreamResolverService]
}) })

View File

@ -16,10 +16,10 @@
<ul class="navbar-nav flex-row ml-auto"> <ul class="navbar-nav flex-row ml-auto">
<li class="nav-item icon"> <li class="nav-item icon">
<mat-icon data-toggle="tooltip" data-placement="bottom" title="Search">search</mat-icon> <mat-icon matTooltipPosition="below" matTooltip="Search">search</mat-icon>
</li> </li>
<li class="nav-item"> <li class="nav-item">
<a class="icon" routerLink="/login" routerLinkActive="active" data-toggle="tooltip" data-placement="bottom" title="Login"> <a class="icon" routerLink="/login" routerLinkActive="active" matTooltipPosition="below" matTooltip="Login">
<mat-icon>account_circle</mat-icon> <mat-icon>account_circle</mat-icon>
</a> </a>
</li> </li>

View File

@ -1,8 +1,8 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http'; import { HttpClient } from '@angular/common/http';
import { Event, Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router'; import { Event, Router, NavigationStart, NavigationEnd, NavigationCancel, NavigationError } from '@angular/router';
import * as $ from "jquery"; //import * as $ from "jquery";
import "bootstrap"; //import "bootstrap";
@Component({ @Component({
selector: 'app-root', selector: 'app-root',
@ -46,11 +46,6 @@ export class AppComponent
} }
}); });
} }
ngAfterViewInit()
{
$('[data-toggle="tooltip"]').tooltip({ trigger: "hover" });
}
} }
interface Library interface Library

View File

@ -7,6 +7,7 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatSelectModule } from '@angular/material/select'; import { MatSelectModule } from '@angular/material/select';
import { MatSliderModule } from '@angular/material/slider'; import { MatSliderModule } from '@angular/material/slider';
import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatTooltipModule } from '@angular/material/tooltip';
import { BrowserModule } from '@angular/platform-browser'; import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { AppRoutingModule } from './app-routing.module'; import { AppRoutingModule } from './app-routing.module';
@ -16,6 +17,7 @@ import { EpisodesListComponent } from './episodes-list/episodes-list.component';
import { NotFoundComponent } from './not-found/not-found.component'; import { NotFoundComponent } from './not-found/not-found.component';
import { PlayerComponent } from './player/player.component'; import { PlayerComponent } from './player/player.component';
import { ShowDetailsComponent } from './show-details/show-details.component'; import { ShowDetailsComponent } from './show-details/show-details.component';
import { CollectionComponent } from './collection/collection.component';
@NgModule({ @NgModule({
@ -25,7 +27,8 @@ import { ShowDetailsComponent } from './show-details/show-details.component';
BrowseComponent, BrowseComponent,
ShowDetailsComponent, ShowDetailsComponent,
EpisodesListComponent, EpisodesListComponent,
PlayerComponent PlayerComponent,
CollectionComponent
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
@ -38,7 +41,8 @@ import { ShowDetailsComponent } from './show-details/show-details.component';
MatIconModule, MatIconModule,
MatSelectModule, MatSelectModule,
MatMenuModule, MatMenuModule,
MatSliderModule MatSliderModule,
MatTooltipModule
], ],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View File

@ -1,8 +1,8 @@
<div class="container-fluid justify-content-center"> <div class="container-fluid justify-content-center">
<button mat-icon-button data-toggle="tooltip" data-placement="bottom" title="Filter"> <button mat-icon-button matTooltipPosition="below" matTooltip="Filter">
<mat-icon>filter_list</mat-icon> <mat-icon>filter_list</mat-icon>
</button> </button>
<button mat-button data-toggle="tooltip" data-placement="bottom" title="Sort" [matMenuTriggerFor]="sortMenu"> <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> <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>
</div> </div>

View File

@ -23,7 +23,7 @@ button
width: 33%; width: 33%;
max-width: 200px; max-width: 200px;
list-style: none; list-style: none;
padding: 1em; padding: .5em;
text-decoration: none; text-decoration: none;
color: inherit; color: inherit;
outline: none; outline: none;
@ -36,6 +36,7 @@ button
@include media-breakpoint-up(md) @include media-breakpoint-up(md)
{ {
width: 20%; width: 20%;
padding: 1em;
} }
@include media-breakpoint-up(lg) @include media-breakpoint-up(lg)

View File

@ -0,0 +1 @@
<p>collection works!</p>

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CollectionComponent } from './collection.component';
describe('CollectionComponent', () => {
let component: CollectionComponent;
let fixture: ComponentFixture<CollectionComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CollectionComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CollectionComponent);
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-collection',
templateUrl: './collection.component.html',
styleUrls: ['./collection.component.scss']
})
export class CollectionComponent implements OnInit {
constructor() { }
ngOnInit() {
}
}

View File

@ -13,14 +13,6 @@
display: block; display: block;
} }
} }
&:hover
{
.episodes
{
visibility: visible;
}
}
} }
.episodes .episodes
@ -32,7 +24,6 @@
min-width: 100%; min-width: 100%;
flex-shrink: 0; flex-shrink: 0;
flex-direction: row; flex-direction: row;
visibility: hidden;
&::-webkit-scrollbar &::-webkit-scrollbar
{ {

View File

@ -12,7 +12,7 @@
<div id="hover"> <div id="hover">
<div class="back"> <div class="back">
<a mat-icon-button data-toggle="tooltip" data-placement="bottom" title="Back" href="/show/{{this.item.showSlug}}" routerLink="/show/{{this.item.showSlug}}"> <a mat-icon-button matTooltipPosition="below" matTooltip="Back" href="/show/{{this.item.showSlug}}" routerLink="/show/{{this.item.showSlug}}">
<mat-icon>arrow_back</mat-icon> <mat-icon>arrow_back</mat-icon>
</a> </a>
<h5>{{this.item.showTitle}}</h5> <h5>{{this.item.showTitle}}</h5>
@ -35,10 +35,10 @@
<div class="buttons"> <div class="buttons">
<div class="left"> <div class="left">
<a *ngIf="this.item.previousEpisode" mat-icon-button data-toggle="tooltip" data-placement="top" title="Previous" routerLink="/watch/{{this.item.previousEpisode}}" href="/watch/{{this.item.previousEpisode}}" queryParamsHandling="merge"> <a *ngIf="this.item.previousEpisode" mat-icon-button matTooltipPosition="above" matTooltip="Previous" routerLink="/watch/{{this.item.previousEpisode}}" href="/watch/{{this.item.previousEpisode}}" queryParamsHandling="merge">
<mat-icon>skip_previous</mat-icon> <mat-icon>skip_previous</mat-icon>
</a> </a>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Play" id="play" (click)="tooglePlayback()"> <button mat-icon-button matTooltipPosition="above" matTooltip="Play" id="play" (click)="tooglePlayback()">
<mat-icon>{{this.playIcon}}</mat-icon> <mat-icon>{{this.playIcon}}</mat-icon>
</button> </button>
<a mat-icon-button id="nextBtn" *ngIf="this.item.nextEpisode" routerLink="/watch/{{this.item.nextEpisode.link}}" href="/watch/{{this.item.nextEpisode.link}}" queryParamsHandling="merge"> <a mat-icon-button id="nextBtn" *ngIf="this.item.nextEpisode" routerLink="/watch/{{this.item.nextEpisode.link}}" href="/watch/{{this.item.nextEpisode.link}}" queryParamsHandling="merge">
@ -55,7 +55,7 @@
</div> </div>
</a> </a>
<div id="volume"> <div id="volume">
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Volume" (click)="toogleMute()"> <button mat-icon-button matTooltipPosition="above" matTooltip="Volume" (click)="toogleMute()">
<mat-icon>{{this.volumeIcon}}</mat-icon> <mat-icon>{{this.volumeIcon}}</mat-icon>
</button> </button>
@ -65,19 +65,19 @@
<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> <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>
<div class="right"> <div class="right">
<button *ngIf="this.item.audios.length > 0" mat-icon-button data-toggle="tooltip" data-placement="top" title="Select audio track"> <button *ngIf="this.item.audios.length > 0" mat-icon-button matTooltipPosition="above" matTooltip="Select audio track">
<mat-icon>music_note</mat-icon> <mat-icon>music_note</mat-icon>
</button> </button>
<button *ngIf="this.item.subtitles.length > 0" mat-icon-button [matMenuTriggerFor]="subtitles" data-toggle="tooltip" data-placement="top" title="Select subtitle track"> <button *ngIf="this.item.subtitles.length > 0" mat-icon-button [matMenuTriggerFor]="subtitles" matTooltipPosition="above" matTooltip="Select subtitle track">
<mat-icon>closed_caption</mat-icon> <mat-icon>closed_caption</mat-icon>
</button> </button>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Cast"> <button mat-icon-button matTooltipPosition="above" matTooltip="Cast">
<mat-icon>cast</mat-icon> <mat-icon>cast</mat-icon>
</button> </button>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Settings"> <button mat-icon-button matTooltipPosition="above" matTooltip="Settings">
<mat-icon>settings</mat-icon> <mat-icon>settings</mat-icon>
</button> </button>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Fullscreen" id="fullscreen" (click)="fullscreen()"> <button mat-icon-button matTooltipPosition="above" matTooltip="Fullscreen" id="fullscreen" (click)="fullscreen()">
<mat-icon>{{fullscreenIcon}}</mat-icon> <mat-icon>{{fullscreenIcon}}</mat-icon>
</button> </button>
</div> </div>

View File

@ -0,0 +1,32 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import { ActivatedRouteSnapshot, Resolve } from '@angular/router';
import { EMPTY, Observable } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Collection } from "../../models/collection";
@Injectable()
export class CollectionResolverService implements Resolve<Collection>
{
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;
}));
}
}

View File

@ -12,19 +12,19 @@
<ng-template #elseBlock><h2 class="date">{{show.startYear}}</h2></ng-template> <ng-template #elseBlock><h2 class="date">{{show.startYear}}</h2></ng-template>
</div> </div>
<div class="buttons"> <div class="buttons">
<button mat-mini-fab data-toggle="tooltip" data-placement="top" title="Play" class="mr-3"> <button mat-mini-fab matTooltipPosition="above" matTooltip="Play" class="mr-3">
<mat-icon>play_arrow</mat-icon> <mat-icon>play_arrow</mat-icon>
</button> </button>
<button *ngIf="this.show.trailerUrl" mat-icon-button data-toggle="tooltip" data-placement="top" title="Trailer"> <button *ngIf="this.show.trailerUrl" mat-icon-button matTooltipPosition="above" matTooltip="Trailer">
<mat-icon>local_movies</mat-icon> <mat-icon>local_movies</mat-icon>
</button> </button>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Download"> <button mat-icon-button matTooltipPosition="above" matTooltip="Download">
<mat-icon>cloud_download</mat-icon> <mat-icon>cloud_download</mat-icon>
</button> </button>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Watched"> <button mat-icon-button matTooltipPosition="above" matTooltip="Watched">
<mat-icon>done</mat-icon> <mat-icon>done</mat-icon>
</button> </button>
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="More"> <button mat-icon-button matTooltipPosition="above" matTooltip="More">
<mat-icon>more_horiz</mat-icon> <mat-icon>more_horiz</mat-icon>
</button> </button>
</div> </div>

View File

@ -17,8 +17,13 @@ a
{ {
width: 100%; width: 100%;
max-height: 75vh; max-height: 75vh;
min-height: 60vh;
object-fit: cover; object-fit: cover;
min-height: 20vh;
@include media-breakpoint-up(md)
{
min-height: 60vh;
}
} }
&:after &:after
@ -194,12 +199,6 @@ hr
min-width: 100%; min-width: 100%;
flex-shrink: 0; flex-shrink: 0;
flex-direction: row; flex-direction: row;
visibility: hidden;
&:hover
{
visibility: visible;
}
&::-webkit-scrollbar &::-webkit-scrollbar
{ {

View File

@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=collection.js.map

View File

@ -0,0 +1 @@
{"version":3,"file":"collection.js","sourceRoot":"","sources":["collection.ts"],"names":[],"mappings":""}

View File

@ -0,0 +1,9 @@
import { Show } from "./show";
export interface Collection
{
slug: string;
name: string;
overview: string;
shows: Show[];
}

View File

@ -0,0 +1,30 @@
using Kyoo.InternalAPI;
using Kyoo.Models;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
namespace Kyoo.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CollectionController : ControllerBase
{
private readonly ILibraryManager libraryManager;
public CollectionController(ILibraryManager libraryManager)
{
this.libraryManager = libraryManager;
}
[HttpGet]
public ActionResult<Collection> GetShows(string collectionSlug)
{
Collection collection = libraryManager.GetCollection(collectionSlug);
if (collection == null)
return NotFound();
return collection;
}
}
}

View File

@ -15,6 +15,7 @@ namespace Kyoo.InternalAPI
List<Genre> GetGenreForShow(long showID); List<Genre> GetGenreForShow(long showID);
List<Season> GetSeasons(long showID); List<Season> GetSeasons(long showID);
int GetSeasonCount(string showSlug, long seasonNumber); int GetSeasonCount(string showSlug, long seasonNumber);
IEnumerable<Show> GetShowsInCollection(long collectionID);
//Internal HTML read //Internal HTML read
(List<Track> audios, List<Track> subtitles) GetStreams(long episodeID, string showSlug); (List<Track> audios, List<Track> subtitles) GetStreams(long episodeID, string showSlug);
@ -31,6 +32,7 @@ namespace Kyoo.InternalAPI
People GetPeopleBySlug(string slug); People GetPeopleBySlug(string slug);
Genre GetGenreBySlug(string slug); Genre GetGenreBySlug(string slug);
Studio GetStudioBySlug(string slug); Studio GetStudioBySlug(string slug);
Collection GetCollection(string slug);
//Check if value exists //Check if value exists
bool IsShowRegistered(string showPath); bool IsShowRegistered(string showPath);
@ -40,6 +42,7 @@ namespace Kyoo.InternalAPI
bool IsEpisodeRegistered(string episodePath); bool IsEpisodeRegistered(string episodePath);
//Register values //Register values
long RegisterCollection(Collection collection);
long RegisterShow(Show show); long RegisterShow(Show show);
long RegisterSeason(Season season); long RegisterSeason(Season season);
long RegisterEpisode(Episode episode); long RegisterEpisode(Episode episode);

View File

@ -97,6 +97,20 @@ namespace Kyoo.InternalAPI
FOREIGN KEY(showID) REFERENCES shows(id) FOREIGN KEY(showID) REFERENCES shows(id)
); );
CREATE TABLE collections(
id INTEGER PRIMARY KEY UNIQUE,
slug TEXT UNIQUE,
name TEXT,
overview TEXT,
imgPrimary TEXT
);
CREATE TABLE collectionsLinks(
collectionID INTEGER,
showID INTEGER,
FOREIGN KEY(collectionID) REFERENCES collections(id),
FOREIGN KEY(showID) REFERENCES shows(id)
);
CREATE TABLE studios( CREATE TABLE studios(
id INTEGER PRIMARY KEY UNIQUE, id INTEGER PRIMARY KEY UNIQUE,
slug TEXT UNIQUE, slug TEXT UNIQUE,
@ -515,6 +529,38 @@ namespace Kyoo.InternalAPI
// return genres; // return genres;
//} //}
} }
public Collection GetCollection(string slug)
{
string query = "SELECT * FROM collections WHERE slug = $slug;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$slug", slug);
SQLiteDataReader reader = cmd.ExecuteReader();
if (reader.Read())
return Collection.FromReader(reader).SetShows(this);
else
return null;
}
}
public IEnumerable<Show> GetShowsInCollection(long collectionID)
{
string query = "SELECT * FROM shows JOIN collectionsLink l ON l.showID = shows.id WHERE l.collectionID = $id;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$id", collectionID);
SQLiteDataReader reader = cmd.ExecuteReader();
List<Show> shows = new List<Show>();
while (reader.Read())
shows.Add(Show.FromReader(reader));
return shows;
}
}
#endregion #endregion
#region Check if items exists #region Check if items exists
@ -638,6 +684,23 @@ namespace Kyoo.InternalAPI
#endregion #endregion
#region Write Into The Database #region Write Into The Database
public long RegisterCollection(Collection collection)
{
string query = "INSERT INTO collections (slug, name, overview, imgPrimary) VALUES($slug, $name, $overview, $imgPrimary);";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$slug", collection.Slug);
cmd.Parameters.AddWithValue("$name", collection.Name);
cmd.Parameters.AddWithValue("$overview", collection.Overview);
cmd.Parameters.AddWithValue("$imgPrimary", collection.ImgPrimary);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT LAST_INSERT_ROWID()";
return (long)cmd.ExecuteScalar();
}
}
public long RegisterShow(Show show) public long RegisterShow(Show show)
{ {
string query = "INSERT INTO shows (slug, title, aliases, path, overview, trailerUrl, startYear, endYear, imgPrimary, imgThumb, imgLogo, imgBackdrop, externalIDs) VALUES($slug, $title, $aliases, $path, $overview, $trailerUrl, $startYear, $endYear, $imgPrimary, $imgThumb, $imgLogo, $imgBackdrop, $externalIDs);"; string query = "INSERT INTO shows (slug, title, aliases, path, overview, trailerUrl, startYear, endYear, imgPrimary, imgThumb, imgLogo, imgBackdrop, externalIDs) VALUES($slug, $title, $aliases, $path, $overview, $trailerUrl, $startYear, $endYear, $imgPrimary, $imgThumb, $imgLogo, $imgBackdrop, $externalIDs);";

View File

@ -34,6 +34,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="ClientApp\src\models\collection.ts" />
<None Remove="ClientApp\src\models\genre.ts" /> <None Remove="ClientApp\src\models\genre.ts" />
<None Remove="ClientApp\src\models\people.ts" /> <None Remove="ClientApp\src\models\people.ts" />
<None Remove="ClientApp\src\models\show.ts" /> <None Remove="ClientApp\src\models\show.ts" />
@ -76,6 +77,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<TypeScriptCompile Include="ClientApp\src\models\collection.ts" />
<TypeScriptCompile Include="ClientApp\src\models\genre.ts" /> <TypeScriptCompile Include="ClientApp\src\models\genre.ts" />
<TypeScriptCompile Include="ClientApp\src\models\people.ts" /> <TypeScriptCompile Include="ClientApp\src\models\people.ts" />
<TypeScriptCompile Include="ClientApp\src\models\show.ts" /> <TypeScriptCompile Include="ClientApp\src\models\show.ts" />

42
Kyoo/Models/Collection.cs Normal file
View File

@ -0,0 +1,42 @@
using Kyoo.InternalAPI;
using Newtonsoft.Json;
using System.Collections.Generic;
namespace Kyoo.Models
{
public class Collection
{
[JsonIgnore] public long id;
public string Slug;
public string Name;
public string Overview;
[JsonIgnore] public string ImgPrimary;
public IEnumerable<Show> Shows;
public Collection() { }
public Collection(long id, string slug, string name, string overview, string imgPrimary)
{
this.id = id;
Slug = slug;
Name = name;
Overview = overview;
ImgPrimary = imgPrimary;
}
public static Collection FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Collection((long)reader["id"],
reader["slug"] as string,
reader["name"] as string,
reader["overview"] as string,
reader["imgPrimary"] as string);
}
public Collection SetShows(ILibraryManager libraryManager)
{
Shows = libraryManager.GetShowsInCollection(id);
return this;
}
}
}

View File

@ -13,6 +13,8 @@ namespace Kyoo
public static IWebHostBuilder CreateWebHostBuilder(string[] args) => public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args) WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseUrls("http://*:5000")
.UseStartup<Startup>(); .UseStartup<Startup>();
} }
} }

View File

@ -1,5 +1,5 @@
{ {
"server.urls": "http://0.0.0.0", "server.urls": "http://0.0.0.0:5000",
"https_port": 44300, "https_port": 44300,
"Logging": { "Logging": {
"LogLevel": { "LogLevel": {