Add UpdateCoverJob.cs

Covers get updated on every pull
If a Manga has no DownloadAvailableChaptersJob, Cover is removed
Add endpoint POST Settings/CleanupCovers that removed covers not associated to any Manga
This commit is contained in:
Glax 2025-05-18 17:05:01 +02:00
parent 9b251169a5
commit 49bd66ccab
6 changed files with 99 additions and 5 deletions

View File

@ -137,9 +137,10 @@ public class JobController(PgsqlContext context, ILog Log) : Controller
Job updateFilesDownloaded = Job updateFilesDownloaded =
new UpdateChaptersDownloadedJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters]); new UpdateChaptersDownloadedJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters]);
Job downloadChapters = new DownloadAvailableChaptersJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters, updateFilesDownloaded]); Job downloadChapters = new DownloadAvailableChaptersJob(m, record.recurrenceTimeMs, dependsOnJobs: [retrieveChapters, updateFilesDownloaded]);
Job UpdateCover = new UpdateCoverJob(m, record.recurrenceTimeMs, downloadChapters);
retrieveChapters.ParentJob = downloadChapters; retrieveChapters.ParentJob = downloadChapters;
updateFilesDownloaded.ParentJob = retrieveChapters; updateFilesDownloaded.ParentJob = retrieveChapters;
return AddJobs([retrieveChapters, downloadChapters, updateFilesDownloaded]); return AddJobs([retrieveChapters, downloadChapters, updateFilesDownloaded, UpdateCover]);
} }
/// <summary> /// <summary>

View File

@ -267,4 +267,28 @@ public class SettingsController(PgsqlContext context, ILog Log) : Controller
return StatusCode(500, e); return StatusCode(500, e);
} }
} }
/// <summary>
/// Creates a UpdateCoverJob for all Manga
/// </summary>
/// <response code="200">Array of JobIds</response>
/// <response code="500">Error during Database Operation</response>
[HttpPost("CleanupCovers")]
[ProducesResponseType<string[]>(Status200OK)]
[ProducesResponseType<string>(Status500InternalServerError, "text/plain")]
public IActionResult CleanupCovers()
{
try
{
Tranga.RemoveStaleFiles(context);
List<UpdateCoverJob> 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);
}
}
} }

View File

@ -149,7 +149,12 @@ using (IServiceScope scope = app.Services.CreateScope())
TrangaSettings.Load(); TrangaSettings.Load();
Tranga.StartLogger(); Tranga.StartLogger();
Tranga.RemoveStaleFiles(app.Services);
using (IServiceScope scope = app.Services.CreateScope())
{
PgsqlContext context = scope.ServiceProvider.GetRequiredService<PgsqlContext>();
Tranga.RemoveStaleFiles(context);
}
Tranga.JobStarterThread.Start(app.Services); Tranga.JobStarterThread.Start(app.Services);
//Tranga.NotificationSenderThread.Start(app.Services); //TODO RE-ENABLE //Tranga.NotificationSenderThread.Start(app.Services); //TODO RE-ENABLE

View File

@ -12,4 +12,5 @@ public enum JobType : byte
UpdateChaptersDownloadedJob = 6, UpdateChaptersDownloadedJob = 6,
MoveMangaLibraryJob = 7, MoveMangaLibraryJob = 7,
UpdateSingleChapterDownloadedJob = 8, UpdateSingleChapterDownloadedJob = 8,
UpdateCoversJob = 9,
} }

View File

@ -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<Job>? dependsOnJobs = null)
: base(TokenGen.CreateToken(typeof(UpdateCoverJob)), JobType.UpdateCoversJob, recurrenceMs, parentJob, dependsOnJobs)
{
this.MangaId = manga.MangaId;
this.Manga = manga;
}
/// <summary>
/// EF ONLY!!!
/// </summary>
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<Job> 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 [];
}
}

View File

@ -32,11 +32,9 @@ public static class Tranga
Log.Info(TRANGA); Log.Info(TRANGA);
} }
internal static void RemoveStaleFiles(IServiceProvider serviceProvider) internal static void RemoveStaleFiles(PgsqlContext context)
{ {
Log.Info($"Removing stale files..."); Log.Info($"Removing stale files...");
using IServiceScope scope = serviceProvider.CreateScope();
PgsqlContext context = scope.ServiceProvider.GetRequiredService<PgsqlContext>();
string[] usedFiles = context.Mangas.Select(m => m.CoverFileNameInCache).Where(s => s != null).ToArray()!; string[] usedFiles = context.Mangas.Select(m => m.CoverFileNameInCache).Where(s => s != null).ToArray()!;
string[] extraneousFiles = new DirectoryInfo(TrangaSettings.coverImageCache).GetFiles() string[] extraneousFiles = new DirectoryInfo(TrangaSettings.coverImageCache).GetFiles()
.Where(f => usedFiles.Contains(f.FullName) == false) .Where(f => usedFiles.Contains(f.FullName) == false)