Use publicationCache to store and update Manga
This commit is contained in:
parent
e360037fda
commit
8c66bbc89f
@ -1,8 +1,11 @@
|
|||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Logging;
|
using Logging;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using Tranga.LibraryConnectors;
|
using Tranga.LibraryConnectors;
|
||||||
|
using Tranga.MangaConnectors;
|
||||||
using Tranga.NotificationConnectors;
|
using Tranga.NotificationConnectors;
|
||||||
|
|
||||||
namespace Tranga;
|
namespace Tranga;
|
||||||
@ -14,7 +17,9 @@ public abstract class GlobalBase
|
|||||||
protected TrangaSettings settings { get; init; }
|
protected TrangaSettings settings { get; init; }
|
||||||
protected HashSet<NotificationConnector> notificationConnectors { get; init; }
|
protected HashSet<NotificationConnector> notificationConnectors { get; init; }
|
||||||
protected HashSet<LibraryConnector> libraryConnectors { get; init; }
|
protected HashSet<LibraryConnector> libraryConnectors { get; init; }
|
||||||
protected List<Manga> cachedPublications { get; init; }
|
private Dictionary<string, Manga> cachedPublications { get; init; }
|
||||||
|
|
||||||
|
protected HashSet<MangaConnector> _connectors;
|
||||||
public static readonly NumberFormatInfo numberFormatDecimalPoint = new (){ NumberDecimalSeparator = "." };
|
public static readonly NumberFormatInfo numberFormatDecimalPoint = new (){ NumberDecimalSeparator = "." };
|
||||||
protected static readonly Regex baseUrlRex = new(@"https?:\/\/[0-9A-z\.-]+(:[0-9]+)?");
|
protected static readonly Regex baseUrlRex = new(@"https?:\/\/[0-9A-z\.-]+(:[0-9]+)?");
|
||||||
|
|
||||||
@ -25,6 +30,7 @@ public abstract class GlobalBase
|
|||||||
this.notificationConnectors = clone.notificationConnectors;
|
this.notificationConnectors = clone.notificationConnectors;
|
||||||
this.libraryConnectors = clone.libraryConnectors;
|
this.libraryConnectors = clone.libraryConnectors;
|
||||||
this.cachedPublications = clone.cachedPublications;
|
this.cachedPublications = clone.cachedPublications;
|
||||||
|
this._connectors = clone._connectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected GlobalBase(Logger? logger, TrangaSettings settings)
|
protected GlobalBase(Logger? logger, TrangaSettings settings)
|
||||||
@ -34,6 +40,85 @@ public abstract class GlobalBase
|
|||||||
this.notificationConnectors = settings.LoadNotificationConnectors(this);
|
this.notificationConnectors = settings.LoadNotificationConnectors(this);
|
||||||
this.libraryConnectors = settings.LoadLibraryConnectors(this);
|
this.libraryConnectors = settings.LoadLibraryConnectors(this);
|
||||||
this.cachedPublications = new();
|
this.cachedPublications = new();
|
||||||
|
this._connectors = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Manga? GetCachedManga(string internalId)
|
||||||
|
{
|
||||||
|
return cachedPublications.TryGetValue(internalId, out Manga manga) switch
|
||||||
|
{
|
||||||
|
true => manga,
|
||||||
|
_ => null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected IEnumerable<Manga> GetAllCachedManga() => cachedPublications.Values;
|
||||||
|
|
||||||
|
protected void AddMangaToCache(Manga manga)
|
||||||
|
{
|
||||||
|
if (!cachedPublications.TryAdd(manga.internalId, manga))
|
||||||
|
{
|
||||||
|
Log($"Overwriting Manga {manga.internalId}");
|
||||||
|
cachedPublications[manga.internalId] = manga;
|
||||||
|
}
|
||||||
|
ExportManga();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void RemoveMangaFromCache(Manga manga) => RemoveMangaFromCache(manga.internalId);
|
||||||
|
|
||||||
|
protected void RemoveMangaFromCache(string internalId)
|
||||||
|
{
|
||||||
|
cachedPublications.Remove(internalId);
|
||||||
|
ExportManga();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ImportManga()
|
||||||
|
{
|
||||||
|
string folder = settings.mangaCacheFolderPath;
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
Directory.CreateDirectory(folder,
|
||||||
|
UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.OtherRead | UnixFileMode.OtherWrite |
|
||||||
|
UnixFileMode.UserRead | UnixFileMode.UserWrite);
|
||||||
|
else
|
||||||
|
Directory.CreateDirectory(folder);
|
||||||
|
|
||||||
|
foreach (FileInfo fileInfo in new DirectoryInfo(folder).GetFiles())
|
||||||
|
{
|
||||||
|
string content = File.ReadAllText(fileInfo.FullName);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Manga m = JsonConvert.DeserializeObject<Manga>(content, new MangaConnectorJsonConverter(this, _connectors));
|
||||||
|
this.cachedPublications.TryAdd(m.internalId, m);
|
||||||
|
}
|
||||||
|
catch (JsonException e)
|
||||||
|
{
|
||||||
|
Log($"Error parsing Manga {fileInfo.Name}:\n{e.Message}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ExportManga()
|
||||||
|
{
|
||||||
|
string folder = settings.mangaCacheFolderPath;
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
Directory.CreateDirectory(folder,
|
||||||
|
UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.OtherRead | UnixFileMode.OtherWrite |
|
||||||
|
UnixFileMode.UserRead | UnixFileMode.UserWrite);
|
||||||
|
else
|
||||||
|
Directory.CreateDirectory(folder);
|
||||||
|
foreach (Manga manga in cachedPublications.Values)
|
||||||
|
{
|
||||||
|
string content = JsonConvert.SerializeObject(manga, Formatting.Indented);
|
||||||
|
string filePath = Path.Combine(folder, $"{manga.internalId}.json");
|
||||||
|
File.WriteAllText(filePath, content, Encoding.UTF8);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (FileInfo fileInfo in new DirectoryInfo(folder).GetFiles())
|
||||||
|
{
|
||||||
|
if(!cachedPublications.Keys.Any(key => fileInfo.Name.Substring(0, fileInfo.Name.LastIndexOf('.')).Equals(key)))
|
||||||
|
fileInfo.Delete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void Log(string message)
|
protected void Log(string message)
|
||||||
|
@ -7,12 +7,12 @@ public class DownloadChapter : Job
|
|||||||
{
|
{
|
||||||
public Chapter chapter { get; init; }
|
public Chapter chapter { get; init; }
|
||||||
|
|
||||||
public DownloadChapter(GlobalBase clone, MangaConnector connector, Chapter chapter, DateTime lastExecution, string? parentJobId = null) : base(clone, JobType.DownloadChapterJob, connector, lastExecution, parentJobId: parentJobId)
|
public DownloadChapter(GlobalBase clone, Chapter chapter, DateTime lastExecution, string? parentJobId = null) : base(clone, JobType.DownloadChapterJob, lastExecution, parentJobId: parentJobId)
|
||||||
{
|
{
|
||||||
this.chapter = chapter;
|
this.chapter = chapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadChapter(GlobalBase clone, MangaConnector connector, Chapter chapter, string? parentJobId = null) : base(clone, JobType.DownloadChapterJob, connector, parentJobId: parentJobId)
|
public DownloadChapter(GlobalBase clone, Chapter chapter, string? parentJobId = null) : base(clone, JobType.DownloadChapterJob, parentJobId: parentJobId)
|
||||||
{
|
{
|
||||||
this.chapter = chapter;
|
this.chapter = chapter;
|
||||||
}
|
}
|
||||||
@ -44,11 +44,15 @@ public class DownloadChapter : Job
|
|||||||
return Array.Empty<Job>();
|
return Array.Empty<Job>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override MangaConnector GetMangaConnector()
|
||||||
|
{
|
||||||
|
return chapter.parentManga.mangaConnector;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
if (obj is not DownloadChapter otherJob)
|
if (obj is not DownloadChapter otherJob)
|
||||||
return false;
|
return false;
|
||||||
return otherJob.mangaConnector == this.mangaConnector &&
|
return otherJob.chapter.Equals(this.chapter);
|
||||||
otherJob.chapter.Equals(this.chapter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,29 +1,29 @@
|
|||||||
using Tranga.MangaConnectors;
|
using Newtonsoft.Json;
|
||||||
|
using Tranga.MangaConnectors;
|
||||||
|
|
||||||
namespace Tranga.Jobs;
|
namespace Tranga.Jobs;
|
||||||
|
|
||||||
public class DownloadNewChapters : Job
|
public class DownloadNewChapters : Job
|
||||||
{
|
{
|
||||||
public Manga manga { get; set; }
|
public string mangaInternalId { get; set; }
|
||||||
|
[JsonIgnore] private Manga? manga => GetCachedManga(mangaInternalId);
|
||||||
public string translatedLanguage { get; init; }
|
public string translatedLanguage { get; init; }
|
||||||
|
|
||||||
public DownloadNewChapters(GlobalBase clone, Manga manga, DateTime lastExecution,
|
public DownloadNewChapters(GlobalBase clone, string mangaInternalId, DateTime lastExecution, bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base(clone, JobType.DownloadNewChaptersJob, lastExecution, recurring, recurrence, parentJobId)
|
||||||
bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base(clone, JobType.DownloadNewChaptersJob, manga.mangaConnector, lastExecution, recurring,
|
|
||||||
recurrence, parentJobId)
|
|
||||||
{
|
{
|
||||||
this.manga = manga;
|
this.mangaInternalId = mangaInternalId;
|
||||||
this.translatedLanguage = translatedLanguage;
|
this.translatedLanguage = translatedLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DownloadNewChapters(GlobalBase clone, MangaConnector connector, Manga manga, bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base (clone, JobType.DownloadNewChaptersJob, connector, recurring, recurrence, parentJobId)
|
public DownloadNewChapters(GlobalBase clone, MangaConnector connector, string mangaInternalId, bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base (clone, JobType.DownloadNewChaptersJob, recurring, recurrence, parentJobId)
|
||||||
{
|
{
|
||||||
this.manga = manga;
|
this.mangaInternalId = mangaInternalId;
|
||||||
this.translatedLanguage = translatedLanguage;
|
this.translatedLanguage = translatedLanguage;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetId()
|
protected override string GetId()
|
||||||
{
|
{
|
||||||
return $"{GetType()}-{manga.internalId}";
|
return $"{GetType()}-{mangaInternalId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
@ -33,27 +33,38 @@ public class DownloadNewChapters : Job
|
|||||||
|
|
||||||
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss)
|
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss)
|
||||||
{
|
{
|
||||||
manga.SaveSeriesInfoJson(settings.downloadLocation);
|
if (manga is null)
|
||||||
Chapter[] chapters = mangaConnector.GetNewChapters(manga, this.translatedLanguage);
|
{
|
||||||
|
Log($"Manga {mangaInternalId} is missing! Can not execute job.");
|
||||||
|
return Array.Empty<Job>();
|
||||||
|
}
|
||||||
|
manga.Value.SaveSeriesInfoJson(settings.downloadLocation);
|
||||||
|
Chapter[] chapters = manga.Value.mangaConnector.GetNewChapters(manga.Value, this.translatedLanguage);
|
||||||
this.progressToken.increments = chapters.Length;
|
this.progressToken.increments = chapters.Length;
|
||||||
List<Job> jobs = new();
|
List<Job> jobs = new();
|
||||||
mangaConnector.CopyCoverFromCacheToDownloadLocation(manga);
|
manga.Value.mangaConnector.CopyCoverFromCacheToDownloadLocation(manga.Value);
|
||||||
foreach (Chapter chapter in chapters)
|
foreach (Chapter chapter in chapters)
|
||||||
{
|
{
|
||||||
DownloadChapter downloadChapterJob = new(this, this.mangaConnector, chapter, parentJobId: this.id);
|
DownloadChapter downloadChapterJob = new(this, chapter, parentJobId: this.id);
|
||||||
jobs.Add(downloadChapterJob);
|
jobs.Add(downloadChapterJob);
|
||||||
}
|
}
|
||||||
UpdateMetadata updateMetadataJob = new(this, this.manga, parentJobId: this.id);
|
UpdateMetadata updateMetadataJob = new(this, mangaInternalId, parentJobId: this.id);
|
||||||
jobs.Add(updateMetadataJob);
|
jobs.Add(updateMetadataJob);
|
||||||
progressToken.Complete();
|
progressToken.Complete();
|
||||||
return jobs;
|
return jobs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override MangaConnector GetMangaConnector()
|
||||||
|
{
|
||||||
|
if (manga is null)
|
||||||
|
throw new Exception($"Missing Manga {mangaInternalId}");
|
||||||
|
return manga.Value.mangaConnector;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
if (obj is not DownloadNewChapters otherJob)
|
if (obj is not DownloadNewChapters otherJob)
|
||||||
return false;
|
return false;
|
||||||
return otherJob.mangaConnector == this.mangaConnector &&
|
return otherJob.manga.Equals(this.manga);
|
||||||
otherJob.manga.Equals(this.manga);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,6 @@ namespace Tranga.Jobs;
|
|||||||
|
|
||||||
public abstract class Job : GlobalBase
|
public abstract class Job : GlobalBase
|
||||||
{
|
{
|
||||||
public MangaConnector mangaConnector { get; init; }
|
|
||||||
public ProgressToken progressToken { get; private set; }
|
public ProgressToken progressToken { get; private set; }
|
||||||
public bool recurring { get; init; }
|
public bool recurring { get; init; }
|
||||||
public TimeSpan? recurrenceTime { get; set; }
|
public TimeSpan? recurrenceTime { get; set; }
|
||||||
@ -15,12 +14,13 @@ public abstract class Job : GlobalBase
|
|||||||
public string? parentJobId { get; init; }
|
public string? parentJobId { get; init; }
|
||||||
public enum JobType : byte { DownloadChapterJob, DownloadNewChaptersJob, UpdateMetaDataJob, MonitorManga }
|
public enum JobType : byte { DownloadChapterJob, DownloadNewChaptersJob, UpdateMetaDataJob, MonitorManga }
|
||||||
|
|
||||||
|
public MangaConnector mangaConnector => GetMangaConnector();
|
||||||
|
|
||||||
public JobType jobType;
|
public JobType jobType;
|
||||||
|
|
||||||
internal Job(GlobalBase clone, JobType jobType, MangaConnector connector, bool recurring = false, TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone)
|
internal Job(GlobalBase clone, JobType jobType, bool recurring = false, TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone)
|
||||||
{
|
{
|
||||||
this.jobType = jobType;
|
this.jobType = jobType;
|
||||||
this.mangaConnector = connector;
|
|
||||||
this.progressToken = new ProgressToken(0);
|
this.progressToken = new ProgressToken(0);
|
||||||
this.recurring = recurring;
|
this.recurring = recurring;
|
||||||
if (recurring && recurrenceTime is null)
|
if (recurring && recurrenceTime is null)
|
||||||
@ -31,11 +31,10 @@ public abstract class Job : GlobalBase
|
|||||||
this.parentJobId = parentJobId;
|
this.parentJobId = parentJobId;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal Job(GlobalBase clone, JobType jobType, MangaConnector connector, DateTime lastExecution, bool recurring = false,
|
internal Job(GlobalBase clone, JobType jobType, DateTime lastExecution, bool recurring = false,
|
||||||
TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone)
|
TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone)
|
||||||
{
|
{
|
||||||
this.jobType = jobType;
|
this.jobType = jobType;
|
||||||
this.mangaConnector = connector;
|
|
||||||
this.progressToken = new ProgressToken(0);
|
this.progressToken = new ProgressToken(0);
|
||||||
this.recurring = recurring;
|
this.recurring = recurring;
|
||||||
if (recurring && recurrenceTime is null)
|
if (recurring && recurrenceTime is null)
|
||||||
@ -95,4 +94,6 @@ public abstract class Job : GlobalBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected abstract IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss);
|
protected abstract IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss);
|
||||||
|
|
||||||
|
protected abstract MangaConnector GetMangaConnector();
|
||||||
}
|
}
|
@ -65,11 +65,9 @@ public class JobBoss : GlobalBase
|
|||||||
RemoveJob(job);
|
RemoveJob(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Job> GetJobsLike(string? connectorName = null, string? internalId = null, string? chapterNumber = null)
|
public IEnumerable<Job> GetJobsLike(string? internalId = null, string? chapterNumber = null)
|
||||||
{
|
{
|
||||||
IEnumerable<Job> ret = this.jobs;
|
IEnumerable<Job> ret = this.jobs;
|
||||||
if (connectorName is not null)
|
|
||||||
ret = ret.Where(job => job.mangaConnector.name == connectorName);
|
|
||||||
|
|
||||||
if (internalId is not null && chapterNumber is not null)
|
if (internalId is not null && chapterNumber is not null)
|
||||||
ret = ret.Where(jjob =>
|
ret = ret.Where(jjob =>
|
||||||
@ -84,18 +82,18 @@ public class JobBoss : GlobalBase
|
|||||||
{
|
{
|
||||||
if (jjob is not DownloadNewChapters job)
|
if (jjob is not DownloadNewChapters job)
|
||||||
return false;
|
return false;
|
||||||
return job.manga.internalId == internalId;
|
return job.mangaInternalId == internalId;
|
||||||
});
|
});
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<Job> GetJobsLike(MangaConnector? mangaConnector = null, Manga? publication = null,
|
public IEnumerable<Job> GetJobsLike(Manga? publication = null,
|
||||||
Chapter? chapter = null)
|
Chapter? chapter = null)
|
||||||
{
|
{
|
||||||
if (chapter is not null)
|
if (chapter is not null)
|
||||||
return GetJobsLike(mangaConnector?.name, chapter.Value.parentManga.internalId, chapter.Value.chapterNumber);
|
return GetJobsLike(chapter.Value.parentManga.internalId, chapter.Value.chapterNumber);
|
||||||
else
|
else
|
||||||
return GetJobsLike(mangaConnector?.name, publication?.internalId);
|
return GetJobsLike(publication?.internalId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Job? GetJobById(string jobId)
|
public Job? GetJobById(string jobId)
|
||||||
@ -154,16 +152,28 @@ public class JobBoss : GlobalBase
|
|||||||
new JobJsonConverter(this, new MangaConnectorJsonConverter(this, connectors)))!;
|
new JobJsonConverter(this, new MangaConnectorJsonConverter(this, connectors)))!;
|
||||||
this.jobs.Add(job);
|
this.jobs.Add(job);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Load Manga-Files
|
||||||
|
ImportManga();
|
||||||
|
|
||||||
//Connect jobs to parent-jobs and add Publications to cache
|
//Connect jobs to parent-jobs
|
||||||
foreach (Job job in this.jobs)
|
foreach (Job job in this.jobs)
|
||||||
{
|
{
|
||||||
this.jobs.FirstOrDefault(jjob => jjob.id == job.parentJobId)?.AddSubJob(job);
|
this.jobs.FirstOrDefault(jjob => jjob.id == job.parentJobId)?.AddSubJob(job);
|
||||||
if (job is DownloadNewChapters dncJob)
|
|
||||||
cachedPublications.Add(dncJob.manga);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<string> coverFileNames = cachedPublications.Select(manga => manga.coverFileNameInCache!).ToHashSet();
|
string[] jobMangaInternalIds = this.jobs.Where(job => job is DownloadNewChapters)
|
||||||
|
.Select(dnc => ((DownloadNewChapters)dnc).mangaInternalId).ToArray();
|
||||||
|
jobMangaInternalIds = jobMangaInternalIds.Concat(
|
||||||
|
this.jobs.Where(job => job is UpdateMetadata)
|
||||||
|
.Select(dnc => ((UpdateMetadata)dnc).mangaInternalId)).ToArray();
|
||||||
|
string[] internalIds = GetAllCachedManga().Select(m => m.internalId).ToArray();
|
||||||
|
|
||||||
|
string[] extraneousIds = internalIds.Except(jobMangaInternalIds).ToArray();
|
||||||
|
foreach (string internalId in extraneousIds)
|
||||||
|
RemoveMangaFromCache(internalId);
|
||||||
|
|
||||||
|
HashSet<string> coverFileNames = GetAllCachedManga().Select(manga => manga.coverFileNameInCache!).ToHashSet();
|
||||||
foreach (string fileName in Directory.GetFiles(settings.coverImageCache)) //Cleanup Unused Covers
|
foreach (string fileName in Directory.GetFiles(settings.coverImageCache)) //Cleanup Unused Covers
|
||||||
{
|
{
|
||||||
if(!coverFileNames.Any(existingManga => fileName.Contains(existingManga)))
|
if(!coverFileNames.Any(existingManga => fileName.Contains(existingManga)))
|
||||||
@ -171,7 +181,7 @@ public class JobBoss : GlobalBase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateJobFile(Job job)
|
internal void UpdateJobFile(Job job)
|
||||||
{
|
{
|
||||||
string jobFilePath = Path.Join(settings.jobsFolderPath, $"{job.id}.json");
|
string jobFilePath = Path.Join(settings.jobsFolderPath, $"{job.id}.json");
|
||||||
|
|
||||||
@ -245,7 +255,9 @@ public class JobBoss : GlobalBase
|
|||||||
Log($"Next job in {jobs.MinBy(job => job.nextExecution)?.nextExecution.Subtract(DateTime.Now)} {jobs.MinBy(job => job.nextExecution)?.id}");
|
Log($"Next job in {jobs.MinBy(job => job.nextExecution)?.nextExecution.Subtract(DateTime.Now)} {jobs.MinBy(job => job.nextExecution)?.id}");
|
||||||
}else if (queueHead.progressToken.state is ProgressToken.State.Standby)
|
}else if (queueHead.progressToken.state is ProgressToken.State.Standby)
|
||||||
{
|
{
|
||||||
Job[] subJobs = jobQueue.Peek().ExecuteReturnSubTasks(this).ToArray();
|
Job eJob = jobQueue.Peek();
|
||||||
|
Job[] subJobs = eJob.ExecuteReturnSubTasks(this).ToArray();
|
||||||
|
UpdateJobFile(eJob);
|
||||||
AddJobs(subJobs);
|
AddJobs(subJobs);
|
||||||
AddJobsToQueue(subJobs);
|
AddJobsToQueue(subJobs);
|
||||||
}else if (queueHead.progressToken.state is ProgressToken.State.Running && DateTime.Now.Subtract(queueHead.progressToken.lastUpdate) > TimeSpan.FromMinutes(5))
|
}else if (queueHead.progressToken.state is ProgressToken.State.Running && DateTime.Now.Subtract(queueHead.progressToken.lastUpdate) > TimeSpan.FromMinutes(5))
|
||||||
|
@ -30,16 +30,9 @@ public class JobJsonConverter : JsonConverter
|
|||||||
return Enum.Parse<Job.JobType>(jo["jobType"]!.Value<byte>().ToString()) switch
|
return Enum.Parse<Job.JobType>(jo["jobType"]!.Value<byte>().ToString()) switch
|
||||||
{
|
{
|
||||||
Job.JobType.UpdateMetaDataJob => new UpdateMetadata(_clone,
|
Job.JobType.UpdateMetaDataJob => new UpdateMetadata(_clone,
|
||||||
jo.GetValue("manga")!.ToObject<Manga>(JsonSerializer.Create(new JsonSerializerSettings()
|
jo.GetValue("mangaInternalId")!.Value<string>()!,
|
||||||
{
|
|
||||||
Converters = { this._mangaConnectorJsonConverter }
|
|
||||||
})),
|
|
||||||
jo.GetValue("parentJobId")!.Value<string?>()),
|
jo.GetValue("parentJobId")!.Value<string?>()),
|
||||||
Job.JobType.DownloadChapterJob => new DownloadChapter(this._clone,
|
Job.JobType.DownloadChapterJob => new DownloadChapter(this._clone,
|
||||||
jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings()
|
|
||||||
{
|
|
||||||
Converters = { this._mangaConnectorJsonConverter }
|
|
||||||
}))!,
|
|
||||||
jo.GetValue("chapter")!.ToObject<Chapter>(JsonSerializer.Create(new JsonSerializerSettings()
|
jo.GetValue("chapter")!.ToObject<Chapter>(JsonSerializer.Create(new JsonSerializerSettings()
|
||||||
{
|
{
|
||||||
Converters = { this._mangaConnectorJsonConverter }
|
Converters = { this._mangaConnectorJsonConverter }
|
||||||
@ -47,10 +40,7 @@ public class JobJsonConverter : JsonConverter
|
|||||||
DateTime.UnixEpoch,
|
DateTime.UnixEpoch,
|
||||||
jo.GetValue("parentJobId")!.Value<string?>()),
|
jo.GetValue("parentJobId")!.Value<string?>()),
|
||||||
Job.JobType.DownloadNewChaptersJob => new DownloadNewChapters(this._clone,
|
Job.JobType.DownloadNewChaptersJob => new DownloadNewChapters(this._clone,
|
||||||
jo.GetValue("manga")!.ToObject<Manga>(JsonSerializer.Create(new JsonSerializerSettings()
|
jo.GetValue("mangaInternalId")!.Value<string>()!,
|
||||||
{
|
|
||||||
Converters = { this._mangaConnectorJsonConverter }
|
|
||||||
})),
|
|
||||||
jo.GetValue("lastExecution") is {} le
|
jo.GetValue("lastExecution") is {} le
|
||||||
? le.ToObject<DateTime>()
|
? le.ToObject<DateTime>()
|
||||||
: DateTime.UnixEpoch,
|
: DateTime.UnixEpoch,
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
using Tranga.MangaConnectors;
|
using System.Text.Json.Serialization;
|
||||||
|
using Tranga.MangaConnectors;
|
||||||
|
|
||||||
namespace Tranga.Jobs;
|
namespace Tranga.Jobs;
|
||||||
|
|
||||||
public class UpdateMetadata : Job
|
public class UpdateMetadata : Job
|
||||||
{
|
{
|
||||||
public Manga manga { get; set; }
|
public string mangaInternalId { get; set; }
|
||||||
|
[JsonIgnore] private Manga? manga => GetCachedManga(mangaInternalId);
|
||||||
|
|
||||||
public UpdateMetadata(GlobalBase clone, Manga manga, string? parentJobId = null) : base(clone, JobType.UpdateMetaDataJob, manga.mangaConnector, parentJobId: parentJobId)
|
public UpdateMetadata(GlobalBase clone, string mangaInternalId, string? parentJobId = null) : base(clone, JobType.UpdateMetaDataJob, parentJobId: parentJobId)
|
||||||
{
|
{
|
||||||
this.manga = manga;
|
this.mangaInternalId = mangaInternalId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override string GetId()
|
protected override string GetId()
|
||||||
{
|
{
|
||||||
return $"{GetType()}-{manga.internalId}";
|
return $"{GetType()}-{mangaInternalId}";
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
@ -23,8 +25,14 @@ public class UpdateMetadata : Job
|
|||||||
|
|
||||||
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss)
|
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss)
|
||||||
{
|
{
|
||||||
|
if (manga is null)
|
||||||
|
{
|
||||||
|
Log($"Manga {mangaInternalId} is missing! Can not execute job.");
|
||||||
|
return Array.Empty<Job>();
|
||||||
|
}
|
||||||
|
|
||||||
//Retrieve new Metadata
|
//Retrieve new Metadata
|
||||||
Manga? possibleUpdatedManga = mangaConnector.GetMangaFromId(manga.publicationId);
|
Manga? possibleUpdatedManga = mangaConnector.GetMangaFromId(manga.Value.publicationId);
|
||||||
if (possibleUpdatedManga is { } updatedManga)
|
if (possibleUpdatedManga is { } updatedManga)
|
||||||
{
|
{
|
||||||
if (updatedManga.Equals(this.manga)) //Check if anything changed
|
if (updatedManga.Equals(this.manga)) //Check if anything changed
|
||||||
@ -33,8 +41,8 @@ public class UpdateMetadata : Job
|
|||||||
return Array.Empty<Job>();
|
return Array.Empty<Job>();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.manga.UpdateMetadata(updatedManga);
|
AddMangaToCache(manga.Value.WithMetadata(updatedManga));
|
||||||
this.manga.SaveSeriesInfoJson(settings.downloadLocation, true);
|
this.manga.Value.SaveSeriesInfoJson(settings.downloadLocation, true);
|
||||||
this.progressToken.Complete();
|
this.progressToken.Complete();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -47,12 +55,18 @@ public class UpdateMetadata : Job
|
|||||||
return Array.Empty<Job>();
|
return Array.Empty<Job>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override MangaConnector GetMangaConnector()
|
||||||
|
{
|
||||||
|
if (manga is null)
|
||||||
|
throw new Exception($"Missing Manga {mangaInternalId}");
|
||||||
|
return manga.Value.mangaConnector;
|
||||||
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (obj is not UpdateMetadata otherJob)
|
if (obj is not UpdateMetadata otherJob)
|
||||||
return false;
|
return false;
|
||||||
return otherJob.mangaConnector == this.mangaConnector &&
|
return otherJob.manga.Equals(this.manga);
|
||||||
otherJob.manga.Equals(this.manga);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -74,16 +74,20 @@ public struct Manga
|
|||||||
this.websiteUrl = websiteUrl;
|
this.websiteUrl = websiteUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdateMetadata(Manga newManga)
|
public Manga WithMetadata(Manga newManga)
|
||||||
{
|
{
|
||||||
this.sortName = newManga.sortName;
|
return this with
|
||||||
this.description = newManga.description;
|
{
|
||||||
this.coverUrl = newManga.coverUrl;
|
sortName = newManga.sortName,
|
||||||
this.authors = authors.Union(newManga.authors).ToList();
|
description = newManga.description,
|
||||||
this.altTitles = altTitles.UnionBy(newManga.altTitles, kv => kv.Key).ToDictionary(x => x.Key, x => x.Value);
|
coverUrl = newManga.coverUrl,
|
||||||
this.tags = tags.Union(newManga.tags).ToArray();
|
authors = authors.Union(newManga.authors).ToList(),
|
||||||
this.releaseStatus = newManga.releaseStatus;
|
altTitles = altTitles.UnionBy(newManga.altTitles, kv => kv.Key).ToDictionary(x => x.Key, x => x.Value),
|
||||||
this.year = newManga.year;
|
tags = tags.Union(newManga.tags).ToArray(),
|
||||||
|
releaseStatus = newManga.releaseStatus,
|
||||||
|
year = newManga.year,
|
||||||
|
websiteUrl = newManga.websiteUrl
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
public override bool Equals(object? obj)
|
||||||
@ -96,6 +100,7 @@ public struct Manga
|
|||||||
this.sortName == compareManga.sortName &&
|
this.sortName == compareManga.sortName &&
|
||||||
this.latestChapterAvailable.Equals(compareManga.latestChapterAvailable) &&
|
this.latestChapterAvailable.Equals(compareManga.latestChapterAvailable) &&
|
||||||
this.authors.All(a => compareManga.authors.Contains(a)) &&
|
this.authors.All(a => compareManga.authors.Contains(a)) &&
|
||||||
|
this.websiteUrl.Equals(compareManga.websiteUrl) &&
|
||||||
this.tags.All(t => compareManga.tags.Contains(t));
|
this.tags.All(t => compareManga.tags.Contains(t));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ public class Bato : MangaConnector
|
|||||||
|
|
||||||
Manga manga = new (this, sortName, authors, description, altTitles, tags, posterUrl, coverFileNameInCache, new Dictionary<string, string>(),
|
Manga manga = new (this, sortName, authors, description, altTitles, tags, posterUrl, coverFileNameInCache, new Dictionary<string, string>(),
|
||||||
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
||||||
cachedPublications.Add(manga);
|
AddMangaToCache(manga);
|
||||||
return manga;
|
return manga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +188,7 @@ public class MangaDex : MangaConnector
|
|||||||
releaseStatus,
|
releaseStatus,
|
||||||
$"https://mangadex.org/title/{publicationId}"
|
$"https://mangadex.org/title/{publicationId}"
|
||||||
);
|
);
|
||||||
cachedPublications.Add(pub);
|
AddMangaToCache(pub);
|
||||||
return pub;
|
return pub;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +143,7 @@ public class MangaKatana : MangaConnector
|
|||||||
|
|
||||||
Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
||||||
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
||||||
cachedPublications.Add(manga);
|
AddMangaToCache(manga);
|
||||||
return manga;
|
return manga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +123,7 @@ public class MangaLife : MangaConnector
|
|||||||
|
|
||||||
Manga manga = new(this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl,
|
Manga manga = new(this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl,
|
||||||
coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
||||||
cachedPublications.Add(manga);
|
AddMangaToCache(manga);
|
||||||
return manga;
|
return manga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ public class Manganato : MangaConnector
|
|||||||
|
|
||||||
Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
||||||
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
||||||
cachedPublications.Add(manga);
|
AddMangaToCache(manga);
|
||||||
return manga;
|
return manga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,7 @@ public class Mangasee : MangaConnector
|
|||||||
|
|
||||||
Manga manga = new(this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl,
|
Manga manga = new(this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl,
|
||||||
coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
||||||
cachedPublications.Add(manga);
|
AddMangaToCache(manga);
|
||||||
return manga;
|
return manga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +120,7 @@ public class Mangaworld: MangaConnector
|
|||||||
|
|
||||||
Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
||||||
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
year, originalLanguage, publicationId, releaseStatus, websiteUrl);
|
||||||
cachedPublications.Add(manga);
|
AddMangaToCache(manga);
|
||||||
return manga;
|
return manga;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ public partial class Server : GlobalBase, IDisposable
|
|||||||
new ("GET", @"/v2/Jobs/Waiting", GetV2JobsWaiting),
|
new ("GET", @"/v2/Jobs/Waiting", GetV2JobsWaiting),
|
||||||
new ("GET", @"/v2/Jobs/Monitoring", GetV2JobsMonitoring),
|
new ("GET", @"/v2/Jobs/Monitoring", GetV2JobsMonitoring),
|
||||||
new ("Get", @"/v2/Job/Types", GetV2JobTypes),
|
new ("Get", @"/v2/Job/Types", GetV2JobTypes),
|
||||||
new ("POST", @"/v2/Job/Create/([a-zA-Z]+)", PostV2JobsCreateType),
|
new ("POST", @"/v2/Job/Create/([a-zA-Z]+)", PostV2JobCreateType),
|
||||||
new ("GET", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)", GetV2JobJobId),
|
new ("GET", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)", GetV2JobJobId),
|
||||||
new ("DELETE", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)", DeleteV2JobJobId),
|
new ("DELETE", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)", DeleteV2JobJobId),
|
||||||
new ("GET", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)/Progress", GetV2JobJobIdProgress),
|
new ("GET", @"/v2/Job/([a-zA-Z\.]+-[-A-Za-z0-9+/]*={0,3}(?:-[0-9]+)?)/Progress", GetV2JobJobIdProgress),
|
||||||
|
@ -38,7 +38,7 @@ public partial class Server
|
|||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, Enum.GetNames(typeof(Job.JobType)));
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, Enum.GetNames(typeof(Job.JobType)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTuple<HttpStatusCode, object?> PostV2JobsCreateType(GroupCollection groups, Dictionary<string, string> requestParameters)
|
private ValueTuple<HttpStatusCode, object?> PostV2JobCreateType(GroupCollection groups, Dictionary<string, string> requestParameters)
|
||||||
{
|
{
|
||||||
if (groups.Count < 1 ||
|
if (groups.Count < 1 ||
|
||||||
!Enum.TryParse(groups[1].Value, true, out Job.JobType jobType))
|
!Enum.TryParse(groups[1].Value, true, out Job.JobType jobType))
|
||||||
@ -59,14 +59,14 @@ public partial class Server
|
|||||||
!TimeSpan.TryParse(intervalStr, out TimeSpan interval))
|
!TimeSpan.TryParse(intervalStr, out TimeSpan interval))
|
||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.InternalServerError, "'interval' Parameter missing, or is not in correct format.");
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.InternalServerError, "'interval' Parameter missing, or is not in correct format.");
|
||||||
requestParameters.TryGetValue("language", out string? language);
|
requestParameters.TryGetValue("language", out string? language);
|
||||||
_parent.jobBoss.AddJob(new DownloadNewChapters(this, ((Manga)manga).mangaConnector, (Manga)manga, true, interval, language));
|
_parent.jobBoss.AddJob(new DownloadNewChapters(this, ((Manga)manga).mangaConnector, ((Manga)manga).internalId, true, interval, language));
|
||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, null);
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, null);
|
||||||
case Job.JobType.UpdateMetaDataJob:
|
case Job.JobType.UpdateMetaDataJob:
|
||||||
if(!requestParameters.TryGetValue("internalId", out mangaId) ||
|
if(!requestParameters.TryGetValue("internalId", out mangaId) ||
|
||||||
!_parent.TryGetPublicationById(mangaId, out manga) ||
|
!_parent.TryGetPublicationById(mangaId, out manga) ||
|
||||||
manga is null)
|
manga is null)
|
||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.NotFound, "InternalId Parameter missing, or is not a valid ID.");
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.NotFound, "InternalId Parameter missing, or is not a valid ID.");
|
||||||
_parent.jobBoss.AddJob(new UpdateMetadata(this, (Manga)manga));
|
_parent.jobBoss.AddJob(new UpdateMetadata(this, ((Manga)manga).internalId));
|
||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, null);
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, null);
|
||||||
case Job.JobType.DownloadNewChaptersJob: //TODO
|
case Job.JobType.DownloadNewChaptersJob: //TODO
|
||||||
case Job.JobType.DownloadChapterJob: //TODO
|
case Job.JobType.DownloadChapterJob: //TODO
|
||||||
|
@ -8,7 +8,7 @@ public partial class Server
|
|||||||
{
|
{
|
||||||
private ValueTuple<HttpStatusCode, object?> GetV2Manga(GroupCollection groups, Dictionary<string, string> requestParameters)
|
private ValueTuple<HttpStatusCode, object?> GetV2Manga(GroupCollection groups, Dictionary<string, string> requestParameters)
|
||||||
{
|
{
|
||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, cachedPublications.Select(m => m.internalId));
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, GetAllCachedManga().Select(m => m.internalId));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ValueTuple<HttpStatusCode, object?> GetV2MangaInternalId(GroupCollection groups, Dictionary<string, string> requestParameters)
|
private ValueTuple<HttpStatusCode, object?> GetV2MangaInternalId(GroupCollection groups, Dictionary<string, string> requestParameters)
|
||||||
@ -28,6 +28,7 @@ public partial class Server
|
|||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.NotFound, $"Manga with ID '{groups[1].Value} could not be found.'");
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.NotFound, $"Manga with ID '{groups[1].Value} could not be found.'");
|
||||||
Job[] jobs = _parent.jobBoss.GetJobsLike(publication: manga).ToArray();
|
Job[] jobs = _parent.jobBoss.GetJobsLike(publication: manga).ToArray();
|
||||||
_parent.jobBoss.RemoveJobs(jobs);
|
_parent.jobBoss.RemoveJobs(jobs);
|
||||||
|
RemoveMangaFromCache(groups[1].Value);
|
||||||
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, null);
|
return new ValueTuple<HttpStatusCode, object?>(HttpStatusCode.OK, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,7 +9,6 @@ public partial class Tranga : GlobalBase
|
|||||||
public bool keepRunning;
|
public bool keepRunning;
|
||||||
public JobBoss jobBoss;
|
public JobBoss jobBoss;
|
||||||
private Server.Server _server;
|
private Server.Server _server;
|
||||||
private HashSet<MangaConnector> _connectors;
|
|
||||||
|
|
||||||
public Tranga(Logger? logger, TrangaSettings settings) : base(logger, settings)
|
public Tranga(Logger? logger, TrangaSettings settings) : base(logger, settings)
|
||||||
{
|
{
|
||||||
@ -54,12 +53,7 @@ public partial class Tranga : GlobalBase
|
|||||||
return _connectors.Select(c => c.name);
|
return _connectors.Select(c => c.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Manga? GetPublicationById(string internalId)
|
public Manga? GetPublicationById(string internalId) => GetCachedManga(internalId);
|
||||||
{
|
|
||||||
if (cachedPublications.Exists(publication => publication.internalId == internalId))
|
|
||||||
return cachedPublications.First(publication => publication.internalId == internalId);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetPublicationById(string internalId, out Manga? manga)
|
public bool TryGetPublicationById(string internalId, out Manga? manga)
|
||||||
{
|
{
|
||||||
|
@ -19,6 +19,7 @@ public class TrangaSettings
|
|||||||
[JsonIgnore] public string libraryConnectorsFilePath => Path.Join(workingDirectory, "libraryConnectors.json");
|
[JsonIgnore] public string libraryConnectorsFilePath => Path.Join(workingDirectory, "libraryConnectors.json");
|
||||||
[JsonIgnore] public string notificationConnectorsFilePath => Path.Join(workingDirectory, "notificationConnectors.json");
|
[JsonIgnore] public string notificationConnectorsFilePath => Path.Join(workingDirectory, "notificationConnectors.json");
|
||||||
[JsonIgnore] public string jobsFolderPath => Path.Join(workingDirectory, "jobs");
|
[JsonIgnore] public string jobsFolderPath => Path.Join(workingDirectory, "jobs");
|
||||||
|
[JsonIgnore] public string mangaCacheFolderPath => Path.Join(workingDirectory, "manga");
|
||||||
[JsonIgnore] public string coverImageCache => Path.Join(workingDirectory, "imageCache");
|
[JsonIgnore] public string coverImageCache => Path.Join(workingDirectory, "imageCache");
|
||||||
[JsonIgnore] internal static readonly string DefaultUserAgent = $"Tranga ({Enum.GetName(Environment.OSVersion.Platform)}; {(Environment.Is64BitOperatingSystem ? "x64" : "")}) / 1.0";
|
[JsonIgnore] internal static readonly string DefaultUserAgent = $"Tranga ({Enum.GetName(Environment.OSVersion.Platform)}; {(Environment.Is64BitOperatingSystem ? "x64" : "")}) / 1.0";
|
||||||
public ushort? version { get; } = 2;
|
public ushort? version { get; } = 2;
|
||||||
|
Loading…
Reference in New Issue
Block a user