From f2249ea39be0edf18943115ac7447e1dcec7dab4 Mon Sep 17 00:00:00 2001 From: Joseph Milazzo Date: Thu, 1 Sep 2022 13:45:34 -0500 Subject: [PATCH] Release Testing Day 3 (#1496) * Tweaked log messaging for library scan when no files were scanned. * When a theme that is set gets removed due to a scan, inform the user to refresh. * Fixed a typo and make Darkness -> Brightness * Make download theme files allowed to be invoked by non-authenticated users, to allow new users to get the default theme. * Hide all series side nav item if there are no libraries exposed to the user * Fixed an API for Tachiyomi when syncing progress * Fixed dashboard not responding to Series Removed and Added events. Ensure we send SeriesRemoved events when they are deleted. * Reverted Hangfire SQLite due to aborted jobs being resumed, when they shouldnt. Fixed some scan loop issues where cover gen wouldn't be invoked always on new libraries. --- API/Controllers/TachiyomiController.cs | 2 +- API/Controllers/ThemeController.cs | 1 + API/Data/Repositories/SeriesRepository.cs | 10 +++++--- API/Services/MetadataService.cs | 2 +- API/Services/Tasks/Scanner/ProcessSeries.cs | 19 ++++++++------ API/Services/Tasks/ScannerService.cs | 25 +++++++++++++++---- API/Startup.cs | 2 +- UI/Web/src/app/_services/theme.service.ts | 15 ++++++++--- .../src/app/dashboard/dashboard.component.ts | 2 +- .../manga-reader/manga-reader.component.html | 2 +- .../sidenav/side-nav/side-nav.component.html | 2 +- .../theme-manager.component.html | 2 +- .../theme-manager/theme-manager.component.ts | 2 +- 13 files changed, 58 insertions(+), 28 deletions(-) diff --git a/API/Controllers/TachiyomiController.cs b/API/Controllers/TachiyomiController.cs index 58f1953d3..f1f6a1f03 100644 --- a/API/Controllers/TachiyomiController.cs +++ b/API/Controllers/TachiyomiController.cs @@ -50,7 +50,7 @@ public class TachiyomiController : BaseApiController if (prevChapterId == -1) { var series = await _unitOfWork.SeriesRepository.GetSeriesDtoByIdAsync(seriesId, userId); - var userHasProgress = series.PagesRead == 0 || series.PagesRead < series.Pages; + var userHasProgress = series.PagesRead != 0 && series.PagesRead < series.Pages; // If the user doesn't have progress, then return null, which the extension will catch as 204 (no content) and report nothing as read if (!userHasProgress) return null; diff --git a/API/Controllers/ThemeController.cs b/API/Controllers/ThemeController.cs index 69793df46..6defbe574 100644 --- a/API/Controllers/ThemeController.cs +++ b/API/Controllers/ThemeController.cs @@ -51,6 +51,7 @@ public class ThemeController : BaseApiController /// Returns css content to the UI. UI is expected to escape the content /// /// + [AllowAnonymous] [HttpGet("download-content")] public async Task> GetThemeContent(int themeId) { diff --git a/API/Data/Repositories/SeriesRepository.cs b/API/Data/Repositories/SeriesRepository.cs index 9d5eec954..43b748a2a 100644 --- a/API/Data/Repositories/SeriesRepository.cs +++ b/API/Data/Repositories/SeriesRepository.cs @@ -122,7 +122,7 @@ public interface ISeriesRepository Task GetSeriesByFolderPath(string folder); Task GetFullSeriesByName(string series, int libraryId); Task GetFullSeriesByAnyName(string seriesName, string localizedName, int libraryId, MangaFormat format, bool withFullIncludes = true); - Task RemoveSeriesNotInList(IList seenSeries, int libraryId); + Task> RemoveSeriesNotInList(IList seenSeries, int libraryId); Task>> GetFolderPathMap(int libraryId); } @@ -230,6 +230,7 @@ public class SeriesRepository : ISeriesRepository { return await _context.Series .Where(s => s.Id == seriesId) + .Include(s => s.Relations) .Include(s => s.Metadata) .ThenInclude(m => m.People) .Include(s => s.Metadata) @@ -1274,9 +1275,9 @@ public class SeriesRepository : ISeriesRepository /// /// /// - public async Task RemoveSeriesNotInList(IList seenSeries, int libraryId) + public async Task> RemoveSeriesNotInList(IList seenSeries, int libraryId) { - if (seenSeries.Count == 0) return; + if (seenSeries.Count == 0) return new List(); var ids = new List(); foreach (var parsedSeries in seenSeries) { @@ -1289,7 +1290,6 @@ public class SeriesRepository : ISeriesRepository { ids.Add(series); } - } var seriesToRemove = await _context.Series @@ -1298,6 +1298,8 @@ public class SeriesRepository : ISeriesRepository .ToListAsync(); _context.Series.RemoveRange(seriesToRemove); + + return seriesToRemove; } public async Task> GetHighlyRated(int userId, int libraryId, UserParams userParams) diff --git a/API/Services/MetadataService.cs b/API/Services/MetadataService.cs index 2862af38f..0dd980a59 100644 --- a/API/Services/MetadataService.cs +++ b/API/Services/MetadataService.cs @@ -36,8 +36,8 @@ public interface IMetadataService /// /// /// Overrides any cache logic and forces execution - Task GenerateCoversForSeries(int libraryId, int seriesId, bool forceUpdate = true); + Task GenerateCoversForSeries(int libraryId, int seriesId, bool forceUpdate = true); Task GenerateCoversForSeries(Series series, bool forceUpdate = false); Task RemoveAbandonedMetadataKeys(); } diff --git a/API/Services/Tasks/Scanner/ProcessSeries.cs b/API/Services/Tasks/Scanner/ProcessSeries.cs index fb7da1ec4..e8db2a97a 100644 --- a/API/Services/Tasks/Scanner/ProcessSeries.cs +++ b/API/Services/Tasks/Scanner/ProcessSeries.cs @@ -171,7 +171,16 @@ public class ProcessSeries : IProcessSeries await _eventHub.SendMessageAsync(MessageFactory.Error, MessageFactory.ErrorEvent($"There was an issue writing to the DB for Series {series}", ex.Message)); + return; } + + if (seriesAdded) + { + await _eventHub.SendMessageAsync(MessageFactory.SeriesAdded, + MessageFactory.SeriesAddedEvent(series.Id, series.Name, series.LibraryId), false); + } + + _logger.LogInformation("[ScannerService] Finished series update on {SeriesName} in {Milliseconds} ms", seriesName, scanWatch.ElapsedMilliseconds); } } catch (Exception ex) @@ -179,13 +188,7 @@ public class ProcessSeries : IProcessSeries _logger.LogError(ex, "[ScannerService] There was an exception updating series for {SeriesName}", series.Name); } - if (seriesAdded) - { - await _eventHub.SendMessageAsync(MessageFactory.SeriesAdded, - MessageFactory.SeriesAddedEvent(series.Id, series.Name, series.LibraryId)); - } - - _logger.LogInformation("[ScannerService] Finished series update on {SeriesName} in {Milliseconds} ms", seriesName, scanWatch.ElapsedMilliseconds); + await _metadataService.GenerateCoversForSeries(series, false); EnqueuePostSeriesProcessTasks(series.LibraryId, series.Id); } @@ -213,7 +216,7 @@ public class ProcessSeries : IProcessSeries public void EnqueuePostSeriesProcessTasks(int libraryId, int seriesId, bool forceUpdate = false) { - BackgroundJob.Enqueue(() => _metadataService.GenerateCoversForSeries(libraryId, seriesId, forceUpdate)); + //BackgroundJob.Enqueue(() => _metadataService.GenerateCoversForSeries(libraryId, seriesId, forceUpdate)); BackgroundJob.Enqueue(() => _wordCountAnalyzerService.ScanSeries(libraryId, seriesId, forceUpdate)); } diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index 710647764..662016415 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -205,7 +205,7 @@ public class ScannerService : IScannerService var scanElapsedTime = await ScanFiles(library, new []{folderPath}, false, TrackFiles, true); _logger.LogInformation("ScanFiles for {Series} took {Time}", series.Name, scanElapsedTime); - await Task.WhenAll(processTasks); + //await Task.WhenAll(processTasks); await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress, MessageFactory.LibraryScanProgressEvent(library.Name, ProgressEventType.Ended, series.Name)); @@ -475,14 +475,29 @@ public class ScannerService : IScannerService // Could I delete anything in a Library's Series where the LastScan date is before scanStart? // NOTE: This implementation is expensive - await _unitOfWork.SeriesRepository.RemoveSeriesNotInList(seenSeries, library.Id); + var removedSeries = await _unitOfWork.SeriesRepository.RemoveSeriesNotInList(seenSeries, library.Id); _unitOfWork.LibraryRepository.Update(library); if (await _unitOfWork.CommitAsync()) { - _logger.LogInformation( - "[ScannerService] Finished scan of {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}", - totalFiles, seenSeries.Count, sw.ElapsedMilliseconds, library.Name); + if (totalFiles == 0) + { + _logger.LogInformation( + "[ScannerService] Finished library scan of {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}. There were no changes", + totalFiles, seenSeries.Count, sw.ElapsedMilliseconds, library.Name); + } + else + { + _logger.LogInformation( + "[ScannerService] Finished library scan of {TotalFiles} files and {ParsedSeriesCount} series in {ElapsedScanTime} milliseconds for {LibraryName}", + totalFiles, seenSeries.Count, sw.ElapsedMilliseconds, library.Name); + } + + foreach (var s in removedSeries) + { + await _eventHub.SendMessageAsync(MessageFactory.SeriesRemoved, + MessageFactory.SeriesRemovedEvent(s.Id, s.Name, s.LibraryId), false); + } } else { diff --git a/API/Startup.cs b/API/Startup.cs index 14af6f0b6..6297453a0 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -156,7 +156,7 @@ namespace API services.AddHangfire(configuration => configuration .UseSimpleAssemblyNameTypeSerializer() .UseRecommendedSerializerSettings() - .UseSQLiteStorage()); + .UseMemoryStorage()); // UseSQLiteStorage - SQLite has some issues around resuming jobs when aborted // Add the processing server as IHostedService services.AddHangfireServer(options => diff --git a/UI/Web/src/app/_services/theme.service.ts b/UI/Web/src/app/_services/theme.service.ts index 23dc8e90c..18e3764b9 100644 --- a/UI/Web/src/app/_services/theme.service.ts +++ b/UI/Web/src/app/_services/theme.service.ts @@ -2,7 +2,8 @@ import { DOCUMENT } from '@angular/common'; import { HttpClient } from '@angular/common/http'; import { Inject, Injectable, OnDestroy, Renderer2, RendererFactory2, SecurityContext } from '@angular/core'; import { DomSanitizer } from '@angular/platform-browser'; -import { map, ReplaySubject, Subject, takeUntil } from 'rxjs'; +import { ToastrService } from 'ngx-toastr'; +import { map, ReplaySubject, Subject, takeUntil, take } from 'rxjs'; import { environment } from 'src/environments/environment'; import { ConfirmService } from '../shared/confirm.service'; import { NotificationProgressEvent } from '../_models/events/notification-progress-event'; @@ -35,7 +36,7 @@ export class ThemeService implements OnDestroy { constructor(rendererFactory: RendererFactory2, @Inject(DOCUMENT) private document: Document, private httpClient: HttpClient, - messageHub: MessageHubService, private domSantizer: DomSanitizer, private confirmService: ConfirmService) { + messageHub: MessageHubService, private domSantizer: DomSanitizer, private confirmService: ConfirmService, private toastr: ToastrService) { this.renderer = rendererFactory.createRenderer(null, null); this.getThemes(); @@ -47,7 +48,9 @@ export class ThemeService implements OnDestroy { if (notificationEvent.name !== EVENTS.SiteThemeProgress) return; if (notificationEvent.eventType === 'ended') { - if (notificationEvent.name === EVENTS.SiteThemeProgress) this.getThemes().subscribe(() => {}); + if (notificationEvent.name === EVENTS.SiteThemeProgress) this.getThemes().subscribe(() => { + + }); } }); } @@ -73,6 +76,12 @@ export class ThemeService implements OnDestroy { return this.httpClient.get(this.baseUrl + 'theme').pipe(map(themes => { this.themeCache = themes; this.themesSource.next(themes); + this.currentTheme$.pipe(take(1)).subscribe(theme => { + if (!themes.includes(theme)) { + this.setTheme(this.defaultTheme); + this.toastr.info('The active theme no longer exists. Please refresh the page.'); + } + }); return themes; })); } diff --git a/UI/Web/src/app/dashboard/dashboard.component.ts b/UI/Web/src/app/dashboard/dashboard.component.ts index 7b7323608..86a2d91b0 100644 --- a/UI/Web/src/app/dashboard/dashboard.component.ts +++ b/UI/Web/src/app/dashboard/dashboard.component.ts @@ -57,7 +57,7 @@ export class DashboardComponent implements OnInit, OnDestroy { this.seriesService.getSeries(seriesAddedEvent.seriesId).subscribe(series => { this.recentlyAddedSeries.unshift(series); - this.cdRef.markForCheck(); + this.cdRef.detectChanges(); }); } else if (res.event === EVENTS.SeriesRemoved) { const seriesRemovedEvent = res.payload as SeriesRemovedEvent; diff --git a/UI/Web/src/app/manga-reader/manga-reader.component.html b/UI/Web/src/app/manga-reader/manga-reader.component.html index 43fcb755c..ebf467c3c 100644 --- a/UI/Web/src/app/manga-reader/manga-reader.component.html +++ b/UI/Web/src/app/manga-reader/manga-reader.component.html @@ -218,7 +218,7 @@
- + {{generalSettingsForm.get('darkness')?.value + '%'}} diff --git a/UI/Web/src/app/sidenav/side-nav/side-nav.component.html b/UI/Web/src/app/sidenav/side-nav/side-nav.component.html index 09bd86022..ce8998ec4 100644 --- a/UI/Web/src/app/sidenav/side-nav/side-nav.component.html +++ b/UI/Web/src/app/sidenav/side-nav/side-nav.component.html @@ -12,7 +12,7 @@ - +
diff --git a/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html b/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html index 2ff1a456e..6760c4218 100644 --- a/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html +++ b/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.html @@ -20,7 +20,7 @@
{{theme.name | sentenceCase}}
{{theme.provider | siteThemeProvider}}
- +
diff --git a/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.ts b/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.ts index b14609f95..a0be18ac4 100644 --- a/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.ts +++ b/UI/Web/src/app/user-settings/theme-manager/theme-manager.component.ts @@ -14,7 +14,7 @@ import { AccountService } from 'src/app/_services/account.service'; }) export class ThemeManagerComponent implements OnInit, OnDestroy { - currentTheme!: SiteTheme; + currentTheme: SiteTheme | undefined; isAdmin: boolean = false; user: User | undefined;