diff --git a/API.Benchmark/API.Benchmark.csproj b/API.Benchmark/API.Benchmark.csproj
new file mode 100644
index 000000000..529f3cc93
--- /dev/null
+++ b/API.Benchmark/API.Benchmark.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net5.0
+ Exe
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/API.Benchmark/ParseScannedFilesBenchmarks.cs b/API.Benchmark/ParseScannedFilesBenchmarks.cs
new file mode 100644
index 000000000..bc0c810ce
--- /dev/null
+++ b/API.Benchmark/ParseScannedFilesBenchmarks.cs
@@ -0,0 +1,40 @@
+using System;
+using System.IO;
+using API.Entities.Enums;
+using API.Interfaces.Services;
+using API.Services;
+using API.Services.Tasks.Scanner;
+using BenchmarkDotNet.Attributes;
+using BenchmarkDotNet.Order;
+using Microsoft.Extensions.Logging;
+using NSubstitute;
+
+namespace API.Benchmark
+{
+ [MemoryDiagnoser]
+ [Orderer(SummaryOrderPolicy.FastestToSlowest)]
+ [RankColumn]
+ [SimpleJob(launchCount: 1, warmupCount: 3, targetCount: 5, invocationCount: 100, id: "Test"), ShortRunJob]
+ public class ParseScannedFilesBenchmarks
+ {
+ private readonly ParseScannedFiles _parseScannedFiles;
+ private readonly ILogger _logger = Substitute.For>();
+ private readonly ILogger _bookLogger = Substitute.For>();
+
+ public ParseScannedFilesBenchmarks()
+ {
+ IBookService bookService = new BookService(_bookLogger);
+ _parseScannedFiles = new ParseScannedFiles(bookService, _logger);
+ }
+
+ [Benchmark]
+ public void Test()
+ {
+ var libraryPath = Path.Join(Directory.GetCurrentDirectory(),
+ "../../../Services/Test Data/ScannerService/Manga");
+ var parsedSeries = _parseScannedFiles.ScanLibrariesForSeries(LibraryType.Manga, new string[] {libraryPath},
+ out var totalFiles, out var scanElapsedTime);
+ }
+
+ }
+}
diff --git a/API.Benchmark/Program.cs b/API.Benchmark/Program.cs
new file mode 100644
index 000000000..8111eaecc
--- /dev/null
+++ b/API.Benchmark/Program.cs
@@ -0,0 +1,18 @@
+using BenchmarkDotNet.Running;
+
+namespace API.Benchmark
+{
+ ///
+ /// To build this, cd into API.Benchmark directory and run
+ /// dotnet build -c Release
+ /// then copy the outputted dll
+ /// dotnet copied_string\API.Benchmark.dll
+ ///
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ BenchmarkRunner.Run();
+ }
+ }
+}
diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs
index 348902f84..fdd8cafa3 100644
--- a/API.Tests/Parser/MangaParserTests.cs
+++ b/API.Tests/Parser/MangaParserTests.cs
@@ -312,14 +312,14 @@ namespace API.Tests.Parser
const string rootPath = @"E:/Manga/";
var expected = new Dictionary();
var filepath = @"E:/Manga/Mujaki no Rakuen/Mujaki no Rakuen Vol12 ch76.cbz";
- expected.Add(filepath, new ParserInfo
- {
- Series = "Mujaki no Rakuen", Volumes = "12",
- Chapters = "76", Filename = "Mujaki no Rakuen Vol12 ch76.cbz", Format = MangaFormat.Archive,
- FullFilePath = filepath
- });
+ expected.Add(filepath, new ParserInfo
+ {
+ Series = "Mujaki no Rakuen", Volumes = "12",
+ Chapters = "76", Filename = "Mujaki no Rakuen Vol12 ch76.cbz", Format = MangaFormat.Archive,
+ FullFilePath = filepath
+ });
- filepath = @"E:/Manga/Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen/Vol 1.cbz";
+ filepath = @"E:/Manga/Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen/Vol 1.cbz";
expected.Add(filepath, new ParserInfo
{
Series = "Shimoneta to Iu Gainen ga Sonzai Shinai Taikutsu na Sekai Man-hen", Volumes = "1",
@@ -423,20 +423,20 @@ namespace API.Tests.Parser
}
Assert.NotNull(actual);
_testOutputHelper.WriteLine($"Validating {file}");
- _testOutputHelper.WriteLine("Format");
Assert.Equal(expectedInfo.Format, actual.Format);
- _testOutputHelper.WriteLine("Series");
+ _testOutputHelper.WriteLine("Format ✓");
Assert.Equal(expectedInfo.Series, actual.Series);
- _testOutputHelper.WriteLine("Chapters");
+ _testOutputHelper.WriteLine("Series ✓");
Assert.Equal(expectedInfo.Chapters, actual.Chapters);
- _testOutputHelper.WriteLine("Volumes");
+ _testOutputHelper.WriteLine("Chapters ✓");
Assert.Equal(expectedInfo.Volumes, actual.Volumes);
- _testOutputHelper.WriteLine("Edition");
+ _testOutputHelper.WriteLine("Volumes ✓");
Assert.Equal(expectedInfo.Edition, actual.Edition);
- _testOutputHelper.WriteLine("Filename");
+ _testOutputHelper.WriteLine("Edition ✓");
Assert.Equal(expectedInfo.Filename, actual.Filename);
- _testOutputHelper.WriteLine("FullFilePath");
+ _testOutputHelper.WriteLine("Filename ✓");
Assert.Equal(expectedInfo.FullFilePath, actual.FullFilePath);
+ _testOutputHelper.WriteLine("FullFilePath ✓");
}
}
}
diff --git a/API/Interfaces/ITaskScheduler.cs b/API/Interfaces/ITaskScheduler.cs
index b75282fd5..ead76e36a 100644
--- a/API/Interfaces/ITaskScheduler.cs
+++ b/API/Interfaces/ITaskScheduler.cs
@@ -1,4 +1,6 @@
-namespace API.Interfaces
+using System.Threading.Tasks;
+
+namespace API.Interfaces
{
public interface ITaskScheduler
{
@@ -6,7 +8,7 @@
/// For use on Server startup
///
void ScheduleTasks();
- void ScheduleStatsTasks();
+ Task ScheduleStatsTasks();
void ScheduleUpdaterTasks();
void ScanLibrary(int libraryId, bool forceUpdate = false);
void CleanupChapters(int[] chapterIds);
@@ -15,5 +17,6 @@
void RefreshSeriesMetadata(int libraryId, int seriesId);
void ScanSeries(int libraryId, int seriesId, bool forceUpdate = false);
void CancelStatsTasks();
+ void RunStatCollection();
}
}
diff --git a/API/Interfaces/Services/IStatsService.cs b/API/Interfaces/Services/IStatsService.cs
index f30222385..19d8d9f4b 100644
--- a/API/Interfaces/Services/IStatsService.cs
+++ b/API/Interfaces/Services/IStatsService.cs
@@ -6,8 +6,6 @@ namespace API.Interfaces.Services
public interface IStatsService
{
Task PathData(ClientInfoDto clientInfoDto);
- Task FinalizeStats();
- Task CollectRelevantData();
Task CollectAndSendStatsData();
}
}
diff --git a/API/Services/HostedServices/StartupTasksHostedService.cs b/API/Services/HostedServices/StartupTasksHostedService.cs
index 02e2fa3d9..58b6eec25 100644
--- a/API/Services/HostedServices/StartupTasksHostedService.cs
+++ b/API/Services/HostedServices/StartupTasksHostedService.cs
@@ -2,7 +2,6 @@
using System.Threading;
using System.Threading.Tasks;
using API.Interfaces;
-using API.Interfaces.Services;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
@@ -27,7 +26,10 @@ namespace API.Services.HostedServices
try
{
- await ManageStartupStatsTasks(scope, taskScheduler);
+ // These methods will automatically check if stat collection is disabled to prevent sending any data regardless
+ // of when setting was changed
+ await taskScheduler.ScheduleStatsTasks();
+ taskScheduler.RunStatCollection();
}
catch (Exception)
{
@@ -35,21 +37,6 @@ namespace API.Services.HostedServices
}
}
- private async Task ManageStartupStatsTasks(IServiceScope serviceScope, ITaskScheduler taskScheduler)
- {
- var unitOfWork = serviceScope.ServiceProvider.GetRequiredService();
-
- var settingsDto = await unitOfWork.SettingsRepository.GetSettingsDtoAsync();
-
- if (!settingsDto.AllowStatCollection) return;
-
- taskScheduler.ScheduleStatsTasks();
-
- var statsService = serviceScope.ServiceProvider.GetRequiredService();
-
- await statsService.CollectAndSendStatsData();
- }
-
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
}
}
diff --git a/API/Services/TaskScheduler.cs b/API/Services/TaskScheduler.cs
index d3f61e545..f12926c68 100644
--- a/API/Services/TaskScheduler.cs
+++ b/API/Services/TaskScheduler.cs
@@ -22,6 +22,7 @@ namespace API.Services
private readonly IStatsService _statsService;
private readonly IVersionUpdaterService _versionUpdaterService;
+ private const string SendDataTask = "finalize-stats";
public static BackgroundJobServer Client => new BackgroundJobServer();
@@ -76,19 +77,17 @@ namespace API.Services
#region StatsTasks
- private const string SendDataTask = "finalize-stats";
- public void ScheduleStatsTasks()
+
+ public async Task ScheduleStatsTasks()
{
- var allowStatCollection = bool.Parse(Task.Run(() => _unitOfWork.SettingsRepository.GetSettingAsync(ServerSettingKey.AllowStatCollection)).GetAwaiter().GetResult().Value);
+ var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection;
if (!allowStatCollection)
{
_logger.LogDebug("User has opted out of stat collection, not registering tasks");
return;
}
- _logger.LogDebug("Adding StatsTasks");
-
- _logger.LogDebug("Scheduling Send data to the Stats server {Setting}", nameof(Cron.Daily));
+ _logger.LogDebug("Scheduling stat collection daily");
RecurringJob.AddOrUpdate(SendDataTask, () => _statsService.CollectAndSendStatsData(), Cron.Daily);
}
@@ -99,6 +98,12 @@ namespace API.Services
RecurringJob.RemoveIfExists(SendDataTask);
}
+ public void RunStatCollection()
+ {
+ _logger.LogInformation("Enqueuing stat collection");
+ BackgroundJob.Enqueue(() => _statsService.CollectAndSendStatsData());
+ }
+
#endregion
#region UpdateTasks
diff --git a/API/Services/Tasks/StatsService.cs b/API/Services/Tasks/StatsService.cs
index 691d13f33..47087fc8d 100644
--- a/API/Services/Tasks/StatsService.cs
+++ b/API/Services/Tasks/StatsService.cs
@@ -50,7 +50,7 @@ namespace API.Services.Tasks
await SaveFile(statisticsDto);
}
- public async Task CollectRelevantData()
+ private async Task CollectRelevantData()
{
_logger.LogDebug("Collecting data from the server and database");
@@ -63,7 +63,7 @@ namespace API.Services.Tasks
await PathData(serverInfo, usageInfo);
}
- public async Task FinalizeStats()
+ private async Task FinalizeStats()
{
try
{
@@ -86,6 +86,12 @@ namespace API.Services.Tasks
public async Task CollectAndSendStatsData()
{
+ var allowStatCollection = (await _unitOfWork.SettingsRepository.GetSettingsDtoAsync()).AllowStatCollection;
+ if (!allowStatCollection)
+ {
+ _logger.LogDebug("User has opted out of stat collection, not registering tasks");
+ return;
+ }
await CollectRelevantData();
await FinalizeStats();
}
diff --git a/Kavita.Common/HashUtil.cs b/Kavita.Common/HashUtil.cs
index f0098f8eb..f959f0af4 100644
--- a/Kavita.Common/HashUtil.cs
+++ b/Kavita.Common/HashUtil.cs
@@ -1,5 +1,4 @@
using System;
-using System.Security.Cryptography;
using System.Text;
namespace Kavita.Common
diff --git a/Kavita.sln b/Kavita.sln
index e49484b02..670808870 100644
--- a/Kavita.sln
+++ b/Kavita.sln
@@ -9,6 +9,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.Tests", "API.Tests\API.
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kavita.Common", "Kavita.Common\Kavita.Common.csproj", "{165A86F5-9E74-4C05-9305-A6F0BA32C9EE}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "API.Benchmark", "API.Benchmark\API.Benchmark.csproj", "{3D781D18-2452-421F-A81A-59254FEE1FEC}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -58,5 +60,17 @@ Global
{165A86F5-9E74-4C05-9305-A6F0BA32C9EE}.Release|x64.Build.0 = Release|Any CPU
{165A86F5-9E74-4C05-9305-A6F0BA32C9EE}.Release|x86.ActiveCfg = Release|Any CPU
{165A86F5-9E74-4C05-9305-A6F0BA32C9EE}.Release|x86.Build.0 = Release|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Debug|x64.Build.0 = Debug|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Debug|x86.Build.0 = Debug|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Release|x64.ActiveCfg = Release|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Release|x64.Build.0 = Release|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Release|x86.ActiveCfg = Release|Any CPU
+ {3D781D18-2452-421F-A81A-59254FEE1FEC}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal
diff --git a/UI/Web/src/app/user-settings/user-preferences/user-preferences.component.ts b/UI/Web/src/app/user-settings/user-preferences/user-preferences.component.ts
index 653fc21fe..ce3a8452b 100644
--- a/UI/Web/src/app/user-settings/user-preferences/user-preferences.component.ts
+++ b/UI/Web/src/app/user-settings/user-preferences/user-preferences.component.ts
@@ -187,13 +187,6 @@ export class UserPreferencesComponent implements OnInit, OnDestroy {
}
transformKeyToOpdsUrl(key: string) {
- let apiUrl = environment.apiUrl;
- if (environment.production) {
- apiUrl = `${location.protocol}//${location.origin}`;
- if (location.port != '80') {
- apiUrl += ':' + location.port;
- }
- }
- return `${apiUrl}opds/${key}`;
+ return `${location.origin}/api/opds/${key}`;
}
}