mirror of
https://github.com/Kareadita/Kavita.git
synced 2025-05-24 00:52:23 -04:00
* Updating wording on card item when total pages is 0, to be just "Cannot Read" since it could be a non-archive file * Refactored cover images to be stored on disk. This first commit has the extraction to disk and the metadata service to handle updating when applicable. * Refactored code to have the actual save to cover image directory done by ImageService. * Implemented the ability to override cover images. * Some cleanup on Image service * Implemented the ability to cleanup old covers nightly * Added a migration to migrate existing covers to new cover image format (files). * Refactored all CoverImages to just be the filename, leaving the Join with Cover directory to higher level code. * Ensure when getting user progress, we pick the first. * Added cleanup cover images for deleted tags. Don't pull any cover images that are blank. * After series update, clear out cover image. No change on UI, but just keeps things clear before metadata refresh hits * Refactored image formats for covers to ImageService. * Fixed an issue where after refactoring how images were stored, the cleanup service was deleting them after each scan. * Changed how ShouldUpdateCoverImage works to check if file exists or not even if cover image is locked. * Fixed unit tests * Added caching back to cover images. * Caching on series as well * Code Cleanup items * Ensure when checking if a file exists in MetadataService, that we join for cover image directory. After we scan library, do one last filter to delete any series that have 0 pages total. * Catch exceptions so we don't run cover migration if this is first time run. * After a scan, only clear out the cache directory and not do a deep clean. * Implemented the ability to backup custom locked covers only. * Fixed unit tests * Trying to figure out why GA crashes when running MetadataServiceTests.cs * Some debugging on GA tests not running * Commented out tests that were causing issues in GA. * Fixed an issue where series cover images wouldn't migrate * Fixed the updating of links to actually do all series and not just locked
166 lines
6.6 KiB
C#
166 lines
6.6 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Security.Cryptography;
|
|
using System.Threading;
|
|
using System.Threading.Channels;
|
|
using System.Threading.Tasks;
|
|
using API.Data;
|
|
using API.Entities;
|
|
using API.Helpers;
|
|
using API.Interfaces;
|
|
using API.Services;
|
|
using Kavita.Common;
|
|
using Kavita.Common.EnvironmentInfo;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.AspNetCore.Identity;
|
|
using Microsoft.AspNetCore.Server.Kestrel.Core;
|
|
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.IO;
|
|
using NetVips;
|
|
using Sentry;
|
|
|
|
namespace API
|
|
{
|
|
public class Program
|
|
{
|
|
private static readonly int HttpPort = Configuration.Port;
|
|
|
|
protected Program()
|
|
{
|
|
}
|
|
|
|
public static async Task Main(string[] args)
|
|
{
|
|
Console.OutputEncoding = System.Text.Encoding.UTF8;
|
|
|
|
// Before anything, check if JWT has been generated properly or if user still has default
|
|
if (!Configuration.CheckIfJwtTokenSet() &&
|
|
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") != Environments.Development)
|
|
{
|
|
Console.WriteLine("Generating JWT TokenKey for encrypting user sessions...");
|
|
var rBytes = new byte[128];
|
|
using (var crypto = new RNGCryptoServiceProvider()) crypto.GetBytes(rBytes);
|
|
Configuration.JwtToken = Convert.ToBase64String(rBytes).Replace("/", string.Empty);
|
|
}
|
|
|
|
var host = CreateHostBuilder(args).Build();
|
|
|
|
using var scope = host.Services.CreateScope();
|
|
var services = scope.ServiceProvider;
|
|
|
|
try
|
|
{
|
|
var context = services.GetRequiredService<DataContext>();
|
|
var roleManager = services.GetRequiredService<RoleManager<AppRole>>();
|
|
|
|
var requiresCoverImageMigration = !Directory.Exists(DirectoryService.CoverImageDirectory);
|
|
try
|
|
{
|
|
// If this is a new install, tables wont exist yet
|
|
if (requiresCoverImageMigration)
|
|
{
|
|
MigrateCoverImages.ExtractToImages(context);
|
|
}
|
|
}
|
|
catch (Exception )
|
|
{
|
|
requiresCoverImageMigration = false;
|
|
}
|
|
|
|
// Apply all migrations on startup
|
|
await context.Database.MigrateAsync();
|
|
|
|
if (requiresCoverImageMigration)
|
|
{
|
|
await MigrateCoverImages.UpdateDatabaseWithImages(context);
|
|
}
|
|
|
|
await Seed.SeedRoles(roleManager);
|
|
await Seed.SeedSettings(context);
|
|
await Seed.SeedUserApiKeys(context);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var logger = services.GetRequiredService<ILogger<Program>>();
|
|
logger.LogError(ex, "An error occurred during migration");
|
|
}
|
|
|
|
await host.RunAsync();
|
|
}
|
|
|
|
private static IHostBuilder CreateHostBuilder(string[] args) =>
|
|
Host.CreateDefaultBuilder(args)
|
|
.ConfigureWebHostDefaults(webBuilder =>
|
|
{
|
|
webBuilder.UseKestrel((opts) =>
|
|
{
|
|
opts.ListenAnyIP(HttpPort, options => { options.Protocols = HttpProtocols.Http1AndHttp2; });
|
|
});
|
|
|
|
var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
|
|
if (environment != Environments.Development)
|
|
{
|
|
webBuilder.UseSentry(options =>
|
|
{
|
|
options.Dsn = "https://40f4e7b49c094172a6f99d61efb2740f@o641015.ingest.sentry.io/5757423";
|
|
options.MaxBreadcrumbs = 200;
|
|
options.AttachStacktrace = true;
|
|
options.Debug = false;
|
|
options.SendDefaultPii = false;
|
|
options.DiagnosticLevel = SentryLevel.Debug;
|
|
options.ShutdownTimeout = TimeSpan.FromSeconds(5);
|
|
options.Release = BuildInfo.Version.ToString();
|
|
options.AddExceptionFilterForType<OutOfMemoryException>();
|
|
options.AddExceptionFilterForType<NetVips.VipsException>();
|
|
options.AddExceptionFilterForType<InvalidDataException>();
|
|
options.AddExceptionFilterForType<KavitaException>();
|
|
|
|
options.BeforeSend = sentryEvent =>
|
|
{
|
|
if (sentryEvent.Exception != null
|
|
&& sentryEvent.Exception.Message.StartsWith("[GetCoverImage]")
|
|
&& sentryEvent.Exception.Message.StartsWith("[BookService]")
|
|
&& sentryEvent.Exception.Message.StartsWith("[ExtractArchive]")
|
|
&& sentryEvent.Exception.Message.StartsWith("[GetSummaryInfo]")
|
|
&& sentryEvent.Exception.Message.StartsWith("[GetSummaryInfo]")
|
|
&& sentryEvent.Exception.Message.StartsWith("[GetNumberOfPagesFromArchive]")
|
|
&& sentryEvent.Exception.Message.Contains("EPUB parsing error")
|
|
&& sentryEvent.Exception.Message.Contains("Unsupported EPUB version")
|
|
&& sentryEvent.Exception.Message.Contains("Incorrect EPUB")
|
|
&& sentryEvent.Exception.Message.Contains("Access is Denied"))
|
|
{
|
|
return null; // Don't send this event to Sentry
|
|
}
|
|
|
|
sentryEvent.ServerName = null; // Never send Server Name to Sentry
|
|
return sentryEvent;
|
|
};
|
|
|
|
options.ConfigureScope(scope =>
|
|
{
|
|
scope.User = new User()
|
|
{
|
|
Id = HashUtil.AnonymousToken()
|
|
};
|
|
scope.Contexts.App.Name = BuildInfo.AppName;
|
|
scope.Contexts.App.Version = BuildInfo.Version.ToString();
|
|
scope.Contexts.App.StartTime = DateTime.UtcNow;
|
|
scope.Contexts.App.Hash = HashUtil.AnonymousToken();
|
|
scope.Contexts.App.Build = BuildInfo.Release;
|
|
scope.SetTag("culture", Thread.CurrentThread.CurrentCulture.Name);
|
|
scope.SetTag("branch", BuildInfo.Branch);
|
|
});
|
|
});
|
|
}
|
|
|
|
webBuilder.UseStartup<Startup>();
|
|
});
|
|
}
|
|
}
|