From f3d207cb4e0645047fff5cd0d4775d0d9edcb048 Mon Sep 17 00:00:00 2001 From: Zoe Roux Date: Sun, 20 Oct 2019 23:17:33 +0200 Subject: [PATCH] Solving bugs and adding library support. --- Kyoo/Controllers/SubtitleController.cs | 8 +- Kyoo/InternalAPI/Crawler/Crawler.cs | 37 +- .../LibraryManager/ILibraryManager.cs | 2 + .../LibraryManager/LibraryManager.cs | 340 +++++++++++++----- .../TheTvDB/ProviderTheTvDB.cs | 2 +- Kyoo/InternalAPI/Transcoder/ITranscoder.cs | 3 +- Kyoo/InternalAPI/Transcoder/Transcoder.cs | 10 +- Unit Tests/Kyoo-InternalAPI/Library-Tests.cs | 5 - 8 files changed, 285 insertions(+), 122 deletions(-) diff --git a/Kyoo/Controllers/SubtitleController.cs b/Kyoo/Controllers/SubtitleController.cs index 76d5a69e..f42d791d 100644 --- a/Kyoo/Controllers/SubtitleController.cs +++ b/Kyoo/Controllers/SubtitleController.cs @@ -49,12 +49,12 @@ namespace Kyoo.Controllers } [HttpGet("extract/{showSlug}-s{seasonNumber}e{episodeNumber}")] - public string ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber) + public async Task ExtractSubtitle(string showSlug, long seasonNumber, long episodeNumber) { Episode episode = libraryManager.GetEpisode(showSlug, seasonNumber, episodeNumber); libraryManager.ClearSubtitles(episode.id); - Track[] tracks = transcoder.ExtractSubtitles(episode.Path); + Track[] tracks = await transcoder.ExtractSubtitles(episode.Path); foreach (Track track in tracks) { track.episodeID = episode.id; @@ -65,14 +65,14 @@ namespace Kyoo.Controllers } [HttpGet("extract/{showSlug}")] - public string ExtractSubtitle(string showSlug) + public async Task ExtractSubtitle(string showSlug) { List episodes = libraryManager.GetEpisodes(showSlug); foreach (Episode episode in episodes) { libraryManager.ClearSubtitles(episode.id); - Track[] tracks = transcoder.ExtractSubtitles(episode.Path); + Track[] tracks = await transcoder.ExtractSubtitles(episode.Path); foreach (Track track in tracks) { track.episodeID = episode.id; diff --git a/Kyoo/InternalAPI/Crawler/Crawler.cs b/Kyoo/InternalAPI/Crawler/Crawler.cs index eb783413..e05fba80 100644 --- a/Kyoo/InternalAPI/Crawler/Crawler.cs +++ b/Kyoo/InternalAPI/Crawler/Crawler.cs @@ -14,6 +14,7 @@ namespace Kyoo.InternalAPI { public class Crawler : ICrawler { + private static ICrawler runningCrawler; private readonly CancellationTokenSource cancellation; private readonly ILibraryManager libraryManager; @@ -33,15 +34,27 @@ namespace Kyoo.InternalAPI public Task Start(bool watch) { - return StartAsync(watch, cancellation.Token); + if (runningCrawler == null) + { + runningCrawler = this; + return StartAsync(watch, cancellation.Token); + } + return null; } private Task StartAsync(bool watch, CancellationToken cancellationToken) { - Debug.WriteLine("&Crawler started"); - IEnumerable paths = libraryManager.GetLibrariesPath(); + IEnumerable episodes = libraryManager.GetAllEpisodes(); + IEnumerable libraryPaths = libraryManager.GetLibrariesPath(); - foreach (string path in paths) + Debug.WriteLine("&Crawler started"); + foreach (Episode episode in episodes) + { + if (!File.Exists(episode.Path)) + libraryManager.RemoveEpisode(episode); + } + + foreach (string path in libraryPaths) { Scan(path, cancellationToken); @@ -50,8 +63,8 @@ namespace Kyoo.InternalAPI } while (!cancellationToken.IsCancellationRequested); - Debug.WriteLine("&Crawler stopped"); + runningCrawler = null; return null; } @@ -65,7 +78,10 @@ namespace Kyoo.InternalAPI return; if (IsVideo(file)) + { + Debug.WriteLine("&Registering episode at: " + file); await ExtractEpisodeData(file, folderPath); + } } } @@ -157,7 +173,8 @@ namespace Kyoo.InternalAPI } Show show = await RegisterOrGetShow(collectionName, showName, showPath, libraryPath); - await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, episodePath); + if (show != null) + await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, episodePath); } } @@ -171,8 +188,11 @@ namespace Kyoo.InternalAPI showProviderIDs = show.ExternalIDs; showID = libraryManager.RegisterShow(show); + if (showID == -1) + return null; + libraryManager.RegisterInLibrary(showID, libraryPath); - if (collectionName != null) + if (collectionName != null && collectionName.Length > 0) { if (!libraryManager.IsCollectionRegistered(Slugifier.ToSlug(collectionName), out long collectionID)) { @@ -224,7 +244,7 @@ namespace Kyoo.InternalAPI { if (!FindExtractedSubtitles(episode)) { - Track[] tracks = transcoder.ExtractSubtitles(episode.Path); + Track[] tracks = await transcoder.ExtractSubtitles(episode.Path); if (tracks != null) { foreach (Track track in tracks) @@ -282,7 +302,6 @@ namespace Kyoo.InternalAPI return false; } - private static readonly string[] videoExtensions = { ".webm", ".mkv", ".flv", ".vob", ".ogg", ".ogv", ".avi", ".mts", ".m2ts", ".ts", ".mov", ".qt", ".asf", ".mp4", ".m4p", ".m4v", ".mpg", ".mp2", ".mpeg", ".mpe", ".mpv", ".m2v", ".3gp", ".3g2" }; private bool IsVideo(string filePath) diff --git a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs index 4bcfd16a..3f335de5 100644 --- a/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs +++ b/Kyoo/InternalAPI/LibraryManager/ILibraryManager.cs @@ -37,6 +37,7 @@ namespace Kyoo.InternalAPI Genre GetGenreBySlug(string slug); Studio GetStudioBySlug(string slug); Collection GetCollection(string slug); + IEnumerable GetAllEpisodes(); //Check if value exists bool IsCollectionRegistered(string collectionSlug); @@ -61,6 +62,7 @@ namespace Kyoo.InternalAPI void AddShowToCollection(long showID, long collectionID); void RegisterInLibrary(long showID, string libraryPath); + void RemoveEpisode(Episode episode); void ClearSubtitles(long episodeID); } } diff --git a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs index 4c97659f..2e326db3 100644 --- a/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs +++ b/Kyoo/InternalAPI/LibraryManager/LibraryManager.cs @@ -52,7 +52,7 @@ namespace Kyoo.InternalAPI imgPrimary TEXT, year INTEGER, externalIDs TEXT, - FOREIGN KEY(showID) REFERENCES shows(id) + FOREIGN KEY(showID) REFERENCES shows(id) ON DELETE CASCADE ); CREATE TABLE episodes( id INTEGER PRIMARY KEY UNIQUE, @@ -61,15 +61,15 @@ namespace Kyoo.InternalAPI seasonNumber INTEGER, episodeNumber INTEGER, absoluteNumber INTEGER, - path TEXT, + path TEXT UNIQUE, title TEXT, overview TEXT, imgPrimary TEXT, releaseDate TEXT, runtime INTEGER, externalIDs TEXT, - FOREIGN KEY(showID) REFERENCES shows(id), - FOREIGN KEY(seasonID) REFERENCES seasons(id) + FOREIGN KEY(showID) REFERENCES shows(id) ON DELETE CASCADE, + FOREIGN KEY(seasonID) REFERENCES seasons(id) ON DELETE CASCADE ); CREATE TABLE tracks( id INTEGER PRIMARY KEY UNIQUE, @@ -82,7 +82,7 @@ namespace Kyoo.InternalAPI isForced BOOLEAN, isExternal BOOLEAN, path TEXT, - FOREIGN KEY(episodeID) REFERENCES episodes(id) + FOREIGN KEY(episodeID) REFERENCES episodes(id) ON DELETE CASCADE ); CREATE TABLE libraries( @@ -94,8 +94,8 @@ namespace Kyoo.InternalAPI CREATE TABLE librariesLinks( libraryID INTEGER, showID INTEGER, - FOREIGN KEY(libraryID) REFERENCES libraries(id), - FOREIGN KEY(showID) REFERENCES shows(id) + FOREIGN KEY(libraryID) REFERENCES libraries(id) ON DELETE CASCADE, + FOREIGN KEY(showID) REFERENCES shows(id) ON DELETE CASCADE ); CREATE TABLE collections( @@ -103,15 +103,15 @@ namespace Kyoo.InternalAPI slug TEXT UNIQUE, name TEXT, overview TEXT, - starYear INTEGER, + startYear INTEGER, endYear INTEGER, imgPrimary TEXT ); CREATE TABLE collectionsLinks( collectionID INTEGER, showID INTEGER, - FOREIGN KEY(collectionID) REFERENCES collections(id), - FOREIGN KEY(showID) REFERENCES shows(id) + FOREIGN KEY(collectionID) REFERENCES collections(id) ON DELETE CASCADE, + FOREIGN KEY(showID) REFERENCES shows(id) ON DELETE CASCADE ); CREATE TABLE studios( @@ -122,8 +122,8 @@ namespace Kyoo.InternalAPI CREATE TABLE studiosLinks( studioID INTEGER, showID INTEGER, - FOREIGN KEY(studioID) REFERENCES studios(id), - FOREIGN KEY(showID) REFERENCES shows(id) + FOREIGN KEY(studioID) REFERENCES studios(id) ON DELETE CASCADE, + FOREIGN KEY(showID) REFERENCES shows(id) ON DELETE CASCADE ); CREATE TABLE people( @@ -138,8 +138,8 @@ namespace Kyoo.InternalAPI showID INTEGER, role TEXT, type TEXT, - FOREIGN KEY(peopleID) REFERENCES people(id), - FOREIGN KEY(showID) REFERENCES shows(id) + FOREIGN KEY(peopleID) REFERENCES people(id) ON DELETE CASCADE, + FOREIGN KEY(showID) REFERENCES shows(id) ON DELETE CASCADE ); CREATE TABLE genres( @@ -150,8 +150,8 @@ namespace Kyoo.InternalAPI CREATE TABLE genresLinks( genreID INTEGER, showID INTEGER, - FOREIGN KEY(genreID) REFERENCES genres(id), - FOREIGN KEY(showID) REFERENCES shows(id) + FOREIGN KEY(genreID) REFERENCES genres(id) ON DELETE CASCADE, + FOREIGN KEY(showID) REFERENCES shows(id) ON DELETE CASCADE );"; using (SQLiteCommand createCmd = new SQLiteCommand(createStatement, sqlConnection)) @@ -404,6 +404,25 @@ namespace Kyoo.InternalAPI } } + public List GetEpisodes(long showID, long seasonNumber) + { + string query = "SELECT * FROM episodes WHERE episodes.showID = $showID AND episodes.seasonNumber = $seasonNumber ORDER BY episodeNumber;"; + + using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) + { + cmd.Parameters.AddWithValue("$showID", showID); + cmd.Parameters.AddWithValue("$seasonNumber", seasonNumber); + SQLiteDataReader reader = cmd.ExecuteReader(); + + List episodes = new List(); + + while (reader.Read()) + episodes.Add(Episode.FromReader(reader)); + + return episodes; + } + } + public Episode GetEpisode(string showSlug, long seasonNumber, long episodeNumber) { string query = "SELECT * FROM episodes JOIN shows ON shows.id = episodes.showID WHERE shows.slug = $showSlug AND episodes.seasonNumber = $seasonNumber AND episodes.episodeNumber = $episodeNumber;"; @@ -627,6 +646,21 @@ namespace Kyoo.InternalAPI return shows; } } + + public IEnumerable GetAllEpisodes() + { + List episodes = new List(); + string query = "SELECT * FROM episodes;"; + + using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) + { + SQLiteDataReader reader = cmd.ExecuteReader(); + + while (reader.Read()) + episodes.Add(Episode.FromReader(reader)); + return episodes; + } + } #endregion #region Check if items exists @@ -724,12 +758,22 @@ namespace Kyoo.InternalAPI 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(); + try + { + cmd.Parameters.AddWithValue("$slug", genre.Slug); + cmd.Parameters.AddWithValue("$name", genre.Name); + cmd.ExecuteNonQuery(); - cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; - return (long)cmd.ExecuteScalar(); + cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; + return (long)cmd.ExecuteScalar(); + } + catch + { + Console.Error.WriteLine("SQL error while trying to insert a people ({0}).", genre.Name); + cmd.CommandText = "SELECT * FROM genres WHERE slug = $slug"; + cmd.Parameters.AddWithValue("$slug", genre.Slug); + return (long)cmd.ExecuteScalar(); + } } } @@ -743,12 +787,22 @@ namespace Kyoo.InternalAPI string query = "INSERT INTO studios (slug, name) VALUES($slug, $name);"; using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { - cmd.Parameters.AddWithValue("$slug", studio.Slug); - cmd.Parameters.AddWithValue("$name", studio.Name); - cmd.ExecuteNonQuery(); + try + { + cmd.Parameters.AddWithValue("$slug", studio.Slug); + cmd.Parameters.AddWithValue("$name", studio.Name); + cmd.ExecuteNonQuery(); - cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; - return (long)cmd.ExecuteScalar(); + cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; + return (long)cmd.ExecuteScalar(); + } + catch (SQLiteException) + { + Console.Error.WriteLine("SQL error while trying to insert a studio ({0}).", studio.Name); + cmd.CommandText = "SELECT * FROM studios WHERE slug = $slug"; + cmd.Parameters.AddWithValue("$slug", studio.Slug); + return (long)cmd.ExecuteScalar(); + } } } @@ -762,14 +816,25 @@ namespace Kyoo.InternalAPI string query = "INSERT INTO people (slug, name, imgPrimary, externalIDs) VALUES($slug, $name, $imgPrimary, $externalIDs);"; using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { - cmd.Parameters.AddWithValue("$slug", people.slug); - cmd.Parameters.AddWithValue("$name", people.Name); - cmd.Parameters.AddWithValue("$imgPrimary", people.imgPrimary); - cmd.Parameters.AddWithValue("$externalIDs", people.externalIDs); - cmd.ExecuteNonQuery(); + try + { + cmd.Parameters.AddWithValue("$slug", people.slug); + cmd.Parameters.AddWithValue("$name", people.Name); + cmd.Parameters.AddWithValue("$imgPrimary", people.imgPrimary); + cmd.Parameters.AddWithValue("$externalIDs", people.externalIDs); + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; + return (long)cmd.ExecuteScalar(); + } + catch + { + Console.Error.WriteLine("SQL error while trying to insert a people ({0}).", people.Name); + cmd.CommandText = "SELECT * FROM people WHERE slug = $slug"; + cmd.Parameters.AddWithValue("$slug", people.slug); + return (long)cmd.ExecuteScalar(); + } - cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; - return (long)cmd.ExecuteScalar(); } } #endregion @@ -781,14 +846,24 @@ namespace Kyoo.InternalAPI using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { - cmd.Parameters.AddWithValue("$slug", collection.Slug); - cmd.Parameters.AddWithValue("$name", collection.Name); - cmd.Parameters.AddWithValue("$overview", collection.Overview); - cmd.Parameters.AddWithValue("$imgPrimary", collection.ImgPrimary); - cmd.ExecuteNonQuery(); + try + { + cmd.Parameters.AddWithValue("$slug", collection.Slug); + cmd.Parameters.AddWithValue("$name", collection.Name); + cmd.Parameters.AddWithValue("$overview", collection.Overview); + cmd.Parameters.AddWithValue("$imgPrimary", collection.ImgPrimary); + cmd.ExecuteNonQuery(); - cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; - return (long)cmd.ExecuteScalar(); + cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; + return (long)cmd.ExecuteScalar(); + } + catch + { + Console.Error.WriteLine("SQL error while trying to create a collection. Collection probably already registered."); + cmd.CommandText = "SELECT * FROM collections WHERE slug = $slug"; + cmd.Parameters.AddWithValue("$slug", collection.Slug); + return (long)cmd.ExecuteScalar(); + } } } @@ -809,47 +884,55 @@ namespace Kyoo.InternalAPI string query = "INSERT INTO shows (slug, title, aliases, path, overview, trailerUrl, startYear, endYear, imgPrimary, imgThumb, imgLogo, imgBackdrop, externalIDs) VALUES($slug, $title, $aliases, $path, $overview, $trailerUrl, $startYear, $endYear, $imgPrimary, $imgThumb, $imgLogo, $imgBackdrop, $externalIDs);"; using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { - cmd.Parameters.AddWithValue("$slug", show.Slug); - cmd.Parameters.AddWithValue("$title", show.Title); - cmd.Parameters.AddWithValue("$aliases", show.GetAliases()); - cmd.Parameters.AddWithValue("$path", show.Path); - cmd.Parameters.AddWithValue("$overview", show.Overview); - cmd.Parameters.AddWithValue("$trailerUrl", show.TrailerUrl); - cmd.Parameters.AddWithValue("$status", show.Status); - cmd.Parameters.AddWithValue("$startYear", show.StartYear); - cmd.Parameters.AddWithValue("$endYear", show.EndYear); - cmd.Parameters.AddWithValue("$imgPrimary", show.ImgPrimary); - cmd.Parameters.AddWithValue("$imgThumb", show.ImgThumb); - cmd.Parameters.AddWithValue("$imgLogo", show.ImgLogo); - cmd.Parameters.AddWithValue("$imgBackdrop", show.ImgBackdrop); - cmd.Parameters.AddWithValue("$externalIDs", show.ExternalIDs); - cmd.ExecuteNonQuery(); - - cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; - long showID = (long)cmd.ExecuteScalar(); - - if (show.Genres != null) + try { - cmd.CommandText = "INSERT INTO genresLinks (genreID, showID) VALUES($genreID, $showID);"; - foreach (Genre genre in show.Genres) + cmd.Parameters.AddWithValue("$slug", show.Slug); + cmd.Parameters.AddWithValue("$title", show.Title); + cmd.Parameters.AddWithValue("$aliases", show.GetAliases()); + cmd.Parameters.AddWithValue("$path", show.Path); + cmd.Parameters.AddWithValue("$overview", show.Overview); + cmd.Parameters.AddWithValue("$trailerUrl", show.TrailerUrl); + cmd.Parameters.AddWithValue("$status", show.Status); + cmd.Parameters.AddWithValue("$startYear", show.StartYear); + cmd.Parameters.AddWithValue("$endYear", show.EndYear); + cmd.Parameters.AddWithValue("$imgPrimary", show.ImgPrimary); + cmd.Parameters.AddWithValue("$imgThumb", show.ImgThumb); + cmd.Parameters.AddWithValue("$imgLogo", show.ImgLogo); + cmd.Parameters.AddWithValue("$imgBackdrop", show.ImgBackdrop); + cmd.Parameters.AddWithValue("$externalIDs", show.ExternalIDs); + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; + long showID = (long)cmd.ExecuteScalar(); + + if (show.Genres != null) { - long genreID = GetOrCreateGenre(genre); - cmd.Parameters.AddWithValue("$genreID", genreID); + 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(); + } + } + + if (show.studio != null) + { + cmd.CommandText = "INSERT INTO studiosLinks (studioID, showID) VALUES($studioID, $showID);"; + long studioID = GetOrCreateStudio(show.studio); + cmd.Parameters.AddWithValue("$studioID", studioID); cmd.Parameters.AddWithValue("$showID", showID); cmd.ExecuteNonQuery(); } - } - if(show.studio != null) + return showID; + } + catch { - cmd.CommandText = "INSERT INTO studiosLinks (studioID, showID) VALUES($studioID, $showID);"; - long studioID = GetOrCreateStudio(show.studio); - cmd.Parameters.AddWithValue("$studioID", studioID); - cmd.Parameters.AddWithValue("$showID", showID); - cmd.ExecuteNonQuery(); + Console.Error.WriteLine("SQL error while trying to insert a show ({0}), show probably already registered.", show.Title); + return -1; } - - return showID; } } @@ -858,17 +941,28 @@ namespace Kyoo.InternalAPI string query = "INSERT INTO seasons (showID, seasonNumber, title, overview, year, imgPrimary, externalIDs) VALUES($showID, $seasonNumber, $title, $overview, $year, $imgPrimary, $externalIDs);"; using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { - cmd.Parameters.AddWithValue("$showID", season.ShowID); - cmd.Parameters.AddWithValue("$seasonNumber", season.seasonNumber); - cmd.Parameters.AddWithValue("$title", season.Title); - cmd.Parameters.AddWithValue("$overview", season.Overview); - cmd.Parameters.AddWithValue("$year", season.year); - cmd.Parameters.AddWithValue("$imgPrimary", season.ImgPrimary); - cmd.Parameters.AddWithValue("$externalIDs", season.ExternalIDs); - cmd.ExecuteNonQuery(); + try + { + cmd.Parameters.AddWithValue("$showID", season.ShowID); + cmd.Parameters.AddWithValue("$seasonNumber", season.seasonNumber); + cmd.Parameters.AddWithValue("$title", season.Title); + cmd.Parameters.AddWithValue("$overview", season.Overview); + cmd.Parameters.AddWithValue("$year", season.year); + cmd.Parameters.AddWithValue("$imgPrimary", season.ImgPrimary); + cmd.Parameters.AddWithValue("$externalIDs", season.ExternalIDs); + cmd.ExecuteNonQuery(); - cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; - return (long)cmd.ExecuteScalar(); + cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; + return (long)cmd.ExecuteScalar(); + } + catch + { + Console.Error.WriteLine("SQL error while trying to insert a season ({0}), season probably already registered.", season.Title); + cmd.CommandText = "SELECT * FROM seasons WHERE showID = $showID AND seasonNumber = $seasonNumber"; + cmd.Parameters.AddWithValue("$showID", season.ShowID); + cmd.Parameters.AddWithValue("$seasonNumber", season.seasonNumber); + return (long)cmd.ExecuteScalar(); + } } } @@ -877,22 +971,34 @@ namespace Kyoo.InternalAPI string query = "INSERT INTO episodes (showID, seasonID, seasonNumber, episodeNumber, absoluteNumber, path, title, overview, releaseDate, runtime, imgPrimary, externalIDs) VALUES($showID, $seasonID, $seasonNumber, $episodeNumber, $absoluteNumber, $path, $title, $overview, $releaseDate, $runtime, $imgPrimary, $externalIDs);"; using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { - cmd.Parameters.AddWithValue("$showID", episode.ShowID); - cmd.Parameters.AddWithValue("$seasonID", episode.SeasonID); - cmd.Parameters.AddWithValue("$seasonNUmber", episode.seasonNumber); - cmd.Parameters.AddWithValue("$episodeNumber", episode.episodeNumber); - cmd.Parameters.AddWithValue("$absoluteNumber", episode.absoluteNumber); - cmd.Parameters.AddWithValue("$path", episode.Path); - cmd.Parameters.AddWithValue("$title", episode.Title); - cmd.Parameters.AddWithValue("$overview", episode.Overview); - cmd.Parameters.AddWithValue("$releaseDate", episode.ReleaseDate); - cmd.Parameters.AddWithValue("$runtime", episode.Runtime); - cmd.Parameters.AddWithValue("$imgPrimary", episode.ImgPrimary); - cmd.Parameters.AddWithValue("$externalIDs", episode.ExternalIDs); - cmd.ExecuteNonQuery(); + try + { + cmd.Parameters.AddWithValue("$showID", episode.ShowID); + cmd.Parameters.AddWithValue("$seasonID", episode.SeasonID); + cmd.Parameters.AddWithValue("$seasonNUmber", episode.seasonNumber); + cmd.Parameters.AddWithValue("$episodeNumber", episode.episodeNumber); + cmd.Parameters.AddWithValue("$absoluteNumber", episode.absoluteNumber); + cmd.Parameters.AddWithValue("$path", episode.Path); + cmd.Parameters.AddWithValue("$title", episode.Title); + cmd.Parameters.AddWithValue("$overview", episode.Overview); + cmd.Parameters.AddWithValue("$releaseDate", episode.ReleaseDate); + cmd.Parameters.AddWithValue("$runtime", episode.Runtime); + cmd.Parameters.AddWithValue("$imgPrimary", episode.ImgPrimary); + cmd.Parameters.AddWithValue("$externalIDs", episode.ExternalIDs); + cmd.ExecuteNonQuery(); - cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; - return (long)cmd.ExecuteScalar(); + cmd.CommandText = "SELECT LAST_INSERT_ROWID()"; + return (long)cmd.ExecuteScalar(); + } + catch + { + Console.Error.WriteLine("SQL error while trying to insert an episode ({0}), episode probably already registered.", episode.Link); + cmd.CommandText = "SELECT * FROM episodes WHERE showID = $showID AND seasonNumber = $seasonNumber AND episodeNumber = $episodeNumber"; + cmd.Parameters.AddWithValue("$showID", episode.ShowID); + cmd.Parameters.AddWithValue("$seasonNumber", episode.seasonNumber); + cmd.Parameters.AddWithValue("$episodeNumber", episode.episodeNumber); + return (long)cmd.ExecuteScalar(); + } } } @@ -946,6 +1052,44 @@ namespace Kyoo.InternalAPI } } + public void RemoveShow(long showID) + { + string query = "DELETE FROM shows WHERE id = $showID;"; + + using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) + { + cmd.Parameters.AddWithValue("$showID", showID); + cmd.ExecuteNonQuery(); + } + } + + public void RemoveSeason(long showID, long seasonID) + { + string query = "DELETE FROM seasons WHERE id = $seasonID;"; + + using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) + { + cmd.Parameters.AddWithValue("$seasonID", seasonID); + cmd.ExecuteNonQuery(); + } + if (GetSeasons(showID).Count == 0) + RemoveShow(showID); + } + + public void RemoveEpisode(Episode episode) + { + string query = "DELETE FROM episodes WHERE id = $episodeID;"; + + using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) + { + cmd.Parameters.AddWithValue("$episodeID", episode.id); + cmd.ExecuteNonQuery(); + } + + if (GetEpisodes(episode.ShowID, episode.seasonNumber).Count == 0) + RemoveSeason(episode.ShowID, episode.SeasonID); + } + public void ClearSubtitles(long episodeID) { string query = "DELETE FROM tracks WHERE episodeID = $episodeID;"; diff --git a/Kyoo/InternalAPI/MetadataProvider/Implementations/TheTvDB/ProviderTheTvDB.cs b/Kyoo/InternalAPI/MetadataProvider/Implementations/TheTvDB/ProviderTheTvDB.cs index 8539065c..fd96cd4e 100644 --- a/Kyoo/InternalAPI/MetadataProvider/Implementations/TheTvDB/ProviderTheTvDB.cs +++ b/Kyoo/InternalAPI/MetadataProvider/Implementations/TheTvDB/ProviderTheTvDB.cs @@ -253,7 +253,7 @@ namespace Kyoo.InternalAPI.MetadataProvider DateTime dateTime = DateTime.ParseExact((string)episode.firstAired, "yyyy-MM-dd", CultureInfo.InvariantCulture); if (absoluteNumber == -1) - absoluteNumber = episode.absoluteNumber as long? ?? -1; + absoluteNumber = (long?)episode.absoluteNumber ?? -1; else { seasonNumber = episode.airedSeason; diff --git a/Kyoo/InternalAPI/Transcoder/ITranscoder.cs b/Kyoo/InternalAPI/Transcoder/ITranscoder.cs index 80cf84f3..a264846f 100644 --- a/Kyoo/InternalAPI/Transcoder/ITranscoder.cs +++ b/Kyoo/InternalAPI/Transcoder/ITranscoder.cs @@ -1,5 +1,6 @@ using Kyoo.Models; using Kyoo.Models.Watch; +using System.Threading.Tasks; namespace Kyoo.InternalAPI { @@ -12,6 +13,6 @@ namespace Kyoo.InternalAPI string Transcode(string path); //Extract all subtitles of a video and save them in the subtitles sub-folder. - Track[] ExtractSubtitles(string path); + Task ExtractSubtitles(string path); } } diff --git a/Kyoo/InternalAPI/Transcoder/Transcoder.cs b/Kyoo/InternalAPI/Transcoder/Transcoder.cs index 7f079fa2..318e5ca3 100644 --- a/Kyoo/InternalAPI/Transcoder/Transcoder.cs +++ b/Kyoo/InternalAPI/Transcoder/Transcoder.cs @@ -20,13 +20,15 @@ namespace Kyoo.InternalAPI Debug.WriteLine("&Api INIT (unmanaged stream size): " + TranscoderAPI.Init() + ", Stream size: " + Marshal.SizeOf()); } - public Track[] ExtractSubtitles(string path) + public async Task ExtractSubtitles(string path) { string output = Path.Combine(Path.GetDirectoryName(path), "Subtitles"); Directory.CreateDirectory(output); - TranscoderAPI.ExtractSubtitles(path, output, out Track[] tracks); - - return tracks; + return await Task.Run(() => + { + TranscoderAPI.ExtractSubtitles(path, output, out Track[] tracks); + return tracks; + }); } public void GetVideo(string path) diff --git a/Unit Tests/Kyoo-InternalAPI/Library-Tests.cs b/Unit Tests/Kyoo-InternalAPI/Library-Tests.cs index 9a6e86d6..b3c061ff 100644 --- a/Unit Tests/Kyoo-InternalAPI/Library-Tests.cs +++ b/Unit Tests/Kyoo-InternalAPI/Library-Tests.cs @@ -1,11 +1,6 @@ using Kyoo.InternalAPI; -using Kyoo.Models; using Microsoft.Extensions.Configuration; using NUnit.Framework; -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; namespace UnitTests.Kyoo_InternalAPI {