diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs index 23123d36..c45cbf82 100644 --- a/Kyoo.Common/Controllers/ILibraryManager.cs +++ b/Kyoo.Common/Controllers/ILibraryManager.cs @@ -40,7 +40,9 @@ namespace Kyoo.Controllers Task GetLibrary(string slug); Task GetCollection(string slug); Task GetShow(string slug); + Task GetSeason(string slug); Task GetSeason(string showSlug, int seasonNumber); + Task GetEpisode(string slug); Task GetEpisode(string showSlug, int seasonNumber, int episodeNumber); Task GetMovieEpisode(string movieSlug); Task GetTrack(string slug, StreamType type = StreamType.Unknown); diff --git a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs index 9789f77f..bfc3cfa6 100644 --- a/Kyoo.Common/Controllers/Implementations/LibraryManager.cs +++ b/Kyoo.Common/Controllers/Implementations/LibraryManager.cs @@ -144,12 +144,22 @@ namespace Kyoo.Controllers { return ShowRepository.Get(slug); } + + public Task GetSeason(string slug) + { + return SeasonRepository.Get(slug); + } public Task GetSeason(string showSlug, int seasonNumber) { return SeasonRepository.Get(showSlug, seasonNumber); } + public Task GetEpisode(string slug) + { + return EpisodeRepository.Get(slug); + } + public Task GetEpisode(string showSlug, int seasonNumber, int episodeNumber) { return EpisodeRepository.Get(showSlug, seasonNumber, episodeNumber); diff --git a/Kyoo/Controllers/ThumbnailsManager.cs b/Kyoo/Controllers/ThumbnailsManager.cs index 23b75846..07a1d709 100644 --- a/Kyoo/Controllers/ThumbnailsManager.cs +++ b/Kyoo/Controllers/ThumbnailsManager.cs @@ -21,12 +21,12 @@ namespace Kyoo.Controllers { try { - using WebClient client = new WebClient(); + using WebClient client = new(); await client.DownloadFileTaskAsync(new Uri(url), localPath); } catch (WebException exception) { - await Console.Error.WriteLineAsync($"\t{what} could not be downloaded.\n\tError: {exception.Message}."); + await Console.Error.WriteLineAsync($"{what} could not be downloaded.\n\tError: {exception.Message}."); } } diff --git a/Kyoo/Tasks/CoreTaskHolder.cs b/Kyoo/Tasks/CoreTaskHolder.cs index 7cae9dc8..5d5948e7 100644 --- a/Kyoo/Tasks/CoreTaskHolder.cs +++ b/Kyoo/Tasks/CoreTaskHolder.cs @@ -10,8 +10,9 @@ namespace Kyoo.Tasks new CreateDatabase(), new PluginLoader(), new Crawler(), - new MetadataLoader(), - new ReScan() + new MetadataProviderLoader(), + new ReScan(), + new ExtractMetadata() }; } } \ No newline at end of file diff --git a/Kyoo/Tasks/ExtractMetadata.cs b/Kyoo/Tasks/ExtractMetadata.cs new file mode 100644 index 00000000..f65d1b42 --- /dev/null +++ b/Kyoo/Tasks/ExtractMetadata.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Kyoo.Controllers; +using Kyoo.Models; +using Microsoft.Extensions.DependencyInjection; + +namespace Kyoo.Tasks +{ + public class ExtractMetadata : ITask + { + public string Slug => "extract"; + public string Name => "Metadata Extractor"; + public string Description => "Extract subtitles or download thumbnails for a show/episode."; + public string HelpMessage => null; + public bool RunOnStartup => false; + public int Priority => 0; + + + private ILibraryManager _library; + private IThumbnailsManager _thumbnails; + private ITranscoder _transcoder; + + public async Task Run(IServiceProvider serviceProvider, CancellationToken token, string arguments = null) + { + string[] args = arguments?.Split('/'); + + if (args == null || args.Length < 2) + return; + + string slug = args[1]; + bool thumbs = args.Length < 3 || string.Equals(args[2], "thumbnails", StringComparison.InvariantCultureIgnoreCase); + bool subs = args.Length < 3 || string.Equals(args[2], "subs", StringComparison.InvariantCultureIgnoreCase); + + using IServiceScope serviceScope = serviceProvider.CreateScope(); + _library = serviceScope.ServiceProvider.GetService(); + _thumbnails = serviceScope.ServiceProvider.GetService(); + _transcoder = serviceScope.ServiceProvider.GetService(); + int id; + + switch (args[0].ToLowerInvariant()) + { + case "show": + case "shows": + Show show = await (int.TryParse(slug, out id) + ? _library!.GetShow(id) + : _library!.GetShow(slug)); + await ExtractShow(show, thumbs, subs, token); + break; + case "season": + case "seasons": + Season season = await (int.TryParse(slug, out id) + ? _library!.GetSeason(id) + : _library!.GetSeason(slug)); + await ExtractSeason(season, thumbs, subs, token); + break; + case "episode": + case "episodes": + Episode episode = await (int.TryParse(slug, out id) + ? _library!.GetEpisode(id) + : _library!.GetEpisode(slug)); + await ExtractEpisode(episode, thumbs, subs); + break; + } + + await _library!.DisposeAsync(); + } + + private async Task ExtractShow(Show show, bool thumbs, bool subs, CancellationToken token) + { + if (thumbs) + await _thumbnails!.Validate(show, true); + foreach (Season season in show.Seasons) + { + if (token.IsCancellationRequested) + return; + await ExtractSeason(season, thumbs, subs, token); + } + } + + private async Task ExtractSeason(Season season, bool thumbs, bool subs, CancellationToken token) + { + if (thumbs) + await _thumbnails!.Validate(season, true); + foreach (Episode episode in season.Episodes) + { + if (token.IsCancellationRequested) + return; + await ExtractEpisode(episode, thumbs, subs); + } + } + + private async Task ExtractEpisode(Episode episode, bool thumbs, bool subs) + { + if (thumbs) + await _thumbnails!.Validate(episode, true); + if (subs) + { + // TODO this doesn't work. + IEnumerable tracks = (await _transcoder!.ExtractInfos(episode.Path)) + .Where(x => x.Type != StreamType.Font); + episode.Tracks = tracks; + await _library.EditEpisode(episode, false); + } + } + + public Task> GetPossibleParameters() + { + return Task.FromResult>(null); + } + + public int? Progress() + { + return null; + } + } +} \ No newline at end of file diff --git a/Kyoo/Tasks/MetadataLoader.cs b/Kyoo/Tasks/MetadataProviderLoader.cs similarity index 96% rename from Kyoo/Tasks/MetadataLoader.cs rename to Kyoo/Tasks/MetadataProviderLoader.cs index a6ae96af..95539677 100644 --- a/Kyoo/Tasks/MetadataLoader.cs +++ b/Kyoo/Tasks/MetadataProviderLoader.cs @@ -8,7 +8,7 @@ using Microsoft.Extensions.DependencyInjection; namespace Kyoo.Tasks { - public class MetadataLoader : ITask + public class MetadataProviderLoader : ITask { public string Slug => "reload-metdata"; public string Name => "Reload Metadata Providers"; diff --git a/Kyoo/Views/API/TaskAPI.cs b/Kyoo/Views/API/TaskAPI.cs index 24ab8845..8e531bf9 100644 --- a/Kyoo/Views/API/TaskAPI.cs +++ b/Kyoo/Views/API/TaskAPI.cs @@ -17,6 +17,7 @@ namespace Kyoo.Api [HttpGet("{taskSlug}/{*args}")] + [HttpPut("{taskSlug}/{*args}")] [Authorize(Policy="Admin")] public IActionResult RunTask(string taskSlug, string args = null) { diff --git a/Kyoo/Views/WebClient b/Kyoo/Views/WebClient index ec79821a..09edd091 160000 --- a/Kyoo/Views/WebClient +++ b/Kyoo/Views/WebClient @@ -1 +1 @@ -Subproject commit ec79821a71ba0db650b850f7c04c5f93abcb68b0 +Subproject commit 09edd091b9bc75b697da4dc16eeaf9aadb9d4b05