Now using the genre table inside the database. Adding menus inside the show details component of the webapp.

This commit is contained in:
Zoe Roux 2019-08-26 02:21:52 +02:00
parent 373c05e3c5
commit 26edab07b0
13 changed files with 328 additions and 33 deletions

View File

@ -10,6 +10,8 @@ import { ShowDetailsComponent } from './show-details/show-details.component';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatProgressBarModule } from '@angular/material/progress-bar'; import { MatProgressBarModule } from '@angular/material/progress-bar';
import { MatButtonModule } from '@angular/material/button';
import { MatDividerModule } from '@angular/material/divider';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -24,7 +26,9 @@ import { MatProgressBarModule } from '@angular/material/progress-bar';
AppRoutingModule, AppRoutingModule,
BrowserAnimationsModule, BrowserAnimationsModule,
MatSnackBarModule, MatSnackBarModule,
MatProgressBarModule MatProgressBarModule,
MatButtonModule,
MatDividerModule
], ],
providers: [], providers: [],
bootstrap: [AppComponent] bootstrap: [AppComponent]

View File

@ -1,12 +1,48 @@
<div class="container pt-5"> <div class="container pt-5">
<div class="row">
<img class="poster" src="thumb/{{this.show.slug}}" /> <img class="poster" src="thumb/{{this.show.slug}}" />
<div class="main">
<div class="info"> <div class="info">
<h1>{{this.show.title}}</h1> <h1>{{this.show.title}}</h1>
<h6 *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</h6> <h6 *ngIf="show.endYear; else elseBlock">{{show.startYear}} - {{show.endYear}}</h6>
<ng-template #elseBlock><h2>{{show.startYear}}</h2></ng-template> <ng-template #elseBlock><h2>{{show.startYear}}</h2></ng-template>
</div> </div>
<!--<mat-divider></mat-divider>-->
<div class="buttons">
<button mat-fab>Play</button>
<button mat-mini-fab>Download</button>
<button mat-mini-fab>Watched</button>
<button mat-mini-fab>More</button>
</div>
</div>
</div> </div>
<div class="main"> <div class="row pt-3">
<p>{{this.show.overview}}</p> <div class="col">
<p class="text-justify">{{this.show.overview}}</p>
</div> </div>
<mat-divider vertical></mat-divider>
<div class="col-2">
<h3>Genres</h3>
<ul>
<li *ngFor="let genre of this.show.genres"><a routerLink="/genre/{{genre.slug}}">{{genre.name}}</a></li>
</ul>
</div>
</div>
<div class="row bg-primary" style="display: block;"> <!--For now we'll leave that for wireframing a bit-->
<h3>Staff</h3>
<div class="scroll-row" style="position: relative;">
<button mat-fab id="leftBtn"></button>
<div class="justify-content-left people-container">
<a class="people" *ngFor="let people of this.show.people" routerLink="/people/{{people.slug}}">
<img [style.background-image]="getPeopleIcon(people.slug)" />
<p class="title">{{people.name}}</p>
<p class="role">{{people.role}}</p>
</a>
</div>
<button mat-fab id="rightBtn"></button>
</div>
</div>
</div>

View File

@ -2,18 +2,112 @@
{ {
width: 25%; width: 25%;
background-color: #333333; background-color: #333333;
display: inline-block;
}
.info
{
display: inline-block;
padding-left: 2.5em;
padding-bottom: 7em;
vertical-align: bottom;
} }
.main .main
{ {
align-self: end;
padding-bottom: 5em;
padding-left: 2.5em;
.info
{
}
.buttons
{
> button
{
outline: none;
margin: .3em;
}
}
}
.people-container
{
display: flex;
overflow: hidden;
}
.people
{
width: 15%;
margin: 1em;
text-decoration: none;
color: inherit;
outline: none;
flex-shrink: 0;
flex-grow: 0;
/*@include media-breakpoint-up(md)
{
width: 25%;
}
@include media-breakpoint-up(lg)
{
width: 20%;
}
@include media-breakpoint-up(xl)
{
width: 18%;
}*/
/*&:focus, &:hover
{
> img
{
outline: solid var(--accentColor);
}
> .title
{
text-decoration: underline;
}
}*/
> img
{
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;
&.role
{
opacity: 0.8;
font-size: 0.8em;
}
}
&:hover
{
cursor: pointer;
}
}
#leftBtn
{
position: absolute;
left: 0;
top: 33%;
outline: none;
}
#rightBtn
{
position: absolute;
right: 0;
top: 33%;
outline: none;
} }

View File

@ -19,6 +19,11 @@ export class ShowDetailsComponent implements OnInit
document.body.style.backgroundImage = "url(/backdrop/" + this.show.slug + ")"; document.body.style.backgroundImage = "url(/backdrop/" + this.show.slug + ")";
} }
getPeopleIcon(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/peopleimg/" + slug + ")");
}
getBackdrop() getBackdrop()
{ {
return this.sanitizer.bypassSecurityTrustStyle("url(/backdrop/" + this.show.slug + ")"); return this.sanitizer.bypassSecurityTrustStyle("url(/backdrop/" + this.show.slug + ")");

View File

@ -36,3 +36,9 @@ $theme: mat-light-theme($primary, $accent);
background-color: theme-color("accentColor"); background-color: theme-color("accentColor");
color: theme-color("textPrimary"); color: theme-color("textPrimary");
} }
.scroll-row
{
padding-left: 0;
padding-right: 0;
}

View File

@ -1,6 +1,5 @@
using Kyoo.InternalAPI; using Kyoo.InternalAPI;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.FileProviders;
namespace Kyoo.Controllers namespace Kyoo.Controllers
{ {
@ -32,5 +31,15 @@ namespace Kyoo.Controllers
return new PhysicalFileResult(thumbPath, "image/jpg"); return new PhysicalFileResult(thumbPath, "image/jpg");
} }
[HttpGet("peopleimg/{peopleSlug}")]
public IActionResult GetPeopleIcon(string peopleSlug)
{
string thumbPath = libraryManager.GetPeopleBySlug(peopleSlug)?.imgPrimary;
if (thumbPath == null)
return NotFound();
return new PhysicalFileResult(thumbPath, "image/jpg");
}
} }
} }

View File

@ -9,10 +9,13 @@ namespace Kyoo.InternalAPI
string GetShowExternalIDs(long showID); string GetShowExternalIDs(long showID);
IEnumerable<Show> QueryShows(string selection); IEnumerable<Show> QueryShows(string selection);
List<People> GetPeople(long showID); List<People> GetPeople(long showID);
List<Genre> GetGenreForShow(long showID);
//Public read //Public read
IEnumerable<Library> GetLibraries(); IEnumerable<Library> GetLibraries();
Show GetShowBySlug(string slug); Show GetShowBySlug(string slug);
People GetPeopleBySlug(string slug);
Genre GetGenreBySlug(string slug);
//Check if value exists //Check if value exists
bool IsShowRegistered(string showPath); bool IsShowRegistered(string showPath);
@ -26,6 +29,8 @@ namespace Kyoo.InternalAPI
long RegisterSeason(Season season); long RegisterSeason(Season season);
long RegisterEpisode(Episode episode); long RegisterEpisode(Episode episode);
long GetOrCreateGenre(Genre genre);
void RegisterShowPeople(long showID, List<People> actors); void RegisterShowPeople(long showID, List<People> actors);
} }
} }

View File

@ -32,7 +32,6 @@ namespace Kyoo.InternalAPI
aliases TEXT, aliases TEXT,
path TEXT UNIQUE, path TEXT UNIQUE,
overview TEXT, overview TEXT,
genres TEXT,
status TEXT, status TEXT,
startYear INTEGER, startYear INTEGER,
endYear INTEGER, endYear INTEGER,
@ -224,7 +223,7 @@ namespace Kyoo.InternalAPI
SQLiteDataReader reader = cmd.ExecuteReader(); SQLiteDataReader reader = cmd.ExecuteReader();
if (reader.Read()) if (reader.Read())
return Show.FromReader(reader).SetPeople(this); return Show.FromReader(reader).SetGenres(this).SetPeople(this);
else else
return null; return null;
} }
@ -242,11 +241,61 @@ namespace Kyoo.InternalAPI
List<People> people = new List<People>(); List<People> people = new List<People>();
while (reader.Read()) while (reader.Read())
people.Add(People.FromReader(reader)); people.Add(People.FromFullReader(reader));
return people; return people;
} }
} }
public People GetPeopleBySlug(string slug)
{
string query = "SELECT * FROM people WHERE slug = $slug;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$slug", slug);
SQLiteDataReader reader = cmd.ExecuteReader();
if (reader.Read())
return People.FromReader(reader);
else
return null;
}
}
public List<Genre> GetGenreForShow(long showID)
{
string query = "SELECT genres.id, genres.slug, genres.name FROM genres JOIN genresLinks l ON l.genreID = genres.id WHERE l.showID = $showID;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$showID", showID);
SQLiteDataReader reader = cmd.ExecuteReader();
List<Genre> genres = new List<Genre>();
while (reader.Read())
genres.Add(Genre.FromReader(reader));
return genres;
}
}
public Genre GetGenreBySlug(string slug)
{
string query = "SELECT * FROM genres WHERE slug = $slug;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$slug", slug);
SQLiteDataReader reader = cmd.ExecuteReader();
if (reader.Read())
return Genre.FromReader(reader);
else
return null;
}
}
#endregion #endregion
#region Check if items exists #region Check if items exists
@ -308,12 +357,31 @@ namespace Kyoo.InternalAPI
return cmd.ExecuteScalar() != null; return cmd.ExecuteScalar() != null;
} }
} }
public long GetOrCreateGenre(Genre genre)
{
Genre existingGenre = GetGenreBySlug(genre.Slug);
if (existingGenre != null)
return existingGenre.id;
string query = "INSERT INTO genres (slug, name) VALUES($slug, $name);";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$slug", genre.Slug);
cmd.Parameters.AddWithValue("$name", genre.Name);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT LAST_INSERT_ROWID()";
return (long)cmd.ExecuteScalar();
}
}
#endregion #endregion
#region Write Into The Database #region Write Into The Database
public long RegisterShow(Show show) public long RegisterShow(Show show)
{ {
string query = "INSERT INTO shows (slug, title, aliases, path, overview, genres, startYear, endYear, imgPrimary, imgThumb, imgLogo, imgBackdrop, externalIDs) VALUES($slug, $title, $aliases, $path, $overview, $genres, $startYear, $endYear, $imgPrimary, $imgThumb, $imgLogo, $imgBackdrop, $externalIDs);"; string query = "INSERT INTO shows (slug, title, aliases, path, overview, startYear, endYear, imgPrimary, imgThumb, imgLogo, imgBackdrop, externalIDs) VALUES($slug, $title, $aliases, $path, $overview, $startYear, $endYear, $imgPrimary, $imgThumb, $imgLogo, $imgBackdrop, $externalIDs);";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{ {
cmd.Parameters.AddWithValue("$slug", show.Slug); cmd.Parameters.AddWithValue("$slug", show.Slug);
@ -321,7 +389,6 @@ namespace Kyoo.InternalAPI
cmd.Parameters.AddWithValue("$aliases", show.GetAliases()); cmd.Parameters.AddWithValue("$aliases", show.GetAliases());
cmd.Parameters.AddWithValue("$path", show.Path); cmd.Parameters.AddWithValue("$path", show.Path);
cmd.Parameters.AddWithValue("$overview", show.Overview); cmd.Parameters.AddWithValue("$overview", show.Overview);
cmd.Parameters.AddWithValue("$genres", show.GetGenres());
cmd.Parameters.AddWithValue("$status", show.Status); cmd.Parameters.AddWithValue("$status", show.Status);
cmd.Parameters.AddWithValue("$startYear", show.StartYear); cmd.Parameters.AddWithValue("$startYear", show.StartYear);
cmd.Parameters.AddWithValue("$endYear", show.EndYear); cmd.Parameters.AddWithValue("$endYear", show.EndYear);
@ -333,7 +400,18 @@ namespace Kyoo.InternalAPI
cmd.ExecuteNonQuery(); cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; cmd.CommandText = "SELECT LAST_INSERT_ROWID()";
return (long)cmd.ExecuteScalar(); long showID = (long)cmd.ExecuteScalar();
cmd.CommandText = "INSERT INTO genresLinks (genreID, showID) VALUES($genreID, $showID);";
foreach (Genre genre in show.Genres)
{
long genreID = GetOrCreateGenre(genre);
cmd.Parameters.AddWithValue("$genreID", genreID);
cmd.Parameters.AddWithValue("$showID", showID);
cmd.ExecuteNonQuery();
}
return showID;
} }
} }

View File

@ -176,7 +176,7 @@ namespace Kyoo.InternalAPI.MetadataProvider
data.aliases, data.aliases,
null, //Path null, //Path
data.overview, data.overview,
data.genre, GetGenres(data.genre),
GetStatus(data.status), GetStatus(data.status),
GetYear(data.firstAired), GetYear(data.firstAired),
null, //endYear null, //endYear

View File

@ -1,4 +1,5 @@
using Kyoo.Models; using Kyoo.Models;
using System.Collections.Generic;
using System.Text; using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -68,5 +69,15 @@ namespace Kyoo.InternalAPI.MetadataProvider
break; break;
} }
} }
public IEnumerable<Genre> GetGenres(string[] input)
{
List<Genre> genres = new List<Genre>();
foreach (string genre in input)
genres.Add(new Genre(ToSlug(genre), genre));
return genres;
}
} }
} }

31
Kyoo/Models/Genre.cs Normal file
View File

@ -0,0 +1,31 @@
using Newtonsoft.Json;
namespace Kyoo.Models
{
public class Genre
{
[JsonIgnore] public readonly long id;
public string Slug;
public string Name;
public Genre(string slug, string name)
{
Slug = slug;
Name = name;
}
public Genre(long id, string slug, string name)
{
this.id = id;
Slug = slug;
Name = name;
}
public static Genre FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new Genre((long)reader["id"],
reader["slug"] as string,
reader["name"] as string);
}
}
}

View File

@ -13,6 +13,15 @@ namespace Kyoo.Models
public string externalIDs; public string externalIDs;
public People(long id, string slug, string name, string imgPrimary, string externalIDs)
{
this.id = id;
this.slug = slug;
Name = name;
this.imgPrimary = imgPrimary;
this.externalIDs = externalIDs;
}
public People(long id, string slug, string name, string role, string type, string imgPrimary, string externalIDs) public People(long id, string slug, string name, string role, string type, string imgPrimary, string externalIDs)
{ {
this.id = id; this.id = id;
@ -25,6 +34,15 @@ namespace Kyoo.Models
} }
public static People FromReader(System.Data.SQLite.SQLiteDataReader reader) public static People FromReader(System.Data.SQLite.SQLiteDataReader reader)
{
return new People((long)reader["id"],
reader["slug"] as string,
reader["name"] as string,
reader["imgPrimary"] as string,
reader["externalIDs"] as string);
}
public static People FromFullReader(System.Data.SQLite.SQLiteDataReader reader)
{ {
return new People((long)reader["id"], return new People((long)reader["id"],
reader["slug"] as string, reader["slug"] as string,

View File

@ -14,7 +14,7 @@ namespace Kyoo.Models
public IEnumerable<string> Aliases; public IEnumerable<string> Aliases;
[JsonIgnore] public string Path; [JsonIgnore] public string Path;
public string Overview; public string Overview;
public IEnumerable<string> Genres; public IEnumerable<Genre> Genres;
public Status? Status; public Status? Status;
public long? StartYear; public long? StartYear;
@ -49,7 +49,7 @@ namespace Kyoo.Models
public Show() { } public Show() { }
public Show(long id, string slug, string title, IEnumerable<string> aliases, string path, string overview, IEnumerable<string> genres, Status? status, long? startYear, long? endYear, string externalIDs) public Show(long id, string slug, string title, IEnumerable<string> aliases, string path, string overview, IEnumerable<Genre> genres, Status? status, long? startYear, long? endYear, string externalIDs)
{ {
this.id = id; this.id = id;
Slug = slug; Slug = slug;
@ -64,7 +64,7 @@ namespace Kyoo.Models
ExternalIDs = externalIDs; ExternalIDs = externalIDs;
} }
public Show(long id, string slug, string title, IEnumerable<string> aliases, string path, string overview, IEnumerable<string> genres, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgLogo, string imgBackdrop, string externalIDs) public Show(long id, string slug, string title, IEnumerable<string> aliases, string path, string overview, Status? status, long? startYear, long? endYear, string imgPrimary, string imgThumb, string imgLogo, string imgBackdrop, string externalIDs)
{ {
this.id = id; this.id = id;
Slug = slug; Slug = slug;
@ -72,7 +72,6 @@ namespace Kyoo.Models
Aliases = aliases; Aliases = aliases;
Path = path; Path = path;
Overview = overview; Overview = overview;
Genres = genres;
Status = status; Status = status;
StartYear = startYear; StartYear = startYear;
EndYear = endYear; EndYear = endYear;
@ -91,7 +90,6 @@ namespace Kyoo.Models
(reader["aliases"] as string)?.Split('|') ?? null, (reader["aliases"] as string)?.Split('|') ?? null,
reader["path"] as string, reader["path"] as string,
reader["overview"] as string, reader["overview"] as string,
(reader["genres"] as string)?.Split('|') ?? null,
reader["status"] as Status?, reader["status"] as Status?,
reader["startYear"] as long?, reader["startYear"] as long?,
reader["endYear"] as long?, reader["endYear"] as long?,
@ -109,9 +107,9 @@ namespace Kyoo.Models
return this; return this;
} }
public Show SetPeople(People[] people) public Show SetGenres(ILibraryManager manager)
{ {
this.people = people; Genres = manager.GetGenreForShow(id);
return this; return this;
} }