mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-07-09 03:04:20 -04:00
Working on the player.
This commit is contained in:
parent
21002fea4a
commit
44c8451735
5
Kyoo/ClientApp/package-lock.json
generated
5
Kyoo/ClientApp/package-lock.json
generated
@ -4358,6 +4358,11 @@
|
|||||||
"integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==",
|
"integrity": "sha512-b9usnbDGnD928gJB3LrCmxoibr3VE4U2SMo5PBuBnokWyDADTqDPXg4YpwKF1trpH+UbGp7QLicO3+aWEy0+mw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"hammerjs": {
|
||||||
|
"version": "2.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
|
||||||
|
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
|
||||||
|
},
|
||||||
"handle-thing": {
|
"handle-thing": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.0.tgz",
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
"@angular/platform-browser-dynamic": "~8.2.0",
|
"@angular/platform-browser-dynamic": "~8.2.0",
|
||||||
"@angular/router": "~8.2.0",
|
"@angular/router": "~8.2.0",
|
||||||
"bootstrap": "^4.3.1",
|
"bootstrap": "^4.3.1",
|
||||||
|
"hammerjs": "^2.0.8",
|
||||||
"jquery": "^3.4.1",
|
"jquery": "^3.4.1",
|
||||||
"popper.js": "^1.15.0",
|
"popper.js": "^1.15.0",
|
||||||
"rxjs": "~6.4.0",
|
"rxjs": "~6.4.0",
|
||||||
|
@ -14,7 +14,7 @@ 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: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService }, runGuardsAndResolvers: "always" },
|
{ path: "watch/:item", component: PlayerComponent, resolve: { item: StreamResolverService } },
|
||||||
{ path: "**", component: NotFoundComponent }
|
{ path: "**", component: NotFoundComponent }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { MatIconModule } from '@angular/material/icon';
|
|||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
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 { MatSnackBarModule } from '@angular/material/snack-bar';
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||||
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';
|
||||||
@ -36,7 +37,8 @@ import { ShowDetailsComponent } from './show-details/show-details.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatMenuModule
|
MatMenuModule,
|
||||||
|
MatSliderModule
|
||||||
],
|
],
|
||||||
providers: [],
|
providers: [],
|
||||||
bootstrap: [AppComponent]
|
bootstrap: [AppComponent]
|
||||||
|
@ -56,9 +56,4 @@ export class EpisodesListComponent implements OnInit
|
|||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
play(episode: Episode)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,56 +1,70 @@
|
|||||||
<div id="root">
|
<div id="root">
|
||||||
<div class="player">
|
<div class="player">
|
||||||
<video id="player" autoplay muted (click)="tooglePlayback()">
|
<video id="player" poster="backdrop/{{this.item.showSlug}}" autoplay muted (click)="tooglePlayback()">
|
||||||
<source src="/api/video/{{this.video}}" type="video/mp4" />
|
<source src="/api/video/{{this.item.link}}" type="video/mp4" />
|
||||||
</video>
|
</video>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="back">
|
<div id="hover">
|
||||||
<button mat-icon-button data-toggle="tooltip" data-placement="bottom" title="Back" (click)="back()">
|
<div class="back">
|
||||||
<mat-icon>arrow_back</mat-icon>
|
<button mat-icon-button data-toggle="tooltip" data-placement="bottom" title="Back" (click)="back()">
|
||||||
</button>
|
<mat-icon>arrow_back</mat-icon>
|
||||||
<h5>{{this.item.showTitle}}</h5>
|
</button>
|
||||||
</div>
|
<h5>{{this.item.showTitle}}</h5>
|
||||||
|
|
||||||
<div class="controller container-fluid">
|
|
||||||
<div class="img">
|
|
||||||
<img src="thumb/{{this.item.showSlug}}" />
|
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
|
||||||
<h3>S{{this.item.seasonNumber}}:E{{this.item.episodeNumber}} - {{this.item.title}}</h3>
|
<div class="controller container-fluid">
|
||||||
<mat-progress-bar color="accent"></mat-progress-bar>
|
<div class="img">
|
||||||
<div class="buttons">
|
<img src="thumb/{{this.item.showSlug}}" />
|
||||||
<div class="left">
|
</div>
|
||||||
<button *ngIf="this.item.episodeNumber != 1" mat-icon-button data-toggle="tooltip" data-placement="top" title="Previous" routerLink="/watch/{{this.item.showSlug}}-s{{this.item.seasonNumber}}e{{this.item.episodeNumber - 1}}">
|
<div class="content">
|
||||||
<mat-icon>skip_previous</mat-icon>
|
<h3>S{{this.item.seasonNumber}}:E{{this.item.episodeNumber}} - {{this.item.title}}</h3>
|
||||||
</button>
|
<mat-progress-bar color="accent"></mat-progress-bar>
|
||||||
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Play" id="play" (click)="tooglePlayback()">
|
<div class="buttons">
|
||||||
<mat-icon>{{this.playIcon}}</mat-icon>
|
<div class="left">
|
||||||
</button>
|
<button *ngIf="this.item.previousEpisode" mat-icon-button data-toggle="tooltip" data-placement="top" title="Previous" routerLink="/watch/{{this.item.previousEpisode}}">
|
||||||
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Next" routerLink="/watch/{{this.item.showSlug}}-s{{this.item.seasonNumber}}e{{this.item.episodeNumber + 1}}">
|
<mat-icon>skip_previous</mat-icon>
|
||||||
<mat-icon>skip_next</mat-icon>
|
</button>
|
||||||
</button>
|
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Play" id="play" (click)="tooglePlayback()">
|
||||||
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Volume">
|
<mat-icon>{{this.playIcon}}</mat-icon>
|
||||||
<mat-icon>volume_up</mat-icon>
|
</button>
|
||||||
</button>
|
<button mat-icon-button id="nextBtn" *ngIf="this.item.nextEpisode" routerLink="/watch/{{this.item.nextEpisode.link}}">
|
||||||
<p>00:00 / --:--</p>
|
<mat-icon>skip_next</mat-icon>
|
||||||
</div>
|
|
||||||
<div class="right">
|
<div id="next">
|
||||||
<button *ngIf="this.item.audios != null" mat-icon-button data-toggle="tooltip" data-placement="top" title="Select audio track">
|
<div id="main">
|
||||||
<mat-icon>music_note</mat-icon>
|
<img src="{{this.item.nextEpisode.thumb}}" />
|
||||||
</button>
|
</div>
|
||||||
<button *ngIf="this.item.subtitles != null" mat-icon-button data-toggle="tooltip" data-placement="top" title="Select subtitle track">
|
<div id="overview">
|
||||||
<mat-icon>closed_caption</mat-icon>
|
<h6>S{{this.item.nextEpisode.seasonNumber}}:E{{this.item.nextEpisode.episodeNumber}} - {{this.item.nextEpisode.title}}</h6>
|
||||||
</button>
|
<p>{{this.item.nextEpisode.overview}}</p>
|
||||||
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Cast">
|
</div>
|
||||||
<mat-icon>cast</mat-icon>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Settings">
|
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Volume">
|
||||||
<mat-icon>settings</mat-icon>
|
<mat-icon>volume_up</mat-icon>
|
||||||
</button>
|
|
||||||
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Fullscreen" id="fullscreen" (click)="fullscreen()">
|
<mat-slider></mat-slider>
|
||||||
<mat-icon>{{fullscreenIcon}}</mat-icon>
|
</button>
|
||||||
</button>
|
<p>{{this.minutes | number: '2.0-0'}}:{{this.seconds | number: '2.0-0'}} / --:--</p>
|
||||||
|
</div>
|
||||||
|
<div class="right">
|
||||||
|
<button *ngIf="this.item.audios != null" mat-icon-button data-toggle="tooltip" data-placement="top" title="Select audio track">
|
||||||
|
<mat-icon>music_note</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button *ngIf="this.item.subtitles != null" mat-icon-button data-toggle="tooltip" data-placement="top" title="Select subtitle track">
|
||||||
|
<mat-icon>closed_caption</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Cast">
|
||||||
|
<mat-icon>cast</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Settings">
|
||||||
|
<mat-icon>settings</mat-icon>
|
||||||
|
</button>
|
||||||
|
<button mat-icon-button data-toggle="tooltip" data-placement="top" title="Fullscreen" id="fullscreen" (click)="fullscreen()">
|
||||||
|
<mat-icon>{{fullscreenIcon}}</mat-icon>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -114,3 +114,62 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#nextBtn
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover
|
||||||
|
{
|
||||||
|
#next
|
||||||
|
{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#next
|
||||||
|
{
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
bottom: 100%;
|
||||||
|
display: none;
|
||||||
|
background-color: #212121;
|
||||||
|
white-space: normal;
|
||||||
|
line-height: normal;
|
||||||
|
cursor: default;
|
||||||
|
height: 150px;
|
||||||
|
|
||||||
|
#main
|
||||||
|
{
|
||||||
|
width: auto;
|
||||||
|
height: 100%;
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-grow: 0;
|
||||||
|
|
||||||
|
> img
|
||||||
|
{
|
||||||
|
width: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#overview
|
||||||
|
{
|
||||||
|
padding: 1%;
|
||||||
|
width: 50%;
|
||||||
|
min-width: 300px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> p
|
||||||
|
{
|
||||||
|
text-align: justify;
|
||||||
|
font-weight: 300;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -12,22 +12,31 @@ import { Location } from "@angular/common";
|
|||||||
export class PlayerComponent implements OnInit
|
export class PlayerComponent implements OnInit
|
||||||
{
|
{
|
||||||
item: WatchItem;
|
item: WatchItem;
|
||||||
video: string;
|
|
||||||
|
hours: number;
|
||||||
|
minutes: number;
|
||||||
|
seconds: number;
|
||||||
|
|
||||||
playIcon: string = "pause"; //Icon used by the play btn.
|
playIcon: string = "pause"; //Icon used by the play btn.
|
||||||
fullscreenIcon: string = "fullscreen"; //Icon used by the fullscreen btn.
|
fullscreenIcon: string = "fullscreen"; //Icon used by the fullscreen btn.
|
||||||
|
|
||||||
private player: HTMLVideoElement;
|
private player: HTMLVideoElement;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private location: Location)
|
constructor(private route: ActivatedRoute, private sanitizer: DomSanitizer, private location: Location) { }
|
||||||
{
|
|
||||||
this.video = this.route.snapshot.paramMap.get("item");
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit()
|
ngOnInit()
|
||||||
{
|
{
|
||||||
document.getElementById("nav").classList.add("d-none");
|
document.getElementById("nav").classList.add("d-none");
|
||||||
this.item = this.route.snapshot.data.item;
|
this.route.data.subscribe((data) =>
|
||||||
|
{
|
||||||
|
this.item = data.item;
|
||||||
|
|
||||||
|
if (this.player)
|
||||||
|
{
|
||||||
|
this.player.load();
|
||||||
|
this.initPlayBtn();
|
||||||
|
}
|
||||||
|
});
|
||||||
console.log("Init");
|
console.log("Init");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,9 +45,25 @@ export class PlayerComponent implements OnInit
|
|||||||
this.player = document.getElementById("player") as HTMLVideoElement;
|
this.player = document.getElementById("player") as HTMLVideoElement;
|
||||||
this.player.controls = false;
|
this.player.controls = false;
|
||||||
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
this.player.onplay = () =>
|
||||||
|
{
|
||||||
|
this.initPlayBtn();
|
||||||
|
}
|
||||||
|
|
||||||
document.addEventListener("fullscreenchange", (event) =>
|
this.player.onpause = () =>
|
||||||
|
{
|
||||||
|
this.playIcon = "play_arrow"
|
||||||
|
$("#play").attr("data-original-title", "Play").tooltip("show");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.player.ontimeupdate = () =>
|
||||||
|
{
|
||||||
|
this.seconds = Math.round(this.player.currentTime % 60);
|
||||||
|
this.minutes = Math.round(this.player.currentTime / 60);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener("fullscreenchange", () =>
|
||||||
{
|
{
|
||||||
if (document.fullscreenElement != null)
|
if (document.fullscreenElement != null)
|
||||||
{
|
{
|
||||||
@ -51,6 +76,8 @@ export class PlayerComponent implements OnInit
|
|||||||
$("#fullscreen").attr("data-original-title", "Fullscreen").tooltip("show");
|
$("#fullscreen").attr("data-original-title", "Fullscreen").tooltip("show");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnDestroy()
|
ngOnDestroy()
|
||||||
@ -65,22 +92,16 @@ export class PlayerComponent implements OnInit
|
|||||||
|
|
||||||
tooglePlayback()
|
tooglePlayback()
|
||||||
{
|
{
|
||||||
let playBtn: HTMLElement = document.getElementById("play");
|
|
||||||
|
|
||||||
if (this.player.paused)
|
if (this.player.paused)
|
||||||
{
|
|
||||||
this.player.play();
|
this.player.play();
|
||||||
|
|
||||||
this.playIcon = "pause"
|
|
||||||
$(playBtn).attr("data-original-title", "Pause").tooltip("show");
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
this.player.pause();
|
this.player.pause();
|
||||||
|
}
|
||||||
|
|
||||||
this.playIcon = "play_arrow"
|
initPlayBtn()
|
||||||
$(playBtn).attr("data-original-title", "Play").tooltip("show");
|
{
|
||||||
}
|
this.playIcon = "pause";
|
||||||
|
$("#play").attr("data-original-title", "Pause").tooltip("show");
|
||||||
}
|
}
|
||||||
|
|
||||||
fullscreen()
|
fullscreen()
|
||||||
@ -90,4 +111,10 @@ export class PlayerComponent implements OnInit
|
|||||||
else
|
else
|
||||||
document.exitFullscreen();
|
document.exitFullscreen();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getThumb(url: string)
|
||||||
|
{
|
||||||
|
return this.sanitizer.bypassSecurityTrustStyle("url(" + url + ")");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
|||||||
|
|
||||||
import { AppModule } from './app/app.module';
|
import { AppModule } from './app/app.module';
|
||||||
import { environment } from './environments/environment';
|
import { environment } from './environments/environment';
|
||||||
|
import "hammerjs"
|
||||||
|
|
||||||
if (environment.production) {
|
if (environment.production) {
|
||||||
enableProdMode();
|
enableProdMode();
|
||||||
|
3
Kyoo/ClientApp/src/models/episode.js
Normal file
3
Kyoo/ClientApp/src/models/episode.js
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
"use strict";
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
//# sourceMappingURL=episode.js.map
|
1
Kyoo/ClientApp/src/models/episode.js.map
Normal file
1
Kyoo/ClientApp/src/models/episode.js.map
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"version":3,"file":"episode.js","sourceRoot":"","sources":["episode.ts"],"names":[],"mappings":""}
|
@ -2,6 +2,8 @@ export interface Episode
|
|||||||
{
|
{
|
||||||
episodeNumber: number;
|
episodeNumber: number;
|
||||||
title: string;
|
title: string;
|
||||||
|
thumb: string;
|
||||||
|
link: string;
|
||||||
overview: string;
|
overview: string;
|
||||||
releaseDate;
|
releaseDate;
|
||||||
runtimeInMinutes: number;
|
runtimeInMinutes: number;
|
||||||
|
@ -1,11 +1,19 @@
|
|||||||
|
import { Episode } from "./episode";
|
||||||
|
|
||||||
export interface WatchItem
|
export interface WatchItem
|
||||||
{
|
{
|
||||||
showTitle: string;
|
showTitle: string;
|
||||||
showSlug: string;
|
showSlug: string;
|
||||||
seasonNumber: number;
|
seasonNumber: number;
|
||||||
episodeNumber: number;
|
episodeNumber: number;
|
||||||
|
video: string;
|
||||||
title: string;
|
title: string;
|
||||||
|
link: string;
|
||||||
releaseDate;
|
releaseDate;
|
||||||
|
|
||||||
|
previousEpisode: string;
|
||||||
|
nextEpisode: Episode;
|
||||||
|
|
||||||
audio: Stream[];
|
audio: Stream[];
|
||||||
subtitles: Stream[];
|
subtitles: Stream[];
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@ namespace Kyoo.InternalAPI
|
|||||||
List<People> GetPeople(long showID);
|
List<People> GetPeople(long showID);
|
||||||
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);
|
||||||
(VideoStream video, List<Stream> audios, List<Stream> subtitles) GetStreams(long episodeID);
|
(VideoStream video, List<Stream> audios, List<Stream> subtitles) GetStreams(long episodeID);
|
||||||
|
|
||||||
//Public read
|
//Public read
|
||||||
@ -22,7 +23,7 @@ namespace Kyoo.InternalAPI
|
|||||||
Season GetSeason(string showSlug, long seasonNumber);
|
Season GetSeason(string showSlug, long seasonNumber);
|
||||||
List<Episode> GetEpisodes(string showSlug, long seasonNumber);
|
List<Episode> GetEpisodes(string showSlug, long seasonNumber);
|
||||||
Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber);
|
Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber);
|
||||||
WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber);
|
WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber, bool complete = true);
|
||||||
People GetPeopleBySlug(string slug);
|
People GetPeopleBySlug(string slug);
|
||||||
Genre GetGenreBySlug(string slug);
|
Genre GetGenreBySlug(string slug);
|
||||||
Studio GetStudioBySlug(string slug);
|
Studio GetStudioBySlug(string slug);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using Kyoo.Models;
|
using Kyoo.Models;
|
||||||
using Kyoo.Models.Watch;
|
using Kyoo.Models.Watch;
|
||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Data.SQLite;
|
using System.Data.SQLite;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
@ -233,7 +234,7 @@ namespace Kyoo.InternalAPI
|
|||||||
|
|
||||||
public List<Season> GetSeasons(long showID)
|
public List<Season> GetSeasons(long showID)
|
||||||
{
|
{
|
||||||
string query = "SELECT * FROM seasons WHERE showID = $showID;";
|
string query = "SELECT * FROM seasons WHERE showID = $showID ORDER BY seasonNumber;";
|
||||||
|
|
||||||
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||||
{
|
{
|
||||||
@ -266,9 +267,23 @@ namespace Kyoo.InternalAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetSeasonCount(string showSlug, long seasonNumber)
|
||||||
|
{
|
||||||
|
string query = "SELECT count(episodes.id) FROM episodes JOIN shows ON shows.id = episodes.showID WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber;";
|
||||||
|
|
||||||
|
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||||
|
{
|
||||||
|
cmd.Parameters.AddWithValue("$showSlug", showSlug);
|
||||||
|
cmd.Parameters.AddWithValue("$seasonNumber", seasonNumber);
|
||||||
|
|
||||||
|
int count = Convert.ToInt32(cmd.ExecuteScalar());
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<Episode> GetEpisodes(string showSlug, long seasonNumber)
|
public List<Episode> GetEpisodes(string showSlug, long seasonNumber)
|
||||||
{
|
{
|
||||||
string query = "SELECT * FROM episodes JOIN shows ON shows.id = episodes.showID WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber;";
|
string query = "SELECT * FROM episodes JOIN shows ON shows.id = episodes.showID WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber ORDER BY episodeNumber;";
|
||||||
|
|
||||||
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
|
||||||
{
|
{
|
||||||
@ -303,7 +318,7 @@ namespace Kyoo.InternalAPI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber)
|
public WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber, bool complete = true)
|
||||||
{
|
{
|
||||||
string query = "SELECT episodes.id, shows.title as showTitle, shows.slug as showSlug, seasonNumber, episodeNumber, episodes.title, releaseDate, episodes.path FROM episodes JOIN shows ON shows.id = episodes.showID WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber AND episodes.episodeNumber = $episodeNumber;";
|
string query = "SELECT episodes.id, shows.title as showTitle, shows.slug as showSlug, seasonNumber, episodeNumber, episodes.title, releaseDate, episodes.path FROM episodes JOIN shows ON shows.id = episodes.showID WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber AND episodes.episodeNumber = $episodeNumber;";
|
||||||
|
|
||||||
@ -315,7 +330,12 @@ namespace Kyoo.InternalAPI
|
|||||||
SQLiteDataReader reader = cmd.ExecuteReader();
|
SQLiteDataReader reader = cmd.ExecuteReader();
|
||||||
|
|
||||||
if (reader.Read())
|
if (reader.Read())
|
||||||
return WatchItem.FromReader(reader).SetStreams(this);
|
{
|
||||||
|
if (complete)
|
||||||
|
return WatchItem.FromReader(reader).SetStreams(this).SetPrevious(this).SetNext(this);
|
||||||
|
else
|
||||||
|
return WatchItem.FromReader(reader);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ namespace Kyoo.Models
|
|||||||
[JsonIgnore] public string ImgPrimary;
|
[JsonIgnore] public string ImgPrimary;
|
||||||
public string ExternalIDs;
|
public string ExternalIDs;
|
||||||
|
|
||||||
|
public string Link; //Used only on the player
|
||||||
public string Thumb; //Used in the API response only
|
public string Thumb; //Used in the API response only
|
||||||
|
|
||||||
|
|
||||||
@ -77,6 +78,7 @@ namespace Kyoo.Models
|
|||||||
public Episode SetThumb(string showSlug)
|
public Episode SetThumb(string showSlug)
|
||||||
{
|
{
|
||||||
Thumb = "thumb/" + showSlug + "/s" + seasonNumber + "/e" + episodeNumber;
|
Thumb = "thumb/" + showSlug + "/s" + seasonNumber + "/e" + episodeNumber;
|
||||||
|
Link = showSlug + "-s" + seasonNumber + "e" + episodeNumber;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,11 @@ namespace Kyoo.Models
|
|||||||
public long seasonNumber;
|
public long seasonNumber;
|
||||||
public long episodeNumber;
|
public long episodeNumber;
|
||||||
public string Title;
|
public string Title;
|
||||||
|
public string Link;
|
||||||
public DateTime? ReleaseDate;
|
public DateTime? ReleaseDate;
|
||||||
[JsonIgnore] public string Path;
|
[JsonIgnore] public string Path;
|
||||||
|
public string previousEpisode;
|
||||||
|
public Episode nextEpisode;
|
||||||
|
|
||||||
[JsonIgnore] public VideoStream video;
|
[JsonIgnore] public VideoStream video;
|
||||||
public IEnumerable<Stream> audios;
|
public IEnumerable<Stream> audios;
|
||||||
@ -34,6 +37,8 @@ namespace Kyoo.Models
|
|||||||
Title = title;
|
Title = title;
|
||||||
ReleaseDate = releaseDate;
|
ReleaseDate = releaseDate;
|
||||||
Path = path;
|
Path = path;
|
||||||
|
|
||||||
|
Link = ShowSlug + "-s" + seasonNumber + "e" + episodeNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WatchItem(long episodeID, string showTitle, string showSlug, long seasonNumber, long episodeNumber, string title, DateTime? releaseDate, string path, Stream[] audios, Stream[] subtitles) : this(episodeID, showTitle, showSlug, seasonNumber, episodeNumber, title, releaseDate, path)
|
public WatchItem(long episodeID, string showTitle, string showSlug, long seasonNumber, long episodeNumber, string title, DateTime? releaseDate, string path, Stream[] audios, Stream[] subtitles) : this(episodeID, showTitle, showSlug, seasonNumber, episodeNumber, title, releaseDate, path)
|
||||||
@ -62,5 +67,29 @@ namespace Kyoo.Models
|
|||||||
subtitles = streams.subtitles;
|
subtitles = streams.subtitles;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public WatchItem SetPrevious(ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
long lastEp = episodeNumber - 1;
|
||||||
|
if(lastEp > 0)
|
||||||
|
previousEpisode = ShowSlug + "-s" + seasonNumber + "e" + lastEp;
|
||||||
|
else if(seasonNumber > 1)
|
||||||
|
{
|
||||||
|
int seasonCount = libraryManager.GetSeasonCount(ShowSlug, seasonNumber - 1);
|
||||||
|
previousEpisode = ShowSlug + "-s" + (seasonNumber - 1) + "e" + seasonCount;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public WatchItem SetNext(ILibraryManager libraryManager)
|
||||||
|
{
|
||||||
|
long seasonCount = libraryManager.GetSeasonCount(ShowSlug, seasonNumber);
|
||||||
|
if (episodeNumber >= seasonCount)
|
||||||
|
nextEpisode = libraryManager.GetEpisode(ShowSlug, seasonNumber + 1, 1);
|
||||||
|
else
|
||||||
|
nextEpisode = libraryManager.GetEpisode(ShowSlug, seasonNumber, episodeNumber + 1);
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user