Skip to content

Commit

Permalink
Event Widget Update (#1098)
Browse files Browse the repository at this point in the history
* Took care of some notes in the code

* Fixed an issue where Extra might get flagged as special too early, if in a word like Extraordinary

* Moved Tag cleanup code into Scanner service. Added a SplitQuery to another heavy API. Refactored Scan loop to remove parallelism and use async instead.

* Lots of rework on the codebase to support detailed messages and easier management of message sending. Need to take a break on this work.

* Progress is being made, but slowly. Code is broken in this commit.

* Progress is being made, but slowly. Code is broken in this commit.

* Fixed merge issue

* Fixed unit tests

* CoverUpdate is now hooked into new ProgressEvent structure

* Refactored code to remove custom observables and have everything use standard messages$

* Refactored a ton of instances to NotificationProgressEvent style and tons of the UI to respect that too. UI is still a bit buggy, but wholistically the work is done.

* Working much better. Sometimes events come in too fast. Currently cover update progress doesn't display on UI

* Fixed unit tests

* Removed SignalREvent to minimize internal event types. Updated the UI to use progress bars. Finished SiteThemeService.

* Merged metadata refresh progress events and changed library scan events to merge cleaner in the UI

* Changed RefreshMetadataProgress to CoverUpdateProgress to reflect the event better.

* Theme Cleanup (#1089)

* Fixed e-ink theme not properly applying correctly

* Fixed some seed changes. Changed card checkboxes to use our themed ones

* Fixed recently added carousel not going to recently-added page

* Fixed an issue where no results found would show when searching for a library name

* Cleaned up list a bit, typeahead dropdown still needs work

* Added a TODO to streamline series-card component

* Removed ng-lazyload-image module since we don't use it. We use lazysizes

* Darken card on hover

* Fixing accordion focus style

* ux pass updates

- Fixed typeahead width
- Fixed changelog download buttons
- Fixed a select
- Fixed various input box-shadows
- Fixed all anchors to only have underline on hover
- Added navtab hover and active effects

* more ux pass

- Fixed spacing on theme cards
- Fixed some light theme issues
- Exposed text-muted-color for theme card subtitle color

* UX pass fixes

- Changed back to bright green for primary on dark theme
- Changed fa icon to black on e-ink

* Merged changelog component

* Fixed anchor buttons text decoration

* Changed nav tabs to have a background color instead of open active state

* When user is not authenticated, make sure we set default theme (dark)

* Cleanup on carousel

* Updated Users tab to use small buttons with icons to align with Library tab

* Cleaned up brand to not underline, removed default link underline on hover in dropdown and pill tabs

* Fixed collection detail posters not rendering

Co-authored-by: Robbie Davis <[email protected]>

* Bump versions by dotnet-bump-version.

* Tweaked some of the emitting code

* Some css, but pretty bad. Robbie please save me

* Removed a todo

* styling update

* Only send filename on FileScanProgress

* Some console.log spam cleanup

* Various updates

* Show events widget activity based on activeEvents

* progress bar color updates

* Code cleanup

Co-authored-by: Robbie Davis <[email protected]>
  • Loading branch information
majora2007 and therobbiedavis committed Feb 24, 2022
1 parent 3be0d34 commit 22206ae
Show file tree
Hide file tree
Showing 49 changed files with 1,023 additions and 464 deletions.
7 changes: 4 additions & 3 deletions API.Benchmark/ParseScannedFilesBenchmarks.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using API.Parser;
using API.Services;
using API.Services.Tasks.Scanner;
using API.SignalR;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Order;
using Microsoft.Extensions.Logging;
Expand All @@ -28,7 +29,8 @@ public ParseScannedFilesBenchmarks()
_parseScannedFiles = new ParseScannedFiles(
Substitute.For<ILogger>(),
directoryService,
new ReadingItemService(_archiveService, new BookService(_bookLogger, directoryService, new ImageService(Substitute.For<ILogger<ImageService>>(), directoryService)), Substitute.For<ImageService>(), directoryService));
new ReadingItemService(_archiveService, new BookService(_bookLogger, directoryService, new ImageService(Substitute.For<ILogger<ImageService>>(), directoryService)), Substitute.For<ImageService>(), directoryService),
Substitute.For<IEventHub>());
}

// [Benchmark]
Expand Down Expand Up @@ -59,8 +61,7 @@ public void MergeName()
Title = "A Town Where You Live",
Volumes = "1"
};
_parseScannedFiles.ScanLibrariesForSeries(LibraryType.Manga, new [] {libraryPath},
out _, out _);
_parseScannedFiles.ScanLibrariesForSeries(LibraryType.Manga, new [] {libraryPath}, "Manga");
_parseScannedFiles.MergeName(p1);
}
}
Expand Down
2 changes: 1 addition & 1 deletion API.Tests/Services/BackupServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class BackupServiceTests
{
private readonly ILogger<BackupService> _logger = Substitute.For<ILogger<BackupService>>();
private readonly IUnitOfWork _unitOfWork;
private readonly IHubContext<MessageHub> _messageHub = Substitute.For<IHubContext<MessageHub>>();
private readonly IEventHub _messageHub = Substitute.For<IEventHub>();
private readonly IConfiguration _config;

private readonly DbConnection _connection;
Expand Down
2 changes: 1 addition & 1 deletion API.Tests/Services/CleanupServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public class CleanupServiceTests
{
private readonly ILogger<CleanupService> _logger = Substitute.For<ILogger<CleanupService>>();
private readonly IUnitOfWork _unitOfWork;
private readonly IHubContext<MessageHub> _messageHub = Substitute.For<IHubContext<MessageHub>>();
private readonly IEventHub _messageHub = Substitute.For<IEventHub>();

private readonly DbConnection _connection;
private readonly DataContext _context;
Expand Down
23 changes: 12 additions & 11 deletions API.Tests/Services/ParseScannedFilesTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using API.Parser;
using API.Services;
using API.Services.Tasks.Scanner;
using API.SignalR;
using API.Tests.Helpers;
using AutoMapper;
using Microsoft.Data.Sqlite;
Expand Down Expand Up @@ -155,7 +156,7 @@ public void GetInfosByName_ShouldReturnGivenMatchingSeriesName()
var fileSystem = new MockFileSystem();
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
var psf = new ParseScannedFiles(Substitute.For<ILogger<ParseScannedFiles>>(), ds,
new MockReadingItemService(new DefaultParser(ds)));
new MockReadingItemService(new DefaultParser(ds)), Substitute.For<IEventHub>());

var infos = new List<ParserInfo>()
{
Expand Down Expand Up @@ -200,7 +201,7 @@ public void GetInfosByName_ShouldReturnGivenMatchingNormalizedSeriesName()
var fileSystem = new MockFileSystem();
var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
var psf = new ParseScannedFiles(Substitute.For<ILogger<ParseScannedFiles>>(), ds,
new MockReadingItemService(new DefaultParser(ds)));
new MockReadingItemService(new DefaultParser(ds)), Substitute.For<IEventHub>());

var infos = new List<ParserInfo>()
{
Expand Down Expand Up @@ -240,7 +241,7 @@ public void GetInfosByName_ShouldReturnGivenMatchingNormalizedSeriesName()
#region MergeName

[Fact]
public void MergeName_ShouldMergeMatchingFormatAndName()
public async Task MergeName_ShouldMergeMatchingFormatAndName()
{
var fileSystem = new MockFileSystem();
fileSystem.AddDirectory("C:/Data/");
Expand All @@ -250,18 +251,18 @@ public void MergeName_ShouldMergeMatchingFormatAndName()

var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
var psf = new ParseScannedFiles(Substitute.For<ILogger<ParseScannedFiles>>(), ds,
new MockReadingItemService(new DefaultParser(ds)));
new MockReadingItemService(new DefaultParser(ds)), Substitute.For<IEventHub>());


psf.ScanLibrariesForSeries(LibraryType.Manga, new List<string>() {"C:/Data/"}, out _, out _);
await psf.ScanLibrariesForSeries(LibraryType.Manga, new List<string>() {"C:/Data/"}, "libraryName");

Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("Accel World", "1", "0", "Accel World v1.cbz", false)));
Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("accel_world", "1", "0", "Accel World v1.cbz", false)));
Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("accelworld", "1", "0", "Accel World v1.cbz", false)));
}

[Fact]
public void MergeName_ShouldMerge_MismatchedFormatSameName()
public async Task MergeName_ShouldMerge_MismatchedFormatSameName()
{
var fileSystem = new MockFileSystem();
fileSystem.AddDirectory("C:/Data/");
Expand All @@ -271,10 +272,10 @@ public void MergeName_ShouldMerge_MismatchedFormatSameName()

var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
var psf = new ParseScannedFiles(Substitute.For<ILogger<ParseScannedFiles>>(), ds,
new MockReadingItemService(new DefaultParser(ds)));
new MockReadingItemService(new DefaultParser(ds)), Substitute.For<IEventHub>());


psf.ScanLibrariesForSeries(LibraryType.Manga, new List<string>() {"C:/Data/"}, out _, out _);
await psf.ScanLibrariesForSeries(LibraryType.Manga, new List<string>() {"C:/Data/"}, "libraryName");

Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("Accel World", "1", "0", "Accel World v1.epub", false)));
Assert.Equal("Accel World", psf.MergeName(ParserInfoFactory.CreateParsedInfo("accel_world", "1", "0", "Accel World v1.epub", false)));
Expand All @@ -285,7 +286,7 @@ public void MergeName_ShouldMerge_MismatchedFormatSameName()
#region ScanLibrariesForSeries

[Fact]
public void ScanLibrariesForSeries_ShouldFindFiles()
public async Task ScanLibrariesForSeries_ShouldFindFiles()
{
var fileSystem = new MockFileSystem();
fileSystem.AddDirectory("C:/Data/");
Expand All @@ -296,10 +297,10 @@ public void ScanLibrariesForSeries_ShouldFindFiles()

var ds = new DirectoryService(Substitute.For<ILogger<DirectoryService>>(), fileSystem);
var psf = new ParseScannedFiles(Substitute.For<ILogger<ParseScannedFiles>>(), ds,
new MockReadingItemService(new DefaultParser(ds)));
new MockReadingItemService(new DefaultParser(ds)), Substitute.For<IEventHub>());


var parsedSeries = psf.ScanLibrariesForSeries(LibraryType.Manga, new List<string>() {"C:/Data/"}, out _, out _);
var parsedSeries = await psf.ScanLibrariesForSeries(LibraryType.Manga, new List<string>() {"C:/Data/"}, "libraryName");

Assert.Equal(3, parsedSeries.Values.Count);
Assert.NotEmpty(parsedSeries.Keys.Where(p => p.Format == MangaFormat.Archive && p.Name.Equals("Accel World")));
Expand Down
2 changes: 1 addition & 1 deletion API.Tests/Services/SiteThemeServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ namespace API.Tests.Services;
public class SiteThemeServiceTests
{
private readonly ILogger<SiteThemeService> _logger = Substitute.For<ILogger<SiteThemeService>>();
private readonly IHubContext<MessageHub> _messageHub = Substitute.For<IHubContext<MessageHub>>();
private readonly IEventHub _messageHub = Substitute.For<IEventHub>();

private readonly DbConnection _connection;
private readonly DataContext _context;
Expand Down
2 changes: 2 additions & 0 deletions API/API.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
<PackageReference Include="HtmlAgilityPack" Version="1.11.38" />
<PackageReference Include="MarkdownDeep.NET.Core" Version="1.5.0.4" />
<PackageReference Include="MediatR" Version="10.0.1" />
<PackageReference Include="MediatR.Extensions.Microsoft.DependencyInjection" Version="10.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="6.0.1" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.1" />
Expand Down
9 changes: 5 additions & 4 deletions API/Controllers/CollectionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,13 @@ namespace API.Controllers
public class CollectionController : BaseApiController
{
private readonly IUnitOfWork _unitOfWork;
private readonly IHubContext<MessageHub> _messageHub;
private readonly IEventHub _eventHub;

/// <inheritdoc />
public CollectionController(IUnitOfWork unitOfWork, IHubContext<MessageHub> messageHub)
public CollectionController(IUnitOfWork unitOfWork, IEventHub eventHub)
{
_unitOfWork = unitOfWork;
_messageHub = messageHub;
_eventHub = eventHub;
}

/// <summary>
Expand Down Expand Up @@ -156,7 +156,8 @@ public async Task<ActionResult> UpdateSeriesForTag(UpdateSeriesForTagDto updateS
{
tag.CoverImageLocked = false;
tag.CoverImage = string.Empty;
await _messageHub.Clients.All.SendAsync(SignalREvents.CoverUpdate, MessageFactory.CoverUpdateEvent(tag.Id, "collectionTag"));
await _eventHub.SendMessageAsync(MessageFactory.CoverUpdate,
MessageFactory.CoverUpdateEvent(tag.Id, "collectionTag"), false);
_unitOfWork.CollectionTagRepository.Update(tag);
}

Expand Down
26 changes: 13 additions & 13 deletions API/Controllers/DownloadController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ public class DownloadController : BaseApiController
private readonly IArchiveService _archiveService;
private readonly IDirectoryService _directoryService;
private readonly IDownloadService _downloadService;
private readonly IHubContext<MessageHub> _messageHub;
private readonly IEventHub _eventHub;
private readonly UserManager<AppUser> _userManager;
private readonly ILogger<DownloadController> _logger;
private const string DefaultContentType = "application/octet-stream";

public DownloadController(IUnitOfWork unitOfWork, IArchiveService archiveService, IDirectoryService directoryService,
IDownloadService downloadService, IHubContext<MessageHub> messageHub, UserManager<AppUser> userManager, ILogger<DownloadController> logger)
IDownloadService downloadService, IEventHub eventHub, UserManager<AppUser> userManager, ILogger<DownloadController> logger)
{
_unitOfWork = unitOfWork;
_archiveService = archiveService;
_directoryService = directoryService;
_downloadService = downloadService;
_messageHub = messageHub;
_eventHub = eventHub;
_userManager = userManager;
_logger = logger;
}
Expand Down Expand Up @@ -119,30 +119,30 @@ private async Task<ActionResult> DownloadFiles(ICollection<MangaFile> files, str
{
try
{
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.DownloadProgressEvent(User.GetUsername(),
Path.GetFileNameWithoutExtension(downloadName), 0F));
Path.GetFileNameWithoutExtension(downloadName), 0F, "started"));
if (files.Count == 1)
{
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.DownloadProgressEvent(User.GetUsername(),
Path.GetFileNameWithoutExtension(downloadName), 1F));
Path.GetFileNameWithoutExtension(downloadName), 1F, "ended"));
return await GetFirstFileDownload(files);
}

var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath),
tempFolder);
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.DownloadProgressEvent(User.GetUsername(),
Path.GetFileNameWithoutExtension(downloadName), 1F));
Path.GetFileNameWithoutExtension(downloadName), 1F, "ended"));
return File(fileBytes, DefaultContentType, downloadName);
}
catch (Exception ex)
{
_logger.LogError(ex, "There was an exception when trying to download files");
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.DownloadProgressEvent(User.GetUsername(),
Path.GetFileNameWithoutExtension(downloadName), 1F));
Path.GetFileNameWithoutExtension(downloadName), 1F, "ended"));
throw;
}
}
Expand Down Expand Up @@ -181,11 +181,11 @@ public async Task<ActionResult> DownloadBookmarkPages(DownloadBookmarkDto downlo
.Select(b => Parser.Parser.NormalizePath(_directoryService.FileSystem.Path.Join(bookmarkDirectory, $"{b.ChapterId}_{b.FileName}")));

var filename = $"{series.Name} - Bookmarks.zip";
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.DownloadProgressEvent(User.GetUsername(), Path.GetFileNameWithoutExtension(filename), 0F));
var (fileBytes, _) = await _archiveService.CreateZipForDownload(files,
$"download_{user.Id}_{series.Id}_bookmarks");
await _messageHub.Clients.All.SendAsync(SignalREvents.DownloadProgress,
await _eventHub.SendMessageAsync(MessageFactory.NotificationProgress,
MessageFactory.DownloadProgressEvent(User.GetUsername(), Path.GetFileNameWithoutExtension(filename), 1F));
return File(fileBytes, DefaultContentType, filename);
}
Expand Down
18 changes: 10 additions & 8 deletions API/Controllers/SeriesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ public class SeriesController : BaseApiController
private readonly ILogger<SeriesController> _logger;
private readonly ITaskScheduler _taskScheduler;
private readonly IUnitOfWork _unitOfWork;
private readonly IHubContext<MessageHub> _messageHub;
private readonly IEventHub _eventHub;

public SeriesController(ILogger<SeriesController> logger, ITaskScheduler taskScheduler, IUnitOfWork unitOfWork, IHubContext<MessageHub> messageHub)

public SeriesController(ILogger<SeriesController> logger, ITaskScheduler taskScheduler, IUnitOfWork unitOfWork, IEventHub eventHub)
{
_logger = logger;
_taskScheduler = taskScheduler;
_unitOfWork = unitOfWork;
_messageHub = messageHub;
_eventHub = eventHub;
}

[HttpPost]
Expand Down Expand Up @@ -93,8 +94,9 @@ public async Task<ActionResult<bool>> DeleteSeries(int seriesId)
await _unitOfWork.CollectionTagRepository.RemoveTagsWithoutSeries();
await _unitOfWork.CommitAsync();
_taskScheduler.CleanupChapters(chapterIds);
await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesRemoved,
MessageFactory.SeriesRemovedEvent(seriesId, series.Name, series.LibraryId));

await _eventHub.SendMessageAsync(MessageFactory.SeriesRemoved,
MessageFactory.SeriesRemovedEvent(seriesId, series.Name, series.LibraryId), false);
}
return Ok(result);
}
Expand Down Expand Up @@ -378,9 +380,9 @@ public async Task<ActionResult> UpdateSeriesMetadata(UpdateSeriesMetadataDto upd
{
foreach (var tag in updateSeriesMetadataDto.Tags)
{
await _messageHub.Clients.All.SendAsync(SignalREvents.SeriesAddedToCollection,
MessageFactory.SeriesAddedToCollection(tag.Id,
updateSeriesMetadataDto.SeriesMetadata.SeriesId));
await _eventHub.SendMessageAsync(MessageFactory.SeriesAddedToCollection,
MessageFactory.SeriesAddedToCollectionEvent(tag.Id,
updateSeriesMetadataDto.SeriesMetadata.SeriesId), false);
}
return Ok("Successfully updated");
}
Expand Down
10 changes: 10 additions & 0 deletions API/DTOs/UpdateUserRole.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Collections.Generic;
using MediatR;

namespace API.DTOs;

public class UpdateUserRole : IRequest<bool>
{
public string Username { get; init; }
public IList<string> Roles { get; init; }
}
3 changes: 3 additions & 0 deletions API/Extensions/ApplicationServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using API.Helpers;
using API.Services;
using API.Services.Tasks;
using API.SignalR;
using API.SignalR.Presence;
using Kavita.Common;
using Microsoft.AspNetCore.Hosting;
Expand Down Expand Up @@ -41,11 +42,13 @@ public static void AddApplicationServices(this IServiceCollection services, ICon
services.AddScoped<IBookmarkService, BookmarkService>();
services.AddScoped<ISiteThemeService, SiteThemeService>();


services.AddScoped<IFileSystem, FileSystem>();
services.AddScoped<IFileService, FileService>();
services.AddScoped<ICacheHelper, CacheHelper>();

services.AddScoped<IPresenceTracker, PresenceTracker>();
services.AddScoped<IEventHub, EventHub>();

services.AddSqLite(config, env);
services.AddLogging(config);
Expand Down
1 change: 1 addition & 0 deletions API/Parser/ParserInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ public bool IsSpecialInfo()
/// <summary>
/// Merges non empty/null properties from info2 into this entity.
/// </summary>
/// <remarks>This does not merge ComicInfo as they should always be the same</remarks>
/// <param name="info2"></param>
public void Merge(ParserInfo info2)
{
Expand Down
Loading

0 comments on commit 22206ae

Please sign in to comment.