A ton of random bugs and polish (#3668)

This commit is contained in:
Joe Milazzo 2025-03-23 17:06:20 -05:00 committed by GitHub
parent b45d92ea5c
commit de651215f5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
144 changed files with 852 additions and 848 deletions

View file

@ -98,10 +98,10 @@
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="8.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Filters" Version="8.0.2" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.6.1" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.7.0" />
<PackageReference Include="System.IO.Abstractions" Version="22.0.12" />
<PackageReference Include="System.Drawing.Common" Version="9.0.3" />
<PackageReference Include="VersOne.Epub" Version="3.3.2" />
<PackageReference Include="VersOne.Epub" Version="3.3.3" />
<PackageReference Include="YamlDotNet" Version="16.3.0" />
</ItemGroup>

View file

@ -8,6 +8,7 @@ using API.Data.Repositories;
using API.DTOs;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Person;
using API.Extensions;
using API.Helpers;
using API.Services;

View file

@ -351,27 +351,6 @@ public class LibraryController : BaseApiController
return Ok();
}
[Authorize(Policy = "RequireAdminRole")]
[HttpPost("analyze")]
public ActionResult Analyze(int libraryId)
{
_taskScheduler.AnalyzeFilesForLibrary(libraryId, true);
return Ok();
}
[Authorize(Policy = "RequireAdminRole")]
[HttpPost("analyze-multiple")]
public ActionResult AnalyzeMultiple(BulkActionDto dto)
{
foreach (var libraryId in dto.Ids)
{
_taskScheduler.AnalyzeFilesForLibrary(libraryId, dto.Force ?? false);
}
return Ok();
}
/// <summary>
/// Copy the library settings (adv tab + optional type) to a set of other libraries.
/// </summary>

View file

@ -9,7 +9,6 @@ using API.DTOs.ReadingLists;
using API.Extensions;
using API.Helpers;
using API.Services;
using API.SignalR;
using Kavita.Common;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@ -39,7 +38,7 @@ public class ReadingListController : BaseApiController
/// <param name="readingListId"></param>
/// <returns></returns>
[HttpGet]
public async Task<ActionResult<ReadingListDto?>> GetList(int readingListId)
public async Task<ActionResult<ReadingListDto>> GetList(int readingListId)
{
var readingList = await _unitOfWork.ReadingListRepository.GetReadingListDtoByIdAsync(readingListId, User.GetUserId());
if (readingList == null)
@ -268,7 +267,7 @@ public class ReadingListController : BaseApiController
var readingList = user.ReadingLists.SingleOrDefault(l => l.Id == dto.ReadingListId);
if (readingList == null) return BadRequest(await _localizationService.Translate(User.GetUserId(), "reading-list-doesnt-exist"));
var chapterIdsForSeries =
await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync(new [] {dto.SeriesId});
await _unitOfWork.SeriesRepository.GetChapterIdsForSeriesAsync([dto.SeriesId]);
// If there are adds, tell tracking this has been modified
if (await _readingListService.AddChaptersToReadingList(dto.SeriesId, chapterIdsForSeries, readingList))

View file

@ -54,7 +54,7 @@ public class ScrobblingController : BaseApiController
}
/// <summary>
/// Get the current user's MAL token & username
/// Get the current user's MAL token and username
/// </summary>
/// <returns></returns>
[HttpGet("mal-token")]

View file

@ -2,6 +2,7 @@
using System.ComponentModel.DataAnnotations;
namespace API.DTOs.Account;
#nullable enable
public record UpdateUserDto
{

View file

@ -5,6 +5,7 @@ using API.Entities.Enums;
using API.Entities.Interfaces;
namespace API.DTOs;
#nullable enable
/// <summary>
/// A Chapter is the lowest grouping of a reading medium. A Chapter contains a set of MangaFiles which represents the underlying
@ -188,8 +189,8 @@ public class ChapterDto : IHasReadTimeEstimate, IHasCoverImage
#endregion
public string CoverImage { get; set; }
public string PrimaryColor { get; set; }
public string SecondaryColor { get; set; }
public string PrimaryColor { get; set; } = string.Empty;
public string SecondaryColor { get; set; } = string.Empty;
public void ResetColorScape()
{

View file

@ -1,4 +1,5 @@
namespace API.DTOs.Collection;
#nullable enable
/// <summary>
/// Represents an Interest Stack from MAL

View file

@ -1,4 +1,5 @@
namespace API.DTOs;
#nullable enable
/// <summary>
/// A primary and secondary color

View file

@ -1,6 +1,7 @@
using API.DTOs.Scrobbling;
namespace API.DTOs.KavitaPlus.ExternalMetadata;
#nullable enable
/// <summary>
/// Used for matching and fetching metadata on a series

View file

@ -2,6 +2,7 @@
using API.DTOs.Scrobbling;
namespace API.DTOs.KavitaPlus.ExternalMetadata;
#nullable enable
internal class MatchSeriesRequestDto
{

View file

@ -1,4 +1,5 @@
namespace API.DTOs.KavitaPlus.License;
#nullable enable
public class EncryptLicenseDto
{

View file

@ -1,4 +1,5 @@
namespace API.DTOs.KavitaPlus.License;
#nullable enable
public class UpdateLicenseDto
{

View file

@ -1,4 +1,5 @@
namespace API.DTOs.KavitaPlus.Metadata;
#nullable enable
public enum CharacterRole
{

View file

@ -2,6 +2,7 @@
using API.Entities.Enums;
namespace API.DTOs;
#nullable enable
public class MangaFileDto
{

View file

@ -1,4 +1,7 @@
using System.Runtime.Serialization;
namespace API.DTOs;
#nullable enable
public class PersonDto
{
@ -6,12 +9,12 @@ public class PersonDto
public required string Name { get; set; }
public bool CoverImageLocked { get; set; }
public string PrimaryColor { get; set; }
public string SecondaryColor { get; set; }
public string? PrimaryColor { get; set; }
public string? SecondaryColor { get; set; }
public string? CoverImage { get; set; }
public string Description { get; set; }
public string? Description { get; set; }
/// <summary>
/// ASIN for person
/// </summary>

View file

@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
namespace API.DTOs;
#nullable enable
public class UpdatePersonDto
{

View file

@ -1,4 +1,5 @@
namespace API.DTOs.Reader;
#nullable enable
public class CreatePersonalToCDto
{

View file

@ -2,6 +2,7 @@
using API.Services.Plus;
namespace API.DTOs.Scrobbling;
#nullable enable
public record MediaRecommendationDto
{

View file

@ -1,4 +1,5 @@
namespace API.DTOs.Scrobbling;
#nullable enable
/// <summary>
/// Represents information about a potential Series for Kavita+

View file

@ -1,6 +1,7 @@
using System;
namespace API.DTOs.Scrobbling;
#nullable enable
public class ScrobbleEventDto
{

View file

@ -2,6 +2,7 @@
using API.DTOs.Recommendation;
namespace API.DTOs.SeriesDetail;
#nullable enable
/// <summary>
/// All the data from Kavita+ for Series Detail

View file

@ -79,8 +79,8 @@ public class SeriesDto : IHasReadTimeEstimate, IHasCoverImage
#endregion
public string? CoverImage { get; set; }
public string PrimaryColor { get; set; }
public string SecondaryColor { get; set; }
public string PrimaryColor { get; set; } = string.Empty;
public string SecondaryColor { get; set; } = string.Empty;
public void ResetColorScape()
{

View file

@ -3,6 +3,7 @@ using API.Entities.Enums;
using API.Services;
namespace API.DTOs.Settings;
#nullable enable
public class ServerSettingDto
{

View file

@ -2,6 +2,7 @@
using API.Entities.Enums;
namespace API.DTOs.SideNav;
#nullable enable
public class SideNavStreamDto
{

View file

@ -1,6 +1,7 @@
using API.Entities.Enums;
namespace API.DTOs;
#nullable enable
/// <summary>
/// Used on Person Profile page

View file

@ -1,6 +1,7 @@
using System;
namespace API.DTOs.Statistics;
#nullable enable
/// <summary>
/// Represents a single User's reading event

View file

@ -2,6 +2,7 @@
using System.Collections.Generic;
namespace API.DTOs.Statistics;
#nullable enable
public class UserReadStatistics
{

View file

@ -1,6 +1,7 @@
using System;
namespace API.DTOs.Stats;
#nullable enable
/// <summary>
/// This is just for the Server tab on UI

View file

@ -1,4 +1,5 @@
namespace API.DTOs;
#nullable enable
/// <summary>
/// This is explicitly for Tachiyomi. Number field was removed in v0.8.0, but Tachiyomi needs it for the hacks.

View file

@ -1,4 +1,5 @@
namespace API.DTOs;
#nullable enable
public class UpdateSeriesDto
{

View file

@ -5,6 +5,7 @@ using API.Entities.Enums;
using API.Entities.Enums.UserPreferences;
namespace API.DTOs;
#nullable enable
public class UserPreferencesDto
{

View file

@ -66,8 +66,8 @@ public class VolumeDto : IHasReadTimeEstimate, IHasCoverImage
public string CoverImage { get; set; }
private bool CoverImageLocked { get; set; }
public string PrimaryColor { get; set; }
public string SecondaryColor { get; set; }
public string PrimaryColor { get; set; } = string.Empty;
public string SecondaryColor { get; set; } = string.Empty;
public void ResetColorScape()
{

View file

@ -12,6 +12,7 @@ using API.Entities.History;
using API.Entities.Interfaces;
using API.Entities.Metadata;
using API.Entities.MetadataMatching;
using API.Entities.Person;
using API.Entities.Scrobble;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;

View file

@ -16,6 +16,7 @@ using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface IAppUserProgressRepository
{
void Update(AppUserProgress userProgress);
@ -41,7 +42,7 @@ public interface IAppUserProgressRepository
Task UpdateAllProgressThatAreMoreThanChapterPages();
Task<IList<FullProgressDto>> GetUserProgressForChapter(int chapterId, int userId = 0);
}
#nullable disable
public class AppUserProgressRepository : IAppUserProgressRepository
{
private readonly DataContext _context;

View file

@ -4,6 +4,7 @@ using System.IO;
using System.Linq;
using API.DTOs.CoverDb;
using API.Entities;
using API.Entities.Person;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

View file

@ -12,6 +12,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface IGenreRepository
{

View file

@ -9,6 +9,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface IMediaErrorRepository
{

View file

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using API.DTOs;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Person;
using API.Extensions;
using API.Extensions.QueryExtensions;
using API.Helpers;
@ -14,6 +15,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface IPersonRepository
{

View file

@ -17,6 +17,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
[Flags]
public enum ReadingListIncludes

View file

@ -12,6 +12,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface IScrobbleRepository
{

View file

@ -39,6 +39,7 @@ using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
[Flags]
public enum SeriesIncludes

View file

@ -13,6 +13,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface ISettingsRepository
{

View file

@ -8,6 +8,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface ISiteThemeRepository
{

View file

@ -11,6 +11,7 @@ using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
public interface ITagRepository
{

View file

@ -23,6 +23,7 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
[Flags]
public enum AppUserIncludes

View file

@ -15,6 +15,7 @@ using Kavita.Common;
using Microsoft.EntityFrameworkCore;
namespace API.Data.Repositories;
#nullable enable
[Flags]
public enum VolumeIncludes

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using API.Entities.Enums;
using API.Entities.Interfaces;
using API.Entities.Person;
using API.Extensions;
using API.Services.Tasks.Scanner.Parser;

View file

@ -12,7 +12,7 @@ public enum LibraryType
/// <summary>
/// Uses Comic regex for filename parsing
/// </summary>
[Description("Comic")]
[Description("Comic (Legacy)")]
Comic = 1,
/// <summary>
/// Uses Manga regex for filename parsing also uses epub metadata
@ -30,8 +30,8 @@ public enum LibraryType
[Description("Light Novel")]
LightNovel = 4,
/// <summary>
/// Uses Comic regex for filename parsing, uses Comic Vine type of Parsing. Will replace Comic type in future
/// Uses Comic regex for filename parsing, uses Comic Vine type of Parsing
/// </summary>
[Description("Comic (Comic Vine)")]
[Description("Comic")]
ComicVine = 5,
}

View file

@ -4,6 +4,7 @@ using System.ComponentModel.DataAnnotations;
using System.Linq;
using API.Entities.Enums;
using API.Entities.Interfaces;
using API.Entities.Person;
using Microsoft.EntityFrameworkCore;
namespace API.Entities.Metadata;

View file

@ -1,6 +1,6 @@
using API.Entities.Enums;
namespace API.Entities;
namespace API.Entities.Person;
public class ChapterPeople
{

View file

@ -1,10 +1,7 @@
using System.Collections.Generic;
using API.Entities.Enums;
using API.Entities.Interfaces;
using API.Entities.Metadata;
using API.Services.Plus;
namespace API.Entities;
namespace API.Entities.Person;
public class Person : IHasCoverImage
{

View file

@ -1,8 +1,7 @@
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Services.Plus;
namespace API.Entities;
namespace API.Entities.Person;
public class SeriesMetadataPeople
{

View file

@ -4,6 +4,7 @@ using Kavita.Common;
using Kavita.Common.EnvironmentInfo;
namespace API.Extensions;
#nullable enable
public static class FlurlExtensions
{

View file

@ -4,7 +4,7 @@ using API.Data.Misc;
using API.Data.Repositories;
using API.Entities;
using API.Entities.Metadata;
using AutoMapper.QueryableExtensions;
using API.Entities.Person;
using Microsoft.EntityFrameworkCore;
namespace API.Extensions.QueryExtensions.Filtering;

View file

@ -3,6 +3,7 @@ using System.Linq;
using API.Data.Misc;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Person;
namespace API.Extensions.QueryExtensions;
#nullable enable

View file

@ -30,6 +30,7 @@ using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Entities.MetadataMatching;
using API.Entities.Person;
using API.Entities.Scrobble;
using API.Extensions.QueryExtensions.Filtering;
using API.Helpers.Converters;

View file

@ -4,6 +4,7 @@ using System.Globalization;
using System.IO;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Person;
using API.Services.Tasks.Scanner.Parser;
namespace API.Helpers.Builders;

View file

@ -2,6 +2,7 @@
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions;
namespace API.Helpers.Builders;

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Entities.Person;
namespace API.Helpers.Builders;

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using API.Data;
@ -7,6 +6,7 @@ using API.DTOs;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions;
using API.Helpers.Builders;

View file

@ -56,9 +56,6 @@ public class Program
Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty);
}
Configuration.KavitaPlusApiUrl = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == Environments.Development
? "http://localhost:5020" : "https://plus.kavitareader.com";
try
{
var host = CreateHostBuilder(args).Build();

View file

@ -73,12 +73,27 @@ public class BookService : IBookService
private const string BookApiUrl = "book-resources?file=";
private readonly PdfComicInfoExtractor _pdfComicInfoExtractor;
/// <summary>
/// Setup the most lenient book parsing options possible as people have some really bad epubs
/// </summary>
public static readonly EpubReaderOptions BookReaderOptions = new()
{
PackageReaderOptions = new PackageReaderOptions
{
IgnoreMissingToc = true,
SkipInvalidManifestItems = true
SkipInvalidManifestItems = true,
},
Epub2NcxReaderOptions = new Epub2NcxReaderOptions
{
IgnoreMissingContentForNavigationPoints = true
},
SpineReaderOptions = new SpineReaderOptions
{
IgnoreMissingManifestItems = true
},
BookCoverReaderOptions = new BookCoverReaderOptions
{
Epub2MetadataIgnoreMissingManifestItem = true
}
};

View file

@ -11,6 +11,7 @@ using API.DTOs.SeriesDetail;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions;
using API.Helpers;
using API.Helpers.Builders;
@ -73,7 +74,7 @@ public class SeriesService : ISeriesService
}
/// <summary>
/// Returns the first chapter for a series to extract metadata from (ie Summary, etc)
/// Returns the first chapter for a series to extract metadata from (ie Summary, etc.)
/// </summary>
/// <param name="series">The full series with all volumes and chapters on it</param>
/// <returns></returns>
@ -324,7 +325,7 @@ public class SeriesService : ISeriesService
await _unitOfWork.CommitAsync();
// Trigger code to cleanup tags, collections, people, etc
// Trigger code to clean up tags, collections, people, etc
try
{
await _taskScheduler.CleanupDbEntries();
@ -915,19 +916,19 @@ public class SeriesService : ISeriesService
// Calculate the time differences between consecutive chapters
var timeDifferences = new List<TimeSpan>();
DateTime? previousChapterTime = null;
foreach (var chapter in chapters)
foreach (var chapterCreatedUtc in chapters.Select(c => c.CreatedUtc))
{
if (previousChapterTime.HasValue && (chapter.CreatedUtc - previousChapterTime.Value) <= TimeSpan.FromHours(1))
if (previousChapterTime.HasValue && (chapterCreatedUtc - previousChapterTime.Value) <= TimeSpan.FromHours(1))
{
continue; // Skip this chapter if it's within an hour of the previous one
}
if ((chapter.CreatedUtc - previousChapterTime ?? TimeSpan.Zero) != TimeSpan.Zero)
if ((chapterCreatedUtc - previousChapterTime ?? TimeSpan.Zero) != TimeSpan.Zero)
{
timeDifferences.Add(chapter.CreatedUtc - previousChapterTime ?? TimeSpan.Zero);
timeDifferences.Add(chapterCreatedUtc - previousChapterTime ?? TimeSpan.Zero);
}
previousChapterTime = chapter.CreatedUtc;
previousChapterTime = chapterCreatedUtc;
}
if (timeDifferences.Count < minimumTimeDeltas)

View file

@ -34,7 +34,6 @@ public interface ITaskScheduler
void RefreshSeriesMetadata(int libraryId, int seriesId, bool forceUpdate = false, bool forceColorscape = false);
Task ScanSeries(int libraryId, int seriesId, bool forceUpdate = false);
void AnalyzeFilesForSeries(int libraryId, int seriesId, bool forceUpdate = false);
void AnalyzeFilesForLibrary(int libraryId, bool forceUpdate = false);
void CancelStatsTasks();
Task RunStatCollection();
void CovertAllCoversToEncoding();
@ -267,11 +266,6 @@ public class TaskScheduler : ITaskScheduler
RecurringJob.AddOrUpdate(ReportStatsTaskId, () => _statsService.Send(), Cron.Daily(Rnd.Next(0, 22)), RecurringJobOptions);
}
public void AnalyzeFilesForLibrary(int libraryId, bool forceUpdate = false)
{
_logger.LogInformation("Enqueuing library file analysis for: {LibraryId}", libraryId);
BackgroundJob.Enqueue(() => _wordCountAnalyzerService.ScanLibrary(libraryId, forceUpdate));
}
/// <summary>
/// Upon cancelling stat, we do report to the Stat service that we are no longer going to be reporting

View file

@ -8,6 +8,7 @@ using API.Data;
using API.Data.Repositories;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Person;
using API.Extensions;
using API.SignalR;
using EasyCaching.Core;

View file

@ -708,7 +708,7 @@ public static partial class Parser
return HasSpecialMarker(filePath);
}
public static string ParseMangaSeries(string filename)
private static string ParseMangaSeries(string filename)
{
foreach (var regex in MangaSeriesRegex)
{
@ -716,6 +716,7 @@ public static partial class Parser
var group = matches
.Select(match => match.Groups["Series"])
.FirstOrDefault(group => group.Success && group != Match.Empty);
if (group != null)
{
return CleanTitle(group.Value);

View file

@ -11,6 +11,7 @@ using API.Data.Repositories;
using API.Entities;
using API.Entities.Enums;
using API.Entities.Metadata;
using API.Entities.Person;
using API.Extensions;
using API.Helpers;
using API.Helpers.Builders;

View file

@ -302,7 +302,8 @@ public class ThemeService : IThemeService
var existingThemes = _directoryService.ScanFiles(_directoryService.SiteThemeDirectory, string.Empty);
if (existingThemes.Any(f => Path.GetFileName(f) == dto.CssFile))
{
throw new KavitaException("Cannot download file, file already on disk");
// This can happen if you delete then immediately download (to refresh). We should just delete the old file and download. Users can always rollback their version with github directly
_directoryService.DeleteFiles(existingThemes.Where(f => Path.GetFileName(f) == dto.CssFile));
}
var finalLocation = await DownloadSiteTheme(dto);

View file

@ -346,7 +346,7 @@ public partial class VersionUpdaterService : IVersionUpdaterService
if (DateTime.UtcNow - fileInfo.LastWriteTimeUtc <= CacheDuration)
{
var cachedData = await File.ReadAllTextAsync(_cacheFilePath);
return System.Text.Json.JsonSerializer.Deserialize<IList<UpdateNotificationDto>>(cachedData);
return JsonSerializer.Deserialize<IList<UpdateNotificationDto>>(cachedData);
}
return null;

View file

@ -41,6 +41,7 @@ using Microsoft.Extensions.Logging;
using Microsoft.Net.Http.Headers;
using Microsoft.OpenApi.Models;
using Serilog;
using Swashbuckle.AspNetCore.SwaggerGen;
using TaskScheduler = API.Services.TaskScheduler;
namespace API;
@ -138,8 +139,8 @@ public class Startup
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "3.1.0",
Title = "Kavita",
Description = $"Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v{BuildInfo.Version.ToString()}",
Title = $"Kavita (v{BuildInfo.Version})",
Description = $"Kavita provides a set of APIs that are authenticated by JWT. JWT token can be copied from local storage. Assume all fields of a payload are required. Built against v{BuildInfo.Version}",
License = new OpenApiLicense
{
Name = "GPL-3.0",