diff --git a/API/Controllers/JobController.cs b/API/Controllers/JobController.cs index c68f1c0..3559933 100644 --- a/API/Controllers/JobController.cs +++ b/API/Controllers/JobController.cs @@ -137,9 +137,10 @@ public class JobController(PgsqlContext context, ILog Log) : Controller Job updateFilesDownloaded = new UpdateChaptersDownloadedJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters]); Job downloadChapters = new DownloadAvailableChaptersJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters, updateFilesDownloaded]); + Job UpdateCover = new UpdateCoverJob(m, record.recurrenceTimeMs, downloadChapters); retrieveChapters.ParentJob = downloadChapters; updateFilesDownloaded.ParentJob = retrieveChapters; - return AddJobs([retrieveChapters, downloadChapters, updateFilesDownloaded]); + return AddJobs([retrieveChapters, downloadChapters, updateFilesDownloaded, UpdateCover]); } /// diff --git a/API/Controllers/SettingsController.cs b/API/Controllers/SettingsController.cs index f6cbd05..2e3dff2 100644 --- a/API/Controllers/SettingsController.cs +++ b/API/Controllers/SettingsController.cs @@ -267,4 +267,28 @@ public class SettingsController(PgsqlContext context, ILog Log) : Controller return StatusCode(500, e); } } + + /// + /// Creates a UpdateCoverJob for all Manga + /// + /// Array of JobIds + /// Error during Database Operation + [HttpPost("CleanupCovers")] + [ProducesResponseType(Status200OK)] + [ProducesResponseType(Status500InternalServerError, "text/plain")] + public IActionResult CleanupCovers() + { + try + { + Tranga.RemoveStaleFiles(context); + List newJobs = context.Mangas.ToList().Select(m => new UpdateCoverJob(m, 0)).ToList(); + context.Jobs.AddRange(newJobs); + return Ok(newJobs.Select(j => j.JobId)); + } + catch (Exception e) + { + Log.Error(e); + return StatusCode(500, e); + } + } } \ No newline at end of file diff --git a/API/Program.cs b/API/Program.cs index 9be2ed9..a51747e 100644 --- a/API/Program.cs +++ b/API/Program.cs @@ -149,7 +149,12 @@ using (IServiceScope scope = app.Services.CreateScope()) TrangaSettings.Load(); Tranga.StartLogger(); -Tranga.RemoveStaleFiles(app.Services); + +using (IServiceScope scope = app.Services.CreateScope()) +{ + PgsqlContext context = scope.ServiceProvider.GetRequiredService(); + Tranga.RemoveStaleFiles(context); +} Tranga.JobStarterThread.Start(app.Services); //Tranga.NotificationSenderThread.Start(app.Services); //TODO RE-ENABLE diff --git a/API/Schema/Jobs/JobType.cs b/API/Schema/Jobs/JobType.cs index 4ce607e..2c81f5e 100644 --- a/API/Schema/Jobs/JobType.cs +++ b/API/Schema/Jobs/JobType.cs @@ -12,4 +12,5 @@ public enum JobType : byte UpdateChaptersDownloadedJob = 6, MoveMangaLibraryJob = 7, UpdateSingleChapterDownloadedJob = 8, + UpdateCoversJob = 9, } \ No newline at end of file diff --git a/API/Schema/Jobs/UpdateCoverJob.cs b/API/Schema/Jobs/UpdateCoverJob.cs new file mode 100644 index 0000000..15ed63b --- /dev/null +++ b/API/Schema/Jobs/UpdateCoverJob.cs @@ -0,0 +1,65 @@ +using System.ComponentModel.DataAnnotations; +using API.Schema.Contexts; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Newtonsoft.Json; + +namespace API.Schema.Jobs; + +public class UpdateCoverJob : Job +{ + [StringLength(64)] [Required] public string MangaId { get; init; } + + private Manga _manga = null!; + + [JsonIgnore] + public Manga Manga + { + get => LazyLoader.Load(this, ref _manga); + init => _manga = value; + } + + + public UpdateCoverJob(Manga manga, ulong recurrenceMs, Job? parentJob = null, ICollection? dependsOnJobs = null) + : base(TokenGen.CreateToken(typeof(UpdateCoverJob)), JobType.UpdateCoversJob, recurrenceMs, parentJob, dependsOnJobs) + { + this.MangaId = manga.MangaId; + this.Manga = manga; + } + + /// + /// EF ONLY!!! + /// + internal UpdateCoverJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string mangaId, string? parentJobId) + : base(lazyLoader, jobId, JobType.UpdateCoversJob, recurrenceMs, parentJobId) + { + this.MangaId = mangaId; + } + + protected override IEnumerable RunInternal(PgsqlContext context) + { + bool keepCover = context.Jobs + .Any(job => job.JobType == JobType.DownloadAvailableChaptersJob + && ((DownloadAvailableChaptersJob)job).MangaId == MangaId); + if (!keepCover) + { + if(File.Exists(Manga.CoverFileNameInCache)) + File.Delete(Manga.CoverFileNameInCache); + try + { + Manga.CoverFileNameInCache = null; + context.Jobs.Remove(this); + context.SaveChanges(); + } + catch (DbUpdateException e) + { + Log.Error(e); + } + } + else + { + return [new DownloadMangaCoverJob(Manga, this)]; + } + return []; + } +} \ No newline at end of file diff --git a/API/Tranga.cs b/API/Tranga.cs index 86c9793..85a84b7 100644 --- a/API/Tranga.cs +++ b/API/Tranga.cs @@ -32,11 +32,9 @@ public static class Tranga Log.Info(TRANGA); } - internal static void RemoveStaleFiles(IServiceProvider serviceProvider) + internal static void RemoveStaleFiles(PgsqlContext context) { Log.Info($"Removing stale files..."); - using IServiceScope scope = serviceProvider.CreateScope(); - PgsqlContext context = scope.ServiceProvider.GetRequiredService(); string[] usedFiles = context.Mangas.Select(m => m.CoverFileNameInCache).Where(s => s != null).ToArray()!; string[] extraneousFiles = new DirectoryInfo(TrangaSettings.coverImageCache).GetFiles() .Where(f => usedFiles.Contains(f.FullName) == false)