diff --git a/API.Tests/Extensions/FileInfoExtensionsTests.cs b/API.Tests/Extensions/FileInfoExtensionsTests.cs index 2f385b63f..5e17ecaeb 100644 --- a/API.Tests/Extensions/FileInfoExtensionsTests.cs +++ b/API.Tests/Extensions/FileInfoExtensionsTests.cs @@ -1,21 +1,33 @@ -namespace API.Tests.Extensions +using System; +using System.Globalization; +using System.IO; +using API.Extensions; +using Xunit; + +namespace API.Tests.Extensions { public class FileInfoExtensionsTests { - // [Fact] - // public void DoesLastWriteMatchTest() - // { - // var fi = Substitute.For(); - // fi.LastWriteTime = DateTime.Now; - // - // var deltaTime = DateTime.Today.Subtract(TimeSpan.FromDays(1)); - // Assert.False(fi.DoesLastWriteMatch(deltaTime)); - // } - // - // [Fact] - // public void IsLastWriteLessThanTest() - // { - // - // } + private static readonly string TestDirectory = Path.Join(Directory.GetCurrentDirectory(), "../../../Extensions/Test Data/"); + + [Fact] + public void HasFileBeenModifiedSince_ShouldBeFalse() + { + var filepath = Path.Join(TestDirectory, "not modified.txt"); + var date = new FileInfo(filepath).LastWriteTime; + Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date)); + File.ReadAllText(filepath); + Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date)); + } + + [Fact] + public void HasFileBeenModifiedSince_ShouldBeTrue() + { + var filepath = Path.Join(TestDirectory, "modified on run.txt"); + var date = new FileInfo(filepath).LastWriteTime; + Assert.False(new FileInfo(filepath).HasFileBeenModifiedSince(date)); + File.AppendAllLines(filepath, new[] { DateTime.Now.ToString(CultureInfo.InvariantCulture) }); + Assert.True(new FileInfo(filepath).HasFileBeenModifiedSince(date)); + } } -} \ No newline at end of file +} diff --git a/API.Tests/Extensions/Test Data/modified on run.txt b/API.Tests/Extensions/Test Data/modified on run.txt new file mode 100644 index 000000000..8a2e4f98c --- /dev/null +++ b/API.Tests/Extensions/Test Data/modified on run.txt @@ -0,0 +1,2 @@ +This file should be modified by the unit test08/20/2021 10:26:03 +08/20/2021 10:26:29 diff --git a/API.Tests/Extensions/Test Data/not modified.txt b/API.Tests/Extensions/Test Data/not modified.txt new file mode 100644 index 000000000..d5c0ce0a5 --- /dev/null +++ b/API.Tests/Extensions/Test Data/not modified.txt @@ -0,0 +1 @@ +Hello, this file should not be modified \ No newline at end of file diff --git a/API.Tests/Parser/MangaParserTests.cs b/API.Tests/Parser/MangaParserTests.cs index d2785edc7..d5c0a23ad 100644 --- a/API.Tests/Parser/MangaParserTests.cs +++ b/API.Tests/Parser/MangaParserTests.cs @@ -64,6 +64,7 @@ namespace API.Tests.Parser [InlineData("Sword Art Online Vol 10 - Alicization Running [Yen Press] [LuCaZ] {r2}.epub", "10")] [InlineData("Noblesse - Episode 406 (52 Pages).7z", "0")] [InlineData("X-Men v1 #201 (September 2007).cbz", "1")] + [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "6")] public void ParseVolumeTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseVolume(filename)); @@ -154,6 +155,7 @@ namespace API.Tests.Parser [InlineData("Please Go Home, Akutsu-San! - Chapter 038.5 - Volume Announcement.cbz", "Please Go Home, Akutsu-San!")] [InlineData("Killing Bites - Vol 11 Chapter 050 Save Me, Nunupi!.cbz", "Killing Bites")] [InlineData("Mad Chimera World - Volume 005 - Chapter 026.cbz", "Mad Chimera World")] + [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "Hentai Ouji to Warawanai Neko.")] public void ParseSeriesTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseSeries(filename)); @@ -222,6 +224,7 @@ namespace API.Tests.Parser [InlineData("Boku No Kokoro No Yabai Yatsu - Chapter 054 I Prayed At The Shrine (V0).cbz", "54")] [InlineData("Ijousha No Ai - Vol.01 Chapter 029 8 Years Ago", "29")] [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09.cbz", "9")] + [InlineData("Hentai Ouji to Warawanai Neko. - Vol. 06 Ch. 034.5", "34.5")] public void ParseChaptersTest(string filename, string expected) { Assert.Equal(expected, API.Parser.Parser.ParseChapter(filename)); diff --git a/API.Tests/Services/ScannerServiceTests.cs b/API.Tests/Services/ScannerServiceTests.cs index c25a7012d..2c7a999f0 100644 --- a/API.Tests/Services/ScannerServiceTests.cs +++ b/API.Tests/Services/ScannerServiceTests.cs @@ -33,7 +33,6 @@ namespace API.Tests.Services private readonly IBookService _bookService = Substitute.For(); private readonly IImageService _imageService = Substitute.For(); private readonly ILogger _metadataLogger = Substitute.For>(); - private readonly IDirectoryService _directoryService = Substitute.For(); private readonly ICacheService _cacheService = Substitute.For(); private readonly DbConnection _connection; diff --git a/API/Controllers/BookController.cs b/API/Controllers/BookController.cs index f8dbaafe8..d48b75707 100644 --- a/API/Controllers/BookController.cs +++ b/API/Controllers/BookController.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using API.DTOs; diff --git a/API/Controllers/DownloadController.cs b/API/Controllers/DownloadController.cs index 62fab915c..21e2a77cb 100644 --- a/API/Controllers/DownloadController.cs +++ b/API/Controllers/DownloadController.cs @@ -70,7 +70,7 @@ namespace API.Controllers { return await GetFirstFileDownload(files); } - var (fileBytes, zipPath) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), + var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), $"download_{User.GetUsername()}_v{volumeId}"); return File(fileBytes, DefaultContentType, $"{series.Name} - Volume {volume.Number}.zip"); } @@ -116,7 +116,7 @@ namespace API.Controllers { return await GetFirstFileDownload(files); } - var (fileBytes, zipPath) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), + var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), $"download_{User.GetUsername()}_c{chapterId}"); return File(fileBytes, DefaultContentType, $"{series.Name} - Chapter {chapter.Number}.zip"); } @@ -137,7 +137,7 @@ namespace API.Controllers { return await GetFirstFileDownload(files); } - var (fileBytes, zipPath) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), + var (fileBytes, _) = await _archiveService.CreateZipForDownload(files.Select(c => c.FilePath), $"download_{User.GetUsername()}_s{seriesId}"); return File(fileBytes, DefaultContentType, $"{series.Name}.zip"); } @@ -194,11 +194,11 @@ namespace API.Controllers var files = _directoryService.GetFilesWithExtension(chapterExtractPath, Parser.Parser.ImageFileExtensions); // Filter out images that aren't in bookmarks Array.Sort(files, _numericComparer); - totalFilePaths.AddRange(files.Where((t, i) => chapterPages.Contains(i))); + totalFilePaths.AddRange(files.Where((_, i) => chapterPages.Contains(i))); } - var (fileBytes, zipPath) = await _archiveService.CreateZipForDownload(totalFilePaths, + var (fileBytes, _) = await _archiveService.CreateZipForDownload(totalFilePaths, tempFolder); DirectoryService.ClearAndDeleteDirectory(fullExtractPath); return File(fileBytes, DefaultContentType, $"{series.Name} - Bookmarks.zip"); diff --git a/API/Controllers/ReaderController.cs b/API/Controllers/ReaderController.cs index c3015bbab..85c0ae88f 100644 --- a/API/Controllers/ReaderController.cs +++ b/API/Controllers/ReaderController.cs @@ -368,7 +368,7 @@ namespace API.Controllers /// /// Removes all bookmarks for all chapters linked to a Series /// - /// + /// /// [HttpPost("remove-bookmarks")] public async Task RemoveBookmarks(RemoveBookmarkForSeriesDto dto) diff --git a/API/Controllers/SeriesController.cs b/API/Controllers/SeriesController.cs index e00d99f40..f938d4bc6 100644 --- a/API/Controllers/SeriesController.cs +++ b/API/Controllers/SeriesController.cs @@ -12,7 +12,6 @@ using API.Interfaces; using Kavita.Common; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; -using Microsoft.EntityFrameworkCore; using Microsoft.Extensions.Logging; namespace API.Controllers diff --git a/API/Controllers/ServerController.cs b/API/Controllers/ServerController.cs index 97aa8bf46..eec7c53cb 100644 --- a/API/Controllers/ServerController.cs +++ b/API/Controllers/ServerController.cs @@ -5,7 +5,6 @@ using System.Threading.Tasks; using API.DTOs.Stats; using API.DTOs.Update; using API.Extensions; -using API.Interfaces; using API.Interfaces.Services; using API.Services.Tasks; using Kavita.Common; @@ -26,11 +25,10 @@ namespace API.Controllers private readonly IBackupService _backupService; private readonly IArchiveService _archiveService; private readonly ICacheService _cacheService; - private readonly ITaskScheduler _taskScheduler; private readonly IVersionUpdaterService _versionUpdaterService; public ServerController(IHostApplicationLifetime applicationLifetime, ILogger logger, IConfiguration config, - IBackupService backupService, IArchiveService archiveService, ICacheService cacheService, ITaskScheduler taskScheduler, + IBackupService backupService, IArchiveService archiveService, ICacheService cacheService, IVersionUpdaterService versionUpdaterService) { _applicationLifetime = applicationLifetime; @@ -39,7 +37,6 @@ namespace API.Controllers _backupService = backupService; _archiveService = archiveService; _cacheService = cacheService; - _taskScheduler = taskScheduler; _versionUpdaterService = versionUpdaterService; } diff --git a/API/DTOs/SeriesByIdsDto.cs b/API/DTOs/SeriesByIdsDto.cs index 75eabc6be..0ffdd8cba 100644 --- a/API/DTOs/SeriesByIdsDto.cs +++ b/API/DTOs/SeriesByIdsDto.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace API.DTOs +namespace API.DTOs { public class SeriesByIdsDto { diff --git a/API/Data/ChapterRepository.cs b/API/Data/ChapterRepository.cs index 7e44d8977..e3510adc4 100644 --- a/API/Data/ChapterRepository.cs +++ b/API/Data/ChapterRepository.cs @@ -1,6 +1,5 @@ using API.Entities; using API.Interfaces.Repositories; -using AutoMapper; using Microsoft.EntityFrameworkCore; namespace API.Data diff --git a/API/Data/Seed.cs b/API/Data/Seed.cs index 838277931..9ccd34212 100644 --- a/API/Data/Seed.cs +++ b/API/Data/Seed.cs @@ -60,11 +60,11 @@ namespace API.Data } await context.SaveChangesAsync(); - + // Port and LoggingLevel are managed in appSettings.json. Update the DB values to match - context.ServerSetting.FirstOrDefault(s => s.Key == ServerSettingKey.Port).Value = + context.ServerSetting.First(s => s.Key == ServerSettingKey.Port).Value = Configuration.Port + string.Empty; - context.ServerSetting.FirstOrDefault(s => s.Key == ServerSettingKey.LoggingLevel).Value = + context.ServerSetting.First(s => s.Key == ServerSettingKey.LoggingLevel).Value = Configuration.LogLevel + string.Empty; await context.SaveChangesAsync(); @@ -74,11 +74,11 @@ namespace API.Data public static async Task SeedSeriesMetadata(DataContext context) { await context.Database.EnsureCreatedAsync(); - + context.Database.EnsureCreated(); var series = await context.Series .Include(s => s.Metadata).ToListAsync(); - + foreach (var s in series) { s.Metadata ??= new SeriesMetadata(); diff --git a/API/Data/SeriesRepository.cs b/API/Data/SeriesRepository.cs index b1620d48d..b9e2f16cd 100644 --- a/API/Data/SeriesRepository.cs +++ b/API/Data/SeriesRepository.cs @@ -1,12 +1,10 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using API.Comparators; using API.DTOs; using API.DTOs.Filtering; using API.Entities; -using API.Entities.Enums; using API.Extensions; using API.Helpers; using API.Interfaces; diff --git a/API/Data/VolumeRepository.cs b/API/Data/VolumeRepository.cs index bcab3d113..c10a3a04e 100644 --- a/API/Data/VolumeRepository.cs +++ b/API/Data/VolumeRepository.cs @@ -1,9 +1,7 @@ using System.Collections.Generic; -using System.IO; using System.Linq; using System.Threading.Tasks; using API.DTOs; -using API.DTOs.Reader; using API.Entities; using API.Interfaces; using AutoMapper; diff --git a/API/Entities/AppUserProgress.cs b/API/Entities/AppUserProgress.cs index 1efe4b102..cb3c1b33c 100644 --- a/API/Entities/AppUserProgress.cs +++ b/API/Entities/AppUserProgress.cs @@ -2,7 +2,6 @@ using System; using System.ComponentModel.DataAnnotations; using API.Entities.Interfaces; -using Microsoft.EntityFrameworkCore; namespace API.Entities { diff --git a/API/Entities/CollectionTag.cs b/API/Entities/CollectionTag.cs index f6058181e..c9dd4fa92 100644 --- a/API/Entities/CollectionTag.cs +++ b/API/Entities/CollectionTag.cs @@ -1,6 +1,4 @@ using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using API.Entities.Interfaces; using Microsoft.EntityFrameworkCore; namespace API.Entities diff --git a/API/Extensions/DirectoryInfoExtensions.cs b/API/Extensions/DirectoryInfoExtensions.cs index a922e7313..892c690b3 100644 --- a/API/Extensions/DirectoryInfoExtensions.cs +++ b/API/Extensions/DirectoryInfoExtensions.cs @@ -1,5 +1,4 @@ -using System; -using System.IO; +using System.IO; using System.Linq; using API.Comparators; diff --git a/API/Extensions/FileInfoExtensions.cs b/API/Extensions/FileInfoExtensions.cs index 6730b6f05..0990c4c6a 100644 --- a/API/Extensions/FileInfoExtensions.cs +++ b/API/Extensions/FileInfoExtensions.cs @@ -5,14 +5,15 @@ namespace API.Extensions { public static class FileInfoExtensions { - public static bool DoesLastWriteMatch(this FileInfo fileInfo, DateTime comparison) + /// + /// Checks if the last write time of the file is after the passed date + /// + /// + /// + /// + public static bool HasFileBeenModifiedSince(this FileInfo fileInfo, DateTime comparison) { - return comparison.Equals(fileInfo.LastWriteTime); - } - - public static bool IsLastWriteLessThan(this FileInfo fileInfo, DateTime comparison) - { - return fileInfo.LastWriteTime < comparison; + return fileInfo?.LastWriteTime > comparison; } } } diff --git a/API/Interfaces/Services/IVersionUpdaterService.cs b/API/Interfaces/Services/IVersionUpdaterService.cs index c47cf08b4..ddde09960 100644 --- a/API/Interfaces/Services/IVersionUpdaterService.cs +++ b/API/Interfaces/Services/IVersionUpdaterService.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Threading.Tasks; using API.DTOs.Update; -using API.Services.Tasks; namespace API.Interfaces.Services { diff --git a/API/Services/ArchiveService.cs b/API/Services/ArchiveService.cs index e0a6fa596..3e019e583 100644 --- a/API/Services/ArchiveService.cs +++ b/API/Services/ArchiveService.cs @@ -30,6 +30,7 @@ namespace API.Services private readonly IDirectoryService _directoryService; private static readonly RecyclableMemoryStreamManager StreamManager = new(); private readonly NaturalSortComparer _comparer; + private const string ComicInfoFilename = "comicinfo"; public ArchiveService(ILogger logger, IDirectoryService directoryService) { @@ -297,7 +298,7 @@ namespace API.Services foreach (var entry in entries) { var filename = Path.GetFileNameWithoutExtension(entry.Key).ToLower(); - if (filename.EndsWith("comicinfo") + if (filename.EndsWith(ComicInfoFilename) && !filename.StartsWith(Parser.Parser.MacOsMetadataFileStartsWith) && !Parser.Parser.HasBlacklistedFolderInPath(entry.Key) && Parser.Parser.IsXml(entry.Key)) @@ -334,7 +335,7 @@ namespace API.Services _logger.LogDebug("Using default compression handling"); using var archive = ZipFile.OpenRead(archivePath); var entry = archive.Entries.SingleOrDefault(x => !Parser.Parser.HasBlacklistedFolderInPath(x.FullName) - && Path.GetFileNameWithoutExtension(x.Name).ToLower() == "comicinfo" + && Path.GetFileNameWithoutExtension(x.Name)?.ToLower() == ComicInfoFilename && !Path.GetFileNameWithoutExtension(x.Name).StartsWith(Parser.Parser.MacOsMetadataFileStartsWith) && Parser.Parser.IsXml(x.FullName)); if (entry != null) diff --git a/API/Services/CacheService.cs b/API/Services/CacheService.cs index 18dadaf06..968abaa72 100644 --- a/API/Services/CacheService.cs +++ b/API/Services/CacheService.cs @@ -9,7 +9,6 @@ using API.Entities.Enums; using API.Extensions; using API.Interfaces; using API.Interfaces.Services; -using Kavita.Common; using Microsoft.Extensions.Logging; namespace API.Services diff --git a/API/Services/Clients/StatsApiClient.cs b/API/Services/Clients/StatsApiClient.cs index e1a274398..d9b09a42f 100644 --- a/API/Services/Clients/StatsApiClient.cs +++ b/API/Services/Clients/StatsApiClient.cs @@ -11,7 +11,9 @@ namespace API.Services.Clients { private readonly HttpClient _client; private readonly ILogger _logger; +#pragma warning disable S1075 private const string ApiUrl = "http://stats.kavitareader.com"; +#pragma warning restore S1075 public StatsApiClient(HttpClient client, ILogger logger) { diff --git a/API/Services/DirectoryService.cs b/API/Services/DirectoryService.cs index 0451088e9..b21cdd475 100644 --- a/API/Services/DirectoryService.cs +++ b/API/Services/DirectoryService.cs @@ -320,7 +320,7 @@ namespace API.Services var fileCount = 0; // Determine whether to parallelize file processing on each folder based on processor count. - var procCount = Environment.ProcessorCount; + //var procCount = Environment.ProcessorCount; // Data structure to hold names of subfolders to be examined for files. var dirs = new Stack(); diff --git a/API/Services/MetadataService.cs b/API/Services/MetadataService.cs index 921f46b82..345dd1563 100644 --- a/API/Services/MetadataService.cs +++ b/API/Services/MetadataService.cs @@ -67,7 +67,10 @@ namespace API.Services public void UpdateMetadata(Chapter chapter, bool forceUpdate) { var firstFile = chapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); - if (!chapter.CoverImageLocked && ShouldFindCoverImage(chapter.CoverImage, forceUpdate) && firstFile != null && !new FileInfo(firstFile.FilePath).IsLastWriteLessThan(firstFile.LastModified)) + if (!chapter.CoverImageLocked + && ShouldFindCoverImage(chapter.CoverImage, forceUpdate) + && firstFile != null + && (forceUpdate || new FileInfo(firstFile.FilePath).HasFileBeenModifiedSince(firstFile.LastModified))) { chapter.Files ??= new List(); chapter.CoverImage = GetCoverImage(firstFile); @@ -88,19 +91,7 @@ namespace API.Services if (firstChapter == null) return; - // Skip calculating Cover Image (I/O) if the chapter already has it set - if (!firstChapter.CoverImageLocked && ShouldFindCoverImage(firstChapter.CoverImage, forceUpdate)) - { - // NOTE: Why do I do this? By the time this method gets executed, the chapter has already been calculated for - // Plus how can we have a volume without at least 1 chapter? - var firstFile = firstChapter.Files.OrderBy(x => x.Chapter).FirstOrDefault(); - if (firstFile != null && !new FileInfo(firstFile.FilePath).IsLastWriteLessThan(firstFile.LastModified)) - { - firstChapter.CoverImage = GetCoverImage(firstFile); - } - } volume.CoverImage = firstChapter.CoverImage; - } /// diff --git a/API/Services/TaskScheduler.cs b/API/Services/TaskScheduler.cs index 1a96014ac..d3f61e545 100644 --- a/API/Services/TaskScheduler.cs +++ b/API/Services/TaskScheduler.cs @@ -119,7 +119,6 @@ namespace API.Services BackgroundJob.Enqueue(() => _cleanupService.Cleanup()); } - public void CleanupChapters(int[] chapterIds) { BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); diff --git a/API/Services/Tasks/ScannerService.cs b/API/Services/Tasks/ScannerService.cs index f54366d21..463c42007 100644 --- a/API/Services/Tasks/ScannerService.cs +++ b/API/Services/Tasks/ScannerService.cs @@ -74,7 +74,7 @@ namespace API.Services.Tasks totalFiles, parsedSeries.Keys.Count, sw.ElapsedMilliseconds + scanElapsedTime, series.Name); CleanupDbEntities(); - BackgroundJob.Enqueue(() => _metadataService.RefreshMetadata(libraryId, forceUpdate)); + BackgroundJob.Enqueue(() => _metadataService.RefreshMetadataForSeries(libraryId, seriesId)); BackgroundJob.Enqueue(() => _cacheService.CleanupChapters(chapterIds)); } else @@ -132,11 +132,14 @@ namespace API.Services.Tasks { ScanLibrary(lib.Id, false); } + } /// - /// Scans a library for file changes. If force update passed, all entities will be rechecked for new cover images and comicInfo.xml changes. + /// Scans a library for file changes. + /// Will kick off a scheduled background task to refresh metadata, + /// ie) all entities will be rechecked for new cover images and comicInfo.xml changes /// /// /// diff --git a/API/Services/Tasks/VersionUpdaterService.cs b/API/Services/Tasks/VersionUpdaterService.cs index bed687539..5b3607ffc 100644 --- a/API/Services/Tasks/VersionUpdaterService.cs +++ b/API/Services/Tasks/VersionUpdaterService.cs @@ -42,7 +42,7 @@ namespace API.Services.Tasks { public override HttpMessageHandler CreateMessageHandler() { return new HttpClientHandler { - ServerCertificateCustomValidationCallback = (a, b, c, d) => true + ServerCertificateCustomValidationCallback = (_, _, _, _) => true }; } } @@ -87,7 +87,7 @@ namespace API.Services.Tasks return updates.Select(CreateDto); } - private UpdateNotificationDto? CreateDto(GithubReleaseMetadata update) + private UpdateNotificationDto CreateDto(GithubReleaseMetadata update) { if (update == null || string.IsNullOrEmpty(update.Tag_Name)) return null; var version = update.Tag_Name.Replace("v", string.Empty); diff --git a/API/Startup.cs b/API/Startup.cs index d4f97e320..cfdae2d9d 100644 --- a/API/Startup.cs +++ b/API/Startup.cs @@ -49,7 +49,7 @@ namespace API services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "Kavita API", Version = "v1" }); - var filePath = Path.Combine(System.AppContext.BaseDirectory, "API.xml"); + var filePath = Path.Combine(AppContext.BaseDirectory, "API.xml"); c.IncludeXmlComments(filePath); }); services.AddResponseCompression(options => diff --git a/Kavita.Common/Configuration.cs b/Kavita.Common/Configuration.cs index 1ea788bc8..3de83b62c 100644 --- a/Kavita.Common/Configuration.cs +++ b/Kavita.Common/Configuration.cs @@ -8,7 +8,7 @@ namespace Kavita.Common { public static class Configuration { - private static string AppSettingsFilename = GetAppSettingFilename(); + private static readonly string AppSettingsFilename = GetAppSettingFilename(); public static string Branch { get => GetBranch(GetAppSettingFilename()); @@ -53,6 +53,7 @@ namespace Kavita.Common var json = File.ReadAllText(filePath); var jsonObj = JsonSerializer.Deserialize(json); const string key = "TokenKey"; + if (jsonObj == null) return string.Empty; if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) { @@ -69,7 +70,7 @@ namespace Kavita.Common return string.Empty; } - private static bool SetJwtToken(string filePath, string token) + private static void SetJwtToken(string filePath, string token) { try { @@ -77,53 +78,37 @@ namespace Kavita.Common var json = File.ReadAllText(filePath) .Replace("\"TokenKey\": \"" + currentToken, "\"TokenKey\": \"" + token); File.WriteAllText(filePath, json); - return true; } catch (Exception) { - return false; + /* Swallow exception */ } } public static bool CheckIfJwtTokenSet() { - //string filePath - try - { - return GetJwtToken(GetAppSettingFilename()) != "super secret unguessable key"; - } - catch (Exception ex) - { - Console.WriteLine("Error writing app settings: " + ex.Message); - } + try + { + return GetJwtToken(GetAppSettingFilename()) != "super secret unguessable key"; + } + catch (Exception ex) + { + Console.WriteLine("Error writing app settings: " + ex.Message); + } - return false; + return false; } - public static bool UpdateJwtToken(string token) - { - try - { - var filePath = GetAppSettingFilename(); - var json = File.ReadAllText(filePath).Replace("super secret unguessable key", token); - File.WriteAllText(GetAppSettingFilename(), json); - return true; - } - catch (Exception) - { - return false; - } - } #endregion #region Port - public static bool SetPort(string filePath, int port) + private static void SetPort(string filePath, int port) { if (new OsInfo(Array.Empty()).IsDocker) { - return true; + return; } try @@ -131,15 +116,14 @@ namespace Kavita.Common var currentPort = GetPort(filePath); var json = File.ReadAllText(filePath).Replace("\"Port\": " + currentPort, "\"Port\": " + port); File.WriteAllText(filePath, json); - return true; } catch (Exception) { - return false; + /* Swallow Exception */ } } - public static int GetPort(string filePath) + private static int GetPort(string filePath) { const int defaultPort = 5000; if (new OsInfo(Array.Empty()).IsDocker) @@ -152,6 +136,7 @@ namespace Kavita.Common var json = File.ReadAllText(filePath); var jsonObj = JsonSerializer.Deserialize(json); const string key = "Port"; + if (jsonObj == null) return defaultPort; if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) { @@ -170,7 +155,7 @@ namespace Kavita.Common #region LogLevel - public static bool SetLogLevel(string filePath, string logLevel) + private static void SetLogLevel(string filePath, string logLevel) { try { @@ -178,20 +163,21 @@ namespace Kavita.Common var json = File.ReadAllText(filePath) .Replace($"\"Default\": \"{currentLevel}\"", $"\"Default\": \"{logLevel}\""); File.WriteAllText(filePath, json); - return true; } catch (Exception) { - return false; + /* Swallow Exception */ } } - public static string GetLogLevel(string filePath) + private static string GetLogLevel(string filePath) { try { var json = File.ReadAllText(filePath); var jsonObj = JsonSerializer.Deserialize(json); + if (jsonObj == null) return string.Empty; + if (jsonObj.TryGetProperty("Logging", out JsonElement tokenElement)) { foreach (var property in tokenElement.EnumerateObject()) @@ -217,7 +203,7 @@ namespace Kavita.Common #endregion - public static string GetBranch(string filePath) + private static string GetBranch(string filePath) { const string defaultBranch = "main"; @@ -226,6 +212,7 @@ namespace Kavita.Common var json = File.ReadAllText(filePath); var jsonObj = JsonSerializer.Deserialize(json); const string key = "Branch"; + if (jsonObj == null) return string.Empty; if (jsonObj.TryGetProperty(key, out JsonElement tokenElement)) { @@ -240,7 +227,7 @@ namespace Kavita.Common return defaultBranch; } - public static bool SetBranch(string filePath, string updatedBranch) + private static void SetBranch(string filePath, string updatedBranch) { try { @@ -248,11 +235,10 @@ namespace Kavita.Common var json = File.ReadAllText(filePath) .Replace("\"Branch\": " + currentBranch, "\"Branch\": " + updatedBranch); File.WriteAllText(filePath, json); - return true; } catch (Exception) { - return false; + /* Swallow Exception */ } } } diff --git a/Kavita.Common/KavitaException.cs b/Kavita.Common/KavitaException.cs index ee4efcb5a..f7942c8b1 100644 --- a/Kavita.Common/KavitaException.cs +++ b/Kavita.Common/KavitaException.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.Serialization; namespace Kavita.Common { @@ -9,13 +10,16 @@ namespace Kavita.Common public class KavitaException : Exception { public KavitaException() - { - - } + { } public KavitaException(string message) : base(message) - { + { } - } + public KavitaException(string message, Exception inner) + : base(message, inner) { } + + protected KavitaException(SerializationInfo info, StreamingContext context) + : base(info, context) + { } } } diff --git a/UI/Web/src/app/app.component.ts b/UI/Web/src/app/app.component.ts index 26046d166..afb8d94b6 100644 --- a/UI/Web/src/app/app.component.ts +++ b/UI/Web/src/app/app.component.ts @@ -7,7 +7,7 @@ import { MessageHubService } from './_services/message-hub.service'; import { NavService } from './_services/nav.service'; import { PresenceHubService } from './_services/presence-hub.service'; import { StatsService } from './_services/stats.service'; -import 'rxjs/add/operator/filter'; +import { filter } from 'rxjs/operators'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; @Component({ @@ -23,7 +23,7 @@ export class AppComponent implements OnInit { // Close any open modals when a route change occurs router.events - .filter(event => event instanceof NavigationStart) + .pipe(filter(event => event instanceof NavigationStart)) .subscribe((event) => { if (this.ngbModal.hasOpenModals()) { this.ngbModal.dismissAll(); diff --git a/UI/Web/src/app/series-detail/series-detail.component.ts b/UI/Web/src/app/series-detail/series-detail.component.ts index 8010c710b..56b562fec 100644 --- a/UI/Web/src/app/series-detail/series-detail.component.ts +++ b/UI/Web/src/app/series-detail/series-detail.component.ts @@ -461,7 +461,7 @@ export class SeriesDetailComponent implements OnInit { }), finalize(() => { this.downloadInProgress = false; - })); + })).subscribe(() => {/* No Operation */});; }); } }