diff --git a/Kyoo.Common/Controllers/IThumbnailsManager.cs b/Kyoo.Common/Controllers/IThumbnailsManager.cs index 75188809..d1423f77 100644 --- a/Kyoo.Common/Controllers/IThumbnailsManager.cs +++ b/Kyoo.Common/Controllers/IThumbnailsManager.cs @@ -6,8 +6,8 @@ namespace Kyoo.Controllers { public interface IThumbnailsManager { - Task Validate(Show show); - Task> Validate(IEnumerable actors); - Task Validate(Episode episode); + Task Validate(Show show, bool alwaysDownload = false); + Task> Validate(IEnumerable actors, bool alwaysDownload = false); + Task Validate(Episode episode, bool alwaysDownload = false); } } diff --git a/Kyoo/Controllers/LibraryManager.cs b/Kyoo/Controllers/LibraryManager.cs index 249d495e..162aa2f4 100644 --- a/Kyoo/Controllers/LibraryManager.cs +++ b/Kyoo/Controllers/LibraryManager.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Linq; using Kyoo.Models.Exceptions; using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Query; namespace Kyoo.Controllers { @@ -385,9 +386,12 @@ namespace Kyoo.Controllers try { + var query = _database.Shows.Include(x => x.GenreLinks) + .Include(x => x.People) + .Include(x => x.ExternalIDs); Show show = _database.Entry(edited).IsKeySet - ? _database.Shows.Include(x => x.GenreLinks).FirstOrDefault(x => x.ID == edited.ID) - : _database.Shows.Include(x => x.GenreLinks).FirstOrDefault(x => x.Slug == edited.Slug); + ? query.FirstOrDefault(x => x.ID == edited.ID) + : query.FirstOrDefault(x => x.Slug == edited.Slug); if (show == null) throw new ItemNotFound($"No show could be found with the id {edited.ID} or the slug {edited.Slug}"); @@ -413,7 +417,11 @@ namespace Kyoo.Controllers }).ToList(); show.People = edited.People?.Select(x => { - x.People = _database.Peoples.FirstOrDefault(y => y.Slug == x.People.Slug) ?? x.People; + People people = _database.Peoples.FirstOrDefault(y => y.Slug == x.People.Slug); + if (people != null) + x.People = people; + else + x.People.ExternalIDs = ValidateExternalIDs(x.People.ExternalIDs); return x; }).ToList(); show.Seasons = edited.Seasons?.Select(x => @@ -427,6 +435,7 @@ namespace Kyoo.Controllers && y.SeasonNumber == x.SeasonNumber && y.EpisodeNumber == x.EpisodeNumber) ?? x; }).ToList(); + show.ExternalIDs = ValidateExternalIDs(show.ExternalIDs); _database.ChangeTracker.DetectChanges(); _database.SaveChanges(); diff --git a/Kyoo/Controllers/ThumbnailsManager.cs b/Kyoo/Controllers/ThumbnailsManager.cs index 5602fd9b..681dd00d 100644 --- a/Kyoo/Controllers/ThumbnailsManager.cs +++ b/Kyoo/Controllers/ThumbnailsManager.cs @@ -17,100 +17,77 @@ namespace Kyoo.Controllers _config = configuration; } - public async Task Validate(Show show) + private static async Task DownloadImage(string url, string localPath, string what) + { + try + { + using WebClient client = new WebClient(); + await client.DownloadFileTaskAsync(new Uri(url), localPath); + } + catch (WebException exception) + { + await Console.Error.WriteLineAsync($"\t{what} could not be downloaded.\n\tError: {exception.Message}."); + } + } + + public async Task Validate(Show show, bool alwaysDownload) { if (show?.Path == null) - return null; - string localThumb = Path.Combine(show.Path, "poster.jpg"); - string localLogo = Path.Combine(show.Path, "logo.png"); - string localBackdrop = Path.Combine(show.Path, "backdrop.jpg"); + return default; - - if (show.Poster != null && !File.Exists(localThumb)) + if (show.Poster != null) { - try - { - using WebClient client = new WebClient(); - await client.DownloadFileTaskAsync(new Uri(show.Poster), localThumb); - } - catch (WebException exception) - { - Console.Error.WriteLine($"\tThe poster of {show.Title} could not be downloaded.\n\tError: {exception.Message}. "); - } + string posterPath = Path.Combine(show.Path, "poster.jpg"); + if (alwaysDownload || !File.Exists(posterPath)) + await DownloadImage(show.Poster, posterPath, $"The poster of {show.Title}"); } - - if (show.Logo != null && !File.Exists(localLogo)) + if (show.Logo != null) { - try - { - using WebClient client = new WebClient(); - await client.DownloadFileTaskAsync(new Uri(show.Logo), localLogo); - } - catch (WebException exception) - { - Console.Error.WriteLine($"\tThe logo of {show.Title} could not be downloaded.\n\tError: {exception.Message}. "); - } + string logoPath = Path.Combine(show.Path, "logo.png"); + if (alwaysDownload || !File.Exists(logoPath)) + await DownloadImage(show.Logo, logoPath, $"The logo of {show.Title}"); } - - if (show.Backdrop != null && !File.Exists(localBackdrop)) + if (show.Backdrop != null) { - try - { - using WebClient client = new WebClient(); - await client.DownloadFileTaskAsync(new Uri(show.Backdrop), localBackdrop); - } - catch (WebException exception) - { - Console.Error.WriteLine($"\tThe backdrop of {show.Title} could not be downloaded.\n\tError: {exception.Message}. "); - } + string backdropPath = Path.Combine(show.Path, "backdrop.jpg"); + if (alwaysDownload || !File.Exists(backdropPath)) + await DownloadImage(show.Backdrop, backdropPath, $"The backdrop of {show.Title}"); } return show; } - public async Task> Validate(IEnumerable people) + public async Task> Validate(IEnumerable people, bool alwaysDownload) { if (people == null) return null; + + string root = _config.GetValue("peoplePath"); + Directory.CreateDirectory(root); + foreach (PeopleLink peop in people) { - string root = _config.GetValue("peoplePath"); - Directory.CreateDirectory(root); - - string localThumb = root + "/" + peop.People.Slug + ".jpg"; - if (peop.People.ImgPrimary == null || File.Exists(localThumb)) + string localPath = Path.Combine(root, peop.People.Slug + ".jpg"); + if (peop.People.ImgPrimary == null) continue; - try - { - using WebClient client = new WebClient(); - await client.DownloadFileTaskAsync(new Uri(peop.People.ImgPrimary), localThumb); - } - catch (WebException exception) - { - Console.Error.WriteLine($"\tThe profile picture of {peop.People.Name} could not be downloaded.\n\tError: {exception.Message}. "); - } + if (alwaysDownload || !File.Exists(localPath)) + await DownloadImage(peop.People.ImgPrimary, localPath, $"The profile picture of {peop.People.Name}"); } - + return people; } - public async Task Validate(Episode episode) + public async Task Validate(Episode episode, bool alwaysDownload) { - if (episode == null || episode.Path == null) - return null; - string localThumb = Path.ChangeExtension(episode.Path, "jpg"); - if (episode.ImgPrimary == null || File.Exists(localThumb)) - return episode; - try - { - using WebClient client = new WebClient(); - await client.DownloadFileTaskAsync(new Uri(episode.ImgPrimary), localThumb); - } - catch (WebException exception) - { - Console.Error.WriteLine($"\tThe thumbnail of {episode.Show.Title} s{episode.SeasonNumber}e{episode.EpisodeNumber} could not be downloaded.\n\tError: {exception.Message}. "); - } + if (episode?.Path == null) + return default; + if (episode.ImgPrimary == null) + { + string localPath = Path.ChangeExtension(episode.Path, "jpg"); + if (alwaysDownload || !File.Exists(localPath)) + await DownloadImage(episode.ImgPrimary, localPath, $"The thumbnail of {episode.Show.Title}"); + } return episode; } } diff --git a/Kyoo/Views/API/ShowsAPI.cs b/Kyoo/Views/API/ShowsAPI.cs index e832b64a..a1da7543 100644 --- a/Kyoo/Views/API/ShowsAPI.cs +++ b/Kyoo/Views/API/ShowsAPI.cs @@ -1,10 +1,12 @@ using Kyoo.Models; using Microsoft.AspNetCore.Mvc; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Kyoo.Controllers; using Kyoo.Models.Exceptions; using Microsoft.AspNetCore.Authorization; +using Microsoft.EntityFrameworkCore; namespace Kyoo.Api { @@ -15,11 +17,15 @@ namespace Kyoo.Api { private readonly ILibraryManager _libraryManager; private readonly IProviderManager _providerManager; + private readonly DatabaseContext _database; + private readonly IThumbnailsManager _thumbnailsManager; - public ShowsAPI(ILibraryManager libraryManager, IProviderManager providerManager) + public ShowsAPI(ILibraryManager libraryManager, IProviderManager providerManager, DatabaseContext database, IThumbnailsManager thumbnailsManager) { _libraryManager = libraryManager; _providerManager = providerManager; + _database = database; + _thumbnailsManager = thumbnailsManager; } [HttpGet] @@ -47,17 +53,33 @@ namespace Kyoo.Api public IActionResult EditShow(string slug, [FromBody] Show show) { if (!ModelState.IsValid) - return BadRequest(show); - show.ID = 0; - show.Slug = slug; - try - { - _libraryManager.EditShow(show); - } - catch (ItemNotFound) - { + return BadRequest(show); + + Show old = _database.Shows.AsNoTracking().FirstOrDefault(x => x.Slug == slug); + if (old == null) return NotFound(); - } + show.ID = old.ID; + show.Slug = slug; + show.Path = old.Path; + _libraryManager.EditShow(show); + return Ok(); + } + + [HttpPost("re-identify/{slug}")] + [Authorize(Policy = "Write")] + public async Task ReIdentityShow(string slug, [FromBody] Show show) + { + if (!ModelState.IsValid) + return BadRequest(show); + Show old = _database.Shows.FirstOrDefault(x => x.Slug == slug); + if (old == null) + return NotFound(); + Show edited = await _providerManager.CompleteShow(show, _libraryManager.GetLibraryForShow(slug)); + edited.ID = old.ID; + edited.Slug = old.Slug; + edited.Path = old.Path; + _libraryManager.EditShow(edited); + await _thumbnailsManager.Validate(edited, true); return Ok(); } @@ -67,13 +89,16 @@ namespace Kyoo.Api { return await _providerManager.SearchShows(name, isMovie, null); } - - [HttpGet("details")] - [Authorize(Policy = "Read")] - public async Task IdentityShow([FromBody] Show show) + + [HttpPost("download-images/{slug}")] + [Authorize(Policy = "Write")] + public async Task DownloadImages(string slug) { - Library library = _libraryManager.GetLibraryForShow(show.Slug); - return await _providerManager.CompleteShow(show, library); + Show show = _libraryManager.GetShowBySlug(slug); + if (show == null) + return NotFound(); + await _thumbnailsManager.Validate(show, true); + return Ok(); } } }