Search view created.

This commit is contained in:
Zoe Roux 2019-10-27 01:49:33 +02:00
parent c84eac21d2
commit 4fb0274410
25 changed files with 636 additions and 215 deletions

View File

@ -30,6 +30,13 @@ const routes: Routes = [
scrollPositionRestoration: "enabled"
})],
exports: [RouterModule],
providers: [LibraryResolverService, ShowResolverService, StreamResolverService]
providers: [
LibraryResolverService,
ShowResolverService,
CollectionResolverService,
PeopleResolverService,
StreamResolverService,
SearchResolverService
]
})
export class AppRoutingModule { }

View File

@ -16,7 +16,7 @@
<ul class="navbar-nav flex-row ml-auto">
<li class="nav-item icon searchbar">
<input placeholder="Search" id="search" type="search" (oninit)="onUpdateValue(this.value)"/>
<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">

View File

@ -66,6 +66,12 @@
}
}
input::-webkit-search-cancel-button
{
display: none;
}
.icon
{
padding: 8px;

View File

@ -48,9 +48,10 @@ export class AppComponent
input.focus();
}
onUpdateValue(value: string)
onUpdateValue(event)
{
console.log("Value: " + value);
console.log("Value: " + event.target.value);
this.router.navigate(["/search/" + event.target.value]);
}
}

View File

@ -20,6 +20,8 @@ import { NotFoundComponent } from './not-found/not-found.component';
import { PlayerComponent } from './player/player.component';
import { ShowDetailsComponent } from './show-details/show-details.component';
import { SearchComponent } from './search/search.component';
import { PeopleListComponent } from './people-list/people-list.component';
import { ShowsListComponent } from './shows-list/shows-list.component';
@NgModule({
@ -31,7 +33,9 @@ import { SearchComponent } from './search/search.component';
EpisodesListComponent,
PlayerComponent,
CollectionComponent,
SearchComponent
SearchComponent,
PeopleListComponent,
ShowsListComponent
],
imports: [
BrowserModule,

View File

@ -1,12 +1,19 @@
<div class="root">
<div class="episodes" id="episodes">
<a class="episode" *ngFor="let episode of this.episodes" id="el-{{episode.episodeNumber}}" routerLink="/watch/{{this.showSlug}}-s{{episode.seasonNumber}}e{{episode.episodeNumber}}" href="/watch/{{this.showSlug}}-s{{episode.seasonNumber}}e{{episode.episodeNumber}}">
<a class="episode" *ngFor="let episode of this.episodes; let i = index" id="el-{{i}}" routerLink="/watch/{{episode.link}}" href="/watch/{{this.showSlug}}-s{{episode.seasonNumber}}e{{episode.episodeNumber}}">
<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>
<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-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 d-none" id="el-leftBtn" (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>

View File

@ -118,6 +118,15 @@
overflow: hidden;
}
.subtitle
{
font-weight: 300;
display: -webkit-box;
-webkit-line-clamp: 1;
-webkit-box-orient: vertical;
overflow: hidden;
}
&:hover
{
.img

View File

@ -9,8 +9,8 @@ import { DomSanitizer } from "@angular/platform-browser";
})
export class EpisodesListComponent implements OnInit
{
@Input() displayShowTitle: boolean = false;
@Input() episodes: Episode[];
@Input() showSlug: string;
private root: HTMLElement;
constructor(private sanitizer: DomSanitizer) { }

View File

@ -0,0 +1,11 @@
<div class="scroll-row mb-5">
<div class="people-container" id="peopleScroll">
<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 d-none" id="pl-leftBtn" (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
<button mat-raised-button color="accent" class="scrollBtn" id="pl-rightBtn" (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
</div>

View File

@ -0,0 +1,155 @@
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.people-container
{
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-thumb
{
background-color: #999;
border-radius: 90px;
&: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%;
@include media-breakpoint-up(sm)
{
width: 22%;
}
@include media-breakpoint-up(md)
{
width: 20%;
}
@include media-breakpoint-up(lg)
{
width: 15%;
}
@include media-breakpoint-up(xl)
{
width: 10%;
}
> 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;
&.role
{
font-size: 0.8em;
}
}
&:hover
{
cursor: pointer;
> img
{
outline: solid var(--accentColor);
}
.name
{
text-decoration: underline;
}
}
}
.scroll-row
{
position: relative;
&:hover
{
.scrollBtn
{
display: block;
}
}
}
.scrollBtn
{
padding: 0;
outline: none;
min-width: 0;
position: absolute;
top: 30%;
bottom: 40%;
display: none;
&#pl-leftBtn
{
left: 0;
padding-left: 10px;
padding-right: 2px;
}
&#pl-rightBtn
{
right: 0;
padding-right: 10px;
padding-left: 2px;
}
}
#leftBtn
{
position: absolute;
left: 0;
top: 33%;
outline: none;
}
#rightBtn
{
position: absolute;
right: 0;
top: 33%;
outline: none;
}

View File

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

View File

@ -0,0 +1,48 @@
import { Component, Input, OnInit } from '@angular/core';
import { DomSanitizer } from "@angular/platform-browser";
import { People } from "../../models/people";
@Component({
selector: 'app-people-list',
templateUrl: './people-list.component.html',
styleUrls: ['./people-list.component.scss']
})
export class PeopleListComponent implements OnInit
{
@Input() people: People[];
private peopleScroll: HTMLElement;
constructor(private sanitizer: DomSanitizer) { }
ngOnInit()
{
this.peopleScroll = document.getElementById("peopleScroll");
}
scrollLeft()
{
let scroll: number = this.peopleScroll.offsetWidth * 0.80;
this.peopleScroll.scrollBy({ top: 0, left: -scroll, behavior: "smooth" });
document.getElementById("pl-rightBtn").classList.remove("d-none");
if (this.peopleScroll.scrollLeft - scroll <= 0)
document.getElementById("pl-leftBtn").classList.add("d-none");
}
scrollRight()
{
let scroll: number = this.peopleScroll.offsetWidth * 0.80;
this.peopleScroll.scrollBy({ top: 0, left: scroll, behavior: "smooth" });
console.log(document.getElementById("pl-leftBtn"));
document.getElementById("pl-leftBtn").classList.remove("d-none");
if (this.peopleScroll.scrollLeft + scroll >= this.peopleScroll.scrollWidth - this.peopleScroll.clientWidth)
document.getElementById("pl-rightBtn").classList.add("d-none");
}
getPeopleIcon(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/peopleimg/" + slug + ")");
}
}

View File

@ -1 +1,12 @@
<p>search works!</p>
<div class="container-fluid mt-3">
<h3>Shows</h3>
</div>
<app-shows-list [shows]="items.shows"></app-shows-list>
<div class="container-fluid mt-5">
<h3>Episodes</h3>
</div>
<app-episodes-list displayShowTitle="true" [episodes]="items.episodes"></app-episodes-list>
<div class="container-fluid mt-5">
<h3>People</h3>
</div>
<app-people-list [people]="items.people"></app-people-list>

View File

@ -15,6 +15,9 @@ export class SearchComponent implements OnInit
ngOnInit()
{
this.items = this.route.snapshot.data.items;
this.route.data.subscribe((data) =>
{
this.items = data.items;
});
}
}

View File

@ -73,19 +73,9 @@
</mat-select>
</mat-form-field>
</div>
<app-episodes-list [showSlug]="this.show.slug" [episodes]="episodes"></app-episodes-list>
<app-episodes-list [episodes]="episodes"></app-episodes-list>
<div class="container-fluid mt-5">
<h3>Staff</h3>
</div>
<div class="scroll-row mb-5">
<div class="people-container" id="peopleScroll">
<a class="people" *ngFor="let people of this.show.people" routerLink="/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 d-none" id="pl-leftBtn" (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
<button mat-raised-button color="accent" class="scrollBtn" id="pl-rightBtn" (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
</div>
<app-people-list [people]="show.people"></app-people-list>

View File

@ -150,156 +150,3 @@ hr
{
opacity: .8;
}
.scroll-row
{
position: relative;
&:hover
{
.scrollBtn
{
display: block;
}
}
}
.scrollBtn
{
padding: 0;
outline: none;
min-width: 0;
position: absolute;
top: 30%;
bottom: 40%;
display: none;
&#pl-leftBtn
{
left: 0;
padding-left: 10px;
padding-right: 2px;
}
&#pl-rightBtn
{
right: 0;
padding-right: 10px;
padding-left: 2px;
}
}
.people-container
{
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-thumb
{
background-color: #999;
border-radius: 90px;
&: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%;
@include media-breakpoint-up(sm)
{
width: 22%;
}
@include media-breakpoint-up(md)
{
width: 20%;
}
@include media-breakpoint-up(lg)
{
width: 15%;
}
@include media-breakpoint-up(xl)
{
width: 10%;
}
> 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;
&.role
{
font-size: 0.8em;
}
}
&:hover
{
cursor: pointer;
> img
{
outline: solid var(--accentColor);
}
.name
{
text-decoration: underline;
}
}
}
#leftBtn
{
position: absolute;
left: 0;
top: 33%;
outline: none;
}
#rightBtn
{
position: absolute;
right: 0;
top: 33%;
outline: none;
}

View File

@ -1,7 +1,7 @@
import { HttpClient } from "@angular/common/http";
import { Component, OnInit } from '@angular/core';
import { MatSnackBar } from "@angular/material/snack-bar";
import { DomSanitizer, Title } from '@angular/platform-browser';
import { Title } from '@angular/platform-browser';
import { ActivatedRoute } from '@angular/router';
import { Episode } from "../../models/episode";
import { Show } from "../../models/show";
@ -19,9 +19,8 @@ export class ShowDetailsComponent implements OnInit
private toolbar: HTMLElement;
private backdrop: HTMLElement;
private peopleScroll: HTMLElement;
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer, private http: HttpClient, private snackBar: MatSnackBar, private title: Title)
constructor(private route: ActivatedRoute, private http: HttpClient, private snackBar: MatSnackBar, private title: Title)
{
this.route.queryParams.subscribe(params =>
{
@ -39,7 +38,6 @@ export class ShowDetailsComponent implements OnInit
this.toolbar = document.getElementById("toolbar");
this.backdrop = document.getElementById("backdrop");
this.peopleScroll = document.getElementById("peopleScroll");
window.addEventListener("scroll", this.scroll, true);
this.toolbar.setAttribute("style", `background-color: rgba(0, 0, 0, 0) !important`);
@ -78,32 +76,4 @@ export class ShowDetailsComponent implements OnInit
this.snackBar.open("An unknow error occured while getting episodes.", null, { horizontalPosition: "left", panelClass: ['snackError'], duration: 2500 });
});
}
scrollLeft()
{
let scroll: number = this.peopleScroll.offsetWidth * 0.80;
this.peopleScroll.scrollBy({ top: 0, left: -scroll, behavior: "smooth" });
document.getElementById("pl-rightBtn").classList.remove("d-none");
if (this.peopleScroll.scrollLeft - scroll <= 0)
document.getElementById("pl-leftBtn").classList.add("d-none");
}
scrollRight()
{
let scroll: number = this.peopleScroll.offsetWidth * 0.80;
console.log("Scroll: " + scroll);
this.peopleScroll.scrollBy({ top: 0, left: scroll, behavior: "smooth" });
document.getElementById("pl-leftBtn").classList.remove("d-none");
if (this.peopleScroll.scrollLeft + scroll >= this.peopleScroll.scrollWidth - this.peopleScroll.clientWidth)
document.getElementById("pl-rightBtn").classList.add("d-none");
}
getPeopleIcon(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/peopleimg/" + slug + ")");
}
}

View File

@ -0,0 +1,12 @@
<div class="scroll-row mb-5">
<div class="shows-container">
<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 d-none" (click)="scrollLeft()"><mat-icon>arrow_left</mat-icon></button>
<button mat-raised-button color="accent" class="scrollBtn" (click)="scrollRight()"><mat-icon>arrow_right</mat-icon></button>
</div>

View File

@ -0,0 +1,235 @@
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@import "~bootstrap/scss/mixins/breakpoints";
.shows-container
{
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-thumb
{
background-color: #999;
border-radius: 90px;
&: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;
@include media-breakpoint-up(sm)
{
width: 25%;
}
@include media-breakpoint-up(md)
{
width: 20%;
padding: 1em;
}
@include media-breakpoint-up(lg)
{
width: 18%;
}
@include media-breakpoint-up(xl)
{
width: 15%;
}
&:focus, &:hover
{
> div
{
outline: solid var(--accentColor);
}
> .title
{
text-decoration: underline;
}
}
> 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;
&.date
{
opacity: 0.8;
font-size: 0.8em;
}
}
&:hover
{
cursor: pointer;
}
}
/*.people
{
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(md)
{
width: 20%;
}
@include media-breakpoint-up(lg)
{
width: 15%;
}
@include media-breakpoint-up(xl)
{
width: 10%;
}
> 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;
&.role
{
font-size: 0.8em;
}
}
&:hover
{
cursor: pointer;
> img
{
outline: solid var(--accentColor);
}
.name
{
text-decoration: underline;
}
}
}*/
.scroll-row
{
position: relative;
&:hover
{
.scrollBtn
{
display: block;
}
}
}
.scrollBtn
{
padding: 0;
outline: none;
min-width: 0;
position: absolute;
top: 30%;
bottom: 40%;
display: none;
&#pl-leftBtn
{
left: 0;
padding-left: 10px;
padding-right: 2px;
}
&#pl-rightBtn
{
right: 0;
padding-right: 10px;
padding-left: 2px;
}
}
#leftBtn
{
position: absolute;
left: 0;
top: 33%;
outline: none;
}
#rightBtn
{
position: absolute;
right: 0;
top: 33%;
outline: none;
}

View File

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

View File

@ -0,0 +1,47 @@
import { Component, OnInit, Input } from '@angular/core';
import { DomSanitizer } from "@angular/platform-browser";
import { Show } from "../../models/show";
@Component({
selector: 'app-shows-list',
templateUrl: './shows-list.component.html',
styleUrls: ['./shows-list.component.scss']
})
export class ShowsListComponent implements OnInit
{
@Input() shows: Show[];
private showsScroll: HTMLElement;
constructor(private sanitizer: DomSanitizer) { }
ngOnInit()
{
this.showsScroll = document.getElementById("showsScroll");
}
scrollLeft()
{
let scroll: number = this.showsScroll.offsetWidth * 0.80;
this.showsScroll.scrollBy({ top: 0, left: -scroll, behavior: "smooth" });
document.getElementById("pl-rightBtn").classList.remove("d-none");
if (this.showsScroll.scrollLeft - scroll <= 0)
document.getElementById("pl-leftBtn").classList.add("d-none");
}
scrollRight()
{
let scroll: number = this.showsScroll.offsetWidth * 0.80;
this.showsScroll.scrollBy({ top: 0, left: scroll, behavior: "smooth" });
document.getElementById("pl-leftBtn").classList.remove("d-none");
if (this.showsScroll.scrollLeft + scroll >= this.showsScroll.scrollWidth - this.showsScroll.clientWidth)
document.getElementById("pl-rightBtn").classList.add("d-none");
}
getThumb(slug: string)
{
return this.sanitizer.bypassSecurityTrustStyle("url(/poster/" + slug + ")");
}
}

View File

@ -8,5 +8,6 @@ export interface Episode
overview: string;
releaseDate;
runtime: number;
externalIDs: string;
externalIDs: string;
showTitle: string;
}

View File

@ -9,6 +9,6 @@ export interface SearchResut
shows: Show[];
episodes: Episode[];
people: People[];
genres: Genre[];
genrwes: Genre[];
studios: Studio[];
}

View File

@ -682,14 +682,14 @@ namespace Kyoo.InternalAPI
{
List<Episode> episodes = new List<Episode>();
SQLiteDataReader reader;
string query = "SELECT * FROM episodes WHERE title LIKE $query ORDER BY seasonNumber, episodeNumber;";
string query = "SELECT episodes.*, shows.slug, shows.title as showTitle FROM episodes JOIN shows ON showID = shows.id WHERE episodes.title LIKE $query ORDER BY seasonNumber, episodeNumber LIMIT 20;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{
cmd.Parameters.AddWithValue("$query", "%" + searchQuery + "%");
reader = cmd.ExecuteReader();
while (reader.Read())
episodes.Add(Episode.FromReader(reader));
episodes.Add(Episode.FromReader(reader).SetThumb(reader["slug"] as string).SetShowTitle(reader["showTitle"] as string));
}
return episodes;
}
@ -698,7 +698,7 @@ namespace Kyoo.InternalAPI
{
List<People> people = new List<People>();
SQLiteDataReader reader;
string query = "SELECT * FROM people WHERE name LIKE $query ORDER BY name;";
string query = "SELECT * FROM people WHERE name LIKE $query ORDER BY name LIMIT 40;";
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
{

View File

@ -22,7 +22,8 @@ namespace Kyoo.Models
[JsonIgnore] public string ImgPrimary;
public string ExternalIDs;
public string Link; //Used only on the player
public string ShowTitle; //Used in the API response only
public string Link; //Used in the API response only
public string Thumb; //Used in the API response only
@ -86,6 +87,12 @@ namespace Kyoo.Models
return this;
}
public Episode SetShowTitle(string showTite)
{
ShowTitle = showTite;
return this;
}
public static string GetSlug(string showSlug, long seasonNumber, long episodeNumber)
{
return showSlug + "-s" + seasonNumber + "e" + episodeNumber;