From 8c66bbc89fca9c0064fbf1893dce5d4fa22e4686 Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 22 Apr 2024 23:45:51 +0200 Subject: [PATCH] Use publicationCache to store and update Manga --- Tranga/GlobalBase.cs | 87 ++++++++++++++++++++++++++- Tranga/Jobs/DownloadChapter.cs | 12 ++-- Tranga/Jobs/DownloadNewChapters.cs | 43 ++++++++----- Tranga/Jobs/Job.cs | 11 ++-- Tranga/Jobs/JobBoss.cs | 38 ++++++++---- Tranga/Jobs/JobJsonConverter.cs | 14 +---- Tranga/Jobs/UpdateMetadata.cs | 34 ++++++++--- Tranga/Manga.cs | 23 ++++--- Tranga/MangaConnectors/Bato.cs | 2 +- Tranga/MangaConnectors/MangaDex.cs | 2 +- Tranga/MangaConnectors/MangaKatana.cs | 2 +- Tranga/MangaConnectors/MangaLife.cs | 2 +- Tranga/MangaConnectors/Manganato.cs | 2 +- Tranga/MangaConnectors/Mangasee.cs | 2 +- Tranga/MangaConnectors/Mangaworld.cs | 2 +- Tranga/Server/Server.cs | 2 +- Tranga/Server/v2Jobs.cs | 6 +- Tranga/Server/v2Manga.cs | 3 +- Tranga/Tranga.cs | 8 +-- Tranga/TrangaSettings.cs | 1 + 20 files changed, 207 insertions(+), 89 deletions(-) diff --git a/Tranga/GlobalBase.cs b/Tranga/GlobalBase.cs index ce01a79..b320ef1 100644 --- a/Tranga/GlobalBase.cs +++ b/Tranga/GlobalBase.cs @@ -1,8 +1,11 @@ using System.Globalization; +using System.Runtime.InteropServices; +using System.Text; using System.Text.RegularExpressions; using Logging; using Newtonsoft.Json; using Tranga.LibraryConnectors; +using Tranga.MangaConnectors; using Tranga.NotificationConnectors; namespace Tranga; @@ -14,7 +17,9 @@ public abstract class GlobalBase protected TrangaSettings settings { get; init; } protected HashSet notificationConnectors { get; init; } protected HashSet libraryConnectors { get; init; } - protected List cachedPublications { get; init; } + private Dictionary cachedPublications { get; init; } + + protected HashSet _connectors; public static readonly NumberFormatInfo numberFormatDecimalPoint = new (){ NumberDecimalSeparator = "." }; 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.libraryConnectors = clone.libraryConnectors; this.cachedPublications = clone.cachedPublications; + this._connectors = clone._connectors; } protected GlobalBase(Logger? logger, TrangaSettings settings) @@ -34,6 +40,85 @@ public abstract class GlobalBase this.notificationConnectors = settings.LoadNotificationConnectors(this); this.libraryConnectors = settings.LoadLibraryConnectors(this); this.cachedPublications = new(); + this._connectors = new(); + } + + protected Manga? GetCachedManga(string internalId) + { + return cachedPublications.TryGetValue(internalId, out Manga manga) switch + { + true => manga, + _ => null + }; + } + + protected IEnumerable 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(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) diff --git a/Tranga/Jobs/DownloadChapter.cs b/Tranga/Jobs/DownloadChapter.cs index 434736e..7e1de35 100644 --- a/Tranga/Jobs/DownloadChapter.cs +++ b/Tranga/Jobs/DownloadChapter.cs @@ -7,12 +7,12 @@ public class DownloadChapter : Job { 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; } - 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; } @@ -44,11 +44,15 @@ public class DownloadChapter : Job return Array.Empty(); } + protected override MangaConnector GetMangaConnector() + { + return chapter.parentManga.mangaConnector; + } + public override bool Equals(object? obj) { if (obj is not DownloadChapter otherJob) return false; - return otherJob.mangaConnector == this.mangaConnector && - otherJob.chapter.Equals(this.chapter); + return otherJob.chapter.Equals(this.chapter); } } \ No newline at end of file diff --git a/Tranga/Jobs/DownloadNewChapters.cs b/Tranga/Jobs/DownloadNewChapters.cs index a202c49..da8c519 100644 --- a/Tranga/Jobs/DownloadNewChapters.cs +++ b/Tranga/Jobs/DownloadNewChapters.cs @@ -1,29 +1,29 @@ -using Tranga.MangaConnectors; +using Newtonsoft.Json; +using Tranga.MangaConnectors; namespace Tranga.Jobs; 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 DownloadNewChapters(GlobalBase clone, Manga manga, DateTime lastExecution, - bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base(clone, JobType.DownloadNewChaptersJob, manga.mangaConnector, lastExecution, recurring, - recurrence, parentJobId) + 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) { - this.manga = manga; + this.mangaInternalId = mangaInternalId; 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; } protected override string GetId() { - return $"{GetType()}-{manga.internalId}"; + return $"{GetType()}-{mangaInternalId}"; } public override string ToString() @@ -33,27 +33,38 @@ public class DownloadNewChapters : Job protected override IEnumerable ExecuteReturnSubTasksInternal(JobBoss jobBoss) { - manga.SaveSeriesInfoJson(settings.downloadLocation); - Chapter[] chapters = mangaConnector.GetNewChapters(manga, this.translatedLanguage); + if (manga is null) + { + Log($"Manga {mangaInternalId} is missing! Can not execute job."); + return Array.Empty(); + } + manga.Value.SaveSeriesInfoJson(settings.downloadLocation); + Chapter[] chapters = manga.Value.mangaConnector.GetNewChapters(manga.Value, this.translatedLanguage); this.progressToken.increments = chapters.Length; List jobs = new(); - mangaConnector.CopyCoverFromCacheToDownloadLocation(manga); + manga.Value.mangaConnector.CopyCoverFromCacheToDownloadLocation(manga.Value); 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); } - UpdateMetadata updateMetadataJob = new(this, this.manga, parentJobId: this.id); + UpdateMetadata updateMetadataJob = new(this, mangaInternalId, parentJobId: this.id); jobs.Add(updateMetadataJob); progressToken.Complete(); 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) { if (obj is not DownloadNewChapters otherJob) return false; - return otherJob.mangaConnector == this.mangaConnector && - otherJob.manga.Equals(this.manga); + return otherJob.manga.Equals(this.manga); } } \ No newline at end of file diff --git a/Tranga/Jobs/Job.cs b/Tranga/Jobs/Job.cs index 8ce37be..71dbc24 100644 --- a/Tranga/Jobs/Job.cs +++ b/Tranga/Jobs/Job.cs @@ -4,7 +4,6 @@ namespace Tranga.Jobs; public abstract class Job : GlobalBase { - public MangaConnector mangaConnector { get; init; } public ProgressToken progressToken { get; private set; } public bool recurring { get; init; } public TimeSpan? recurrenceTime { get; set; } @@ -15,12 +14,13 @@ public abstract class Job : GlobalBase public string? parentJobId { get; init; } public enum JobType : byte { DownloadChapterJob, DownloadNewChaptersJob, UpdateMetaDataJob, MonitorManga } + public MangaConnector mangaConnector => GetMangaConnector(); + 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.mangaConnector = connector; this.progressToken = new ProgressToken(0); this.recurring = recurring; if (recurring && recurrenceTime is null) @@ -31,11 +31,10 @@ public abstract class Job : GlobalBase 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) { this.jobType = jobType; - this.mangaConnector = connector; this.progressToken = new ProgressToken(0); this.recurring = recurring; if (recurring && recurrenceTime is null) @@ -95,4 +94,6 @@ public abstract class Job : GlobalBase } protected abstract IEnumerable ExecuteReturnSubTasksInternal(JobBoss jobBoss); + + protected abstract MangaConnector GetMangaConnector(); } \ No newline at end of file diff --git a/Tranga/Jobs/JobBoss.cs b/Tranga/Jobs/JobBoss.cs index 99670b4..85a27a4 100644 --- a/Tranga/Jobs/JobBoss.cs +++ b/Tranga/Jobs/JobBoss.cs @@ -65,11 +65,9 @@ public class JobBoss : GlobalBase RemoveJob(job); } - public IEnumerable GetJobsLike(string? connectorName = null, string? internalId = null, string? chapterNumber = null) + public IEnumerable GetJobsLike(string? internalId = null, string? chapterNumber = null) { IEnumerable 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) ret = ret.Where(jjob => @@ -84,18 +82,18 @@ public class JobBoss : GlobalBase { if (jjob is not DownloadNewChapters job) return false; - return job.manga.internalId == internalId; + return job.mangaInternalId == internalId; }); return ret; } - public IEnumerable GetJobsLike(MangaConnector? mangaConnector = null, Manga? publication = null, + public IEnumerable GetJobsLike(Manga? publication = null, Chapter? chapter = 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 - return GetJobsLike(mangaConnector?.name, publication?.internalId); + return GetJobsLike(publication?.internalId); } public Job? GetJobById(string jobId) @@ -154,16 +152,28 @@ public class JobBoss : GlobalBase new JobJsonConverter(this, new MangaConnectorJsonConverter(this, connectors)))!; 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) { this.jobs.FirstOrDefault(jjob => jjob.id == job.parentJobId)?.AddSubJob(job); - if (job is DownloadNewChapters dncJob) - cachedPublications.Add(dncJob.manga); } - HashSet 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 coverFileNames = GetAllCachedManga().Select(manga => manga.coverFileNameInCache!).ToHashSet(); foreach (string fileName in Directory.GetFiles(settings.coverImageCache)) //Cleanup Unused Covers { 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"); @@ -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}"); }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); AddJobsToQueue(subJobs); }else if (queueHead.progressToken.state is ProgressToken.State.Running && DateTime.Now.Subtract(queueHead.progressToken.lastUpdate) > TimeSpan.FromMinutes(5)) diff --git a/Tranga/Jobs/JobJsonConverter.cs b/Tranga/Jobs/JobJsonConverter.cs index 9b37258..26a1a2a 100644 --- a/Tranga/Jobs/JobJsonConverter.cs +++ b/Tranga/Jobs/JobJsonConverter.cs @@ -30,16 +30,9 @@ public class JobJsonConverter : JsonConverter return Enum.Parse(jo["jobType"]!.Value().ToString()) switch { Job.JobType.UpdateMetaDataJob => new UpdateMetadata(_clone, - jo.GetValue("manga")!.ToObject(JsonSerializer.Create(new JsonSerializerSettings() - { - Converters = { this._mangaConnectorJsonConverter } - })), + jo.GetValue("mangaInternalId")!.Value()!, jo.GetValue("parentJobId")!.Value()), Job.JobType.DownloadChapterJob => new DownloadChapter(this._clone, - jo.GetValue("mangaConnector")!.ToObject(JsonSerializer.Create(new JsonSerializerSettings() - { - Converters = { this._mangaConnectorJsonConverter } - }))!, jo.GetValue("chapter")!.ToObject(JsonSerializer.Create(new JsonSerializerSettings() { Converters = { this._mangaConnectorJsonConverter } @@ -47,10 +40,7 @@ public class JobJsonConverter : JsonConverter DateTime.UnixEpoch, jo.GetValue("parentJobId")!.Value()), Job.JobType.DownloadNewChaptersJob => new DownloadNewChapters(this._clone, - jo.GetValue("manga")!.ToObject(JsonSerializer.Create(new JsonSerializerSettings() - { - Converters = { this._mangaConnectorJsonConverter } - })), + jo.GetValue("mangaInternalId")!.Value()!, jo.GetValue("lastExecution") is {} le ? le.ToObject() : DateTime.UnixEpoch, diff --git a/Tranga/Jobs/UpdateMetadata.cs b/Tranga/Jobs/UpdateMetadata.cs index 121ce47..38902f3 100644 --- a/Tranga/Jobs/UpdateMetadata.cs +++ b/Tranga/Jobs/UpdateMetadata.cs @@ -1,19 +1,21 @@ -using Tranga.MangaConnectors; +using System.Text.Json.Serialization; +using Tranga.MangaConnectors; namespace Tranga.Jobs; 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() { - return $"{GetType()}-{manga.internalId}"; + return $"{GetType()}-{mangaInternalId}"; } public override string ToString() @@ -23,8 +25,14 @@ public class UpdateMetadata : Job protected override IEnumerable ExecuteReturnSubTasksInternal(JobBoss jobBoss) { + if (manga is null) + { + Log($"Manga {mangaInternalId} is missing! Can not execute job."); + return Array.Empty(); + } + //Retrieve new Metadata - Manga? possibleUpdatedManga = mangaConnector.GetMangaFromId(manga.publicationId); + Manga? possibleUpdatedManga = mangaConnector.GetMangaFromId(manga.Value.publicationId); if (possibleUpdatedManga is { } updatedManga) { if (updatedManga.Equals(this.manga)) //Check if anything changed @@ -33,8 +41,8 @@ public class UpdateMetadata : Job return Array.Empty(); } - this.manga.UpdateMetadata(updatedManga); - this.manga.SaveSeriesInfoJson(settings.downloadLocation, true); + AddMangaToCache(manga.Value.WithMetadata(updatedManga)); + this.manga.Value.SaveSeriesInfoJson(settings.downloadLocation, true); this.progressToken.Complete(); } else @@ -47,12 +55,18 @@ public class UpdateMetadata : Job return Array.Empty(); } + protected override MangaConnector GetMangaConnector() + { + if (manga is null) + throw new Exception($"Missing Manga {mangaInternalId}"); + return manga.Value.mangaConnector; + } + public override bool Equals(object? obj) { if (obj is not UpdateMetadata otherJob) return false; - return otherJob.mangaConnector == this.mangaConnector && - otherJob.manga.Equals(this.manga); + return otherJob.manga.Equals(this.manga); } } \ No newline at end of file diff --git a/Tranga/Manga.cs b/Tranga/Manga.cs index d1a0e85..139b9c5 100644 --- a/Tranga/Manga.cs +++ b/Tranga/Manga.cs @@ -74,16 +74,20 @@ public struct Manga this.websiteUrl = websiteUrl; } - public void UpdateMetadata(Manga newManga) + public Manga WithMetadata(Manga newManga) { - this.sortName = newManga.sortName; - this.description = newManga.description; - this.coverUrl = newManga.coverUrl; - this.authors = authors.Union(newManga.authors).ToList(); - this.altTitles = altTitles.UnionBy(newManga.altTitles, kv => kv.Key).ToDictionary(x => x.Key, x => x.Value); - this.tags = tags.Union(newManga.tags).ToArray(); - this.releaseStatus = newManga.releaseStatus; - this.year = newManga.year; + return this with + { + sortName = newManga.sortName, + description = newManga.description, + coverUrl = newManga.coverUrl, + authors = authors.Union(newManga.authors).ToList(), + altTitles = altTitles.UnionBy(newManga.altTitles, kv => kv.Key).ToDictionary(x => x.Key, x => x.Value), + tags = tags.Union(newManga.tags).ToArray(), + releaseStatus = newManga.releaseStatus, + year = newManga.year, + websiteUrl = newManga.websiteUrl + }; } public override bool Equals(object? obj) @@ -96,6 +100,7 @@ public struct Manga this.sortName == compareManga.sortName && this.latestChapterAvailable.Equals(compareManga.latestChapterAvailable) && this.authors.All(a => compareManga.authors.Contains(a)) && + this.websiteUrl.Equals(compareManga.websiteUrl) && this.tags.All(t => compareManga.tags.Contains(t)); } diff --git a/Tranga/MangaConnectors/Bato.cs b/Tranga/MangaConnectors/Bato.cs index 657af00..b7257cc 100644 --- a/Tranga/MangaConnectors/Bato.cs +++ b/Tranga/MangaConnectors/Bato.cs @@ -116,7 +116,7 @@ public class Bato : MangaConnector Manga manga = new (this, sortName, authors, description, altTitles, tags, posterUrl, coverFileNameInCache, new Dictionary(), year, originalLanguage, publicationId, releaseStatus, websiteUrl); - cachedPublications.Add(manga); + AddMangaToCache(manga); return manga; } diff --git a/Tranga/MangaConnectors/MangaDex.cs b/Tranga/MangaConnectors/MangaDex.cs index c764dcd..69a4385 100644 --- a/Tranga/MangaConnectors/MangaDex.cs +++ b/Tranga/MangaConnectors/MangaDex.cs @@ -188,7 +188,7 @@ public class MangaDex : MangaConnector releaseStatus, $"https://mangadex.org/title/{publicationId}" ); - cachedPublications.Add(pub); + AddMangaToCache(pub); return pub; } diff --git a/Tranga/MangaConnectors/MangaKatana.cs b/Tranga/MangaConnectors/MangaKatana.cs index 9ab937a..5088108 100644 --- a/Tranga/MangaConnectors/MangaKatana.cs +++ b/Tranga/MangaConnectors/MangaKatana.cs @@ -143,7 +143,7 @@ public class MangaKatana : MangaConnector Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl); - cachedPublications.Add(manga); + AddMangaToCache(manga); return manga; } diff --git a/Tranga/MangaConnectors/MangaLife.cs b/Tranga/MangaConnectors/MangaLife.cs index 9245ec2..cb8f1c6 100644 --- a/Tranga/MangaConnectors/MangaLife.cs +++ b/Tranga/MangaConnectors/MangaLife.cs @@ -123,7 +123,7 @@ public class MangaLife : MangaConnector Manga manga = new(this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl); - cachedPublications.Add(manga); + AddMangaToCache(manga); return manga; } diff --git a/Tranga/MangaConnectors/Manganato.cs b/Tranga/MangaConnectors/Manganato.cs index 793c0d0..2377c7e 100644 --- a/Tranga/MangaConnectors/Manganato.cs +++ b/Tranga/MangaConnectors/Manganato.cs @@ -129,7 +129,7 @@ public class Manganato : MangaConnector Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl); - cachedPublications.Add(manga); + AddMangaToCache(manga); return manga; } diff --git a/Tranga/MangaConnectors/Mangasee.cs b/Tranga/MangaConnectors/Mangasee.cs index 935c866..bd44307 100644 --- a/Tranga/MangaConnectors/Mangasee.cs +++ b/Tranga/MangaConnectors/Mangasee.cs @@ -178,7 +178,7 @@ public class Mangasee : MangaConnector Manga manga = new(this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl); - cachedPublications.Add(manga); + AddMangaToCache(manga); return manga; } diff --git a/Tranga/MangaConnectors/Mangaworld.cs b/Tranga/MangaConnectors/Mangaworld.cs index fbacfaa..9f4ca3e 100644 --- a/Tranga/MangaConnectors/Mangaworld.cs +++ b/Tranga/MangaConnectors/Mangaworld.cs @@ -120,7 +120,7 @@ public class Mangaworld: MangaConnector Manga manga = new (this, sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, year, originalLanguage, publicationId, releaseStatus, websiteUrl); - cachedPublications.Add(manga); + AddMangaToCache(manga); return manga; } diff --git a/Tranga/Server/Server.cs b/Tranga/Server/Server.cs index 863b9d9..decd1ed 100644 --- a/Tranga/Server/Server.cs +++ b/Tranga/Server/Server.cs @@ -33,7 +33,7 @@ public partial class Server : GlobalBase, IDisposable new ("GET", @"/v2/Jobs/Waiting", GetV2JobsWaiting), new ("GET", @"/v2/Jobs/Monitoring", GetV2JobsMonitoring), 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 ("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), diff --git a/Tranga/Server/v2Jobs.cs b/Tranga/Server/v2Jobs.cs index fda77a0..e40d9a9 100644 --- a/Tranga/Server/v2Jobs.cs +++ b/Tranga/Server/v2Jobs.cs @@ -38,7 +38,7 @@ public partial class Server return new ValueTuple(HttpStatusCode.OK, Enum.GetNames(typeof(Job.JobType))); } - private ValueTuple PostV2JobsCreateType(GroupCollection groups, Dictionary requestParameters) + private ValueTuple PostV2JobCreateType(GroupCollection groups, Dictionary requestParameters) { if (groups.Count < 1 || !Enum.TryParse(groups[1].Value, true, out Job.JobType jobType)) @@ -59,14 +59,14 @@ public partial class Server !TimeSpan.TryParse(intervalStr, out TimeSpan interval)) return new ValueTuple(HttpStatusCode.InternalServerError, "'interval' Parameter missing, or is not in correct format."); 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.OK, null); case Job.JobType.UpdateMetaDataJob: if(!requestParameters.TryGetValue("internalId", out mangaId) || !_parent.TryGetPublicationById(mangaId, out manga) || manga is null) return new ValueTuple(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.OK, null); case Job.JobType.DownloadNewChaptersJob: //TODO case Job.JobType.DownloadChapterJob: //TODO diff --git a/Tranga/Server/v2Manga.cs b/Tranga/Server/v2Manga.cs index b8c3a28..91c7994 100644 --- a/Tranga/Server/v2Manga.cs +++ b/Tranga/Server/v2Manga.cs @@ -8,7 +8,7 @@ public partial class Server { private ValueTuple GetV2Manga(GroupCollection groups, Dictionary requestParameters) { - return new ValueTuple(HttpStatusCode.OK, cachedPublications.Select(m => m.internalId)); + return new ValueTuple(HttpStatusCode.OK, GetAllCachedManga().Select(m => m.internalId)); } private ValueTuple GetV2MangaInternalId(GroupCollection groups, Dictionary requestParameters) @@ -28,6 +28,7 @@ public partial class Server return new ValueTuple(HttpStatusCode.NotFound, $"Manga with ID '{groups[1].Value} could not be found.'"); Job[] jobs = _parent.jobBoss.GetJobsLike(publication: manga).ToArray(); _parent.jobBoss.RemoveJobs(jobs); + RemoveMangaFromCache(groups[1].Value); return new ValueTuple(HttpStatusCode.OK, null); } diff --git a/Tranga/Tranga.cs b/Tranga/Tranga.cs index 4f28670..dc26411 100644 --- a/Tranga/Tranga.cs +++ b/Tranga/Tranga.cs @@ -9,7 +9,6 @@ public partial class Tranga : GlobalBase public bool keepRunning; public JobBoss jobBoss; private Server.Server _server; - private HashSet _connectors; public Tranga(Logger? logger, TrangaSettings settings) : base(logger, settings) { @@ -54,12 +53,7 @@ public partial class Tranga : GlobalBase return _connectors.Select(c => c.name); } - public Manga? GetPublicationById(string internalId) - { - if (cachedPublications.Exists(publication => publication.internalId == internalId)) - return cachedPublications.First(publication => publication.internalId == internalId); - return null; - } + public Manga? GetPublicationById(string internalId) => GetCachedManga(internalId); public bool TryGetPublicationById(string internalId, out Manga? manga) { diff --git a/Tranga/TrangaSettings.cs b/Tranga/TrangaSettings.cs index 2ad9492..7047006 100644 --- a/Tranga/TrangaSettings.cs +++ b/Tranga/TrangaSettings.cs @@ -19,6 +19,7 @@ public class TrangaSettings [JsonIgnore] public string libraryConnectorsFilePath => Path.Join(workingDirectory, "libraryConnectors.json"); [JsonIgnore] public string notificationConnectorsFilePath => Path.Join(workingDirectory, "notificationConnectors.json"); [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] internal static readonly string DefaultUserAgent = $"Tranga ({Enum.GetName(Environment.OSVersion.Platform)}; {(Environment.Is64BitOperatingSystem ? "x64" : "")}) / 1.0"; public ushort? version { get; } = 2;