From f54b75c988976a5a2f569d381468c8b808693eb5 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 24 Aug 2022 15:58:54 -0500 Subject: [PATCH 1/6] Added a ToList() to avoid a bug where a person could be removed from a list while iterating over the list. --- API/Helpers/PersonHelper.cs | 3 ++- API/Services/Tasks/Scanner/ProcessSeries.cs | 2 +- API/Services/Tasks/ScannerService.cs | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/API/Helpers/PersonHelper.cs b/API/Helpers/PersonHelper.cs index 5aa3624e18..fd6ca7baab 100644 --- a/API/Helpers/PersonHelper.cs +++ b/API/Helpers/PersonHelper.cs @@ -82,7 +82,8 @@ public static void KeepOnlySamePeopleBetweenLists(IEnumerable existingPe { foreach (var person in existingPeople) { - var existingPerson = removeAllExcept.FirstOrDefault(p => p.Role == person.Role && person.NormalizedName.Equals(p.NormalizedName)); + var existingPerson = removeAllExcept + .FirstOrDefault(p => p.Role == person.Role && person.NormalizedName.Equals(p.NormalizedName)); if (existingPerson == null) { action?.Invoke(person); diff --git a/API/Services/Tasks/Scanner/ProcessSeries.cs b/API/Services/Tasks/Scanner/ProcessSeries.cs index 30a166e442..5b307ec551 100644 --- a/API/Services/Tasks/Scanner/ProcessSeries.cs +++ b/API/Services/Tasks/Scanner/ProcessSeries.cs @@ -375,7 +375,7 @@ private static void UpdateSeriesMetadata(Series series, LibraryType libraryType) // NOTE: The issue here is that people is just from chapter, but series metadata might already have some people on it // I might be able to filter out people that are in locked fields? var people = chapters.SelectMany(c => c.People).ToList(); - PersonHelper.KeepOnlySamePeopleBetweenLists(series.Metadata.People, + PersonHelper.KeepOnlySamePeopleBetweenLists(series.Metadata.People.ToList(), people, person => { switch (person.Role) diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index febc3c4ce0..db589107b7 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -436,7 +436,7 @@ await _eventHub.SendMessageAsync(MessageFactory.Info, var shouldUseLibraryScan = !(await _unitOfWork.LibraryRepository.DoAnySeriesFoldersMatch(libraryFolderPaths)); if (!shouldUseLibraryScan) { - _logger.LogInformation("Library {LibraryName} consists of one ore more Series folders, using series scan", library.Name); + _logger.LogError("Library {LibraryName} consists of one or more Series folders, using series scan", library.Name); } @@ -485,7 +485,6 @@ void TrackFiles(Tuple> parsedInfo) await Task.WhenAll(processTasks); - //await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended, string.Empty)); await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.FileScanProgressEvent(string.Empty, library.Name, ProgressEventType.Ended)); _logger.LogInformation("[ScannerService] Finished file scan in {ScanAndUpdateTime}. Updating database", scanElapsedTime); From b0102761d9558ad279d5fc6f150927aae5a049c6 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 24 Aug 2022 16:16:43 -0500 Subject: [PATCH 2/6] When deleting a series, want to read page will now automatically remove that series from the view. --- .../want-to-read/want-to-read.component.html | 3 +- .../want-to-read/want-to-read.component.ts | 35 +++++++++++++++---- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.html b/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.html index f6ada219fb..f29596aab0 100644 --- a/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.html +++ b/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.html @@ -20,9 +20,10 @@
{{seriesPagination.totalItems}} Series
[filterOpen]="filterOpen" [jumpBarKeys]="jumpbarKeys" [trackByIdentity]="trackByIdentity" + [refresh]="refresh" (applyFilter)="updateFilter($event)"> - diff --git a/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.ts b/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.ts index a6f70316d2..b873c97e4c 100644 --- a/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.ts +++ b/UI/Web/src/app/want-to-read/want-to-read/want-to-read.component.ts @@ -7,6 +7,7 @@ import { BulkSelectionService } from 'src/app/cards/bulk-selection.service'; import { FilterSettings } from 'src/app/metadata-filter/filter-settings'; import { FilterUtilitiesService } from 'src/app/shared/_services/filter-utilities.service'; import { UtilityService, KEY_CODES } from 'src/app/shared/_services/utility.service'; +import { SeriesRemovedEvent } from 'src/app/_models/events/series-removed-event'; import { JumpKey } from 'src/app/_models/jumpbar/jump-key'; import { Pagination } from 'src/app/_models/pagination'; import { Series } from 'src/app/_models/series'; @@ -35,6 +36,7 @@ export class WantToReadComponent implements OnInit, OnDestroy { seriesPagination!: Pagination; filter: SeriesFilter | undefined = undefined; filterSettings: FilterSettings = new FilterSettings(); + refresh: EventEmitter = new EventEmitter(); filterActiveCheck!: SeriesFilter; filterActive: boolean = false; @@ -43,7 +45,7 @@ export class WantToReadComponent implements OnInit, OnDestroy { filterOpen: EventEmitter = new EventEmitter(); - private onDestory: Subject = new Subject(); + private onDestroy: Subject = new Subject(); trackByIdentity = (index: number, item: Series) => `${item.name}_${item.localizedName}_${item.pagesRead}`; bulkActionCallback = (action: Action, data: any) => { @@ -77,7 +79,7 @@ export class WantToReadComponent implements OnInit, OnDestroy { private seriesService: SeriesService, private titleService: Title, public bulkSelectionService: BulkSelectionService, private actionService: ActionService, private messageHub: MessageHubService, private filterUtilityService: FilterUtilitiesService, private utilityService: UtilityService, @Inject(DOCUMENT) private document: Document, - private readonly cdRef: ChangeDetectorRef, private scrollService: ScrollService) { + private readonly cdRef: ChangeDetectorRef, private scrollService: ScrollService, private hubService: MessageHubService) { this.router.routeReuseStrategy.shouldReuseRoute = () => false; this.titleService.setTitle('Want To Read'); @@ -85,12 +87,26 @@ export class WantToReadComponent implements OnInit, OnDestroy { [this.filterSettings.presets, this.filterSettings.openByDefault] = this.filterUtilityService.filterPresetsFromUrl(this.route.snapshot); this.filterActiveCheck = this.seriesService.createSeriesFilter(); this.cdRef.markForCheck(); + + this.hubService.messages$.pipe(takeUntil(this.onDestroy)).subscribe((event) => { + if (event.event === EVENTS.SeriesRemoved) { + const seriesRemoved = event.payload as SeriesRemovedEvent; + if (!this.utilityService.deepEqual(this.filter, this.filterActiveCheck)) { + this.loadPage(); + return; + } + + this.series = this.series.filter(s => s.id != seriesRemoved.seriesId); + this.seriesPagination.totalItems--; + this.cdRef.markForCheck(); + this.refresh.emit(); + } + }); } ngOnInit(): void { - - this.messageHub.messages$.pipe(takeUntil(this.onDestory), debounceTime(2000)).subscribe(event => { + this.messageHub.messages$.pipe(takeUntil(this.onDestroy), debounceTime(2000)).subscribe(event => { if (event.event === EVENTS.SeriesRemoved) { this.loadPage(); } @@ -102,8 +118,8 @@ export class WantToReadComponent implements OnInit, OnDestroy { } ngOnDestroy() { - this.onDestory.next(); - this.onDestory.complete(); + this.onDestroy.next(); + this.onDestroy.complete(); } @HostListener('document:keydown.shift', ['$event']) @@ -120,6 +136,13 @@ export class WantToReadComponent implements OnInit, OnDestroy { } } + removeSeries(seriesId: number) { + this.series = this.series.filter(s => s.id != seriesId); + this.seriesPagination.totalItems--; + this.cdRef.markForCheck(); + this.refresh.emit(); + } + loadPage() { this.filterActive = !this.utilityService.deepEqual(this.filter, this.filterActiveCheck); this.isLoading = true; From 6bb115290ea942c5acadf97e24d9da76aaf424b6 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 24 Aug 2022 16:31:13 -0500 Subject: [PATCH 3/6] Fixed a series lookup which was ignoring format --- API/Data/Repositories/SeriesRepository.cs | 5 +++-- API/Services/Tasks/Scanner/ProcessSeries.cs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/API/Data/Repositories/SeriesRepository.cs b/API/Data/Repositories/SeriesRepository.cs index 3324d8713f..149148cb1c 100644 --- a/API/Data/Repositories/SeriesRepository.cs +++ b/API/Data/Repositories/SeriesRepository.cs @@ -121,7 +121,7 @@ public interface ISeriesRepository Task GetSeriesIdByFolder(string folder); Task GetSeriesByFolderPath(string folder); Task GetFullSeriesByName(string series, int libraryId); - Task GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId); + Task GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId, MangaFormat format); Task RemoveSeriesNotInList(IList seenSeries, int libraryId); Task>> GetFolderPathMap(int libraryId); } @@ -1218,12 +1218,13 @@ public Task GetFullSeriesByName(string series, int libraryId) /// /// /// - public Task GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId) + public Task GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId, MangaFormat format) { var normalizedSeries = Parser.Parser.Normalize(seriesName); var normalizedLocalized = Parser.Parser.Normalize(localizedName); var query = _context.Series .Where(s => s.LibraryId == libraryId) + .Where(s => s.Format == format && format != MangaFormat.Unknown) .Where(s => s.NormalizedName.Equals(normalizedSeries) || (s.NormalizedLocalizedName.Equals(normalizedSeries) && s.NormalizedLocalizedName != string.Empty)); if (!string.IsNullOrEmpty(normalizedLocalized)) diff --git a/API/Services/Tasks/Scanner/ProcessSeries.cs b/API/Services/Tasks/Scanner/ProcessSeries.cs index 5b307ec551..3a281cd728 100644 --- a/API/Services/Tasks/Scanner/ProcessSeries.cs +++ b/API/Services/Tasks/Scanner/ProcessSeries.cs @@ -93,7 +93,7 @@ await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, { series = await _unitOfWork.SeriesRepository.GetFullSeriesByAnyName(firstInfo.Series, firstInfo.LocalizedSeries, - library.Id); + library.Id, firstInfo.Format); } catch (Exception ex) { From 0dc7be62366d2761502556069e935992d2a34cea Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 24 Aug 2022 17:35:52 -0500 Subject: [PATCH 4/6] Ignore XML comment warnings --- API/API.csproj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/API/API.csproj b/API/API.csproj index 0af5832f3b..b5d91d566e 100644 --- a/API/API.csproj +++ b/API/API.csproj @@ -19,6 +19,12 @@ 1701;1702;1591 + + + True + $(NoWarn);1591 + + en From c8579cb71a00c17290adcf2baaef881f112d979d Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 24 Aug 2022 17:50:24 -0500 Subject: [PATCH 5/6] Removed a note since it was already working that way --- API/Services/Tasks/ScannerService.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index db589107b7..09b1884ac7 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -459,8 +459,6 @@ void TrackFiles(Tuple> parsedInfo) Format = parsedFiles.First().Format }; - // NOTE: Could we check if there are multiple found series (different series) and process each one? - if (skippedScan) { seenSeries.AddRange(parsedFiles.Select(pf => new ParsedSeries() From 1deec343d18feeecc5508a57d860eb6fd8fc92d6 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Wed, 24 Aug 2022 18:03:36 -0500 Subject: [PATCH 6/6] Fixed unit test --- API.Tests/Repository/SeriesRepositoryTests.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/API.Tests/Repository/SeriesRepositoryTests.cs b/API.Tests/Repository/SeriesRepositoryTests.cs index 16f365d886..65491d3335 100644 --- a/API.Tests/Repository/SeriesRepositoryTests.cs +++ b/API.Tests/Repository/SeriesRepositoryTests.cs @@ -125,9 +125,12 @@ private async Task SetupSeriesData() } }; + var s = DbFactory.Series("The Idaten Deities Know Only Peace", "Heion Sedai no Idaten-tachi"); + s.Format = MangaFormat.Archive; + library.Series = new List() { - DbFactory.Series("The Idaten Deities Know Only Peace", "Heion Sedai no Idaten-tachi"), + s, }; _unitOfWork.LibraryRepository.Add(library); @@ -135,13 +138,14 @@ private async Task SetupSeriesData() } - [InlineData("Heion Sedai no Idaten-tachi", "", "The Idaten Deities Know Only Peace")] // Matching on localized name in DB + [InlineData("Heion Sedai no Idaten-tachi", "", MangaFormat.Archive, "The Idaten Deities Know Only Peace")] // Matching on localized name in DB + [InlineData("Heion Sedai no Idaten-tachi", "", MangaFormat.Pdf, null)] public async Task GetFullSeriesByAnyName_Should(string seriesName, string localizedName, string? expected) { var firstSeries = await _unitOfWork.SeriesRepository.GetSeriesByIdAsync(1); var series = await _unitOfWork.SeriesRepository.GetFullSeriesByAnyName(seriesName, localizedName, - 1); + 1, MangaFormat.Unknown); if (expected == null) { Assert.Null(series);