diff --git a/Kyoo.Common/Controllers/ILibraryManager.cs b/Kyoo.Common/Controllers/ILibraryManager.cs index cec60504..8268cb66 100644 --- a/Kyoo.Common/Controllers/ILibraryManager.cs +++ b/Kyoo.Common/Controllers/ILibraryManager.cs @@ -44,6 +44,7 @@ namespace Kyoo.Controllers //Register values void Register(object obj); Task Edit(object obj, bool resetOld); + void RegisterShowLinks(Library library, Collection collection, Show show); Task SaveChanges(); // Validate values diff --git a/Kyoo.Common/Models/Show.cs b/Kyoo.Common/Models/Show.cs index d540dd24..4801fb35 100644 --- a/Kyoo.Common/Models/Show.cs +++ b/Kyoo.Common/Models/Show.cs @@ -7,7 +7,7 @@ namespace Kyoo.Models { public class Show : IOnMerge { - [NotMergableAttribute] [JsonIgnore] public long ID { get; set; } + [JsonIgnore] public long ID { get; set; } public string Slug { get; set; } public string Title { get; set; } diff --git a/Kyoo.Common/Utility.cs b/Kyoo.Common/Utility.cs index 364235af..1183e5ea 100644 --- a/Kyoo.Common/Utility.cs +++ b/Kyoo.Common/Utility.cs @@ -99,10 +99,7 @@ namespace Kyoo if (second == null) return first; - Type type = first.GetType(); - if (second.GetType() != type && second.GetType().IsAssignableFrom(type)) - type = second.GetType(); - + Type type = typeof(T); foreach (PropertyInfo property in type.GetProperties().Where(x => x.CanRead && x.CanWrite)) { if (Attribute.GetCustomAttribute(property, typeof(NotMergableAttribute)) != null) @@ -134,10 +131,10 @@ namespace Kyoo public static T Nullify(T obj) { - Type type = obj.GetType(); + Type type = typeof(T); foreach (PropertyInfo property in type.GetProperties()) { - if (!property.CanWrite || Attribute.GetCustomAttribute(property, typeof(NotMergableAttribute)) != null) + if (!property.CanWrite) continue; object defaultValue = property.PropertyType.IsValueType diff --git a/Kyoo/Controllers/LibraryManager.cs b/Kyoo/Controllers/LibraryManager.cs index ebfdf467..8d7aaaf2 100644 --- a/Kyoo/Controllers/LibraryManager.cs +++ b/Kyoo/Controllers/LibraryManager.cs @@ -191,6 +191,20 @@ namespace Kyoo.Controllers }); } + public void RegisterShowLinks(Library library, Collection collection, Show show) + { + if (collection != null) + { + _database.LibraryLinks.AddIfNotExist(new LibraryLink {Library = library, Collection = collection}, + x => x.Library == library && x.Collection == collection && x.ShowID == null); + _database.CollectionLinks.AddIfNotExist(new CollectionLink { Collection = collection, Show = show}, + x => x.Collection == collection && x.Show == show); + } + else + _database.LibraryLinks.AddIfNotExist(new LibraryLink {Library = library, Show = show}, + x => x.Library == library && x.Collection == null && x.Show == show); + } + public Task SaveChanges() { return SaveChanges(0); @@ -226,12 +240,11 @@ namespace Kyoo.Controllers if (resetOld) Utility.Nullify(existing); - _database.ChangeTracker.DetectChanges(); Utility.Merge(existing, obj); + ValidateRootEntry(_database.Entry(existing), entry => entry.State != EntityState.Added); + _database.ChangeTracker.DetectChanges(); - ValidateRootEntry(_database.Entry(existing), entry => entry.State != EntityState.Unchanged - && entry.State != EntityState.Deleted); await _database.SaveChangesAsync(); } finally @@ -264,14 +277,12 @@ namespace Kyoo.Controllers } } - private void ValidateRootEntry(EntityEntry entry, Func shouldRun, object parentObject = null) + private void ValidateRootEntry(EntityEntry entry, Func shouldRun) { if (!shouldRun.Invoke(entry)) return; foreach (NavigationEntry navigation in entry.Navigations) { - if (!navigation.Metadata.IsCollection() && ReferenceEquals(navigation.CurrentValue, parentObject)) - continue; ValidateNavigation(navigation); if (navigation.CurrentValue == null) continue; @@ -279,14 +290,10 @@ namespace Kyoo.Controllers { IEnumerable entities = (IEnumerable)navigation.CurrentValue; foreach (object childEntry in entities) - { - if (ReferenceEquals(childEntry, parentObject)) - continue; - ValidateRootEntry(_database.Entry(childEntry), shouldRun, entry.Entity); - } + ValidateRootEntry(_database.Entry(childEntry), shouldRun); } else - ValidateRootEntry(_database.Entry(navigation.CurrentValue), shouldRun, entry.Entity); + ValidateRootEntry(_database.Entry(navigation.CurrentValue), shouldRun); } } @@ -328,7 +335,7 @@ namespace Kyoo.Controllers return list.Select(x => { T tmp = Validate(x); - if (!ReferenceEquals(x, tmp)) + if (tmp != x) _database.Entry(x).State = EntityState.Detached; return tmp ?? x; })/*.GroupBy(GetSlug).Select(x => x.First()).Where(x => x != null)*/.ToList(); @@ -338,41 +345,13 @@ namespace Kyoo.Controllers { return obj switch { - Library library => _database.Libraries - .Include(x => x.Links) - .Include(x => x.Providers) - .FirstOrDefault(x => x.Slug == library.Slug), - Collection collection => _database.Collections - .Include(x => x.Links) - .FirstOrDefault(x => x.Slug == collection.Slug), - Show show => _database.Shows - .Include(x => x.Seasons) - .Include(x => x.Episodes) - .Include(x => x.People) - .Include(x => x.GenreLinks) - .Include(x => x.Studio) - .Include(x => x.ExternalIDs) - .FirstOrDefault(x => x.Slug == show.Slug), - Season season => _database.Seasons - .Include(x => x.Episodes) - .Include(x => x.ExternalIDs) - .Include(x => x.Show) - .FirstOrDefault(x => x.Show.Slug == season.Show.Slug && x.SeasonNumber == season.SeasonNumber), - Episode episode => _database.Episodes - .Include(x => x.Season) - .Include(x => x.Show) - .Include(x => x.ExternalIDs) - .Include(x => x.Tracks) - .FirstOrDefault(x => x.EpisodeNumber == episode.EpisodeNumber - && x.SeasonNumber == episode.SeasonNumber - && x.Show.Slug == episode.Show.Slug), - Studio studio => _database.Studios - .Include(x => x.Shows) - .FirstOrDefault(x => x.Slug == studio.Slug), - People people => _database.Peoples - .Include(x => x.Roles) - .Include(x => x.ExternalIDs) - .FirstOrDefault(x => x.Slug == people.Slug), + Library library => GetLibrary(library.Slug), + Collection collection => GetCollection(collection.Slug), + Show show => GetShow(show.Slug), + Season season => GetSeason(season.Show.Slug, season.SeasonNumber), + Episode episode => GetEpisode(episode.Show.Slug, episode.SeasonNumber, episode.EpisodeNumber), + Studio studio => GetStudio(studio.Slug), + People people => GetPeople(people.Slug), Genre genre => GetGenre(genre.Slug), ProviderID provider => GetProvider(provider.Name), _ => null diff --git a/Kyoo/Controllers/ProviderManager.cs b/Kyoo/Controllers/ProviderManager.cs index fa1a0573..5dc6791c 100644 --- a/Kyoo/Controllers/ProviderManager.cs +++ b/Kyoo/Controllers/ProviderManager.cs @@ -76,12 +76,9 @@ namespace Kyoo.Controllers return collection; } - public async Task CompleteShow(Show old, Library library) + public async Task CompleteShow(Show show, Library library) { - Show show = await GetMetadata(provider => provider.GetShowByID(old), library, $"the show {old.Title}"); - show.GenreLinks = show.GenreLinks?.GroupBy(x => x.Genre.Slug).Select(x => x.First()).ToList(); - show.People = show.People?.GroupBy(x => x.Slug).Select(x => x.First()).ToList(); - return show; + return await GetMetadata(provider => provider.GetShowByID(show), library, $"the show {show.Title}"); } public async Task SearchShow(string showName, bool isMovie, Library library) diff --git a/Kyoo/Startup.cs b/Kyoo/Startup.cs index afeb6590..22baaf05 100644 --- a/Kyoo/Startup.cs +++ b/Kyoo/Startup.cs @@ -51,9 +51,9 @@ namespace Kyoo services.AddDbContext(options => { options.UseLazyLoadingProxies() - .UseNpgsql(_configuration.GetConnectionString("Database")) - .EnableSensitiveDataLogging(); - //.UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); + .UseNpgsql(_configuration.GetConnectionString("Database")); + // .EnableSensitiveDataLogging() + // .UseLoggerFactory(LoggerFactory.Create(builder => builder.AddConsole())); }); services.AddDbContext(options => diff --git a/Kyoo/Tasks/Crawler.cs b/Kyoo/Tasks/Crawler.cs index 3225dfe2..065bc613 100644 --- a/Kyoo/Tasks/Crawler.cs +++ b/Kyoo/Tasks/Crawler.cs @@ -142,12 +142,8 @@ namespace Kyoo.Controllers long absoluteNumber = long.TryParse(match.Groups["Absolute"].Value, out tmp) ? tmp : -1; Collection collection = await GetCollection(libraryManager, collectionName, library); - - if (collection != null) - libraryManager.Register(collection); - bool isMovie = seasonNumber == -1 && episodeNumber == -1 && absoluteNumber == -1; - Show show = await GetShow(libraryManager, collection, showName, showPath, isMovie, library); + Show show = await GetShow(libraryManager, showName, showPath, isMovie, library); if (isMovie) libraryManager.Register(await GetMovie(show, path)); else @@ -156,6 +152,9 @@ namespace Kyoo.Controllers Episode episode = await GetEpisode(libraryManager, show, season, episodeNumber, absoluteNumber, path, library); libraryManager.Register(episode); } + if (collection != null) + libraryManager.Register(collection); + libraryManager.RegisterShowLinks(library, collection, show); Console.WriteLine($"Registering episode at: {path}"); await libraryManager.SaveChanges(); } @@ -163,19 +162,14 @@ namespace Kyoo.Controllers private async Task GetCollection(ILibraryManager libraryManager, string collectionName, Library library) { if (string.IsNullOrEmpty(collectionName)) - return default; + return await Task.FromResult(null); Collection name = libraryManager.GetCollection(Utility.ToSlug(collectionName)); if (name != null) return name; return await _metadataProvider.GetCollectionFromName(collectionName, library); } - private async Task GetShow(ILibraryManager libraryManager, - Collection collection, - string showTitle, - string showPath, - bool isMovie, - Library library) + private async Task GetShow(ILibraryManager libraryManager, string showTitle, string showPath, bool isMovie, Library library) { Show show = libraryManager.GetShowByPath(showPath); if (show != null) @@ -185,15 +179,6 @@ namespace Kyoo.Controllers show.People = await _metadataProvider.GetPeople(show, library); await _thumbnailsManager.Validate(show.People); await _thumbnailsManager.Validate(show); - - if (collection != null) - { - libraryManager.Register(new LibraryLink {Library = library, Collection = collection}); - libraryManager.Register(new CollectionLink { Collection = collection, Show = show}); - } - else - libraryManager.Register(new LibraryLink {Library = library, Show = show}); - return show; } @@ -211,20 +196,9 @@ namespace Kyoo.Controllers return season; } - private async Task GetEpisode(ILibraryManager libraryManager, - Show show, - Season season, - long episodeNumber, - long absoluteNumber, - string episodePath, - Library library) + private async Task GetEpisode(ILibraryManager libraryManager, Show show, Season season, long episodeNumber, long absoluteNumber, string episodePath, Library library) { - Episode episode = await _metadataProvider.GetEpisode(show, - episodePath, - season?.SeasonNumber ?? -1, - episodeNumber, - absoluteNumber, - library); + Episode episode = await _metadataProvider.GetEpisode(show, episodePath, season?.SeasonNumber ?? -1, episodeNumber, absoluteNumber, library); if (season == null) season = await GetSeason(libraryManager, show, episode.SeasonNumber, library); episode.Season = season; @@ -249,8 +223,7 @@ namespace Kyoo.Controllers private async Task> GetTracks(Episode episode) { IEnumerable tracks = await _transcoder.GetTrackInfo(episode.Path); - List epTracks = tracks.Where(x => x.Type != StreamType.Subtitle) - .Concat(GetExtractedSubtitles(episode)).ToList(); + List epTracks = tracks.Where(x => x.Type != StreamType.Subtitle).Concat(GetExtractedSubtitles(episode)).ToList(); if (epTracks.Count(x => !x.IsExternal) < tracks.Count()) epTracks.AddRange(await _transcoder.ExtractSubtitles(episode.Path)); episode.Tracks = epTracks; @@ -289,33 +262,7 @@ namespace Kyoo.Controllers return tracks; } - 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 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 static bool IsVideo(string filePath) { diff --git a/Kyoo/Tasks/ReScan.cs b/Kyoo/Tasks/ReScan.cs index 3565dafb..22c7aeb5 100644 --- a/Kyoo/Tasks/ReScan.cs +++ b/Kyoo/Tasks/ReScan.cs @@ -62,8 +62,6 @@ namespace Kyoo.Tasks edited.ID = old.ID; edited.Slug = old.Slug; edited.Path = old.Path; - edited.Seasons = old.Seasons; - edited.Episodes = old.Episodes; await libraryManager.Edit(edited, true); await _thumbnailsManager.Validate(edited, true); }