S{{this.item.seasonNumber}}:E{{this.item.episodeNumber}} - {{this.item.title}}
diff --git a/Kyoo/ClientApp/src/app/player/player.component.ts b/Kyoo/ClientApp/src/app/player/player.component.ts
index 5e4e4097..943ff377 100644
--- a/Kyoo/ClientApp/src/app/player/player.component.ts
+++ b/Kyoo/ClientApp/src/app/player/player.component.ts
@@ -207,7 +207,6 @@ export class PlayerComponent implements OnInit
$(window).keydown((e) =>
{
- console.log(e.keyCode);
switch (e.keyCode)
{
case 32: //space
@@ -313,6 +312,7 @@ export class PlayerComponent implements OnInit
this.title.setTitle("Kyoo");
$(document).unbind();
+ $(window).unbind();
$('[data-toggle="tooltip"]').hide();
}
diff --git a/Kyoo/Controllers/SubtitleController.cs b/Kyoo/Controllers/SubtitleController.cs
index 9ce91ec9..cb20049d 100644
--- a/Kyoo/Controllers/SubtitleController.cs
+++ b/Kyoo/Controllers/SubtitleController.cs
@@ -2,7 +2,12 @@
using Kyoo.Models;
using Kyoo.Models.Watch;
using Microsoft.AspNetCore.Mvc;
+using System.Collections.Generic;
using System.Diagnostics;
+using System.IO;
+using System.Net;
+using System.Net.Http;
+using System.Threading.Tasks;
namespace Kyoo.Controllers
{
@@ -19,8 +24,8 @@ namespace Kyoo.Controllers
this.transcoder = transcoder;
}
- [HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{codec?}")]
- public IActionResult GetSubtitle(string showSlug, int seasonNumber, int episodeNumber, string identifier, string codec)
+ [HttpGet("{showSlug}-s{seasonNumber:int}e{episodeNumber:int}.{identifier}.{extension?}")]
+ public IActionResult GetSubtitle(string showSlug, int seasonNumber, int episodeNumber, string identifier, string extension)
{
string languageTag = identifier.Substring(0, 3);
bool forced = identifier.Length > 3 && identifier.Substring(4) == "forced";
@@ -30,10 +35,16 @@ namespace Kyoo.Controllers
if (subtitle == null)
return NotFound();
- string mime = "text/vtt";
+
+ if (subtitle.Codec == "subrip" && extension == "vtt") //The request wants a WebVTT from a Subrip subtitle, convert it on the fly and send it.
+ {
+ return new ConvertSubripToVtt(subtitle.Path);
+ }
+
+ string mime;
if (subtitle.Codec == "ass")
mime = "text/x-ssa";
- else if (subtitle.Codec == "subrip")
+ else
mime = "application/x-subrip";
//Should use appropriate mime type here
@@ -44,9 +55,87 @@ namespace Kyoo.Controllers
public string ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber)
{
Episode episode = libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber);
- transcoder.ExtractSubtitles(episode.Path);
+ libraryManager.ClearSubtitles(episode.id);
- return "Processing...";
+ Track[] tracks = transcoder.ExtractSubtitles(episode.Path);
+ foreach (Track track in tracks)
+ {
+ track.episodeID = episode.id;
+ libraryManager.RegisterTrack(track);
+ }
+
+ return "Done. " + tracks.Length + " track(s) extracted.";
+ }
+
+ [HttpGet("extract/{showSlug}")]
+ public string ExtractSubtitle(string showSlug)
+ {
+ List
episodes = libraryManager.GetEpisodes(showSlug);
+ foreach (Episode episode in episodes)
+ {
+ libraryManager.ClearSubtitles(episode.id);
+
+ Track[] tracks = transcoder.ExtractSubtitles(episode.Path);
+ foreach (Track track in tracks)
+ {
+ track.episodeID = episode.id;
+ libraryManager.RegisterTrack(track);
+ }
+ }
+
+ return "Done.";
+ }
+ }
+
+
+ public class ConvertSubripToVtt : IActionResult
+ {
+ private string path;
+ private string lastLine = "";
+
+ public ConvertSubripToVtt(string subtitlePath)
+ {
+ path = subtitlePath;
+ }
+
+ public async Task ExecuteResultAsync(ActionContext context)
+ {
+ context.HttpContext.Response.StatusCode = 200;
+ //HttpContext.Response.Headers.Add("Content-Disposition", "attachement");
+ context.HttpContext.Response.Headers.Add("Content-Type", "text/vtt");
+
+ using (StreamWriter writer = new StreamWriter(context.HttpContext.Response.Body))
+ {
+ await writer.WriteLineAsync("WEBVTT");
+ await writer.WriteLineAsync("");
+ await writer.WriteLineAsync("");
+
+ string line;
+ using (StreamReader reader = new StreamReader(path))
+ {
+ while ((line = await reader.ReadLineAsync()) != null)
+ {
+ string processedLine = ConvertLine(line);
+ if(processedLine != null)
+ await writer.WriteLineAsync(processedLine);
+
+ lastLine = processedLine;
+ }
+ }
+ }
+
+ await context.HttpContext.Response.Body.FlushAsync();
+ }
+
+ public string ConvertLine(string line)
+ {
+ if (lastLine == "")
+ line = null;
+
+ if (lastLine == null) //The line is a timecode only if the last line is an index line and we already set it to null.
+ line = line.Replace(',', '.'); //This is never called.
+
+ return line;
}
}
}
\ No newline at end of file
diff --git a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs
index b5983f0b..150c9938 100644
--- a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs
+++ b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs
@@ -24,6 +24,7 @@ namespace Kyoo.InternalAPI
IEnumerable GetLibraries();
Show GetShowBySlug(string slug);
Season GetSeason(string showSlug, long seasonNumber);
+ List GetEpisodes(string showSlug);
List GetEpisodes(string showSlug, long seasonNumber);
Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber);
WatchItem GetWatchItem(string showSlug, long seasonNumber, long episodeNumber, bool complete = true);
@@ -48,5 +49,7 @@ namespace Kyoo.InternalAPI
long GetOrCreateStudio(Studio studio);
void RegisterShowPeople(long showID, List actors);
+
+ void ClearSubtitles(long episodeID);
}
}
diff --git a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs
index b1d0c967..2fa9fe0a 100644
--- a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs
+++ b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs
@@ -318,6 +318,24 @@ namespace Kyoo.InternalAPI
}
}
+ public List GetEpisodes(string showSlug)
+ {
+ string query = "SELECT * FROM episodes JOIN shows ON shows.id = episodes.showID WHERE shows.slug = $showSlug ORDER BY episodeNumber;";
+
+ using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
+ {
+ cmd.Parameters.AddWithValue("$showSlug", showSlug);
+ SQLiteDataReader reader = cmd.ExecuteReader();
+
+ List episodes = new List();
+
+ while (reader.Read())
+ episodes.Add(Episode.FromReader(reader).SetThumb(showSlug));
+
+ return episodes;
+ }
+ }
+
public List 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 ORDER BY episodeNumber;";
@@ -735,6 +753,17 @@ namespace Kyoo.InternalAPI
}
}
}
+
+ public void ClearSubtitles(long episodeID)
+ {
+ string query = "DELETE FROM tracks WHERE episodeID = $episodeID;";
+
+ using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection))
+ {
+ cmd.Parameters.AddWithValue("$episodeID", episodeID);
+ cmd.ExecuteNonQuery();
+ }
+ }
#endregion
}
}
diff --git a/Kyoo/InternalAPI/Transcoder/Transcoder.cs b/Kyoo/InternalAPI/Transcoder/Transcoder.cs
index 74e12b95..0a599601 100644
--- a/Kyoo/InternalAPI/Transcoder/Transcoder.cs
+++ b/Kyoo/InternalAPI/Transcoder/Transcoder.cs
@@ -1,8 +1,10 @@
using Kyoo.InternalAPI.TranscoderLink;
using Kyoo.Models;
+using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using System.Diagnostics;
using System.IO;
+using System.Threading.Tasks;
namespace Kyoo.InternalAPI
{