diff --git a/Kyoo.Common/Controllers/ICrawler.cs b/Kyoo.Common/Controllers/ICrawler.cs index bbb6d4dc..6dc29922 100644 --- a/Kyoo.Common/Controllers/ICrawler.cs +++ b/Kyoo.Common/Controllers/ICrawler.cs @@ -5,8 +5,8 @@ namespace Kyoo.Controllers { public interface ICrawler { - Task Start(bool watch); + void Start(); - Task StopAsync(); + void Cancel(); } } diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs index 3e40d923..b920219b 100644 --- a/Kyoo.Common/Controllers/ILibraryManager.cs +++ b/Kyoo.Common/Controllers/ILibraryManager.cs @@ -63,9 +63,9 @@ namespace Kyoo.Controllers long GetOrCreateGenre(Genre genre); long GetOrCreateStudio(Studio studio); - void RegisterShowPeople(long showID, List actors); + void RegisterShowPeople(long showID, IEnumerable actors); void AddShowToCollection(long showID, long collectionID); - void RegisterInLibrary(long showID, string libraryPath); + void RegisterInLibrary(long showID, Library library); void RemoveEpisode(Episode episode); void ClearSubtitles(long episodeID); diff --git a/Kyoo.Common/Controllers/IMetadataProvider.cs b/Kyoo.Common/Controllers/IMetadataProvider.cs index 1b46283f..878129bb 100644 --- a/Kyoo.Common/Controllers/IMetadataProvider.cs +++ b/Kyoo.Common/Controllers/IMetadataProvider.cs @@ -6,18 +6,18 @@ namespace Kyoo.Controllers { public interface IMetadataProvider { + public string Name { get; } + //For the collection Task GetCollectionFromName(string name); //For the show Task GetShowByID(string id); Task GetShowFromName(string showName, string showPath); - Task GetImages(Show show); - Task> GetPeople(string id); + Task> GetPeople(string id); //For the seasons Task GetSeason(string showName, long seasonNumber); - Task GetSeasonImage(string showName, long seasonNumber); //For the episodes Task GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath); diff --git a/Kyoo.Common/Controllers/IProviderManager.cs b/Kyoo.Common/Controllers/IProviderManager.cs new file mode 100644 index 00000000..3f775013 --- /dev/null +++ b/Kyoo.Common/Controllers/IProviderManager.cs @@ -0,0 +1,15 @@ +using System.Collections.Generic; +using System.Threading.Tasks; +using Kyoo.Models; + +namespace Kyoo.Controllers +{ + public interface IProviderManager + { + Task GetCollectionFromName(string name, Library library); + Task GetShowFromName(string showName, string showPath, Library library); + Task GetSeason(string showName, long seasonNumber, Library library); + Task GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath, Library library); + Task> GetPeople(string showExternalIDs, Library library); + } +} \ No newline at end of file diff --git a/Kyoo.Common/Controllers/IThumbnailsManager.cs b/Kyoo.Common/Controllers/IThumbnailsManager.cs index ac88cc40..4144f1ec 100644 --- a/Kyoo.Common/Controllers/IThumbnailsManager.cs +++ b/Kyoo.Common/Controllers/IThumbnailsManager.cs @@ -7,7 +7,7 @@ namespace Kyoo.Controllers.ThumbnailsManager public interface IThumbnailsManager { Task Validate(Show show); - Task> Validate(List actors); + Task> Validate(IEnumerable actors); Task Validate(Episode episode); } } diff --git a/Kyoo.Common/Models/Collection.cs b/Kyoo.Common/Models/Collection.cs index 2c520313..81ade2a7 100644 --- a/Kyoo.Common/Models/Collection.cs +++ b/Kyoo.Common/Models/Collection.cs @@ -1,50 +1,76 @@ using Kyoo.Controllers; using Newtonsoft.Json; using System.Collections.Generic; +using System.Linq; +using Kyoo.Utility; namespace Kyoo.Models { - public class Collection + public class Collection : IMergable + { - [JsonIgnore] public long id; - public string Slug; - public string Name; - public string Poster; - public string Overview; - [JsonIgnore] public string ImgPrimary; - public IEnumerable Shows; + [JsonIgnore] public long id = -1; + public string Slug; + public string Name; + public string Poster; + public string Overview; + [JsonIgnore] public string ImgPrimary; + public IEnumerable Shows; - public Collection() { } + public Collection() + { + } - public Collection(long id, string slug, string name, string overview, string imgPrimary) - { - this.id = id; - Slug = slug; - Name = name; - Overview = overview; - ImgPrimary = imgPrimary; - } + public Collection(long id, string slug, string name, string overview, string imgPrimary) + { + this.id = id; + Slug = slug; + Name = name; + Overview = overview; + ImgPrimary = imgPrimary; + } - public static Collection FromReader(System.Data.SQLite.SQLiteDataReader reader) - { - Collection col = new Collection((long)reader["id"], - reader["slug"] as string, - reader["name"] as string, - reader["overview"] as string, - reader["imgPrimary"] as string); - col.Poster = "poster/" + col.Slug; - return col; - } + public static Collection FromReader(System.Data.SQLite.SQLiteDataReader reader) + { + Collection col = new Collection((long) reader["id"], + reader["slug"] as string, + reader["name"] as string, + reader["overview"] as string, + reader["imgPrimary"] as string); + col.Poster = "poster/" + col.Slug; + return col; + } - public Show AsShow() - { - return new Show(-1, Slug, Name, null, null, Overview, null, null, null, null, null, null); - } + public Show AsShow() + { + return new Show(-1, Slug, Name, null, null, Overview, null, null, null, null, null, null); + } - public Collection SetShows(ILibraryManager libraryManager) - { - Shows = libraryManager.GetShowsInCollection(id); - return this; - } + public Collection SetShows(ILibraryManager libraryManager) + { + Shows = libraryManager.GetShowsInCollection(id); + return this; + } + + public Collection Merge(Collection collection) + { + if (id == -1) + id = collection.id; + if (Slug == null) + Slug = collection.Slug; + if (Name == null) + Name = collection.Name; + if (Poster == null) + Poster = collection.Poster; + if (Overview == null) + Overview = collection.Overview; + if (ImgPrimary == null) + ImgPrimary = collection.ImgPrimary; + if (Shows == null) + Shows = collection.Shows; + else + Shows = Shows.Concat(collection.Shows); + return this; + } } } diff --git a/Kyoo.Common/Models/Episode.cs b/Kyoo.Common/Models/Episode.cs index 58661490..c7d53dbc 100644 --- a/Kyoo.Common/Models/Episode.cs +++ b/Kyoo.Common/Models/Episode.cs @@ -1,9 +1,10 @@ using Newtonsoft.Json; using System; +using Kyoo.Utility; namespace Kyoo.Models { - public class Episode + public class Episode : IMergable { [JsonIgnore] public long id; [JsonIgnore] public long ShowID; @@ -97,5 +98,35 @@ namespace Kyoo.Models { return showSlug + "-s" + seasonNumber + "e" + episodeNumber; } + + public Episode Merge(Episode other) + { + if (id == -1) + id = other.id; + if (ShowID == -1) + ShowID = other.ShowID; + if (SeasonID == -1) + SeasonID = other.SeasonID; + if (seasonNumber == -1) + seasonNumber = other.seasonNumber; + if (episodeNumber == -1) + episodeNumber = other.episodeNumber; + if (absoluteNumber == -1) + absoluteNumber = other.absoluteNumber; + if (Path == null) + Path = other.Path; + if (Title == null) + Title = other.Title; + if (Overview == null) + Overview = other.Overview; + if (ReleaseDate == null) + ReleaseDate = other.ReleaseDate; + if (Runtime == -1) + Runtime = other.Runtime; + if (ImgPrimary == null) + ImgPrimary = other.ImgPrimary; + ExternalIDs += '|' + other.ExternalIDs; + return this; + } } } diff --git a/Kyoo.Common/Models/Library.cs b/Kyoo.Common/Models/Library.cs index 638091c9..c0a0fe8b 100644 --- a/Kyoo.Common/Models/Library.cs +++ b/Kyoo.Common/Models/Library.cs @@ -7,14 +7,16 @@ namespace Kyoo.Models [JsonIgnore] public readonly long id; public string Slug; public string Name; - public string Path; + public string[] Paths; + public string[] Providers; - public Library(long id, string slug, string name, string path) + public Library(long id, string slug, string name, string[] paths, string[] providers) { this.id = id; Slug = slug; Name = name; - Path = path; + Paths = paths; + Providers = providers; } public static Library FromReader(System.Data.SQLite.SQLiteDataReader reader) @@ -22,7 +24,8 @@ namespace Kyoo.Models return new Library((long)reader["id"], reader["slug"] as string, reader["name"] as string, - reader["path"] as string); + (reader["path"] as string)?.Split('|'), + (reader["providers"] as string)?.Split('|')); } } } diff --git a/Kyoo.Common/Models/People.cs b/Kyoo.Common/Models/People.cs index 79003c23..abb44c53 100644 --- a/Kyoo.Common/Models/People.cs +++ b/Kyoo.Common/Models/People.cs @@ -1,8 +1,9 @@ -using Newtonsoft.Json; +using Kyoo.Utility; +using Newtonsoft.Json; namespace Kyoo.Models { - public class People + public class People : IMergable { [JsonIgnore] public long id; public string slug; @@ -52,5 +53,23 @@ namespace Kyoo.Models reader["imgPrimary"] as string, reader["externalIDs"] as string); } + + public People Merge(People other) + { + if (id == -1) + id = other.id; + if (slug == null) + slug = other.slug; + if (Name == null) + Name = other.Name; + if (Role == null) + Role = other.Role; + if (Type == null) + Type = other.Type; + if (imgPrimary == null) + imgPrimary = other.imgPrimary; + externalIDs += '|' + other.externalIDs; + return this; + } } } diff --git a/Kyoo.Common/Models/Season.cs b/Kyoo.Common/Models/Season.cs index c555d932..6c9133f1 100644 --- a/Kyoo.Common/Models/Season.cs +++ b/Kyoo.Common/Models/Season.cs @@ -1,8 +1,10 @@ -using Newtonsoft.Json; +using System.Linq; +using Kyoo.Utility; +using Newtonsoft.Json; namespace Kyoo.Models { - public class Season + public class Season : IMergable { [JsonIgnore] public readonly long id; [JsonIgnore] public long ShowID; @@ -40,5 +42,23 @@ namespace Kyoo.Models reader["imgPrimary"] as string, reader["externalIDs"] as string); } + + public Season Merge(Season other) + { + if (ShowID == -1) + ShowID = other.ShowID; + if (seasonNumber == -1) + seasonNumber = other.seasonNumber; + if (Title == null) + Title = other.Title; + if (Overview == null) + Overview = other.Overview; + if (year == null) + year = other.year; + if (ImgPrimary == null) + ImgPrimary = other.ImgPrimary; + ExternalIDs += '|' + other.ExternalIDs; + return this; + } } } diff --git a/Kyoo.Common/Models/Show.cs b/Kyoo.Common/Models/Show.cs index 7b975413..bd179283 100644 --- a/Kyoo.Common/Models/Show.cs +++ b/Kyoo.Common/Models/Show.cs @@ -1,10 +1,12 @@ using Kyoo.Controllers; using Newtonsoft.Json; using System.Collections.Generic; +using System.Linq; +using Kyoo.Utility; namespace Kyoo.Models { - public class Show + public class Show : IMergable { [JsonIgnore] public long id = -1; @@ -111,7 +113,7 @@ namespace Kyoo.Models return new Show((long)reader["id"], reader["slug"] as string, reader["title"] as string, - (reader["aliases"] as string)?.Split('|') ?? null, + (reader["aliases"] as string)?.Split('|'), reader["path"] as string, reader["overview"] as string, reader["trailerUrl"] as string, @@ -161,6 +163,46 @@ namespace Kyoo.Models seasons = manager.GetSeasons(id); return this; } + + public Show Merge(Show other) + { + if (id == -1) + id = other.id; + if (Slug == null) + Slug = other.Slug; + if (Title == null) + Title = other.Title; + if (Aliases == null) + Aliases = other.Aliases; + else + Aliases = Aliases.Concat(other.Aliases); + if (Genres == null) + Genres = other.Genres; + else + Genres = Genres.Concat(other.Genres); + if (Path == null) + Path = other.Path; + if (Overview == null) + Overview = other.Overview; + if (TrailerUrl == null) + TrailerUrl = other.TrailerUrl; + if (Status == null) + Status = other.Status; + if (StartYear == null) + StartYear = other.StartYear; + if (EndYear == null) + EndYear = other.EndYear; + if (ImgPrimary == null) + ImgPrimary = other.ImgPrimary; + if (ImgThumb == null) + ImgThumb = other.ImgThumb; + if (ImgLogo == null) + ImgLogo = other.ImgLogo; + if (ImgBackdrop == null) + ImgBackdrop = other.ImgBackdrop; + ExternalIDs += '|' + other.ExternalIDs; + return this; + } } public enum Status { Finished, Airing } diff --git a/Kyoo.Common/Utility/IMergable.cs b/Kyoo.Common/Utility/IMergable.cs new file mode 100644 index 00000000..3c56420b --- /dev/null +++ b/Kyoo.Common/Utility/IMergable.cs @@ -0,0 +1,9 @@ +using System.Collections.Generic; + +namespace Kyoo.Utility +{ + public interface IMergable + { + public T Merge(T other); + } +} \ No newline at end of file diff --git a/Kyoo/Controllers/Crawler.cs b/Kyoo/Controllers/Crawler.cs index 3a3662ef..a2591c45 100644 --- a/Kyoo/Controllers/Crawler.cs +++ b/Kyoo/Controllers/Crawler.cs @@ -14,16 +14,15 @@ namespace Kyoo.Controllers { public class Crawler : ICrawler { - private static ICrawler runningCrawler; - private bool isScanning; + private bool isRunning; private readonly CancellationTokenSource cancellation; private readonly ILibraryManager libraryManager; - private readonly IMetadataProvider metadataProvider; + private readonly IProviderManager metadataProvider; private readonly ITranscoder transcoder; private readonly IConfiguration config; - public Crawler(ILibraryManager libraryManager, IMetadataProvider metadataProvider, ITranscoder transcoder, IConfiguration configuration) + public Crawler(ILibraryManager libraryManager, IProviderManager metadataProvider, ITranscoder transcoder, IConfiguration configuration) { this.libraryManager = libraryManager; this.metadataProvider = metadataProvider; @@ -32,30 +31,27 @@ namespace Kyoo.Controllers cancellation = new CancellationTokenSource(); } - public async Task Start(bool watch) + public void Start() { - if (runningCrawler == null) - { - runningCrawler = this; - await StartAsync(watch, cancellation.Token); - } - else if (runningCrawler is Crawler crawler) - { - if (!crawler.isScanning) - { - await crawler.StopAsync(); - runningCrawler = this; - await StartAsync(watch, cancellation.Token); - } - } + if (isRunning) + return; + isRunning = true; + StartAsync(cancellation.Token); } - private Task StartAsync(bool watch, CancellationToken cancellationToken) + public void Cancel() + { + if (!isRunning) + return; + isRunning = false; + cancellation.Cancel(); + } + + private async void StartAsync(CancellationToken cancellationToken) { IEnumerable episodes = libraryManager.GetAllEpisodes(); - IEnumerable libraryPaths = libraryManager.GetLibrariesPath(); + IEnumerable libraries = libraryManager.GetLibraries(); - isScanning = true; Debug.WriteLine("&Crawler started"); foreach (Episode episode in episodes) { @@ -63,106 +59,46 @@ namespace Kyoo.Controllers libraryManager.RemoveEpisode(episode); } - foreach (string path in libraryPaths) - { - Scan(path, cancellationToken); + foreach (Library library in libraries) + await Scan(library, cancellationToken); - if(watch) - Watch(path, cancellationToken); - } - - isScanning = false; - if (watch) - while (!cancellationToken.IsCancellationRequested); + isRunning = false; Debug.WriteLine("&Crawler stopped"); - runningCrawler = null; - return null; } - private async void Scan(string folderPath, CancellationToken cancellationToken) + private async Task Scan(Library library, CancellationToken cancellationToken) { - string[] files = Directory.GetFiles(folderPath, "*", SearchOption.AllDirectories); + IEnumerable files = new List(); + files = library.Paths.Aggregate(files, (current, path) => + current.Concat(Directory.GetFiles(path, "*", SearchOption.AllDirectories))); foreach (string file in files) { if (cancellationToken.IsCancellationRequested) return; - - if (IsVideo(file)) - { - Debug.WriteLine("&Registering episode at: " + file); - await ExtractEpisodeData(file, folderPath); - } + if (!IsVideo(file)) + continue; + await RegisterFile(file, library); } } - private void Watch(string folderPath, CancellationToken cancellationToken) + private async Task RegisterFile(string path, Library library) { - Debug.WriteLine("Folder watching not implemented yet."); - //Debug.WriteLine("&Watching " + folderPath + " for changes"); - //using (FileSystemWatcher watcher = new FileSystemWatcher()) - //{ - // watcher.Path = folderPath; - // watcher.IncludeSubdirectories = true; - // watcher.NotifyFilter = NotifyFilters.LastAccess - // | NotifyFilters.LastWrite - // | NotifyFilters.FileName - // | NotifyFilters.Size - // | NotifyFilters.DirectoryName; - - // watcher.Created += FileCreated; - // watcher.Changed += FileChanged; - // watcher.Renamed += FileRenamed; - // watcher.Deleted += FileDeleted; - - - // watcher.EnableRaisingEvents = true; - - // while (!cancellationToken.IsCancellationRequested); - //} - } - - //private void FileCreated(object sender, FileSystemEventArgs e) - //{ - // Debug.WriteLine("&File Created at " + e.FullPath); - // if (IsVideo(e.FullPath)) - // { - // Debug.WriteLine("&Created file is a video"); - // _ = TryRegisterEpisode(e.FullPath); - // } - //} - - //private void FileChanged(object sender, FileSystemEventArgs e) - //{ - // Debug.WriteLine("&File Changed at " + e.FullPath); - //} - - //private void FileRenamed(object sender, RenamedEventArgs e) - //{ - // Debug.WriteLine("&File Renamed at " + e.FullPath); - //} - - //private void FileDeleted(object sender, FileSystemEventArgs e) - //{ - // Debug.WriteLine("&File Deleted at " + e.FullPath); - //} - - private async Task ExtractEpisodeData(string episodePath, string libraryPath) - { - if (!libraryManager.IsEpisodeRegistered(episodePath)) + if (!libraryManager.IsEpisodeRegistered(path)) { - string relativePath = episodePath.Substring(libraryPath.Length); + string relativePath = path.Substring(library.Paths.Length); string patern = config.GetValue("regex"); Regex regex = new Regex(patern, RegexOptions.IgnoreCase); Match match = regex.Match(relativePath); - string showPath = Path.GetDirectoryName(episodePath); + string showPath = Path.GetDirectoryName(path); string collectionName = match.Groups["Collection"]?.Value; string showName = match.Groups["ShowTitle"].Value; bool seasonSuccess = long.TryParse(match.Groups["Season"].Value, out long seasonNumber); bool episodeSucess = long.TryParse(match.Groups["Episode"].Value, out long episodeNumber); long absoluteNumber = -1; + Debug.WriteLine("&Registering episode at: " + path); if (!seasonSuccess || !episodeSucess) { //Considering that the episode is using absolute path. @@ -182,37 +118,37 @@ namespace Kyoo.Controllers } } - Show show = await RegisterOrGetShow(collectionName, showName, showPath, libraryPath); + Show show = await RegisterOrGetShow(collectionName, showName, showPath, library); if (show != null) - await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, episodePath); + await RegisterEpisode(show, seasonNumber, episodeNumber, absoluteNumber, path, library); } } - private async Task RegisterOrGetShow(string collectionName, string showTitle, string showPath, string libraryPath) + private async Task RegisterOrGetShow(string collectionName, string showTitle, string showPath, Library library) { string showProviderIDs; if (!libraryManager.IsShowRegistered(showPath, out long showID)) { - Show show = await metadataProvider.GetShowFromName(showTitle, showPath); + Show show = await metadataProvider.GetShowFromName(showTitle, showPath, library); showProviderIDs = show.ExternalIDs; showID = libraryManager.RegisterShow(show); if (showID == -1) return null; - libraryManager.RegisterInLibrary(showID, libraryPath); + libraryManager.RegisterInLibrary(showID, library); if (!string.IsNullOrEmpty(collectionName)) { if (!libraryManager.IsCollectionRegistered(Slugifier.ToSlug(collectionName), out long collectionID)) { - Collection collection = await metadataProvider.GetCollectionFromName(collectionName); + Collection collection = await metadataProvider.GetCollectionFromName(collectionName, library); collectionID = libraryManager.RegisterCollection(collection); } libraryManager.AddShowToCollection(showID, collectionID); } - List actors = await metadataProvider.GetPeople(show.ExternalIDs); + IEnumerable actors = await metadataProvider.GetPeople(show.ExternalIDs, library); libraryManager.RegisterShowPeople(showID, actors); } else @@ -221,27 +157,27 @@ namespace Kyoo.Controllers return new Show { id = showID, ExternalIDs = showProviderIDs, Title = showTitle }; } - private async Task RegisterEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath) + private async Task RegisterEpisode(Show show, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath, Library library) { long seasonID = -1; if (seasonNumber != -1) { if (!libraryManager.IsSeasonRegistered(show.id, seasonNumber, out seasonID)) { - Season season = await metadataProvider.GetSeason(show.Title, seasonNumber); + Season season = await metadataProvider.GetSeason(show.Title, seasonNumber, library); season.ShowID = show.id; seasonID = libraryManager.RegisterSeason(season); } } - Episode episode = await metadataProvider.GetEpisode(show.ExternalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath); + Episode episode = await metadataProvider.GetEpisode(show.ExternalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath, library); episode.ShowID = show.id; if (seasonID == -1) { if (!libraryManager.IsSeasonRegistered(show.id, episode.seasonNumber, out seasonID)) { - Season season = await metadataProvider.GetSeason(show.Title, episode.seasonNumber); + Season season = await metadataProvider.GetSeason(show.Title, episode.seasonNumber, library); season.ShowID = show.id; seasonID = libraryManager.RegisterSeason(season); } @@ -263,18 +199,15 @@ namespace Kyoo.Controllers libraryManager.RegisterTrack(track); } - if (episode.Path.EndsWith(".mkv")) + if (episode.Path.EndsWith(".mkv") && CountExtractedSubtitles(episode) != subcount) { - if (CountExtractedSubtitles(episode) != subcount) + Track[] subtitles = await transcoder.ExtractSubtitles(episode.Path); + if (subtitles != null) { - Track[] subtitles = await transcoder.ExtractSubtitles(episode.Path); - if (subtitles != null) + foreach (Track track in subtitles) { - foreach (Track track in subtitles) - { - track.episodeID = episode.id; - libraryManager.RegisterTrack(track); - } + track.episodeID = episode.id; + libraryManager.RegisterTrack(track); } } } diff --git a/Kyoo/Controllers/LibraryManager.cs b/Kyoo/Controllers/LibraryManager.cs index e55c5f5e..33a00035 100644 --- a/Kyoo/Controllers/LibraryManager.cs +++ b/Kyoo/Controllers/LibraryManager.cs @@ -29,7 +29,7 @@ namespace Kyoo.Controllers sqlConnection = new SQLiteConnection($"Data Source={databasePath};Version=3"); sqlConnection.Open(); - string createStatement = @"CREATE TABLE shows( + const string createStatement = @"CREATE TABLE shows( id INTEGER PRIMARY KEY UNIQUE, slug TEXT UNIQUE, title TEXT, @@ -92,7 +92,8 @@ namespace Kyoo.Controllers id INTEGER PRIMARY KEY UNIQUE, slug TEXT UNIQUE, name TEXT, - path TEXT + path TEXT, + providers TEXT ); CREATE TABLE librariesLinks( libraryID INTEGER, @@ -209,10 +210,11 @@ namespace Kyoo.Controllers public string GetShowExternalIDs(long showID) { - string query = string.Format("SELECT * FROM shows WHERE id = {0};", showID); - + string query = "SELECT * FROM shows WHERE id = $showID;"; + using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { + cmd.Parameters.AddWithValue("$showID", showID); SQLiteDataReader reader = cmd.ExecuteReader(); if (reader.Read()) @@ -949,13 +951,14 @@ namespace Kyoo.Controllers } } - public void RegisterInLibrary(long showID, string libraryPath) + public void RegisterInLibrary(long showID, Library library) { - string query = "INSERT INTO librariesLinks (libraryID, showID) SELECT id, $showID FROM libraries WHERE libraries.path = $libraryPath;"; + string query = + "INSERT INTO librariesLinks (libraryID, showID) SELECT id, $showID FROM libraries WHERE libraries.id = $libraryID;"; using (SQLiteCommand cmd = new SQLiteCommand(query, sqlConnection)) { - cmd.Parameters.AddWithValue("$libraryPath", libraryPath); + cmd.Parameters.AddWithValue("$libraryID", library.id); cmd.Parameters.AddWithValue("$showID", showID); cmd.ExecuteNonQuery(); } @@ -1102,21 +1105,21 @@ namespace Kyoo.Controllers } } - public void RegisterShowPeople(long showID, List people) + public void RegisterShowPeople(long showID, IEnumerable people) { if (people == null) return; string linkQuery = "INSERT INTO peopleLinks (peopleID, showID, role, type) VALUES($peopleID, $showID, $role, $type);"; - for (int i = 0; i < people.Count; i++) + foreach (People peop in people) { using (SQLiteCommand cmd = new SQLiteCommand(linkQuery, sqlConnection)) { - cmd.Parameters.AddWithValue("$peopleID", GetOrCreatePeople(people[i])); + cmd.Parameters.AddWithValue("$peopleID", GetOrCreatePeople(peop)); cmd.Parameters.AddWithValue("$showID", showID); - cmd.Parameters.AddWithValue("$role", people[i].Role); - cmd.Parameters.AddWithValue("$type", people[i].Type); + cmd.Parameters.AddWithValue("$role", peop.Role); + cmd.Parameters.AddWithValue("$type", peop.Type); cmd.ExecuteNonQuery(); } } diff --git a/Kyoo/Controllers/ProviderManager.cs b/Kyoo/Controllers/ProviderManager.cs index 4cf11925..7a1635d8 100644 --- a/Kyoo/Controllers/ProviderManager.cs +++ b/Kyoo/Controllers/ProviderManager.cs @@ -1,124 +1,87 @@ -using Kyoo.Models; -using Microsoft.Extensions.Configuration; -using System; +using System; +using Kyoo.Models; using System.Collections.Generic; -using System.IO; using System.Linq; -using System.Reflection; using System.Threading.Tasks; using Kyoo.Controllers.ThumbnailsManager; +using Kyoo.Utility; namespace Kyoo.Controllers { - public class ProviderManager : IMetadataProvider + public class ProviderManager : IProviderManager { private readonly IEnumerable providers; private readonly IThumbnailsManager thumbnailsManager; - private readonly IConfiguration config; - public ProviderManager(IThumbnailsManager thumbnailsManager, IPluginManager pluginManager, IConfiguration config) + public ProviderManager(IThumbnailsManager thumbnailsManager, IPluginManager pluginManager) { this.thumbnailsManager = thumbnailsManager; - this.config = config; providers = pluginManager.GetPlugins(); } - public Show Merge(IEnumerable shows) + public async Task GetMetadata(Func> providerCall, Library library, string what) where T : IMergable, new() { - return shows.FirstOrDefault(); - } - - public Season Merge(IEnumerable seasons) - { - return seasons.FirstOrDefault(); - } - - public Episode Merge(IEnumerable episodes) - { - return episodes.FirstOrDefault(); //Should do something if the return is null; - } - - //For all the following methods, it should use all providers and merge the data. - - public Task GetCollectionFromName(string name) - { - return providers[0].GetCollectionFromName(name); - } - - public Task GetImages(Show show) - { - return providers[0].GetImages(show); - } - - public async Task GetSeason(string showName, int seasonNumber) - { - List datas = new List(); - for (int i = 0; i < providers.Count; i++) + T ret = new T(); + + foreach (IMetadataProvider provider in providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name))) { - datas.Add(await providers[i].GetSeason(showName, seasonNumber)); + try + { + if (library.Providers.Contains(provider.Name)) + ret = ret.Merge(await providerCall(provider)); + } catch (Exception ex) { + Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. (Excepetion: {ex.Message}"); + } } - - return Merge(datas); + return ret; } - - public async Task GetShowByID(string id) + + public async Task> GetMetadata(Func>> providerCall, Library library, string what) { - List datas = new List(); - for (int i = 0; i < providers.Count; i++) + List ret = new List(); + + foreach (IMetadataProvider provider in providers.OrderBy(provider => Array.IndexOf(library.Providers, provider.Name))) { - datas.Add(await providers[i].GetShowByID(id)); + try + { + if (library.Providers.Contains(provider.Name)) + ret.AddRange(await providerCall(provider)); + } catch (Exception ex) { + Console.Error.WriteLine($"The provider {provider.Name} coudln't work for {what}. (Excepetion: {ex.Message}"); + } } - - return Merge(datas); + return ret; + } + + public async Task GetCollectionFromName(string name, Library library) + { + return await GetMetadata(provider => provider.GetCollectionFromName(name), library, $"the collection {name}"); } - public async Task GetShowFromName(string showName, string showPath) + public async Task GetShowFromName(string showName, string showPath, Library library) { - List datas = new List(); - for (int i = 0; i < providers.Count; i++) - { - datas.Add(await providers[i].GetShowFromName(showName, showPath)); - } - - Show show = Merge(datas); - return await thumbnailsManager.Validate(show); + Show show = await GetMetadata(provider => provider.GetShowFromName(showName, showPath), library, $"the show {showName}"); + await thumbnailsManager.Validate(show); + return show; } - public async Task GetSeason(string showName, long seasonNumber) + public async Task GetSeason(string showName, long seasonNumber, Library library) { - List datas = new List(); - for (int i = 0; i < providers.Count; i++) - { - datas.Add(await providers[i].GetSeason(showName, seasonNumber)); - } - - return Merge(datas); + return await GetMetadata(provider => provider.GetSeason(showName, seasonNumber), library, $"the season ${seasonNumber} of {showName}"); } - public Task GetSeasonImage(string showName, long seasonNumber) + public async Task GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath, Library library) { - //Should select the best provider for this show. - - return providers[0].GetSeasonImage(showName, seasonNumber); + Episode episode = await GetMetadata(provider => provider.GetEpisode(externalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath), library, $"the episode at {episodePath}"); + await thumbnailsManager.Validate(episode); + return episode; } - public async Task GetEpisode(string externalIDs, long seasonNumber, long episodeNumber, long absoluteNumber, string episodePath) + public async Task> GetPeople(string showExternalIDs, Library library) { - List datas = new List(); - for (int i = 0; i < providers.Count; i++) - { - datas.Add(await providers[i].GetEpisode(externalIDs, seasonNumber, episodeNumber, absoluteNumber, episodePath)); - } - - Episode episode = Merge(datas); - episode.Path = episodePath; - return await thumbnailsManager.Validate(episode); - } - - public async Task> GetPeople(string id) - { - List actors = await providers[0].GetPeople(id); - return await thumbnailsManager.Validate(actors); + IEnumerable people = await GetMetadata(provider => provider.GetPeople(showExternalIDs), library, $"unknown data"); + people = await thumbnailsManager.Validate(people); + return people; } } } diff --git a/Kyoo/Controllers/ThumbnailsManager.cs b/Kyoo/Controllers/ThumbnailsManager.cs index 3e0a468c..a3d25b65 100644 --- a/Kyoo/Controllers/ThumbnailsManager.cs +++ b/Kyoo/Controllers/ThumbnailsManager.cs @@ -67,20 +67,20 @@ namespace Kyoo.Controllers.ThumbnailsManager return show; } - public async Task> Validate(List people) + public async Task> Validate(IEnumerable people) { - for (int i = 0; i < people?.Count; i++) + foreach (People peop in people) { string root = config.GetValue("peoplePath"); Directory.CreateDirectory(root); - string localThumb = root + "/" + people[i].slug + ".jpg"; - if (people[i].imgPrimary != null && !File.Exists(localThumb)) + string localThumb = root + "/" + peop.slug + ".jpg"; + if (peop.imgPrimary != null && !File.Exists(localThumb)) { try { using WebClient client = new WebClient(); - await client.DownloadFileTaskAsync(new Uri(people[i].imgPrimary), localThumb); + await client.DownloadFileTaskAsync(new Uri(peop.imgPrimary), localThumb); } catch (WebException) { diff --git a/Kyoo/HtmlAPI/AdminController.cs b/Kyoo/HtmlAPI/AdminController.cs index fdd006c6..2ac4ce86 100644 --- a/Kyoo/HtmlAPI/AdminController.cs +++ b/Kyoo/HtmlAPI/AdminController.cs @@ -18,10 +18,10 @@ namespace Kyoo.Controllers this.crawler = crawler; } - [HttpGet("scan/{watch}")] - public IActionResult ScanLibrary(bool watch) + [HttpGet("scan")] + public IActionResult ScanLibrary() { - crawler.Start(watch); + crawler.Start(); return Ok("Scanning"); } } diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index f2b74b67..b7fedf32 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -35,7 +35,7 @@ namespace Kyoo services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.