diff --git a/Kyoo/ClientApp/src/app/player/player.component.html b/Kyoo/ClientApp/src/app/player/player.component.html
index cf824fe2..90ce7779 100644
--- a/Kyoo/ClientApp/src/app/player/player.component.html
+++ b/Kyoo/ClientApp/src/app/player/player.component.html
@@ -1,7 +1,8 @@
diff --git a/Kyoo/Controllers/SubtitleController.cs b/Kyoo/Controllers/SubtitleController.cs
index e1f71fad..15591ca1 100644
--- a/Kyoo/Controllers/SubtitleController.cs
+++ b/Kyoo/Controllers/SubtitleController.cs
@@ -1,4 +1,5 @@
using Kyoo.InternalAPI;
+using Kyoo.Models.Watch;
using Microsoft.AspNetCore.Mvc;
namespace Kyoo.Controllers
@@ -14,10 +15,16 @@ namespace Kyoo.Controllers
this.libraryManager = libraryManager;
}
- [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}-{languageTag}.ass")]
- public IActionResult GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag)
+ [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}-{languageTag}.{format?}")]
+ public IActionResult GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag, string format)
{
- return PhysicalFile(@"D:\Videos\Devilman\Subtitles\fre\Devilman Crybaby S01E01.fre.ass", "text/x-ssa");
+ Stream subtitle = libraryManager.GetSubtitle(showSlug, seasonNumber, episodeNumber, languageTag);
+
+ if (subtitle == null)
+ return NotFound();
+
+ //Should use appropriate mime type here
+ return PhysicalFile(subtitle.Path, "text/x-ssa");
}
}
}
\ No newline at end of file
diff --git a/Kyoo/Controllers/VideoController.cs b/Kyoo/Controllers/VideoController.cs
index 2eeebade..0d379422 100644
--- a/Kyoo/Controllers/VideoController.cs
+++ b/Kyoo/Controllers/VideoController.cs
@@ -22,11 +22,35 @@ namespace Kyoo.Controllers
{
WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
+ if (System.IO.File.Exists(episode.Path))
+ return PhysicalFile(episode.Path, "video/x-matroska", true);
+ else
+ return NotFound();
+ }
+
+ [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}/stream")]
+ public IActionResult Stream(string showSlug, long seasonNumber, long episodeNumber)
+ {
+ WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
+
if (System.IO.File.Exists(episode.Path))
{
- //Should check if video is playable on the client and transcode if needed.
- //Should use the right mime type
- return PhysicalFile(episode.Path, "video/mp4", true);
+ string path = transcoder.Stream(episode.Path);
+ return PhysicalFile(path, "video/mp4", true);
+ }
+ else
+ return NotFound();
+ }
+
+ [HttpGet("{showSlug}-s{seasonNumber}e{episodeNumber}/transcode")]
+ public IActionResult Transcode(string showSlug, long seasonNumber, long episodeNumber)
+ {
+ WatchItem episode = libraryManager.GetWatchItem(showSlug, seasonNumber, episodeNumber);
+
+ if (System.IO.File.Exists(episode.Path))
+ {
+ string path = transcoder.Transcode(episode.Path);
+ return PhysicalFile(path, "video/mp4", true);
}
else
return NotFound();
diff --git a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs
index 79c9ac2e..8d5d821e 100644
--- a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs
+++ b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs
@@ -15,7 +15,10 @@ namespace Kyoo.InternalAPI
List
GetGenreForShow(long showID);
List GetSeasons(long showID);
int GetSeasonCount(string showSlug, long seasonNumber);
- (VideoStream video, List audios, List subtitles) GetStreams(long episodeID);
+
+ //Internal HTML read
+ (List audios, List subtitles) GetStreams(long episodeID);
+ Stream GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag);
//Public read
IEnumerable GetLibraries();
diff --git a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs
index 55870ab8..0efb67bf 100644
--- a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs
+++ b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs
@@ -73,24 +73,14 @@ namespace Kyoo.InternalAPI
CREATE TABLE streams(
id INTEGER PRIMARY KEY UNIQUE,
episodeID INTEGER,
- streamIndex INTEGER,
streamType TEXT,
- codec TEXT,
+ tile TEXT,
language TEXT,
- channelLayout TEXT,
- profile TEXT,
- aspectRatio TEXT,
- bitRate INTEGER,
- sampleRate INTEGER,
+ codec TEXT,
isDefault BOOLEAN,
isForced BOOLEAN,
- isExternal BOOLEAN,
- height INTEGER,
- width INTEGER,
- frameRate NUMBER,
- level NUMBER,
- pixelFormat TEXT,
- bitDepth INTEGER,
+ isExternal BOOLEAN,
+ path TEXT,
FOREIGN KEY(episodeID) REFERENCES episodes(id)
);
@@ -199,6 +189,52 @@ namespace Kyoo.InternalAPI
}
+ public (List audios, List subtitles) GetStreams(long episodeID)
+ {
+ string query = "SELECT * FROM streams WHERE episodeID = $episodeID;";
+
+ using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
+ {
+ cmd.Parameters.AddWithValue("$episodeID", episodeID);
+ SQLiteDataReader reader = cmd.ExecuteReader();
+
+ List audios = new List();
+ List subtitles = new List();
+
+ while (reader.Read())
+ {
+ Stream stream = Stream.FromReader(reader);
+
+ if (stream.type == StreamType.Audio)
+ audios.Add(stream);
+ else if (stream.type == StreamType.Subtitle)
+ subtitles.Add(stream);
+ }
+
+ return (audios, subtitles);
+ }
+ }
+
+ public Stream GetSubtitle(string showSlug, long seasonNumber, long episodeNumber, string languageTag)
+ {
+ string query = "SELECT streams.* FROM streams JOIN episodes ON streams.episodeID = episodes.id JOIN shows ON episodes.showID = shows.id WHERE shows.showSlug = $showSlug, episodes.seasonNumber = $seasonNumber, episodes.episodeNumber = $episodeNumber, streams.language = $languageTag;";
+
+ using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
+ {
+ cmd.Parameters.AddWithValue("$showSlug", showSlug);
+ cmd.Parameters.AddWithValue("$seasonNumber", seasonNumber);
+ cmd.Parameters.AddWithValue("$episodeNumber", episodeNumber);
+ cmd.Parameters.AddWithValue("$languageTag", languageTag);
+ SQLiteDataReader reader = cmd.ExecuteReader();
+
+ if (reader.Read())
+ return Stream.FromReader(reader);
+
+ return null;
+ }
+ }
+
+
public IEnumerable QueryShows(string selection)
{
string query = "SELECT * FROM shows ORDER BY title;";
@@ -341,25 +377,6 @@ namespace Kyoo.InternalAPI
}
}
- public (VideoStream video, List audios, List subtitles) GetStreams(long episodeID)
- {
- return (new VideoStream(), null, null);
- //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("$episodeID", episodeID);
- // SQLiteDataReader reader = cmd.ExecuteReader();
-
- // List genres = new List();
-
- // while (reader.Read())
- // genres.Add(Stream.FromReader(reader));
-
- // return genres;
- //}
- }
-
public List GetPeople(long showID)
{
string query = "SELECT people.id, people.slug, people.name, people.imgPrimary, people.externalIDs, l.role, l.type FROM people JOIN peopleLinks l ON l.peopleID = people.id WHERE l.showID = $showID;";
diff --git a/Kyoo/InternalAPI/Transcoder/ITranscoder.cs b/Kyoo/InternalAPI/Transcoder/ITranscoder.cs
index 37f6728b..8c7277a7 100644
--- a/Kyoo/InternalAPI/Transcoder/ITranscoder.cs
+++ b/Kyoo/InternalAPI/Transcoder/ITranscoder.cs
@@ -2,6 +2,12 @@ namespace Kyoo.InternalAPI
{
public interface ITranscoder
{
+ //Should transcode to a mp4 container (same video/audio format if possible, no subtitles).
+ string Stream(string path);
+
+ //Should transcode to a mp4 container with a h264 video format and a AAC audio format, no subtitles.
+ string Transcode(string path);
+
void GetVideo(string Path);
dynamic ScanVideo(string Path);
diff --git a/Kyoo/InternalAPI/Transcoder/Transcoder.cs b/Kyoo/InternalAPI/Transcoder/Transcoder.cs
index 79d73909..16938d7f 100644
--- a/Kyoo/InternalAPI/Transcoder/Transcoder.cs
+++ b/Kyoo/InternalAPI/Transcoder/Transcoder.cs
@@ -22,5 +22,15 @@ namespace Kyoo.InternalAPI
{
return TranscoderAPI.ScanVideo(path);
}
+
+ public string Stream(string path)
+ {
+ return @"D:\Videos\Anohana\AnoHana S01E01.mp4";
+ }
+
+ public string Transcode(string path)
+ {
+ return @"D:\Videos\Anohana\AnoHana S01E01.mp4";
+ }
}
}
diff --git a/Kyoo/Models/Stream.cs b/Kyoo/Models/Stream.cs
index 0e1c3153..dd91de5e 100644
--- a/Kyoo/Models/Stream.cs
+++ b/Kyoo/Models/Stream.cs
@@ -1,17 +1,46 @@
-namespace Kyoo.Models.Watch
+using Newtonsoft.Json;
+
+namespace Kyoo.Models.Watch
{
- public struct Stream
+ public enum StreamType
{
+ Audio, Subtitle, Unknow
+ }
+
+ public class Stream
+ {
+ [JsonIgnore] public StreamType type;
public string Title;
public string Language;
public bool IsDefault;
public bool IsForced;
public string Format;
- }
- public struct VideoStream
- {
- public string Title;
- public string Language;
+ [JsonIgnore] public bool IsExternal;
+ [JsonIgnore] public string Path;
+
+ public Stream(StreamType type, string title, string language, bool isDefault, bool isForced, string format, bool isExternal, string path)
+ {
+ this.type = type;
+ Title = title;
+ Language = language;
+ IsDefault = isDefault;
+ IsForced = isForced;
+ Format = format;
+ IsExternal = isExternal;
+ Path = path;
+ }
+
+ public static Stream FromReader(System.Data.SQLite.SQLiteDataReader reader)
+ {
+ return new Stream(reader["streamType"] as StreamType? ?? StreamType.Unknow,
+ reader["title"] as string,
+ reader["language"] as string,
+ reader["isDefault"] as bool? ?? false,
+ reader["isForced"] as bool? ?? false,
+ reader["codec"] as string,
+ reader["isExternal"] as bool? ?? false,
+ reader["path"] as string);
+ }
}
}
diff --git a/Kyoo/Models/WatchItem.cs b/Kyoo/Models/WatchItem.cs
index d7fcfe3b..6e6c7f88 100644
--- a/Kyoo/Models/WatchItem.cs
+++ b/Kyoo/Models/WatchItem.cs
@@ -21,7 +21,6 @@ namespace Kyoo.Models
public string previousEpisode;
public Episode nextEpisode;
- [JsonIgnore] public VideoStream video;
public IEnumerable audios;
public IEnumerable subtitles;
@@ -61,8 +60,7 @@ namespace Kyoo.Models
public WatchItem SetStreams(ILibraryManager libraryManager)
{
- (VideoStream video, IEnumerable audios, IEnumerable subtitles) streams = libraryManager.GetStreams(episodeID);
- video = streams.video;
+ (IEnumerable audios, IEnumerable subtitles) streams = libraryManager.GetStreams(episodeID);
audios = streams.audios;
subtitles = streams.subtitles;
return this;