From a76770b2400f3da28059b246f9ed0ce2b159a1a1 Mon Sep 17 00:00:00 2001 From: Joe Milazzo Date: Wed, 1 Feb 2023 08:22:02 -0800 Subject: [PATCH] Auto Collection Bugfixes (#1769) * SeriesGroup tag can now have comma separated value to allow a series to be a part of multiple collections. * Added a missing unit test * Refactored how collection tags are created to work in the scan loop reliably. * Added a unit test for RemoveTagsWithoutSeries * Fixed a bug in reading list title generation to avoid Volume 0 if the underlying file had a title set. Fixed a misconfigured unit test. --- API.Tests/Helpers/EntityFactory.cs | 8 -- API.Tests/Helpers/PersonHelperTests.cs | 2 +- .../Services/CollectionTagServiceTests.cs | 42 +++++++ API.Tests/Services/ReadingListServiceTests.cs | 111 ++++++++++++++---- API/Data/DbFactory.cs | 12 +- .../Repositories/CollectionTagRepository.cs | 6 +- .../Repositories/ReadingListRepository.cs | 5 +- API/Data/Repositories/SeriesRepository.cs | 3 + API/Helpers/ReadingListHelper.cs | 49 -------- API/Services/CollectionTagService.cs | 29 ++++- API/Services/ReadingListService.cs | 46 ++++++++ API/Services/Tasks/Scanner/ProcessSeries.cs | 25 +++- openapi.json | 2 +- 13 files changed, 234 insertions(+), 106 deletions(-) delete mode 100644 API/Helpers/ReadingListHelper.cs diff --git a/API.Tests/Helpers/EntityFactory.cs b/API.Tests/Helpers/EntityFactory.cs index 06fbc35bd..a73a611e2 100644 --- a/API.Tests/Helpers/EntityFactory.cs +++ b/API.Tests/Helpers/EntityFactory.cs @@ -61,14 +61,6 @@ public static class EntityFactory }; } - public static SeriesMetadata CreateSeriesMetadata(ICollection collectionTags) - { - return new SeriesMetadata() - { - CollectionTags = collectionTags - }; - } - public static CollectionTag CreateCollectionTag(int id, string title, string summary, bool promoted) { return DbFactory.CollectionTag(id, title, summary, promoted); diff --git a/API.Tests/Helpers/PersonHelperTests.cs b/API.Tests/Helpers/PersonHelperTests.cs index d5dafd963..85f1687c9 100644 --- a/API.Tests/Helpers/PersonHelperTests.cs +++ b/API.Tests/Helpers/PersonHelperTests.cs @@ -103,7 +103,7 @@ public class PersonHelperTests DbFactory.Person("Joe Shmo", PersonRole.CoverArtist) }; var peopleRemoved = new List(); - PersonHelper.RemovePeople(existingPeople, Array.Empty(), PersonRole.Writer, person => + PersonHelper.RemovePeople(existingPeople, new List(), PersonRole.Writer, person => { peopleRemoved.Add(person); }); diff --git a/API.Tests/Services/CollectionTagServiceTests.cs b/API.Tests/Services/CollectionTagServiceTests.cs index 150e8d02b..bb8da9ad0 100644 --- a/API.Tests/Services/CollectionTagServiceTests.cs +++ b/API.Tests/Services/CollectionTagServiceTests.cs @@ -110,4 +110,46 @@ public class CollectionTagServiceTests : AbstractDbTest Assert.Empty(metadatas.First().CollectionTags); Assert.NotEmpty(await _unitOfWork.SeriesRepository.GetSeriesMetadataForIdsAsync(new[] {2})); } + + [Fact] + public async Task GetTagOrCreate_ShouldReturnNewTag() + { + await SeedSeries(); + var tag = await _service.GetTagOrCreate(0, "GetTagOrCreate_ShouldReturnNewTag"); + Assert.NotNull(tag); + Assert.NotSame(0, tag.Id); + } + + [Fact] + public async Task GetTagOrCreate_ShouldReturnExistingTag() + { + await SeedSeries(); + var tag = await _service.GetTagOrCreate(1, string.Empty); + Assert.NotNull(tag); + Assert.NotSame(1, tag.Id); + } + + [Fact] + public async Task RemoveTagsWithoutSeries_ShouldRemoveAbandonedEntries() + { + await SeedSeries(); + // Setup a tag with one series + var tag = await _service.GetTagOrCreate(0, "Tag with a series"); + await _unitOfWork.CommitAsync(); + + var metadatas = await _unitOfWork.SeriesRepository.GetSeriesMetadataForIdsAsync(new[] {1}); + tag.SeriesMetadatas.Add(metadatas.First()); + var tagId = tag.Id; + await _unitOfWork.CommitAsync(); + + // Validate it doesn't remove tags it shouldn't + await _service.RemoveTagsWithoutSeries(); + Assert.NotNull(await _unitOfWork.CollectionTagRepository.GetTagAsync(tagId)); + + await _service.RemoveTagFromSeries(tag, new[] {1}); + + // Validate it does remove tags it should + await _service.RemoveTagsWithoutSeries(); + Assert.Null(await _unitOfWork.CollectionTagRepository.GetTagAsync(tagId)); + } } diff --git a/API.Tests/Services/ReadingListServiceTests.cs b/API.Tests/Services/ReadingListServiceTests.cs index 23c54c5a0..2ba712aa7 100644 --- a/API.Tests/Services/ReadingListServiceTests.cs +++ b/API.Tests/Services/ReadingListServiceTests.cs @@ -432,7 +432,6 @@ public class ReadingListServiceTests #endregion - #region CalculateAgeRating [Fact] @@ -502,6 +501,29 @@ public class ReadingListServiceTests public async Task CalculateAgeRating_ShouldUpdateToMax() { await ResetDb(); + var s = new Series() + { + Name = "Test", + Metadata = DbFactory.SeriesMetadata(new List()), + Volumes = new List() + { + new Volume() + { + Name = "0", + Chapters = new List() + { + new Chapter() + { + Number = "1", + }, + new Chapter() + { + Number = "2", + } + } + } + } + }; _context.AppUser.Add(new AppUser() { UserName = "majora2007", @@ -514,34 +536,14 @@ public class ReadingListServiceTests Type = LibraryType.Book, Series = new List() { - new Series() - { - Name = "Test", - Metadata = DbFactory.SeriesMetadata(new List()), - Volumes = new List() - { - new Volume() - { - Name = "0", - Chapters = new List() - { - new Chapter() - { - Number = "1", - }, - new Chapter() - { - Number = "2", - } - } - } - } - } + s } }, } }); + s.Metadata.AgeRating = AgeRating.G; + await _context.SaveChangesAsync(); var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync("majora2007", AppUserIncludes.ReadingLists); @@ -558,7 +560,66 @@ public class ReadingListServiceTests await _unitOfWork.CommitAsync(); await _readingListService.CalculateReadingListAgeRating(readingList); - Assert.Equal(AgeRating.Unknown, readingList.AgeRating); + Assert.Equal(AgeRating.G, readingList.AgeRating); + } + + #endregion + + #region FormatTitle + + [Fact] + public void FormatTitle_ShouldFormatCorrectly() + { + // Manga Library & Archive + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Manga, "1"))); + Assert.Equal("Chapter 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Manga, "1", "1"))); + Assert.Equal("Chapter 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Manga, "1", "1", "The Title"))); + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Manga, "1", chapterTitleName: "The Title"))); + Assert.Equal("The Title", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Manga, chapterTitleName: "The Title"))); + + // Comic Library & Archive + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Comic, "1"))); + Assert.Equal("Issue #1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Comic, "1", "1"))); + Assert.Equal("Issue #1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Comic, "1", "1", "The Title"))); + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Comic, "1", chapterTitleName: "The Title"))); + Assert.Equal("The Title", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Comic, chapterTitleName: "The Title"))); + + // Book Library & Archive + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Book, "1"))); + Assert.Equal("Book 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Book, "1", "1"))); + Assert.Equal("Book 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Book, "1", "1", "The Title"))); + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Book, "1", chapterTitleName: "The Title"))); + Assert.Equal("The Title", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Archive, LibraryType.Book, chapterTitleName: "The Title"))); + + // Manga Library & EPUB + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Manga, "1"))); + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Manga, "1", "1"))); + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Manga, "1", "1", "The Title"))); + Assert.Equal("The Title", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Manga, "1", chapterTitleName: "The Title"))); + Assert.Equal("The Title", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Manga, chapterTitleName: "The Title"))); + + // Book Library & EPUB + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Book, "1"))); + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Book, "1", "1"))); + Assert.Equal("Volume 1", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Book, "1", "1", "The Title"))); + Assert.Equal("The Title", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Book, "1", chapterTitleName: "The Title"))); + Assert.Equal("The Title", ReadingListService.FormatTitle(CreateListItemDto(MangaFormat.Epub, LibraryType.Book, chapterTitleName: "The Title"))); + + } + + private static ReadingListItemDto CreateListItemDto(MangaFormat seriesFormat, LibraryType libraryType, + string volumeNumber = API.Services.Tasks.Scanner.Parser.Parser.DefaultVolume, + string chapterNumber = API.Services.Tasks.Scanner.Parser.Parser.DefaultChapter, + string chapterTitleName = "") + { + return new ReadingListItemDto() + { + SeriesFormat = seriesFormat, + LibraryType = libraryType, + VolumeNumber = volumeNumber, + ChapterNumber = chapterNumber, + ChapterTitleName = chapterTitleName + }; } #endregion diff --git a/API/Data/DbFactory.cs b/API/Data/DbFactory.cs index 08fcc2e9a..33b6678fd 100644 --- a/API/Data/DbFactory.cs +++ b/API/Data/DbFactory.cs @@ -27,7 +27,7 @@ public static class DbFactory NormalizedLocalizedName = Services.Tasks.Scanner.Parser.Parser.Normalize(name), SortName = name, Volumes = new List(), - Metadata = SeriesMetadata(Array.Empty()) + Metadata = SeriesMetadata(new List()) }; } @@ -46,7 +46,7 @@ public static class DbFactory NormalizedLocalizedName = Services.Tasks.Scanner.Parser.Parser.Normalize(localizedName), SortName = name, Volumes = new List(), - Metadata = SeriesMetadata(Array.Empty()) + Metadata = SeriesMetadata(new List()) }; } @@ -76,11 +76,6 @@ public static class DbFactory }; } - public static SeriesMetadata SeriesMetadata(ComicInfo info) - { - return SeriesMetadata(Array.Empty()); - } - public static SeriesMetadata SeriesMetadata(ICollection collectionTags) { return new SeriesMetadata() @@ -98,7 +93,8 @@ public static class DbFactory NormalizedTitle = Services.Tasks.Scanner.Parser.Parser.Normalize(title?.Trim()), Title = title?.Trim(), Summary = summary?.Trim(), - Promoted = promoted + Promoted = promoted, + SeriesMetadatas = new List() }; } diff --git a/API/Data/Repositories/CollectionTagRepository.cs b/API/Data/Repositories/CollectionTagRepository.cs index 1c86d4826..5038a5892 100644 --- a/API/Data/Repositories/CollectionTagRepository.cs +++ b/API/Data/Repositories/CollectionTagRepository.cs @@ -31,7 +31,7 @@ public interface ICollectionTagRepository Task GetFullTagAsync(int tagId, CollectionTagIncludes includes = CollectionTagIncludes.SeriesMetadata); void Update(CollectionTag tag); Task RemoveTagsWithoutSeries(); - Task> GetAllTagsAsync(); + Task> GetAllTagsAsync(CollectionTagIncludes includes = CollectionTagIncludes.None); Task> GetAllCoverImagesAsync(); Task TagExists(string title); } @@ -66,7 +66,6 @@ public class CollectionTagRepository : ICollectionTagRepository /// public async Task RemoveTagsWithoutSeries() { - // TODO: Write a Unit test to validate this works var tagsToDelete = await _context.CollectionTag .Include(c => c.SeriesMetadatas) .Where(c => c.SeriesMetadatas.Count == 0) @@ -77,10 +76,11 @@ public class CollectionTagRepository : ICollectionTagRepository return await _context.SaveChangesAsync(); } - public async Task> GetAllTagsAsync() + public async Task> GetAllTagsAsync(CollectionTagIncludes includes = CollectionTagIncludes.None) { return await _context.CollectionTag .OrderBy(c => c.NormalizedTitle) + .Includes(includes) .ToListAsync(); } diff --git a/API/Data/Repositories/ReadingListRepository.cs b/API/Data/Repositories/ReadingListRepository.cs index d0d5d4872..bae5d9591 100644 --- a/API/Data/Repositories/ReadingListRepository.cs +++ b/API/Data/Repositories/ReadingListRepository.cs @@ -5,6 +5,7 @@ using API.DTOs.ReadingLists; using API.Entities; using API.Entities.Enums; using API.Helpers; +using API.Services; using AutoMapper; using AutoMapper.QueryableExtensions; using Microsoft.EntityFrameworkCore; @@ -145,7 +146,7 @@ public class ReadingListRepository : IReadingListRepository { TotalPages = chapter.Pages, ChapterNumber = chapter.Range, - ReleaseDate = chapter.ReleaseDate, + chapter.ReleaseDate, ReadingListItem = data, ChapterTitleName = chapter.TitleName, @@ -201,7 +202,7 @@ public class ReadingListRepository : IReadingListRepository foreach (var item in items) { - item.Title = ReadingListHelper.FormatTitle(item); + item.Title = ReadingListService.FormatTitle(item); } // Attach progress information diff --git a/API/Data/Repositories/SeriesRepository.cs b/API/Data/Repositories/SeriesRepository.cs index e99449330..13995b409 100644 --- a/API/Data/Repositories/SeriesRepository.cs +++ b/API/Data/Repositories/SeriesRepository.cs @@ -199,6 +199,9 @@ public class SeriesRepository : ISeriesRepository var query = _context.Series .Where(s => s.LibraryId == libraryId) + .Include(s => s.Metadata) + .ThenInclude(m => m.CollectionTags) + .Include(s => s.Metadata) .ThenInclude(m => m.People) diff --git a/API/Helpers/ReadingListHelper.cs b/API/Helpers/ReadingListHelper.cs deleted file mode 100644 index e5a3a6524..000000000 --- a/API/Helpers/ReadingListHelper.cs +++ /dev/null @@ -1,49 +0,0 @@ -using System; -using System.Text.RegularExpressions; -using API.DTOs.ReadingLists; -using API.Entities; -using API.Entities.Enums; -using API.Services; - -namespace API.Helpers; - -public static class ReadingListHelper -{ - private static readonly Regex JustNumbers = new Regex(@"^\d+$", RegexOptions.Compiled | RegexOptions.IgnoreCase, - Services.Tasks.Scanner.Parser.Parser.RegexTimeout); - public static string FormatTitle(ReadingListItemDto item) - { - var title = string.Empty; - if (item.ChapterNumber == Services.Tasks.Scanner.Parser.Parser.DefaultChapter) { - title = $"Volume {item.VolumeNumber}"; - } - - if (item.SeriesFormat == MangaFormat.Epub) { - var specialTitle = Services.Tasks.Scanner.Parser.Parser.CleanSpecialTitle(item.ChapterNumber); - if (specialTitle == Services.Tasks.Scanner.Parser.Parser.DefaultChapter) - { - if (!string.IsNullOrEmpty(item.ChapterTitleName)) - { - title = item.ChapterTitleName; - } - else - { - title = $"Volume {Services.Tasks.Scanner.Parser.Parser.CleanSpecialTitle(item.VolumeNumber)}"; - } - } else { - title = $"Volume {specialTitle}"; - } - } - - var chapterNum = item.ChapterNumber; - if (!string.IsNullOrEmpty(chapterNum) && !JustNumbers.Match(item.ChapterNumber).Success) { - chapterNum = Services.Tasks.Scanner.Parser.Parser.CleanSpecialTitle(item.ChapterNumber); - } - - if (title == string.Empty) { - title = ReaderService.FormatChapterName(item.LibraryType, true, true) + chapterNum; - } - return title; - } - -} diff --git a/API/Services/CollectionTagService.cs b/API/Services/CollectionTagService.cs index 986e2e4a8..10cc31a7c 100644 --- a/API/Services/CollectionTagService.cs +++ b/API/Services/CollectionTagService.cs @@ -21,6 +21,8 @@ public interface ICollectionTagService Task RemoveTagFromSeries(CollectionTag tag, IEnumerable seriesIds); Task GetTagOrCreate(int tagId, string title); void AddTagToSeriesMetadata(CollectionTag tag, SeriesMetadata metadata); + CollectionTag CreateTag(string title); + Task RemoveTagsWithoutSeries(); } @@ -113,10 +115,13 @@ public class CollectionTagService : ICollectionTagService public void AddTagToSeriesMetadata(CollectionTag tag, SeriesMetadata metadata) { metadata.CollectionTags ??= new List(); - if (metadata.CollectionTags.Any(t => t.Title.Equals(tag.Title, StringComparison.InvariantCulture))) return; + if (metadata.CollectionTags.Any(t => t.NormalizedTitle.Equals(tag.NormalizedTitle, StringComparison.InvariantCulture))) return; metadata.CollectionTags.Add(tag); - _unitOfWork.SeriesMetadataRepository.Update(metadata); + if (metadata.Id != 0) + { + _unitOfWork.SeriesMetadataRepository.Update(metadata); + } } public async Task RemoveTagFromSeries(CollectionTag tag, IEnumerable seriesIds) @@ -148,10 +153,26 @@ public class CollectionTagService : ICollectionTagService var tag = await _unitOfWork.CollectionTagRepository.GetFullTagAsync(tagId); if (tag == null) { - tag = DbFactory.CollectionTag(0, title, string.Empty, false); - _unitOfWork.CollectionTagRepository.Add(tag); + tag = CreateTag(title); } return tag; } + + /// + /// This just creates the entity and adds to tracking. Use for checks of duplication. + /// + /// + /// + public CollectionTag CreateTag(string title) + { + var tag = DbFactory.CollectionTag(0, title, string.Empty, false); + _unitOfWork.CollectionTagRepository.Add(tag); + return tag; + } + + public async Task RemoveTagsWithoutSeries() + { + return await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries() > 0; + } } diff --git a/API/Services/ReadingListService.cs b/API/Services/ReadingListService.cs index 821bb1a69..ee996ddec 100644 --- a/API/Services/ReadingListService.cs +++ b/API/Services/ReadingListService.cs @@ -1,11 +1,13 @@ using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using System.Threading.Tasks; using API.Comparators; using API.Data; using API.Data.Repositories; using API.DTOs.ReadingLists; using API.Entities; +using API.Entities.Enums; using Microsoft.Extensions.Logging; namespace API.Services; @@ -31,6 +33,8 @@ public class ReadingListService : IReadingListService private readonly IUnitOfWork _unitOfWork; private readonly ILogger _logger; private readonly ChapterSortComparerZeroFirst _chapterSortComparerForInChapterSorting = new ChapterSortComparerZeroFirst(); + private static readonly Regex JustNumbers = new Regex(@"^\d+$", RegexOptions.Compiled | RegexOptions.IgnoreCase, + Tasks.Scanner.Parser.Parser.RegexTimeout); public ReadingListService(IUnitOfWork unitOfWork, ILogger logger) { @@ -38,6 +42,48 @@ public class ReadingListService : IReadingListService _logger = logger; } + public static string FormatTitle(ReadingListItemDto item) + { + var title = string.Empty; + if (item.ChapterNumber == Tasks.Scanner.Parser.Parser.DefaultChapter && item.VolumeNumber != Tasks.Scanner.Parser.Parser.DefaultVolume) { + title = $"Volume {item.VolumeNumber}"; + } + + if (item.SeriesFormat == MangaFormat.Epub) { + var specialTitle = Tasks.Scanner.Parser.Parser.CleanSpecialTitle(item.ChapterNumber); + if (specialTitle == Tasks.Scanner.Parser.Parser.DefaultChapter) + { + if (!string.IsNullOrEmpty(item.ChapterTitleName)) + { + title = item.ChapterTitleName; + } + else + { + title = $"Volume {Tasks.Scanner.Parser.Parser.CleanSpecialTitle(item.VolumeNumber)}"; + } + } else { + title = $"Volume {specialTitle}"; + } + } + + var chapterNum = item.ChapterNumber; + if (!string.IsNullOrEmpty(chapterNum) && !JustNumbers.Match(item.ChapterNumber).Success) { + chapterNum = Tasks.Scanner.Parser.Parser.CleanSpecialTitle(item.ChapterNumber); + } + + if (title != string.Empty) return title; + + if (item.ChapterNumber == Tasks.Scanner.Parser.Parser.DefaultChapter && + !string.IsNullOrEmpty(item.ChapterTitleName)) + { + title = item.ChapterTitleName; + } + else + { + title = ReaderService.FormatChapterName(item.LibraryType, true, true) + chapterNum; + } + return title; + } /// diff --git a/API/Services/Tasks/Scanner/ProcessSeries.cs b/API/Services/Tasks/Scanner/ProcessSeries.cs index 5c1b97604..cfc1ed224 100644 --- a/API/Services/Tasks/Scanner/ProcessSeries.cs +++ b/API/Services/Tasks/Scanner/ProcessSeries.cs @@ -7,6 +7,7 @@ using System.Threading; using System.Threading.Tasks; using API.Data; using API.Data.Metadata; +using API.Data.Repositories; using API.Entities; using API.Entities.Enums; using API.Extensions; @@ -50,6 +51,7 @@ public class ProcessSeries : IProcessSeries private IList _genres; private IList _people; private IList _tags; + private Dictionary _collectionTags; public ProcessSeries(IUnitOfWork unitOfWork, ILogger logger, IEventHub eventHub, IDirectoryService directoryService, ICacheHelper cacheHelper, IReadingItemService readingItemService, @@ -76,6 +78,9 @@ public class ProcessSeries : IProcessSeries _genres = await _unitOfWork.GenreRepository.GetAllGenresAsync(); _people = await _unitOfWork.PersonRepository.GetAllPeople(); _tags = await _unitOfWork.TagRepository.GetAllTagsAsync(); + _collectionTags = (await _unitOfWork.CollectionTagRepository.GetAllTagsAsync(CollectionTagIncludes.SeriesMetadata)) + .ToDictionary(t => t.NormalizedTitle); + } public async Task ProcessSeriesAsync(IList parsedInfos, Library library, bool forceUpdate = false) @@ -154,7 +159,7 @@ public class ProcessSeries : IProcessSeries series.NormalizedLocalizedName = Parser.Parser.Normalize(series.LocalizedName); } - await UpdateSeriesMetadata(series, library); + UpdateSeriesMetadata(series, library); // Update series FolderPath here await UpdateSeriesFolderPath(parsedInfos, library, series); @@ -226,7 +231,7 @@ public class ProcessSeries : IProcessSeries BackgroundJob.Enqueue(() => _wordCountAnalyzerService.ScanSeries(libraryId, seriesId, forceUpdate)); } - private async Task UpdateSeriesMetadata(Series series, Library library) + private void UpdateSeriesMetadata(Series series, Library library) { series.Metadata ??= DbFactory.SeriesMetadata(new List()); var isBook = library.Type == LibraryType.Book; @@ -283,10 +288,19 @@ public class ProcessSeries : IProcessSeries if (!string.IsNullOrEmpty(firstChapter.SeriesGroup) && library.ManageCollections) { - _logger.LogDebug("Collection tag found for {SeriesName}", series.Name); + _logger.LogDebug("Collection tag(s) found for {SeriesName}, updating collections", series.Name); - var tag = await _collectionTagService.GetTagOrCreate(0, firstChapter.SeriesGroup); - _collectionTagService.AddTagToSeriesMetadata(tag, series.Metadata); + foreach (var collection in firstChapter.SeriesGroup.Split(',')) + { + var normalizedName = Parser.Parser.Normalize(collection); + if (!_collectionTags.TryGetValue(normalizedName, out var tag)) + { + tag = _collectionTagService.CreateTag(collection); + _collectionTags.Add(normalizedName, tag); + } + + _collectionTagService.AddTagToSeriesMetadata(tag, series.Metadata); + } } // Handle People @@ -519,6 +533,7 @@ public class ProcessSeries : IProcessSeries series.Volumes = nonDeletedVolumes; } + // DO I need this anymore? _logger.LogDebug("[ScannerService] Updated {SeriesName} volumes from count of {StartingVolumeCount} to {VolumeCount}", series.Name, startingVolumeCount, series.Volumes.Count); } diff --git a/openapi.json b/openapi.json index c3289d528..4a306bfab 100644 --- a/openapi.json +++ b/openapi.json @@ -7,7 +7,7 @@ "name": "GPL-3.0", "url": "https://github.com/Kareadita/Kavita/blob/develop/LICENSE" }, - "version": "0.6.1.32" + "version": "0.6.1.33" }, "servers": [ {