mirror of
https://github.com/C9Glax/tranga.git
synced 2025-07-02 08:54:16 +02:00
Manga and Chapters are shared across Connectors
This commit is contained in:
@ -1,4 +1,5 @@
|
||||
using API.Schema.Contexts;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using API.Schema.Contexts;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@ -6,31 +7,44 @@ namespace API.Schema.Jobs;
|
||||
|
||||
public class DownloadAvailableChaptersJob : JobWithDownloading
|
||||
{
|
||||
private MangaConnectorMangaEntry? _mangaConnectorMangaEntry = null!;
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; } = null!;
|
||||
private Manga? _manga;
|
||||
|
||||
[JsonIgnore]
|
||||
public MangaConnectorMangaEntry MangaConnectorMangaEntry
|
||||
public Manga Manga
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _mangaConnectorMangaEntry) ?? throw new InvalidOperationException();
|
||||
init => _mangaConnectorMangaEntry = value;
|
||||
get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
MangaId = value.Key;
|
||||
_manga = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DownloadAvailableChaptersJob(MangaConnectorMangaEntry mangaConnectorMangaEntry, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(DownloadAvailableChaptersJob)), JobType.DownloadAvailableChaptersJob, recurrenceMs, mangaConnectorMangaEntry.MangaConnector, parentJob, dependsOnJobs)
|
||||
public DownloadAvailableChaptersJob(Manga manga, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(DownloadAvailableChaptersJob)), JobType.DownloadAvailableChaptersJob, recurrenceMs, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.MangaConnectorMangaEntry = mangaConnectorMangaEntry;
|
||||
this.Manga = manga;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal DownloadAvailableChaptersJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string mangaConnectorName, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.DownloadAvailableChaptersJob, recurrenceMs, mangaConnectorName, parentJobId)
|
||||
internal DownloadAvailableChaptersJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.DownloadAvailableChaptersJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
|
||||
this.MangaId = mangaId;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Job> RunInternal(PgsqlContext context)
|
||||
{
|
||||
return MangaConnectorMangaEntry.Manga.Chapters.Where(c => c.Downloaded == false).Select(chapter => new DownloadSingleChapterJob(chapter, this.MangaConnectorMangaEntry));
|
||||
// Chapters that aren't downloaded and for which no downloading-Job exists
|
||||
IEnumerable<Chapter> newChapters = Manga.Chapters
|
||||
.Where(c =>
|
||||
c.Downloaded == false &&
|
||||
context.Jobs.Any(j =>
|
||||
j.JobType == JobType.DownloadSingleChapterJob &&
|
||||
((DownloadSingleChapterJob)j).Chapter.ParentMangaId == MangaId) == false);
|
||||
return newChapters.Select(c => new DownloadSingleChapterJob(c, this));
|
||||
}
|
||||
}
|
@ -8,34 +8,42 @@ namespace API.Schema.Jobs;
|
||||
|
||||
public class DownloadMangaCoverJob : JobWithDownloading
|
||||
{
|
||||
private MangaConnectorMangaEntry? _mangaConnectorMangaEntry = null!;
|
||||
[JsonIgnore]
|
||||
public MangaConnectorMangaEntry MangaConnectorMangaEntry
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _mangaConnectorMangaEntry) ?? throw new InvalidOperationException();
|
||||
init => _mangaConnectorMangaEntry = value;
|
||||
}
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; } = null!;
|
||||
private Manga? _manga;
|
||||
|
||||
public DownloadMangaCoverJob(MangaConnectorMangaEntry mangaConnectorEntry, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(DownloadMangaCoverJob)), JobType.DownloadMangaCoverJob, 0, mangaConnectorEntry.MangaConnector, parentJob, dependsOnJobs)
|
||||
[JsonIgnore]
|
||||
public Manga Manga
|
||||
{
|
||||
this.MangaConnectorMangaEntry = mangaConnectorEntry;
|
||||
get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
MangaId = value.Key;
|
||||
_manga = value;
|
||||
}
|
||||
}
|
||||
|
||||
public DownloadMangaCoverJob(Manga manga, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(DownloadMangaCoverJob)), JobType.DownloadMangaCoverJob, 0, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.Manga = manga;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal DownloadMangaCoverJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string mangaConnectorName, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.DownloadMangaCoverJob, recurrenceMs, mangaConnectorName, parentJobId)
|
||||
internal DownloadMangaCoverJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.DownloadMangaCoverJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
|
||||
this.MangaId = mangaId;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Job> RunInternal(PgsqlContext context)
|
||||
{
|
||||
//TODO MangaConnector Selection
|
||||
MangaConnectorId<Manga> mcId = Manga.MangaConnectorIds.First();
|
||||
try
|
||||
{
|
||||
MangaConnectorMangaEntry.Manga.CoverFileNameInCache = MangaConnectorMangaEntry.MangaConnector.SaveCoverImageToCache(MangaConnectorMangaEntry.Manga);
|
||||
Manga.CoverFileNameInCache = mcId.MangaConnector.SaveCoverImageToCache(mcId);
|
||||
context.SaveChanges();
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
|
@ -16,39 +16,30 @@ namespace API.Schema.Jobs;
|
||||
public class DownloadSingleChapterJob : JobWithDownloading
|
||||
{
|
||||
[StringLength(64)] [Required] public string ChapterId { get; init; } = null!;
|
||||
private Chapter? _chapter = null!;
|
||||
|
||||
private Chapter? _chapter;
|
||||
|
||||
[JsonIgnore]
|
||||
public Chapter Chapter
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _chapter) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
ChapterId = value.ChapterId;
|
||||
ChapterId = value.Key;
|
||||
_chapter = value;
|
||||
}
|
||||
}
|
||||
|
||||
private MangaConnectorMangaEntry? _mangaConnectorMangaEntry = null!;
|
||||
[JsonIgnore]
|
||||
public MangaConnectorMangaEntry MangaConnectorMangaEntry
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _mangaConnectorMangaEntry) ?? throw new InvalidOperationException();
|
||||
init => _mangaConnectorMangaEntry = value;
|
||||
}
|
||||
|
||||
public DownloadSingleChapterJob(Chapter chapter, MangaConnectorMangaEntry mangaConnectorMangaEntry, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(DownloadSingleChapterJob)), JobType.DownloadSingleChapterJob, 0, mangaConnectorMangaEntry.MangaConnector, parentJob, dependsOnJobs)
|
||||
public DownloadSingleChapterJob(Chapter chapter, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(DownloadSingleChapterJob)), JobType.DownloadSingleChapterJob, 0, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.Chapter = chapter;
|
||||
this.MangaConnectorMangaEntry = mangaConnectorMangaEntry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal DownloadSingleChapterJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string mangaConnectorName, string chapterId, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.DownloadSingleChapterJob, recurrenceMs, mangaConnectorName, parentJobId)
|
||||
internal DownloadSingleChapterJob(ILazyLoader lazyLoader, string key, string chapterId, ulong recurrenceMs, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.DownloadSingleChapterJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
this.ChapterId = chapterId;
|
||||
}
|
||||
@ -60,13 +51,16 @@ public class DownloadSingleChapterJob : JobWithDownloading
|
||||
Log.Info("Chapter was already downloaded.");
|
||||
return [];
|
||||
}
|
||||
string[] imageUrls = MangaConnectorMangaEntry.MangaConnector.GetChapterImageUrls(Chapter);
|
||||
|
||||
//TODO MangaConnector Selection
|
||||
MangaConnectorId<Chapter> mcId = Chapter.MangaConnectorIds.First();
|
||||
|
||||
string[] imageUrls = mcId.MangaConnector.GetChapterImageUrls(mcId);
|
||||
if (imageUrls.Length < 1)
|
||||
{
|
||||
Log.Info($"No imageUrls for chapter {ChapterId}");
|
||||
Log.Info($"No imageUrls for chapter {Chapter}");
|
||||
return [];
|
||||
}
|
||||
context.Entry(Chapter.MangaConnectorMangaEntry.Manga).Reference<LocalLibrary>(m => m.Library).Load(); //Need to explicitly load, because we are not accessing navigation directly...
|
||||
string saveArchiveFilePath = Chapter.FullArchiveFilePath;
|
||||
Log.Debug($"Chapter path: {saveArchiveFilePath}");
|
||||
|
||||
@ -98,7 +92,7 @@ public class DownloadSingleChapterJob : JobWithDownloading
|
||||
string tempFolder = Directory.CreateTempSubdirectory("trangatemp").FullName;
|
||||
Log.Debug($"Created temp folder: {tempFolder}");
|
||||
|
||||
Log.Info($"Downloading images: {ChapterId}");
|
||||
Log.Info($"Downloading images: {Chapter}");
|
||||
int chapterNum = 0;
|
||||
//Download all Images to temporary Folder
|
||||
foreach (string imageUrl in imageUrls)
|
||||
@ -113,12 +107,12 @@ public class DownloadSingleChapterJob : JobWithDownloading
|
||||
}
|
||||
}
|
||||
|
||||
CopyCoverFromCacheToDownloadLocation(Chapter.MangaConnectorMangaEntry.Manga);
|
||||
CopyCoverFromCacheToDownloadLocation(Chapter.ParentManga);
|
||||
|
||||
Log.Debug($"Creating ComicInfo.xml {ChapterId}");
|
||||
Log.Debug($"Creating ComicInfo.xml {Chapter}");
|
||||
File.WriteAllText(Path.Join(tempFolder, "ComicInfo.xml"), Chapter.GetComicInfoXmlString());
|
||||
|
||||
Log.Debug($"Packaging images to archive {ChapterId}");
|
||||
Log.Debug($"Packaging images to archive {Chapter}");
|
||||
//ZIP-it and ship-it
|
||||
ZipFile.CreateFromDirectory(tempFolder, saveArchiveFilePath);
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||
@ -133,11 +127,11 @@ public class DownloadSingleChapterJob : JobWithDownloading
|
||||
if (j.JobType != JobType.UpdateChaptersDownloadedJob)
|
||||
return false;
|
||||
UpdateChaptersDownloadedJob job = (UpdateChaptersDownloadedJob)j;
|
||||
return job.MangaId == this.Chapter.MangaConnectorMangaEntry.MangaId;
|
||||
return job.MangaId == Chapter.ParentMangaId;
|
||||
}))
|
||||
return [];
|
||||
|
||||
return [new UpdateChaptersDownloadedJob(Chapter.MangaConnectorMangaEntry.Manga, 0, this.ParentJob)];
|
||||
return [new UpdateChaptersDownloadedJob(Chapter.ParentManga, 0, this.ParentJob)];
|
||||
}
|
||||
|
||||
private void ProcessImage(string imagePath)
|
||||
@ -188,9 +182,12 @@ public class DownloadSingleChapterJob : JobWithDownloading
|
||||
Log.Debug($"Cover already exists at {publicationFolder}");
|
||||
return;
|
||||
}
|
||||
|
||||
//TODO MangaConnector Selection
|
||||
MangaConnectorId<Manga> mcId = manga.MangaConnectorIds.First();
|
||||
|
||||
Log.Info($"Copying cover to {publicationFolder}");
|
||||
string? fileInCache = manga.CoverFileNameInCache ?? MangaConnectorMangaEntry.MangaConnector.SaveCoverImageToCache(manga);
|
||||
string? fileInCache = manga.CoverFileNameInCache ?? mcId.MangaConnector.SaveCoverImageToCache(mcId);
|
||||
if (fileInCache is null)
|
||||
{
|
||||
Log.Error($"File {fileInCache} does not exist");
|
||||
|
@ -8,19 +8,15 @@ using Newtonsoft.Json;
|
||||
|
||||
namespace API.Schema.Jobs;
|
||||
|
||||
[PrimaryKey("JobId")]
|
||||
public abstract class Job : IComparable<Job>
|
||||
[PrimaryKey("Key")]
|
||||
public abstract class Job : Identifiable, IComparable<Job>
|
||||
{
|
||||
[StringLength(64)]
|
||||
[Required]
|
||||
public string JobId { get; init; }
|
||||
|
||||
[StringLength(64)] public string? ParentJobId { get; private set; }
|
||||
[JsonIgnore] public Job? ParentJob { get; internal set; }
|
||||
private ICollection<Job> _dependsOnJobs = null!;
|
||||
private ICollection<Job>? _dependsOnJobs;
|
||||
[JsonIgnore] public ICollection<Job> DependsOnJobs
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _dependsOnJobs);
|
||||
get => LazyLoader.Load(this, ref _dependsOnJobs) ?? throw new InvalidOperationException();
|
||||
init => _dependsOnJobs = value;
|
||||
}
|
||||
|
||||
@ -37,14 +33,14 @@ public abstract class Job : IComparable<Job>
|
||||
[JsonIgnore] [NotMapped] internal bool IsCompleted => state is >= (JobState)128 and < (JobState)192;
|
||||
|
||||
[NotMapped] [JsonIgnore] protected ILog Log { get; init; }
|
||||
[NotMapped] [JsonIgnore] protected ILazyLoader LazyLoader { get; init; }
|
||||
[NotMapped] [JsonIgnore] protected ILazyLoader LazyLoader { get; init; } = null!;
|
||||
|
||||
protected Job(string jobId, JobType jobType, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
protected Job(string key, JobType jobType, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(key)
|
||||
{
|
||||
this.JobId = jobId;
|
||||
this.JobType = jobType;
|
||||
this.RecurrenceMs = recurrenceMs;
|
||||
this.ParentJobId = parentJob?.JobId;
|
||||
this.ParentJobId = parentJob?.Key;
|
||||
this.ParentJob = parentJob;
|
||||
this.DependsOnJobs = dependsOnJobs ?? [];
|
||||
|
||||
@ -54,10 +50,10 @@ public abstract class Job : IComparable<Job>
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
protected internal Job(ILazyLoader lazyLoader, string jobId, JobType jobType, ulong recurrenceMs, string? parentJobId)
|
||||
protected internal Job(ILazyLoader lazyLoader, string key, JobType jobType, ulong recurrenceMs, string? parentJobId)
|
||||
: base(key)
|
||||
{
|
||||
this.LazyLoader = lazyLoader;
|
||||
this.JobId = jobId;
|
||||
this.JobType = jobType;
|
||||
this.RecurrenceMs = recurrenceMs;
|
||||
this.ParentJobId = parentJobId;
|
||||
@ -68,7 +64,7 @@ public abstract class Job : IComparable<Job>
|
||||
|
||||
public IEnumerable<Job> Run(PgsqlContext context, ref bool running)
|
||||
{
|
||||
Log.Info($"Running job {JobId}");
|
||||
Log.Info($"Running job {this}");
|
||||
DateTime jobStart = DateTime.UtcNow;
|
||||
Job[]? ret = null;
|
||||
|
||||
@ -78,7 +74,7 @@ public abstract class Job : IComparable<Job>
|
||||
context.SaveChanges();
|
||||
running = true;
|
||||
ret = RunInternal(context).ToArray();
|
||||
Log.Info($"Job {JobId} completed. Generated {ret.Length} new jobs.");
|
||||
Log.Info($"Job {this} completed. Generated {ret.Length} new jobs.");
|
||||
this.state = this.RecurrenceMs > 0 ? JobState.CompletedWaiting : JobState.Completed;
|
||||
this.LastExecution = DateTime.UtcNow;
|
||||
context.SaveChanges();
|
||||
@ -87,7 +83,7 @@ public abstract class Job : IComparable<Job>
|
||||
{
|
||||
if (e is not DbUpdateException)
|
||||
{
|
||||
Log.Error($"Failed to run job {JobId}", e);
|
||||
Log.Error($"Failed to run job {this}", e);
|
||||
this.state = JobState.Failed;
|
||||
this.Enabled = false;
|
||||
this.LastExecution = DateTime.UtcNow;
|
||||
@ -95,7 +91,7 @@ public abstract class Job : IComparable<Job>
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.Error($"Failed to update Database {JobId}", e);
|
||||
Log.Error($"Failed to update Database {this}", e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -109,10 +105,10 @@ public abstract class Job : IComparable<Job>
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
{
|
||||
Log.Error($"Failed to update Database {JobId}", e);
|
||||
Log.Error($"Failed to update Database {this}", e);
|
||||
}
|
||||
|
||||
Log.Info($"Finished Job {JobId}! (took {DateTime.UtcNow.Subtract(jobStart).TotalMilliseconds}ms)");
|
||||
Log.Info($"Finished Job {this}! (took {DateTime.UtcNow.Subtract(jobStart).TotalMilliseconds}ms)");
|
||||
return ret ?? [];
|
||||
}
|
||||
|
||||
@ -146,14 +142,8 @@ public abstract class Job : IComparable<Job>
|
||||
// Sort by NextExecution-time
|
||||
if (this.NextExecution < other.NextExecution)
|
||||
return -1;
|
||||
// Sort by JobPriority
|
||||
if (JobQueueSorter.GetPriority(this) > JobQueueSorter.GetPriority(other))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{JobId}";
|
||||
}
|
||||
public override string ToString() => base.ToString();
|
||||
}
|
@ -1,37 +1,18 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using API.Schema.MangaConnectors;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace API.Schema.Jobs;
|
||||
|
||||
public abstract class JobWithDownloading : Job
|
||||
{
|
||||
[StringLength(32)] [Required] public string MangaConnectorName { get; private set; } = null!;
|
||||
[JsonIgnore] private MangaConnector? _mangaConnector;
|
||||
[JsonIgnore]
|
||||
public MangaConnector MangaConnector
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _mangaConnector) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
MangaConnectorName = value.Name;
|
||||
_mangaConnector = value;
|
||||
}
|
||||
}
|
||||
|
||||
protected JobWithDownloading(string jobId, JobType jobType, ulong recurrenceMs, MangaConnector mangaConnector, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(jobId, jobType, recurrenceMs, parentJob, dependsOnJobs)
|
||||
public JobWithDownloading(string key, JobType jobType, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(key, jobType, recurrenceMs, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.MangaConnector = mangaConnector;
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF CORE ONLY!!!
|
||||
/// </summary>
|
||||
internal JobWithDownloading(ILazyLoader lazyLoader, string jobId, JobType jobType, ulong recurrenceMs, string mangaConnectorName, string? parentJobId)
|
||||
: base(lazyLoader, jobId, jobType, recurrenceMs, parentJobId)
|
||||
public JobWithDownloading(ILazyLoader lazyLoader, string key, JobType jobType, ulong recurrenceMs, string? parentJobId)
|
||||
: base(lazyLoader, key, jobType, recurrenceMs, parentJobId)
|
||||
{
|
||||
this.MangaConnectorName = mangaConnectorName;
|
||||
|
||||
}
|
||||
}
|
@ -23,8 +23,8 @@ public class MoveFileOrFolderJob : Job
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal MoveFileOrFolderJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string fromLocation, string toLocation, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.MoveFileOrFolderJob, recurrenceMs, parentJobId)
|
||||
internal MoveFileOrFolderJob(ILazyLoader lazyLoader, string key, ulong recurrenceMs, string fromLocation, string toLocation, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.MoveFileOrFolderJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
this.FromLocation = fromLocation;
|
||||
this.ToLocation = toLocation;
|
||||
|
@ -8,43 +8,45 @@ namespace API.Schema.Jobs;
|
||||
|
||||
public class MoveMangaLibraryJob : Job
|
||||
{
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; }
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; } = null!;
|
||||
private Manga? _manga;
|
||||
|
||||
private Manga? _manga = null!;
|
||||
|
||||
[JsonIgnore]
|
||||
public Manga Manga
|
||||
public Manga Manga
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException();
|
||||
init => _manga = value;
|
||||
}
|
||||
|
||||
[StringLength(64)] [Required] public string ToLibraryId { get; private set; } = null!;
|
||||
private LocalLibrary? _toLibrary = null!;
|
||||
[JsonIgnore]
|
||||
public LocalLibrary ToLibrary
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _toLibrary) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
ToLibraryId = value.LocalLibraryId;
|
||||
_toLibrary = value;
|
||||
MangaId = value.Key;
|
||||
_manga = value;
|
||||
}
|
||||
}
|
||||
|
||||
public MoveMangaLibraryJob(Manga manga, LocalLibrary toLibrary, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
[StringLength(64)] [Required] public string ToLibraryId { get; private set; } = null!;
|
||||
private FileLibrary? _toFileLibrary;
|
||||
[JsonIgnore]
|
||||
public FileLibrary ToFileLibrary
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _toFileLibrary) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
ToLibraryId = value.Key;
|
||||
_toFileLibrary = value;
|
||||
}
|
||||
}
|
||||
|
||||
public MoveMangaLibraryJob(Manga manga, FileLibrary toFileLibrary, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(MoveMangaLibraryJob)), JobType.MoveMangaLibraryJob, 0, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.MangaId = manga.MangaId;
|
||||
this.Manga = manga;
|
||||
this.ToLibrary = toLibrary;
|
||||
this.ToFileLibrary = toFileLibrary;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal MoveMangaLibraryJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string mangaId, string toLibraryId, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.MoveMangaLibraryJob, recurrenceMs, parentJobId)
|
||||
internal MoveMangaLibraryJob(ILazyLoader lazyLoader, string key, ulong recurrenceMs, string mangaId, string toLibraryId, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.MoveMangaLibraryJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
this.MangaId = mangaId;
|
||||
this.ToLibraryId = toLibraryId;
|
||||
@ -52,9 +54,9 @@ public class MoveMangaLibraryJob : Job
|
||||
|
||||
protected override IEnumerable<Job> RunInternal(PgsqlContext context)
|
||||
{
|
||||
context.Entry(Manga).Reference<LocalLibrary>(m => m.Library).Load();
|
||||
context.Entry(Manga).Reference<FileLibrary>(m => m.Library).Load();
|
||||
Dictionary<Chapter, string> oldPath = Manga.Chapters.ToDictionary(c => c, c => c.FullArchiveFilePath);
|
||||
Manga.Library = ToLibrary;
|
||||
Manga.Library = ToFileLibrary;
|
||||
try
|
||||
{
|
||||
context.SaveChanges();
|
||||
|
@ -8,43 +8,56 @@ namespace API.Schema.Jobs;
|
||||
|
||||
public class RetrieveChaptersJob : JobWithDownloading
|
||||
{
|
||||
private MangaConnectorMangaEntry? _mangaConnectorMangaEntry = null!;
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; } = null!;
|
||||
private Manga? _manga;
|
||||
|
||||
[JsonIgnore]
|
||||
public MangaConnectorMangaEntry MangaConnectorMangaEntry
|
||||
public Manga Manga
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _mangaConnectorMangaEntry) ?? throw new InvalidOperationException();
|
||||
init => _mangaConnectorMangaEntry = value;
|
||||
get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
MangaId = value.Key;
|
||||
_manga = value;
|
||||
}
|
||||
}
|
||||
|
||||
[StringLength(8)] [Required] public string Language { get; private set; }
|
||||
|
||||
public RetrieveChaptersJob(MangaConnectorMangaEntry mangaConnectorMangaEntry, string language, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(RetrieveChaptersJob)), JobType.RetrieveChaptersJob, recurrenceMs, mangaConnectorMangaEntry.MangaConnector, parentJob, dependsOnJobs)
|
||||
public RetrieveChaptersJob(Manga manga, string language, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(RetrieveChaptersJob)), JobType.RetrieveChaptersJob, recurrenceMs, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.MangaConnectorMangaEntry = mangaConnectorMangaEntry;
|
||||
this.Manga = manga;
|
||||
this.Language = language;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal RetrieveChaptersJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string mangaConnectorName, string language, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.RetrieveChaptersJob, recurrenceMs, mangaConnectorName, parentJobId)
|
||||
internal RetrieveChaptersJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string language, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.RetrieveChaptersJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
this.MangaId = mangaId;
|
||||
this.Language = language;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Job> RunInternal(PgsqlContext context)
|
||||
{
|
||||
//TODO MangaConnector Selection
|
||||
MangaConnectorId<Manga> mcId = Manga.MangaConnectorIds.First();
|
||||
|
||||
// This gets all chapters that are not downloaded
|
||||
Chapter[] allChapters = MangaConnectorMangaEntry.MangaConnector.GetChapters(MangaConnectorMangaEntry, Language).DistinctBy(c => c.ChapterId).ToArray();
|
||||
Chapter[] newChapters = allChapters.Where(chapter => MangaConnectorMangaEntry.Manga.Chapters.Select(c => c.ChapterId).Contains(chapter.ChapterId) == false).ToArray();
|
||||
Log.Info($"{MangaConnectorMangaEntry.Manga.Chapters.Count} existing + {newChapters.Length} new chapters.");
|
||||
(Chapter, MangaConnectorId<Chapter>)[] allChapters = mcId.MangaConnector.GetChapters(mcId, Language).DistinctBy(c => c.Item1.Key).ToArray();
|
||||
(Chapter, MangaConnectorId<Chapter>)[] newChapters = allChapters.Where(chapter => Manga.Chapters.Any(ch => chapter.Item1.Key == ch.Key && ch.Downloaded) == false).ToArray();
|
||||
Log.Info($"{Manga.Chapters.Count} existing + {newChapters.Length} new chapters.");
|
||||
|
||||
try
|
||||
{
|
||||
foreach (Chapter newChapter in newChapters)
|
||||
MangaConnectorMangaEntry.Manga.Chapters.Add(newChapter);
|
||||
foreach ((Chapter chapter, MangaConnectorId<Chapter> mcId) newChapter in newChapters)
|
||||
{
|
||||
Manga.Chapters.Add(newChapter.chapter);
|
||||
context.MangaConnectorToChapter.Add(newChapter.mcId);
|
||||
}
|
||||
context.SaveChanges();
|
||||
}
|
||||
catch (DbUpdateException e)
|
||||
|
@ -8,36 +8,38 @@ namespace API.Schema.Jobs;
|
||||
|
||||
public class UpdateChaptersDownloadedJob : Job
|
||||
{
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; }
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; } = null!;
|
||||
private Manga? _manga;
|
||||
|
||||
private Manga _manga = null!;
|
||||
|
||||
[JsonIgnore]
|
||||
public Manga Manga
|
||||
public Manga Manga
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _manga);
|
||||
init => _manga = value;
|
||||
get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
MangaId = value.Key;
|
||||
_manga = value;
|
||||
}
|
||||
}
|
||||
|
||||
public UpdateChaptersDownloadedJob(Manga manga, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(UpdateChaptersDownloadedJob)), JobType.UpdateChaptersDownloadedJob, recurrenceMs, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.MangaId = manga.MangaId;
|
||||
this.Manga = manga;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal UpdateChaptersDownloadedJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string mangaId, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.UpdateChaptersDownloadedJob, recurrenceMs, parentJobId)
|
||||
internal UpdateChaptersDownloadedJob(ILazyLoader lazyLoader, string key, ulong recurrenceMs, string mangaId, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.UpdateChaptersDownloadedJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
this.MangaId = mangaId;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Job> RunInternal(PgsqlContext context)
|
||||
{
|
||||
context.Entry(Manga).Reference<LocalLibrary>(m => m.Library).Load();
|
||||
context.Entry(Manga).Reference<FileLibrary>(m => m.Library).Load();
|
||||
foreach (Chapter mangaChapter in Manga.Chapters)
|
||||
{
|
||||
mangaChapter.Downloaded = mangaChapter.CheckDownloaded();
|
||||
|
@ -8,41 +8,48 @@ namespace API.Schema.Jobs;
|
||||
|
||||
public class UpdateCoverJob : Job
|
||||
{
|
||||
private MangaConnectorMangaEntry? _mangaConnectorMangaEntry = null!;
|
||||
[StringLength(64)] [Required] public string MangaId { get; init; } = null!;
|
||||
private Manga? _manga;
|
||||
|
||||
[JsonIgnore]
|
||||
public MangaConnectorMangaEntry MangaConnectorMangaEntry
|
||||
public Manga Manga
|
||||
{
|
||||
get => LazyLoader.Load(this, ref _mangaConnectorMangaEntry) ?? throw new InvalidOperationException();
|
||||
init => _mangaConnectorMangaEntry = value;
|
||||
get => LazyLoader.Load(this, ref _manga) ?? throw new InvalidOperationException();
|
||||
init
|
||||
{
|
||||
MangaId = value.Key;
|
||||
_manga = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public UpdateCoverJob(MangaConnectorMangaEntry mangaConnectorMangaEntry, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
public UpdateCoverJob(Manga manga, ulong recurrenceMs, Job? parentJob = null, ICollection<Job>? dependsOnJobs = null)
|
||||
: base(TokenGen.CreateToken(typeof(UpdateCoverJob)), JobType.UpdateCoverJob, recurrenceMs, parentJob, dependsOnJobs)
|
||||
{
|
||||
this.MangaConnectorMangaEntry = mangaConnectorMangaEntry;
|
||||
this.Manga = manga;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// EF ONLY!!!
|
||||
/// </summary>
|
||||
internal UpdateCoverJob(ILazyLoader lazyLoader, string jobId, ulong recurrenceMs, string? parentJobId)
|
||||
: base(lazyLoader, jobId, JobType.UpdateCoverJob, recurrenceMs, parentJobId)
|
||||
internal UpdateCoverJob(ILazyLoader lazyLoader, string key, string mangaId, ulong recurrenceMs, string? parentJobId)
|
||||
: base(lazyLoader, key, JobType.UpdateCoverJob, recurrenceMs, parentJobId)
|
||||
{
|
||||
this.MangaId = mangaId;
|
||||
}
|
||||
|
||||
protected override IEnumerable<Job> RunInternal(PgsqlContext context)
|
||||
{
|
||||
bool keepCover = context.Jobs
|
||||
.Any(job => job.JobType == JobType.DownloadAvailableChaptersJob
|
||||
&& ((DownloadAvailableChaptersJob)job).MangaConnectorMangaEntry.MangaId == MangaConnectorMangaEntry.MangaId);
|
||||
&& ((DownloadAvailableChaptersJob)job).MangaId == MangaId);
|
||||
if (!keepCover)
|
||||
{
|
||||
if(File.Exists(MangaConnectorMangaEntry.Manga.CoverFileNameInCache))
|
||||
File.Delete(MangaConnectorMangaEntry.Manga.CoverFileNameInCache);
|
||||
if(File.Exists(Manga.CoverFileNameInCache))
|
||||
File.Delete(Manga.CoverFileNameInCache);
|
||||
try
|
||||
{
|
||||
MangaConnectorMangaEntry.Manga.CoverFileNameInCache = null;
|
||||
Manga.CoverFileNameInCache = null;
|
||||
context.Jobs.Remove(this);
|
||||
context.SaveChanges();
|
||||
}
|
||||
@ -53,7 +60,7 @@ public class UpdateCoverJob : Job
|
||||
}
|
||||
else
|
||||
{
|
||||
return [new DownloadMangaCoverJob(MangaConnectorMangaEntry, this)];
|
||||
return [new DownloadMangaCoverJob(Manga, this)];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
Reference in New Issue
Block a user