Temp commit to record attempts. Stream APIs are implemented and working. Added some new test cases based on deployed Kavita server testing.

This commit is contained in:
Joseph Milazzo 2021-03-17 14:29:50 -05:00
parent 55cd0c5fe5
commit 0a85555f38
16 changed files with 247 additions and 90 deletions

View File

@ -49,6 +49,7 @@ namespace API.Tests
[InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "0")] [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 12", "0")]
[InlineData("VanDread-v01-c001[MD].zip", "1")] [InlineData("VanDread-v01-c001[MD].zip", "1")]
[InlineData("Ichiban_Ushiro_no_Daimaou_v04_ch27_[VISCANS].zip", "4")] [InlineData("Ichiban_Ushiro_no_Daimaou_v04_ch27_[VISCANS].zip", "4")]
[InlineData("Mob Psycho 100 v02 (2019) (Digital) (Shizu).cbz", "2")]
public void ParseVolumeTest(string filename, string expected) public void ParseVolumeTest(string filename, string expected)
{ {
Assert.Equal(expected, ParseVolume(filename)); Assert.Equal(expected, ParseVolume(filename));
@ -100,6 +101,9 @@ namespace API.Tests
[InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09", "Kedouin Makoto - Corpse Party Musume")] [InlineData("Kedouin Makoto - Corpse Party Musume, Chapter 09", "Kedouin Makoto - Corpse Party Musume")]
[InlineData("Goblin Slayer Side Story - Year One 025.5", "Goblin Slayer Side Story - Year One")] [InlineData("Goblin Slayer Side Story - Year One 025.5", "Goblin Slayer Side Story - Year One")]
[InlineData("Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire)", "Goblin Slayer - Brand New Day")] [InlineData("Goblin Slayer - Brand New Day 006.5 (2019) (Digital) (danke-Empire)", "Goblin Slayer - Brand New Day")]
[InlineData("Yumekui-Merry_DKThias_Chapter11v2.zip", "Yumekui-Merry")]
[InlineData("Yumekui-Merry DKThiasScanlations Chapter51v2", "Yumekui-Merry")]
[InlineData("Yumekui-Merry_DKThiasScanlations&RenzokuseiScans_Chapter61", "Yumekui-Merry")]
public void ParseSeriesTest(string filename, string expected) public void ParseSeriesTest(string filename, string expected)
{ {
Assert.Equal(expected, ParseSeries(filename)); Assert.Equal(expected, ParseSeries(filename));
@ -130,6 +134,7 @@ namespace API.Tests
[InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "1")] [InlineData("Yumekui_Merry_v01_c01[Bakayarou-Kuu].rar", "1")]
[InlineData("Yumekui-Merry_DKThias_Chapter11v2.zip", "11")] [InlineData("Yumekui-Merry_DKThias_Chapter11v2.zip", "11")]
[InlineData("Yumekui-Merry DKThiasScanlations Chapter51v2", "51")] [InlineData("Yumekui-Merry DKThiasScanlations Chapter51v2", "51")]
[InlineData("Yumekui-Merry_DKThiasScanlations&RenzokuseiScans_Chapter61", "61")]
[InlineData("Goblin Slayer Side Story - Year One 017.5", "17.5")] [InlineData("Goblin Slayer Side Story - Year One 017.5", "17.5")]
[InlineData("Beelzebub_53[KSH].zip", "53")] [InlineData("Beelzebub_53[KSH].zip", "53")]
[InlineData("Black Bullet - v4 c20.5 [batoto]", "20.5")] [InlineData("Black Bullet - v4 c20.5 [batoto]", "20.5")]
@ -139,7 +144,7 @@ namespace API.Tests
[InlineData("Vol 1", "0")] [InlineData("Vol 1", "0")]
[InlineData("VanDread-v01-c001[MD].zip", "1")] [InlineData("VanDread-v01-c001[MD].zip", "1")]
[InlineData("Goblin Slayer Side Story - Year One 025.5", "25.5")] [InlineData("Goblin Slayer Side Story - Year One 025.5", "25.5")]
//[InlineData("[Tempus Edax Rerum] Epigraph of the Closed Curve - Chapter 6.zip", "6")] [InlineData("Mob Psycho 100 v02 (2019) (Digital) (Shizu).cbz", "0")]
public void ParseChaptersTest(string filename, string expected) public void ParseChaptersTest(string filename, string expected)
{ {
Assert.Equal(expected, ParseChapter(filename)); Assert.Equal(expected, ParseChapter(filename));

View File

@ -6,12 +6,17 @@
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild> <EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
<DebugSymbols>false</DebugSymbols>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.0" /> <PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="8.1.0" />
<PackageReference Include="Hangfire" Version="1.7.18" /> <PackageReference Include="Hangfire" Version="1.7.18" />
<PackageReference Include="Hangfire.AspNetCore" Version="1.7.18" /> <PackageReference Include="Hangfire.AspNetCore" Version="1.7.18" />
<PackageReference Include="Hangfire.LiteDB" Version="0.4.0" /> <PackageReference Include="Hangfire.LiteDB" Version="0.4.0" />
<PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" /> <PackageReference Include="Hangfire.MaximumConcurrentExecutions" Version="1.1.0" />
<PackageReference Include="Hangfire.MemoryStorage.Core" Version="1.4.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" NoWarn="NU1605" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.1" NoWarn="NU1605" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.1" NoWarn="NU1605" /> <PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="5.0.1" NoWarn="NU1605" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.1" /> <PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="5.0.1" />

View File

@ -2,15 +2,26 @@
namespace API.Comparators namespace API.Comparators
{ {
public class ChapterSortComparer : IComparer<int> public class ChapterSortComparer : IComparer<float>
{ {
public int Compare(int x, int y) // public int Compare(int x, int y)
// {
// if (x == 0 && y == 0) return 0;
// // if x is 0, it comes second
// if (x == 0) return 1;
// // if y is 0, it comes second
// if (y == 0) return -1;
//
// return x.CompareTo(y);
// }
public int Compare(float x, float y)
{ {
if (x == 0 && y == 0) return 0; if (x == 0.0 && y == 0.0) return 0;
// if x is 0, it comes second // if x is 0, it comes second
if (x == 0) return 1; if (x == 0.0) return 1;
// if y is 0, it comes second // if y is 0, it comes second
if (y == 0) return -1; if (y == 0.0) return -1;
return x.CompareTo(y); return x.CompareTo(y);
} }

View File

@ -140,6 +140,15 @@ namespace API.Controllers
return Ok(await _unitOfWork.SeriesRepository.GetInProgress(user.Id, libraryId, limit)); return Ok(await _unitOfWork.SeriesRepository.GetInProgress(user.Id, libraryId, limit));
} }
[HttpGet("continue-reading")]
public async Task<ActionResult<IEnumerable<SeriesDto>>> GetContinueReading(int libraryId = 0, int limit = 20)
{
var user = await _unitOfWork.UserRepository.GetUserByUsernameAsync(User.GetUsername());
return Ok(await _unitOfWork.VolumeRepository.GetContinueReading(user.Id, libraryId, limit));
}
} }
} }

View File

@ -0,0 +1,23 @@
namespace API.DTOs
{
public class InProgressChapterDto
{
public int Id { get; init; }
/// <summary>
/// Range of chapters. Chapter 2-4 -> "2-4". Chapter 2 -> "2".
/// </summary>
public string Range { get; init; }
/// <summary>
/// Smallest number of the Range.
/// </summary>
public string Number { get; init; }
/// <summary>
/// Total number of pages in all MangaFiles
/// </summary>
public int Pages { get; init; }
public int SeriesId { get; init; }
public int LibraryId { get; init; }
public string SeriesName { get; init; }
}
}

View File

@ -21,5 +21,7 @@
/// Review from logged in user. Calculated at API-time. /// Review from logged in user. Calculated at API-time.
/// </summary> /// </summary>
public string UserReview { get; set; } public string UserReview { get; set; }
public int LibraryId { get; set; }
} }
} }

View File

@ -280,87 +280,52 @@ namespace API.Data
} }
/// <summary> /// <summary>
/// Returns a list of Series that were added within 2 weeks. /// Returns a list of Series that were added, ordered by Created desc
/// </summary> /// </summary>
/// <param name="libraryId">Library to restrict to, if 0, will apply to all libraries</param> /// <param name="libraryId">Library to restrict to, if 0, will apply to all libraries</param>
/// <param name="limit"></param> /// <param name="limit">How many series to pick.</param>
/// <returns></returns> /// <returns></returns>
public async Task<IEnumerable<SeriesDto>> GetRecentlyAdded(int libraryId, int limit) public async Task<IEnumerable<SeriesDto>> GetRecentlyAdded(int libraryId, int limit)
{ {
// TODO: Remove 2 week condition
var twoWeeksAgo = DateTime.Today.Subtract(TimeSpan.FromDays(14));
_logger.LogDebug("2 weeks from today is: {Date}", twoWeeksAgo);
return await _context.Series return await _context.Series
.Where(s => s.Created > twoWeeksAgo && (libraryId <= 0 || s.LibraryId == libraryId)) .Where(s => (libraryId <= 0 || s.LibraryId == libraryId))
.Take(limit) .Take(limit)
.OrderBy(s => s.Created) .OrderByDescending(s => s.Created)
.AsNoTracking() .AsNoTracking()
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider) .ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
.ToListAsync(); .ToListAsync();
} }
/// <summary>
///
/// </summary>
/// <param name="userId"></param>
/// <param name="libraryId"></param>
/// <param name="limit"></param>
/// <returns></returns>
public async Task<IEnumerable<SeriesDto>> GetInProgress(int userId, int libraryId, int limit) public async Task<IEnumerable<SeriesDto>> GetInProgress(int userId, int libraryId, int limit)
{ {
//&& (libraryId <= 0 || s.Series.LibraryId == libraryId) //var twoWeeksAgo = DateTime.Today.Subtract(TimeSpan.FromDays(14)); // TODO: Think about moving this to a setting
var twoWeeksAgo = DateTime.Today.Subtract(TimeSpan.FromDays(14));
_logger.LogInformation("GetInProgress");
_logger.LogDebug("2 weeks from today is: {Date}", twoWeeksAgo);
// var series = await _context.Series
// .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new
// {
// Series = s,
// Progress = progress
// })
// .DefaultIfEmpty()
// .Where(s => s.Series.Created > twoWeeksAgo
// && s.Progress.AppUserId == userId
// && s.Progress.PagesRead > s.Series.Pages)
// .Take(limit)
// .OrderBy(s => s.Series.Created)
// .AsNoTracking()
// .Select(s => s.Series)
// .ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
// .ToListAsync();
var series = await _context.Series var series = await _context.Series
.Where(s => s.Created > twoWeeksAgo) // && (libraryId <= 0 || s.LibraryId == libraryId) .Join(_context.AppUserProgresses, s => s.Id, progress => progress.SeriesId, (s, progress) => new
.AsNoTracking() {
.ProjectTo<SeriesDto>(_mapper.ConfigurationProvider) Series = s,
.ToListAsync(); progress.PagesRead,
progress.AppUserId,
await AddSeriesModifiers(userId, series); progress.LastModified
})
return series.Where(s => s.PagesRead > 0).Take(limit).ToList(); .Where(s => s.AppUserId == userId
} && s.PagesRead > 0
&& s.PagesRead < s.Series.Pages
&& (libraryId <= 0 || s.Series.LibraryId == libraryId) )
public async Task<IEnumerable<SeriesDto>> GetSeriesStream(int userId) .Take(limit)
{ .OrderByDescending(s => s.LastModified)
// Testing out In Progress to figure out how to design generalized solution .AsNoTracking()
var userProgress = await _context.AppUserProgresses .Select(s => s.Series)
.Where(p => p.AppUserId == userId && p.PagesRead > 0) .Distinct()
.AsNoTracking() .ProjectTo<SeriesDto>(_mapper.ConfigurationProvider)
.ToListAsync(); .ToListAsync();
if (!userProgress.Any()) return new SeriesDto[] {}; return series;
var seriesIds = userProgress.Select(p => p.SeriesId).ToList();
/*
*select P.*, S.Name, S.Pages from AppUserProgresses AS P
LEFT join Series as "S" on s.Id = P.SeriesId
where AppUserId = 1 AND P.PagesRead > 0 AND P.PagesRead < S.Pages
*
*/
// var series = await _context.Series
// .Where(s => seriesIds.Contains(s.Id) && s.Pages) // I need a join
return new SeriesDto[] {};
} }
} }
} }

View File

@ -12,21 +12,21 @@ namespace API.Data
private readonly DataContext _context; private readonly DataContext _context;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly UserManager<AppUser> _userManager; private readonly UserManager<AppUser> _userManager;
private readonly ILogger<UnitOfWork> _seriesLogger; private readonly ILogger<UnitOfWork> _logger;
public UnitOfWork(DataContext context, IMapper mapper, UserManager<AppUser> userManager, ILogger<UnitOfWork> seriesLogger) public UnitOfWork(DataContext context, IMapper mapper, UserManager<AppUser> userManager, ILogger<UnitOfWork> logger)
{ {
_context = context; _context = context;
_mapper = mapper; _mapper = mapper;
_userManager = userManager; _userManager = userManager;
_seriesLogger = seriesLogger; _logger = logger;
} }
public ISeriesRepository SeriesRepository => new SeriesRepository(_context, _mapper, _seriesLogger); public ISeriesRepository SeriesRepository => new SeriesRepository(_context, _mapper, _logger);
public IUserRepository UserRepository => new UserRepository(_context, _userManager); public IUserRepository UserRepository => new UserRepository(_context, _userManager);
public ILibraryRepository LibraryRepository => new LibraryRepository(_context, _mapper); public ILibraryRepository LibraryRepository => new LibraryRepository(_context, _mapper);
public IVolumeRepository VolumeRepository => new VolumeRepository(_context, _mapper); public IVolumeRepository VolumeRepository => new VolumeRepository(_context, _mapper, _logger);
public ISettingsRepository SettingsRepository => new SettingsRepository(_context, _mapper); public ISettingsRepository SettingsRepository => new SettingsRepository(_context, _mapper);

View File

@ -1,12 +1,15 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using API.Comparators;
using API.DTOs; using API.DTOs;
using API.Entities; using API.Entities;
using API.Extensions;
using API.Interfaces; using API.Interfaces;
using AutoMapper; using AutoMapper;
using AutoMapper.QueryableExtensions; using AutoMapper.QueryableExtensions;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
namespace API.Data namespace API.Data
{ {
@ -14,11 +17,13 @@ namespace API.Data
{ {
private readonly DataContext _context; private readonly DataContext _context;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly ILogger _logger;
public VolumeRepository(DataContext context, IMapper mapper) public VolumeRepository(DataContext context, IMapper mapper, ILogger logger)
{ {
_context = context; _context = context;
_mapper = mapper; _mapper = mapper;
_logger = logger;
} }
public void Update(Volume volume) public void Update(Volume volume)
@ -84,5 +89,95 @@ namespace API.Data
.AsNoTracking() .AsNoTracking()
.ToListAsync(); .ToListAsync();
} }
/// <summary>
/// Gets the first (ordered) volume/chapter in a series where the user has progress on it. Only completed volumes/chapters, next entity shouldn't
/// have any read progress on it.
/// </summary>
/// <param name="userId"></param>
/// <param name="libraryId"></param>
/// <param name="limit"></param>
/// <returns></returns>
public async Task<IEnumerable<InProgressChapterDto>> GetContinueReading(int userId, int libraryId, int limit)
{
_logger.LogInformation("Get Continue Reading");
var progress = await _context.Chapter
.Join(_context.AppUserProgresses, chapter => chapter.Id, progress => progress.ChapterId,
(chapter, progress) =>
new
{
Chapter = chapter,
Progress = progress
})
.Join(_context.Series, arg => arg.Progress.SeriesId, series => series.Id, (arg, series) =>
new
{
arg.Chapter,
arg.Progress,
Series = series
})
.AsNoTracking()
.Where(arg => arg.Progress.AppUserId == userId
&& arg.Progress.PagesRead < arg.Chapter.Pages)
.OrderByDescending(d => d.Progress.LastModified)
.Take(limit)
.ToListAsync();
return progress
.OrderBy(c => float.Parse(c.Chapter.Number), new ChapterSortComparer())
.DistinctBy(p => p.Series.Id)
.Select(arg => new InProgressChapterDto()
{
Id = arg.Chapter.Id,
Number = arg.Chapter.Number,
Range = arg.Chapter.Range,
SeriesId = arg.Progress.SeriesId,
SeriesName = arg.Series.Name,
LibraryId = arg.Series.LibraryId,
Pages = arg.Chapter.Pages,
});
// var chapters = await _context.Chapter
// .Join(_context.AppUserProgresses, chapter => chapter.Id, progress => progress.ChapterId, (chapter, progress) =>
// new
// {
// Chapter = chapter,
// Progress = progress
// })
// .Where(arg => arg.Progress.AppUserId == userId && arg.Progress.PagesRead < arg.Chapter.Pages)
// .Join(_context.Series, arg => arg.Progress.SeriesId, series => series.Id, (arg, series) =>
// new
// {
// arg.Chapter,
// arg.Progress,
// Series = series
// })
// .AsNoTracking()
// //.OrderBy(s => s.Chapter.Number)
// .GroupBy(p => p.Series.Id)
// .Select(g => g.FirstOrDefault())
// .Select(arg => new InProgressChapterDto()
// {
// Id = arg.Chapter.Id,
// Number = arg.Chapter.Number,
// Range = arg.Chapter.Range,
// SeriesId = arg.Progress.SeriesId,
// SeriesName = arg.Series.Name,
// LibraryId = arg.Series.LibraryId,
// Pages = arg.Chapter.Pages,
// })
//
// //.OrderBy(c => float.Parse(c.Number)) //can't convert to SQL
//
// .ToListAsync();
//
//
// return chapters;
// return chapters
// .OrderBy(c => float.Parse(c.Number), new ChapterSortComparer())
// .DistinctBy(c => c.SeriesName);
}
} }
} }

View File

@ -7,6 +7,7 @@ using API.Services.Tasks;
using AutoMapper; using AutoMapper;
using Hangfire; using Hangfire;
using Hangfire.LiteDB; using Hangfire.LiteDB;
using Hangfire.MemoryStorage;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -45,15 +46,7 @@ namespace API.Extensions
var loggingSection = config.GetSection("Logging"); var loggingSection = config.GetSection("Logging");
loggingBuilder.AddFile(loggingSection); loggingBuilder.AddFile(loggingSection);
}); });
services.AddHangfire(configuration => configuration
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseLiteDbStorage());
// Add the processing server as IHostedService
services.AddHangfireServer();
return services; return services;
} }

View File

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace API.Extensions
{
public static class EnumerableExtensions
{
public static IEnumerable<TSource> DistinctBy<TSource, TKey>
(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
var seenKeys = new HashSet<TKey>();
foreach (var element in source)
{
if (seenKeys.Add(keySelector(element)))
{
yield return element;
}
}
}
}
}

View File

@ -20,6 +20,7 @@ namespace API.Helpers
CreateMap<Chapter, ChapterDto>(); CreateMap<Chapter, ChapterDto>();
CreateMap<Series, SeriesDto>(); CreateMap<Series, SeriesDto>();
//CreateMap<Series, InProgressChapterDto>();
CreateMap<AppUserPreferences, UserPreferencesDto>(); CreateMap<AppUserPreferences, UserPreferencesDto>();

View File

@ -13,5 +13,6 @@ namespace API.Interfaces
Task<IList<MangaFile>> GetFilesForChapter(int chapterId); Task<IList<MangaFile>> GetFilesForChapter(int chapterId);
Task<IList<Chapter>> GetChaptersAsync(int volumeId); Task<IList<Chapter>> GetChaptersAsync(int volumeId);
Task<byte[]> GetChapterCoverImageAsync(int chapterId); Task<byte[]> GetChapterCoverImageAsync(int chapterId);
Task<IEnumerable<InProgressChapterDto>> GetContinueReading(int userId, int libraryId, int limit);
} }
} }

View File

@ -43,9 +43,9 @@ namespace API
logger.LogError(ex, "An error occurred during migration"); logger.LogError(ex, "An error occurred during migration");
} }
// Load all tasks from DI (TODO: This is not working) // Load all tasks from DI (TODO: This is not working - WarmupServicesStartupTask is Null)
var startupTasks = host.Services.GetServices<WarmupServicesStartupTask>(); var startupTasks = host.Services.GetServices<WarmupServicesStartupTask>();
// Execute all the tasks // Execute all the tasks
foreach (var startupTask in startupTasks) foreach (var startupTask in startupTasks)
{ {

View File

@ -66,7 +66,7 @@ namespace API.Services.Tasks
//[DisableConcurrentExecution(5)] //[DisableConcurrentExecution(5)]
[AutomaticRetry(Attempts = 0, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Delete)] [AutomaticRetry(Attempts = 0, LogEvents = false, OnAttemptsExceeded = AttemptsExceededAction.Delete)]
public void ScanLibrary(int libraryId, bool forceUpdate) public async void ScanLibrary(int libraryId, bool forceUpdate)
{ {
_forceUpdate = forceUpdate; _forceUpdate = forceUpdate;
var sw = Stopwatch.StartNew(); var sw = Stopwatch.StartNew();

View File

@ -6,6 +6,8 @@ using API.Extensions;
using API.Middleware; using API.Middleware;
using API.Services; using API.Services;
using Hangfire; using Hangfire;
using Hangfire.LiteDB;
using Hangfire.MemoryStorage;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
@ -25,10 +27,12 @@ namespace API
public class Startup public class Startup
{ {
private readonly IConfiguration _config; private readonly IConfiguration _config;
private readonly IWebHostEnvironment _env;
public Startup(IConfiguration config) public Startup(IConfiguration config, IWebHostEnvironment env)
{ {
_config = config; _config = config;
_env = env;
} }
// This method gets called by the runtime. Use this method to add services to the container. // This method gets called by the runtime. Use this method to add services to the container.
@ -63,6 +67,24 @@ namespace API
services.AddResponseCaching(); services.AddResponseCaching();
if (_env.IsDevelopment())
{
services.AddHangfire(configuration => configuration
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseMemoryStorage());
}
else
{
services.AddHangfire(configuration => configuration
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseLiteDbStorage());
}
// Add the processing server as IHostedService
services.AddHangfireServer();
// services // services
// .AddStartupTask<WarmupServicesStartupTask>() // .AddStartupTask<WarmupServicesStartupTask>()
@ -127,6 +149,10 @@ namespace API
}); });
applicationLifetime.ApplicationStopping.Register(OnShutdown); applicationLifetime.ApplicationStopping.Register(OnShutdown);
applicationLifetime.ApplicationStarted.Register(() =>
{
Console.WriteLine("Kavita - v0.3");
});
} }
private void OnShutdown() private void OnShutdown()