From 21af75f4106c718e9ae38ae0926beb176a15205e Mon Sep 17 00:00:00 2001 From: Glax Date: Tue, 20 Aug 2024 20:47:13 +0200 Subject: [PATCH 1/9] Faster download for images-urls. #224 --- Tranga/MangaConnectors/ChromiumDownloadClient.cs | 15 +++++++++++++-- Tranga/MangaConnectors/DownloadClient.cs | 2 +- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Tranga/MangaConnectors/ChromiumDownloadClient.cs b/Tranga/MangaConnectors/ChromiumDownloadClient.cs index 8ddf850..c63e85a 100644 --- a/Tranga/MangaConnectors/ChromiumDownloadClient.cs +++ b/Tranga/MangaConnectors/ChromiumDownloadClient.cs @@ -1,5 +1,6 @@ using System.Net; using System.Text; +using System.Text.RegularExpressions; using HtmlAgilityPack; using PuppeteerSharp; using PuppeteerSharp.Input; @@ -11,10 +12,11 @@ internal class ChromiumDownloadClient : DownloadClient private IBrowser browser { get; set; } private const string ChromiumVersion = "1154303"; private const int StartTimeoutMs = 30000; + private HttpDownloadClient _httpDownloadClient; private async Task DownloadBrowser() { - BrowserFetcher browserFetcher = new BrowserFetcher(); + BrowserFetcher browserFetcher = new (); foreach(string rev in browserFetcher.LocalRevisions().Where(rev => rev != ChromiumVersion)) browserFetcher.Remove(rev); if (!browserFetcher.LocalRevisions().Contains(ChromiumVersion)) @@ -58,9 +60,18 @@ internal class ChromiumDownloadClient : DownloadClient public ChromiumDownloadClient(GlobalBase clone) : base(clone) { this.browser = DownloadBrowser().Result; + _httpDownloadClient = new(this); } - protected override RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null) + private readonly Regex _imageUrlRex = new(@"https?:\/\/.*\.(?:p?jpe?g|gif|a?png|bmp|avif|webp)(\?.*)?"); + internal override RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null) + { + return _imageUrlRex.IsMatch(url) + ? _httpDownloadClient.MakeRequestInternal(url, referrer) + : MakeRequestBrowser(url, referrer, clickButton); + } + + private RequestResult MakeRequestBrowser(string url, string? referrer = null, string? clickButton = null) { IPage page = this.browser.NewPageAsync().Result; page.DefaultTimeout = 10000; diff --git a/Tranga/MangaConnectors/DownloadClient.cs b/Tranga/MangaConnectors/DownloadClient.cs index 0e9b343..f6f876d 100644 --- a/Tranga/MangaConnectors/DownloadClient.cs +++ b/Tranga/MangaConnectors/DownloadClient.cs @@ -40,6 +40,6 @@ internal abstract class DownloadClient : GlobalBase return result; } - protected abstract RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null); + internal abstract RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null); public abstract void Close(); } \ No newline at end of file From ea37e81ece8c191f7dbf4d556e1bb64f9f69d774 Mon Sep 17 00:00:00 2001 From: Glax Date: Tue, 20 Aug 2024 20:53:03 +0200 Subject: [PATCH 2/9] Fix last commit --- Tranga/MangaConnectors/ChromiumDownloadClient.cs | 3 +-- Tranga/MangaConnectors/HttpDownloadClient.cs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Tranga/MangaConnectors/ChromiumDownloadClient.cs b/Tranga/MangaConnectors/ChromiumDownloadClient.cs index c63e85a..d7e6523 100644 --- a/Tranga/MangaConnectors/ChromiumDownloadClient.cs +++ b/Tranga/MangaConnectors/ChromiumDownloadClient.cs @@ -3,7 +3,6 @@ using System.Text; using System.Text.RegularExpressions; using HtmlAgilityPack; using PuppeteerSharp; -using PuppeteerSharp.Input; namespace Tranga.MangaConnectors; @@ -12,7 +11,7 @@ internal class ChromiumDownloadClient : DownloadClient private IBrowser browser { get; set; } private const string ChromiumVersion = "1154303"; private const int StartTimeoutMs = 30000; - private HttpDownloadClient _httpDownloadClient; + private readonly HttpDownloadClient _httpDownloadClient; private async Task DownloadBrowser() { diff --git a/Tranga/MangaConnectors/HttpDownloadClient.cs b/Tranga/MangaConnectors/HttpDownloadClient.cs index 46a0008..3b2e5c3 100644 --- a/Tranga/MangaConnectors/HttpDownloadClient.cs +++ b/Tranga/MangaConnectors/HttpDownloadClient.cs @@ -16,7 +16,7 @@ internal class HttpDownloadClient : DownloadClient Client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", settings.userAgent); } - protected override RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null) + internal override RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null) { if(clickButton is not null) Log("Can not click button on static site."); From f4336f977749c9c01c37e10f3cad838f0c5272c6 Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 26 Aug 2024 10:35:16 +0200 Subject: [PATCH 3/9] #227 Mangasee Return results that have similarity over 95% or at least top ten results --- Tranga/MangaConnectors/Mangasee.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/Tranga/MangaConnectors/Mangasee.cs b/Tranga/MangaConnectors/Mangasee.cs index 2de2b2f..b10421c 100644 --- a/Tranga/MangaConnectors/Mangasee.cs +++ b/Tranga/MangaConnectors/Mangasee.cs @@ -61,21 +61,28 @@ public class Mangasee : MangaConnector } } + private readonly string[] _filterWords = {"a", "the", "of", "as", "to", "no", "for", "on", "with", "be", "and", "in", "wa", "at", "be", "ni"}; + private string ToFilteredString(string input) => string.Join(' ', input.ToLower().Split(' ').Where(word => _filterWords.Contains(word))); private SearchResult[] FilteredResults(string publicationTitle, SearchResult[] unfilteredSearchResults) { Dictionary similarity = new(); foreach (SearchResult sr in unfilteredSearchResults) { List scores = new(); - foreach (string se in sr.a) - scores.Add(NeedlemanWunschStringUtil.CalculateSimilarity(se.ToLower(), publicationTitle.ToLower())); - scores.Add(NeedlemanWunschStringUtil.CalculateSimilarity(sr.s.ToLower(), publicationTitle.ToLower())); + string filteredPublicationString = ToFilteredString(publicationTitle); + string filteredSString = ToFilteredString(sr.s); + scores.Add(NeedlemanWunschStringUtil.CalculateSimilarity(filteredSString, filteredPublicationString)); + foreach (string srA in sr.a) + { + string filteredAString = ToFilteredString(srA); + scores.Add(NeedlemanWunschStringUtil.CalculateSimilarity(filteredAString, filteredPublicationString)); + } similarity.Add(sr, scores.Sum() / scores.Count); } - SearchResult[] similarity90 = similarity.Where(s => s.Value < 10).Select(s => s.Key).ToArray(); - - return similarity90; + List ret = similarity.OrderBy(s => s.Value).Take(10).Select(s => s.Key).ToList(); + ret.AddRange(similarity.Where(s => s.Value < 5).Select(s => s.Key)); + return ret.ToArray(); } public override Manga? GetMangaFromId(string publicationId) From 69d68845171768dcc6371db7173a39596b9ab4d2 Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 26 Aug 2024 11:17:59 +0200 Subject: [PATCH 4/9] #227 Fix wrong filtering, only return top 10 results --- Tranga/MangaConnectors/Mangasee.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Tranga/MangaConnectors/Mangasee.cs b/Tranga/MangaConnectors/Mangasee.cs index b10421c..1bc7445 100644 --- a/Tranga/MangaConnectors/Mangasee.cs +++ b/Tranga/MangaConnectors/Mangasee.cs @@ -62,7 +62,7 @@ public class Mangasee : MangaConnector } private readonly string[] _filterWords = {"a", "the", "of", "as", "to", "no", "for", "on", "with", "be", "and", "in", "wa", "at", "be", "ni"}; - private string ToFilteredString(string input) => string.Join(' ', input.ToLower().Split(' ').Where(word => _filterWords.Contains(word))); + private string ToFilteredString(string input) => string.Join(' ', input.ToLower().Split(' ').Where(word => _filterWords.Contains(word) == false)); private SearchResult[] FilteredResults(string publicationTitle, SearchResult[] unfilteredSearchResults) { Dictionary similarity = new(); @@ -81,7 +81,6 @@ public class Mangasee : MangaConnector } List ret = similarity.OrderBy(s => s.Value).Take(10).Select(s => s.Key).ToList(); - ret.AddRange(similarity.Where(s => s.Value < 5).Select(s => s.Key)); return ret.ToArray(); } From 63b493fa9ce4d858a8577584a3ae8959e124275d Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 26 Aug 2024 12:36:35 +0200 Subject: [PATCH 5/9] Rework TrangaSettings --- CLI/Program.cs | 33 +--- Tranga/Chapter.cs | 12 +- Tranga/GlobalBase.cs | 25 ++- Tranga/Jobs/DownloadNewChapters.cs | 2 +- Tranga/Jobs/JobBoss.cs | 12 +- Tranga/Jobs/UpdateMetadata.cs | 2 +- Tranga/Manga.cs | 4 +- Tranga/MangaConnectors/Bato.cs | 2 +- Tranga/MangaConnectors/DownloadClient.cs | 6 +- Tranga/MangaConnectors/HttpDownloadClient.cs | 2 +- Tranga/MangaConnectors/MangaConnector.cs | 10 +- Tranga/MangaConnectors/MangaDex.cs | 2 +- Tranga/MangaConnectors/MangaHere.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/MangaConnectors/ManhuaPlus.cs | 2 +- Tranga/Server.cs | 38 ++--- Tranga/Tranga.cs | 5 +- Tranga/TrangaArgs.cs | 32 +--- Tranga/TrangaSettings.cs | 163 ++++++++++--------- 23 files changed, 163 insertions(+), 201 deletions(-) diff --git a/CLI/Program.cs b/CLI/Program.cs index ec21751..f927ea2 100644 --- a/CLI/Program.cs +++ b/CLI/Program.cs @@ -47,37 +47,16 @@ internal sealed class TrangaCli : Command string? logFolderPath = settings.fileLoggerPath ?? ""; Logger logger = new(enabledLoggers.ToArray(), Console.Out, Console.OutputEncoding, logFolderPath); - TrangaSettings? trangaSettings = null; - - if (settings.downloadLocation is not null && settings.workingDirectory is not null) - { - trangaSettings = new TrangaSettings(settings.downloadLocation, settings.workingDirectory); - }else if (settings.downloadLocation is not null) - { - if (trangaSettings is null) - trangaSettings = new TrangaSettings(downloadLocation: settings.downloadLocation); - else - trangaSettings = new TrangaSettings(downloadLocation: settings.downloadLocation, settings.workingDirectory); - }else if (settings.workingDirectory is not null) - { - if (trangaSettings is null) - trangaSettings = new TrangaSettings(downloadLocation: settings.workingDirectory); - else - trangaSettings = new TrangaSettings(settings.downloadLocation, settings.workingDirectory); - } - else - { - trangaSettings = new TrangaSettings(); - } - - Directory.CreateDirectory(trangaSettings.downloadLocation); - Directory.CreateDirectory(trangaSettings.workingDirectory); + if(settings.workingDirectory is not null) + TrangaSettings.LoadFromWorkingDirectory(settings.workingDirectory); + if(settings.downloadLocation is not null) + TrangaSettings.CreateOrUpdate(downloadDirectory: settings.downloadLocation); Tranga.Tranga? api = null; Thread trangaApi = new Thread(() => { - api = new(logger, trangaSettings); + api = new(logger); }); trangaApi.Start(); @@ -120,7 +99,7 @@ internal sealed class TrangaCli : Command parameters.Add(new ValueTuple(name, value)); } - string requestString = $"http://localhost:{trangaSettings.apiPortNumber}/{requestPath}"; + string requestString = $"http://localhost:{TrangaSettings.apiPortNumber}/{requestPath}"; if (parameters.Any()) { requestString += "?"; diff --git a/Tranga/Chapter.cs b/Tranga/Chapter.cs index 4677d7b..369b8fc 100644 --- a/Tranga/Chapter.cs +++ b/Tranga/Chapter.cs @@ -87,15 +87,15 @@ public readonly struct Chapter : IComparable /// Checks if a chapter-archive is already present /// /// true if chapter is present - internal bool CheckChapterIsDownloaded(string downloadLocation) + internal bool CheckChapterIsDownloaded() { - if (!Directory.Exists(Path.Join(downloadLocation, parentManga.folderName))) + if (!Directory.Exists(Path.Join(TrangaSettings.downloadLocation, parentManga.folderName))) return false; - FileInfo[] archives = new DirectoryInfo(Path.Join(downloadLocation, parentManga.folderName)).GetFiles().Where(file => file.Name.Split('.')[^1] == "cbz").ToArray(); + FileInfo[] archives = new DirectoryInfo(Path.Join(TrangaSettings.downloadLocation, parentManga.folderName)).GetFiles().Where(file => file.Name.Split('.')[^1] == "cbz").ToArray(); Regex volChRex = new(@"(?:Vol(?:ume)?\.([0-9]+)\D*)?Ch(?:apter)?\.([0-9]+(?:\.[0-9]+)*)"); Chapter t = this; - string thisPath = GetArchiveFilePath(downloadLocation); + string thisPath = GetArchiveFilePath(); FileInfo? archive = archives.FirstOrDefault(archive => { Match m = volChRex.Match(archive.Name); @@ -112,9 +112,9 @@ public readonly struct Chapter : IComparable /// Creates full file path of chapter-archive /// /// Filepath - internal string GetArchiveFilePath(string downloadLocation) + internal string GetArchiveFilePath() { - return Path.Join(downloadLocation, parentManga.folderName, $"{parentManga.folderName} - {this.fileName}.cbz"); + return Path.Join(TrangaSettings.downloadLocation, parentManga.folderName, $"{parentManga.folderName} - {this.fileName}.cbz"); } /// diff --git a/Tranga/GlobalBase.cs b/Tranga/GlobalBase.cs index f372f2c..49a0d79 100644 --- a/Tranga/GlobalBase.cs +++ b/Tranga/GlobalBase.cs @@ -11,7 +11,6 @@ public abstract class GlobalBase { [JsonIgnore] public Logger? logger { get; init; } - protected TrangaSettings settings { get; init; } protected HashSet notificationConnectors { get; init; } protected HashSet libraryConnectors { get; init; } private Dictionary cachedPublications { get; init; } @@ -21,18 +20,16 @@ public abstract class GlobalBase protected GlobalBase(GlobalBase clone) { this.logger = clone.logger; - this.settings = clone.settings; this.notificationConnectors = clone.notificationConnectors; this.libraryConnectors = clone.libraryConnectors; this.cachedPublications = clone.cachedPublications; } - protected GlobalBase(Logger? logger, TrangaSettings settings) + protected GlobalBase(Logger? logger) { this.logger = logger; - this.settings = settings; - this.notificationConnectors = settings.LoadNotificationConnectors(this); - this.libraryConnectors = settings.LoadLibraryConnectors(this); + this.notificationConnectors = TrangaSettings.LoadNotificationConnectors(this); + this.libraryConnectors = TrangaSettings.LoadLibraryConnectors(this); this.cachedPublications = new(); } @@ -81,20 +78,20 @@ public abstract class GlobalBase notificationConnectors.RemoveWhere(nc => nc.notificationConnectorType == notificationConnector.notificationConnectorType); notificationConnectors.Add(notificationConnector); - while(IsFileInUse(settings.notificationConnectorsFilePath)) + while(IsFileInUse(TrangaSettings.notificationConnectorsFilePath)) Thread.Sleep(100); Log("Exporting notificationConnectors"); - File.WriteAllText(settings.notificationConnectorsFilePath, JsonConvert.SerializeObject(notificationConnectors)); + File.WriteAllText(TrangaSettings.notificationConnectorsFilePath, JsonConvert.SerializeObject(notificationConnectors)); } protected void DeleteNotificationConnector(NotificationConnector.NotificationConnectorType notificationConnectorType) { Log($"Removing {notificationConnectorType}"); notificationConnectors.RemoveWhere(nc => nc.notificationConnectorType == notificationConnectorType); - while(IsFileInUse(settings.notificationConnectorsFilePath)) + while(IsFileInUse(TrangaSettings.notificationConnectorsFilePath)) Thread.Sleep(100); Log("Exporting notificationConnectors"); - File.WriteAllText(settings.notificationConnectorsFilePath, JsonConvert.SerializeObject(notificationConnectors)); + File.WriteAllText(TrangaSettings.notificationConnectorsFilePath, JsonConvert.SerializeObject(notificationConnectors)); } protected void UpdateLibraries() @@ -109,20 +106,20 @@ public abstract class GlobalBase libraryConnectors.RemoveWhere(lc => lc.libraryType == libraryConnector.libraryType); libraryConnectors.Add(libraryConnector); - while(IsFileInUse(settings.libraryConnectorsFilePath)) + while(IsFileInUse(TrangaSettings.libraryConnectorsFilePath)) Thread.Sleep(100); Log("Exporting libraryConnectors"); - File.WriteAllText(settings.libraryConnectorsFilePath, JsonConvert.SerializeObject(libraryConnectors, Formatting.Indented)); + File.WriteAllText(TrangaSettings.libraryConnectorsFilePath, JsonConvert.SerializeObject(libraryConnectors, Formatting.Indented)); } protected void DeleteLibraryConnector(LibraryConnector.LibraryType libraryType) { Log($"Removing {libraryType}"); libraryConnectors.RemoveWhere(lc => lc.libraryType == libraryType); - while(IsFileInUse(settings.libraryConnectorsFilePath)) + while(IsFileInUse(TrangaSettings.libraryConnectorsFilePath)) Thread.Sleep(100); Log("Exporting libraryConnectors"); - File.WriteAllText(settings.libraryConnectorsFilePath, JsonConvert.SerializeObject(libraryConnectors, Formatting.Indented)); + File.WriteAllText(TrangaSettings.libraryConnectorsFilePath, JsonConvert.SerializeObject(libraryConnectors, Formatting.Indented)); } protected bool IsFileInUse(string filePath) => IsFileInUse(filePath, this.logger); diff --git a/Tranga/Jobs/DownloadNewChapters.cs b/Tranga/Jobs/DownloadNewChapters.cs index ebcbde7..29c3e60 100644 --- a/Tranga/Jobs/DownloadNewChapters.cs +++ b/Tranga/Jobs/DownloadNewChapters.cs @@ -33,7 +33,7 @@ public class DownloadNewChapters : Job protected override IEnumerable ExecuteReturnSubTasksInternal(JobBoss jobBoss) { - manga.SaveSeriesInfoJson(settings.downloadLocation); + manga.SaveSeriesInfoJson(); Chapter[] chapters = mangaConnector.GetNewChapters(manga, this.translatedLanguage); this.progressToken.increments = chapters.Length; List jobs = new(); diff --git a/Tranga/Jobs/JobBoss.cs b/Tranga/Jobs/JobBoss.cs index c5324d0..610d70c 100644 --- a/Tranga/Jobs/JobBoss.cs +++ b/Tranga/Jobs/JobBoss.cs @@ -140,15 +140,15 @@ public class JobBoss : GlobalBase private void LoadJobsList(HashSet connectors) { - if (!Directory.Exists(settings.jobsFolderPath)) //No jobs to load + if (!Directory.Exists(TrangaSettings.jobsFolderPath)) //No jobs to load { - Directory.CreateDirectory(settings.jobsFolderPath); + Directory.CreateDirectory(TrangaSettings.jobsFolderPath); return; } Regex idRex = new (@"(.*)\.json"); //Load json-job-files - foreach (FileInfo file in new DirectoryInfo(settings.jobsFolderPath).EnumerateFiles().Where(fileInfo => idRex.IsMatch(fileInfo.Name))) + foreach (FileInfo file in new DirectoryInfo(TrangaSettings.jobsFolderPath).EnumerateFiles().Where(fileInfo => idRex.IsMatch(fileInfo.Name))) { Log($"Adding {file.Name}"); Job? job = JsonConvert.DeserializeObject(File.ReadAllText(file.FullName), @@ -180,14 +180,14 @@ public class JobBoss : GlobalBase AddMangaToCache(dncJob.manga); } - string[] coverFiles = Directory.GetFiles(settings.coverImageCache); + string[] coverFiles = Directory.GetFiles(TrangaSettings.coverImageCache); foreach(string fileName in coverFiles.Where(fileName => !GetAllCachedManga().Any(manga => manga.coverFileNameInCache == fileName))) File.Delete(fileName); } internal void UpdateJobFile(Job job, string? oldFile = null) { - string newJobFilePath = Path.Join(settings.jobsFolderPath, $"{job.id}.json"); + string newJobFilePath = Path.Join(TrangaSettings.jobsFolderPath, $"{job.id}.json"); if (!this.jobs.Any(jjob => jjob.id == job.id)) { @@ -234,7 +234,7 @@ public class JobBoss : GlobalBase //Remove files with jobs not in this.jobs-list Regex idRex = new (@"(.*)\.json"); - foreach (FileInfo file in new DirectoryInfo(settings.jobsFolderPath).EnumerateFiles()) + foreach (FileInfo file in new DirectoryInfo(TrangaSettings.jobsFolderPath).EnumerateFiles()) { if (idRex.IsMatch(file.Name)) { diff --git a/Tranga/Jobs/UpdateMetadata.cs b/Tranga/Jobs/UpdateMetadata.cs index 4dc3ae7..72b5a60 100644 --- a/Tranga/Jobs/UpdateMetadata.cs +++ b/Tranga/Jobs/UpdateMetadata.cs @@ -34,7 +34,7 @@ public class UpdateMetadata : Job } this.manga = manga.WithMetadata(updatedManga); - this.manga.SaveSeriesInfoJson(settings.downloadLocation, true); + this.manga.SaveSeriesInfoJson(true); this.mangaConnector.CopyCoverFromCacheToDownloadLocation(manga); foreach (Job job in jobBoss.GetJobsLike(publication: this.manga)) { diff --git a/Tranga/Manga.cs b/Tranga/Manga.cs index 22fc99a..5ebad19 100644 --- a/Tranga/Manga.cs +++ b/Tranga/Manga.cs @@ -140,9 +140,9 @@ public struct Manga latestChapterDownloaded = latestChapterDownloaded < chapterNumber ? chapterNumber : latestChapterDownloaded; } - public void SaveSeriesInfoJson(string downloadDirectory, bool overwrite = false) + public void SaveSeriesInfoJson(bool overwrite = false) { - string publicationFolder = CreatePublicationFolder(downloadDirectory); + string publicationFolder = CreatePublicationFolder(TrangaSettings.downloadLocation); string seriesInfoPath = Path.Join(publicationFolder, "series.json"); if(overwrite || (!overwrite && !File.Exists(seriesInfoPath))) File.WriteAllText(seriesInfoPath,this.GetSeriesInfoJson()); diff --git a/Tranga/MangaConnectors/Bato.cs b/Tranga/MangaConnectors/Bato.cs index d50081b..5b5f370 100644 --- a/Tranga/MangaConnectors/Bato.cs +++ b/Tranga/MangaConnectors/Bato.cs @@ -193,7 +193,7 @@ public class Bato : MangaConnector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); - return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken); + return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken); } private string[] ParseImageUrlsFromHtml(string mangaUrl) diff --git a/Tranga/MangaConnectors/DownloadClient.cs b/Tranga/MangaConnectors/DownloadClient.cs index f6f876d..298774f 100644 --- a/Tranga/MangaConnectors/DownloadClient.cs +++ b/Tranga/MangaConnectors/DownloadClient.cs @@ -14,15 +14,15 @@ internal abstract class DownloadClient : GlobalBase public RequestResult MakeRequest(string url, RequestType requestType, string? referrer = null, string? clickButton = null) { - if (!settings.requestLimits.ContainsKey(requestType)) + if (!TrangaSettings.requestLimits.ContainsKey(requestType)) { Log("RequestType not configured for rate-limit."); return new RequestResult(HttpStatusCode.NotAcceptable, null, Stream.Null); } - int rateLimit = settings.userAgent == TrangaSettings.DefaultUserAgent + int rateLimit = TrangaSettings.userAgent == TrangaSettings.DefaultUserAgent ? TrangaSettings.DefaultRequestLimits[requestType] - : settings.requestLimits[requestType]; + : TrangaSettings.requestLimits[requestType]; TimeSpan timeBetweenRequests = TimeSpan.FromMinutes(1).Divide(rateLimit); _lastExecutedRateLimit.TryAdd(requestType, DateTime.Now.Subtract(timeBetweenRequests)); diff --git a/Tranga/MangaConnectors/HttpDownloadClient.cs b/Tranga/MangaConnectors/HttpDownloadClient.cs index 3b2e5c3..238306b 100644 --- a/Tranga/MangaConnectors/HttpDownloadClient.cs +++ b/Tranga/MangaConnectors/HttpDownloadClient.cs @@ -13,7 +13,7 @@ internal class HttpDownloadClient : DownloadClient public HttpDownloadClient(GlobalBase clone) : base(clone) { - Client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", settings.userAgent); + Client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", TrangaSettings.userAgent); } internal override RequestResult MakeRequestInternal(string url, string? referrer = null, string? clickButton = null) diff --git a/Tranga/MangaConnectors/MangaConnector.cs b/Tranga/MangaConnectors/MangaConnector.cs index 5c71de8..5af28e5 100644 --- a/Tranga/MangaConnectors/MangaConnector.cs +++ b/Tranga/MangaConnectors/MangaConnector.cs @@ -23,7 +23,7 @@ public abstract class MangaConnector : GlobalBase protected MangaConnector(GlobalBase clone, string name) : base(clone) { this.name = name; - Directory.CreateDirectory(settings.coverImageCache); + Directory.CreateDirectory(TrangaSettings.coverImageCache); } public string name { get; } //Name of the Connector (e.g. Website) @@ -65,7 +65,7 @@ public abstract class MangaConnector : GlobalBase Log($"Checking for duplicates {manga}"); List newChaptersList = allChapters.Where(nChapter => float.TryParse(nChapter.chapterNumber, numberFormatDecimalPoint, out float chapterNumber) && chapterNumber > manga.ignoreChaptersBelow - && !nChapter.CheckChapterIsDownloaded(settings.downloadLocation)).ToList(); + && !nChapter.CheckChapterIsDownloaded()).ToList(); Log($"{newChaptersList.Count} new chapters. {manga}"); try { @@ -167,7 +167,7 @@ public abstract class MangaConnector : GlobalBase { Log($"Copy cover {manga}"); //Check if Publication already has a Folder and cover - string publicationFolder = manga.CreatePublicationFolder(settings.downloadLocation); + string publicationFolder = manga.CreatePublicationFolder(TrangaSettings.downloadLocation); DirectoryInfo dirInfo = new (publicationFolder); if (dirInfo.EnumerateFiles().Any(info => info.Name.Contains("cover", StringComparison.InvariantCultureIgnoreCase))) { @@ -291,7 +291,7 @@ public abstract class MangaConnector : GlobalBase //https?:\/\/[a-zA-Z0-9-]+\.([a-zA-Z0-9-]+\.[a-zA-Z0-9]+)\/(?:.+\/)*(.+\.([a-zA-Z]+)) for only second level domains Match match = urlRex.Match(url); string filename = $"{match.Groups[1].Value}-{mangaInternalId}.{match.Groups[3].Value}"; - string saveImagePath = Path.Join(settings.coverImageCache, filename); + string saveImagePath = Path.Join(TrangaSettings.coverImageCache, filename); if (File.Exists(saveImagePath)) return saveImagePath; @@ -299,7 +299,7 @@ public abstract class MangaConnector : GlobalBase RequestResult coverResult = downloadClient.MakeRequest(url, requestType); using MemoryStream ms = new(); coverResult.result.CopyTo(ms); - Directory.CreateDirectory(settings.coverImageCache); + Directory.CreateDirectory(TrangaSettings.coverImageCache); File.WriteAllBytes(saveImagePath, ms.ToArray()); Log($"Saving cover to {saveImagePath}"); return saveImagePath; diff --git a/Tranga/MangaConnectors/MangaDex.cs b/Tranga/MangaConnectors/MangaDex.cs index 60f05fd..005da07 100644 --- a/Tranga/MangaConnectors/MangaDex.cs +++ b/Tranga/MangaConnectors/MangaDex.cs @@ -290,6 +290,6 @@ public class MangaDex : MangaConnector File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); //Download Chapter-Images - return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); + return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); } } \ No newline at end of file diff --git a/Tranga/MangaConnectors/MangaHere.cs b/Tranga/MangaConnectors/MangaHere.cs index fc9406e..0da1c5a 100644 --- a/Tranga/MangaConnectors/MangaHere.cs +++ b/Tranga/MangaConnectors/MangaHere.cs @@ -186,7 +186,7 @@ public class MangaHere : MangaConnector if (progressToken is not null) progressToken.increments = images;//we blip to normal length, in downloadchapterimages it is increasaed by the amount of urls again - return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); + return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); } private string[] ParseImageUrlsFromHtml(HtmlDocument document) diff --git a/Tranga/MangaConnectors/MangaKatana.cs b/Tranga/MangaConnectors/MangaKatana.cs index e2284c4..64ab6c4 100644 --- a/Tranga/MangaConnectors/MangaKatana.cs +++ b/Tranga/MangaConnectors/MangaKatana.cs @@ -217,7 +217,7 @@ public class MangaKatana : MangaConnector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); - return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken); + return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken); } private string[] ParseImageUrlsFromHtml(string mangaUrl) diff --git a/Tranga/MangaConnectors/MangaLife.cs b/Tranga/MangaConnectors/MangaLife.cs index 43ca2e0..44b54a5 100644 --- a/Tranga/MangaConnectors/MangaLife.cs +++ b/Tranga/MangaConnectors/MangaLife.cs @@ -194,6 +194,6 @@ public class MangaLife : MangaConnector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); - return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); + return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); } } \ No newline at end of file diff --git a/Tranga/MangaConnectors/Manganato.cs b/Tranga/MangaConnectors/Manganato.cs index 1f3a0e5..c0a922a 100644 --- a/Tranga/MangaConnectors/Manganato.cs +++ b/Tranga/MangaConnectors/Manganato.cs @@ -209,7 +209,7 @@ public class Manganato : MangaConnector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); - return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, "https://chapmanganato.com/", progressToken:progressToken); + return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://chapmanganato.com/", progressToken:progressToken); } private string[] ParseImageUrlsFromHtml(HtmlDocument document) diff --git a/Tranga/MangaConnectors/Mangasee.cs b/Tranga/MangaConnectors/Mangasee.cs index 1bc7445..7128910 100644 --- a/Tranga/MangaConnectors/Mangasee.cs +++ b/Tranga/MangaConnectors/Mangasee.cs @@ -225,6 +225,6 @@ public class Mangasee : MangaConnector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); - return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); + return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); } } \ No newline at end of file diff --git a/Tranga/MangaConnectors/Mangaworld.cs b/Tranga/MangaConnectors/Mangaworld.cs index d5725d7..7cbe7ef 100644 --- a/Tranga/MangaConnectors/Mangaworld.cs +++ b/Tranga/MangaConnectors/Mangaworld.cs @@ -209,7 +209,7 @@ public class Mangaworld: MangaConnector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); - return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, "https://www.mangaworld.bz/", progressToken:progressToken); + return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://www.mangaworld.bz/", progressToken:progressToken); } private string[] ParseImageUrlsFromHtml(HtmlDocument document) diff --git a/Tranga/MangaConnectors/ManhuaPlus.cs b/Tranga/MangaConnectors/ManhuaPlus.cs index 3fe392c..524c267 100644 --- a/Tranga/MangaConnectors/ManhuaPlus.cs +++ b/Tranga/MangaConnectors/ManhuaPlus.cs @@ -179,6 +179,6 @@ public class ManhuaPlus : MangaConnector string comicInfoPath = Path.GetTempFileName(); File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString()); - return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); + return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken); } } \ No newline at end of file diff --git a/Tranga/Server.cs b/Tranga/Server.cs index e2f19f0..95dad91 100644 --- a/Tranga/Server.cs +++ b/Tranga/Server.cs @@ -19,9 +19,9 @@ public class Server : GlobalBase { this._parent = parent; if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - this._listener.Prefixes.Add($"http://*:{settings.apiPortNumber}/"); + this._listener.Prefixes.Add($"http://*:{TrangaSettings.apiPortNumber}/"); else - this._listener.Prefixes.Add($"http://localhost:{settings.apiPortNumber}/"); + this._listener.Prefixes.Add($"http://localhost:{TrangaSettings.apiPortNumber}/"); Thread listenThread = new (Listen); listenThread.Start(); Thread watchThread = new(WatchRunning); @@ -198,16 +198,16 @@ public class Server : GlobalBase SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.Where(jjob => jjob is DownloadNewChapters).OrderBy(jjob => ((DownloadNewChapters)jjob).manga.sortName)); break; case "Settings": - SendResponse(HttpStatusCode.OK, response, settings); + SendResponse(HttpStatusCode.OK, response, TrangaSettings.Serialize()); break; case "Settings/userAgent": - SendResponse(HttpStatusCode.OK, response, settings.userAgent); + SendResponse(HttpStatusCode.OK, response, TrangaSettings.userAgent); break; case "Settings/customRequestLimit": - SendResponse(HttpStatusCode.OK, response, settings.requestLimits); + SendResponse(HttpStatusCode.OK, response, TrangaSettings.requestLimits); break; case "Settings/AprilFoolsMode": - SendResponse(HttpStatusCode.OK, response, settings.aprilFoolsMode); + SendResponse(HttpStatusCode.OK, response, TrangaSettings.aprilFoolsMode); break; case "NotificationConnectors": SendResponse(HttpStatusCode.OK, response, notificationConnectors); @@ -314,7 +314,7 @@ public class Server : GlobalBase } if (requestVariables.TryGetValue("customFolderName", out customFolderName)) - manga.MovePublicationFolder(settings.downloadLocation, customFolderName); + manga.MovePublicationFolder(TrangaSettings.downloadLocation, customFolderName); requestVariables.TryGetValue("translatedLanguage", out translatedLanguage); _parent.jobBoss.AddJob(new DownloadNewChapters(this, connector!, manga, true, interval, translatedLanguage: translatedLanguage??"en")); @@ -343,7 +343,7 @@ public class Server : GlobalBase } if (requestVariables.TryGetValue("customFolderName", out customFolderName)) - manga.MovePublicationFolder(settings.downloadLocation, customFolderName); + manga.MovePublicationFolder(TrangaSettings.downloadLocation, customFolderName); requestVariables.TryGetValue("translatedLanguage", out translatedLanguage); _parent.jobBoss.AddJob(new DownloadNewChapters(this, connector!, manga, false, translatedLanguage: translatedLanguage??"en")); @@ -405,7 +405,7 @@ public class Server : GlobalBase SendResponse(HttpStatusCode.BadRequest, response); break; } - settings.UpdateDownloadLocation(downloadLocation, moveFiles); + TrangaSettings.UpdateDownloadLocation(downloadLocation, moveFiles); SendResponse(HttpStatusCode.Accepted, response); break; case "Settings/AprilFoolsMode": @@ -415,7 +415,7 @@ public class Server : GlobalBase SendResponse(HttpStatusCode.BadRequest, response); break; } - settings.UpdateAprilFoolsMode(aprilFoolsModeEnabled); + TrangaSettings.UpdateAprilFoolsMode(aprilFoolsModeEnabled); SendResponse(HttpStatusCode.Accepted, response); break; /*case "Settings/UpdateWorkingDirectory": @@ -433,11 +433,11 @@ public class Server : GlobalBase SendResponse(HttpStatusCode.BadRequest, response); break; } - settings.UpdateUserAgent(customUserAgent); + TrangaSettings.UpdateUserAgent(customUserAgent); SendResponse(HttpStatusCode.Accepted, response); break; case "Settings/userAgent/Reset": - settings.UpdateUserAgent(null); + TrangaSettings.UpdateUserAgent(null); SendResponse(HttpStatusCode.Accepted, response); break; case "Settings/customRequestLimit": @@ -449,18 +449,12 @@ public class Server : GlobalBase SendResponse(HttpStatusCode.BadRequest, response); break; } - - if (settings.requestLimits.ContainsKey(requestType)) - { - settings.requestLimits[requestType] = requestsPerMinute; - SendResponse(HttpStatusCode.Accepted, response); - }else - SendResponse(HttpStatusCode.BadRequest, response); - settings.ExportSettings(); + + TrangaSettings.UpdateRateLimit(requestType, requestsPerMinute); + SendResponse(HttpStatusCode.Accepted, response); break; case "Settings/customRequestLimit/Reset": - settings.requestLimits = TrangaSettings.DefaultRequestLimits; - settings.ExportSettings(); + TrangaSettings.ResetRateLimits(); break; case "NotificationConnectors/Update": if (!requestVariables.TryGetValue("notificationConnector", out notificationConnectorStr) || diff --git a/Tranga/Tranga.cs b/Tranga/Tranga.cs index 1471365..3c9a209 100644 --- a/Tranga/Tranga.cs +++ b/Tranga/Tranga.cs @@ -11,10 +11,9 @@ public partial class Tranga : GlobalBase private Server _server; private HashSet _connectors; - public Tranga(Logger? logger, TrangaSettings settings) : base(logger, settings) + public Tranga(Logger? logger) : base(logger) { Log("\n\n _______ \n|_ _|.----..---.-..-----..-----..---.-.\n | | | _|| _ || || _ || _ |\n |___| |__| |___._||__|__||___ ||___._|\n |_____| \n\n"); - Log(settings.ToString()); keepRunning = true; _connectors = new HashSet() { @@ -70,7 +69,7 @@ public partial class Tranga : GlobalBase { while (keepRunning) { - if(!settings.aprilFoolsMode || !IsAprilFirst()) + if(!TrangaSettings.aprilFoolsMode || !IsAprilFirst()) jobBoss.CheckJobs(); else Log("April Fools Mode in Effect"); diff --git a/Tranga/TrangaArgs.cs b/Tranga/TrangaArgs.cs index e95ad91..77dfea3 100644 --- a/Tranga/TrangaArgs.cs +++ b/Tranga/TrangaArgs.cs @@ -36,34 +36,14 @@ public partial class Tranga : GlobalBase enabledLoggers.Add(Logger.LoggerType.FileLogger); Logger logger = new(enabledLoggers.ToArray(), Console.Out, Console.OutputEncoding, directoryPath); - TrangaSettings? settings = null; bool dlp = fetched.TryGetValue(downloadLocation, out string[]? downloadLocationPath); - bool wdp = fetched.TryGetValue(downloadLocation, out string[]? workingDirectoryPath); + bool wdp = fetched.TryGetValue(workingDirectory, out string[]? workingDirectoryPath); - if (dlp && wdp) - { - settings = new TrangaSettings(downloadLocationPath![0], workingDirectoryPath![0]); - }else if (dlp) - { - if (settings is null) - settings = new TrangaSettings(downloadLocation: downloadLocationPath![0]); - else - settings = new TrangaSettings(downloadLocation: downloadLocationPath![0], settings.workingDirectory); - }else if (wdp) - { - if (settings is null) - settings = new TrangaSettings(downloadLocation: workingDirectoryPath![0]); - else - settings = new TrangaSettings(settings.downloadLocation, workingDirectoryPath![0]); - } - else - { - settings = new TrangaSettings(); - } - - Directory.CreateDirectory(settings.downloadLocation);//TODO validate path - Directory.CreateDirectory(settings.workingDirectory);//TODO validate path + if (wdp) + TrangaSettings.LoadFromWorkingDirectory(workingDirectoryPath![0]); + if(dlp) + TrangaSettings.CreateOrUpdate(downloadDirectory: downloadLocationPath![0]); - Tranga _ = new (logger, settings); + Tranga _ = new (logger); } } \ No newline at end of file diff --git a/Tranga/TrangaSettings.cs b/Tranga/TrangaSettings.cs index 2ad9492..e2b9390 100644 --- a/Tranga/TrangaSettings.cs +++ b/Tranga/TrangaSettings.cs @@ -1,7 +1,6 @@ using System.Runtime.InteropServices; -using System.Text.Json.Nodes; -using System.Text.RegularExpressions; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Tranga.LibraryConnectors; using Tranga.MangaConnectors; using Tranga.NotificationConnectors; @@ -9,20 +8,20 @@ using static System.IO.UnixFileMode; namespace Tranga; -public class TrangaSettings +public static class TrangaSettings { - public string downloadLocation { get; private set; } - public string workingDirectory { get; private set; } - public int apiPortNumber { get; init; } - public string userAgent { get; private set; } = DefaultUserAgent; - [JsonIgnore] public string settingsFilePath => Path.Join(workingDirectory, "settings.json"); - [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 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; - public bool aprilFoolsMode { get; private set; } = true; + public static string downloadLocation { get; private set; } = (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/Manga" : Path.Join(Directory.GetCurrentDirectory(), "Downloads")); + public static string workingDirectory { get; private set; } = Path.Join(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/usr/share" : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "tranga-api"); + public static int apiPortNumber { get; private set; } = 6531; + public static string userAgent { get; private set; } = DefaultUserAgent; + [JsonIgnore] public static string settingsFilePath => Path.Join(workingDirectory, "settings.json"); + [JsonIgnore] public static string libraryConnectorsFilePath => Path.Join(workingDirectory, "libraryConnectors.json"); + [JsonIgnore] public static string notificationConnectorsFilePath => Path.Join(workingDirectory, "notificationConnectors.json"); + [JsonIgnore] public static string jobsFolderPath => Path.Join(workingDirectory, "jobs"); + [JsonIgnore] public static string coverImageCache => Path.Join(workingDirectory, "imageCache"); + public static ushort? version { get; } = 2; + public static bool aprilFoolsMode { get; private set; } = true; [JsonIgnore]internal static readonly Dictionary DefaultRequestLimits = new () { {RequestType.MangaInfo, 250}, @@ -33,50 +32,38 @@ public class TrangaSettings {RequestType.Default, 60} }; - public Dictionary requestLimits { get; set; } = DefaultRequestLimits; + public static Dictionary requestLimits { get; set; } = DefaultRequestLimits; - public TrangaSettings(string? downloadLocation = null, string? workingDirectory = null, int? apiPortNumber = null) + public static void LoadFromWorkingDirectory(string directory) { - string wd = workingDirectory ?? Path.Join(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/usr/share" : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "tranga-api"); - string sfp = Path.Join(wd, "settings.json"); - - string lockFilePath = $"{sfp}.lock"; - if (File.Exists(sfp) && !File.Exists(lockFilePath)) - {//Load from settings file - FileStream lockFile = File.Create(lockFilePath,0, FileOptions.DeleteOnClose); //lock settingsfile - string settingsStr = File.ReadAllText(sfp); - settingsStr = Regex.Replace(settingsStr, @"""MangaDexAuthor"": [0-9]+,", "");//https://github.com/C9Glax/tranga/pull/161 Remove sometime in the future :3 - TrangaSettings settings = JsonConvert.DeserializeObject(settingsStr)!; - this.requestLimits = settings.requestLimits; - this.userAgent = settings.userAgent; - this.downloadLocation = downloadLocation ?? settings.downloadLocation; - this.workingDirectory = workingDirectory ?? settings.workingDirectory; - this.apiPortNumber = apiPortNumber ?? settings.apiPortNumber; - lockFile.Close(); //unlock settingsfile - } - else if(!File.Exists(sfp)) - {//No settings file exists - if (downloadLocation?.Length < 1 || workingDirectory?.Length < 1) - throw new ArgumentException("Download-location and working-directory paths can not be empty!"); - this.requestLimits = DefaultRequestLimits; - this.userAgent = DefaultUserAgent; - this.apiPortNumber = apiPortNumber ?? 6531; - this.downloadLocation = downloadLocation ?? (RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/Manga" : Path.Join(Directory.GetCurrentDirectory(), "Downloads")); - this.workingDirectory = workingDirectory ?? Path.Join(RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "/usr/share" : Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "tranga-api"); - ExportSettings(); + TrangaSettings.workingDirectory = directory; + if (!File.Exists(settingsFilePath)) + { + return; } else - {//Settingsfile is locked - this.requestLimits = DefaultRequestLimits; - this.userAgent = DefaultUserAgent; - this.apiPortNumber = apiPortNumber!.Value; - this.downloadLocation = downloadLocation!; - this.workingDirectory = workingDirectory!; + { + Deserialize(File.ReadAllText(settingsFilePath)); } - UpdateDownloadLocation(this.downloadLocation, false); + + Directory.CreateDirectory(downloadLocation); + Directory.CreateDirectory(workingDirectory); + ExportSettings(); } - public HashSet LoadLibraryConnectors(GlobalBase clone) + public static void CreateOrUpdate(string? downloadDirectory = null, string? pWorkingDirectory = null, int? pApiPortNumber = null, string? pUserAgent = null, bool? pAprilFoolsMode = null) + { + TrangaSettings.downloadLocation = downloadDirectory ?? TrangaSettings.downloadLocation; + TrangaSettings.workingDirectory = pWorkingDirectory ?? TrangaSettings.workingDirectory; + TrangaSettings.apiPortNumber = pApiPortNumber ?? TrangaSettings.apiPortNumber; + TrangaSettings.userAgent = pUserAgent ?? TrangaSettings.userAgent; + TrangaSettings.aprilFoolsMode = pAprilFoolsMode ?? TrangaSettings.aprilFoolsMode; + Directory.CreateDirectory(downloadLocation); + Directory.CreateDirectory(workingDirectory); + ExportSettings(); + } + + public static HashSet LoadLibraryConnectors(GlobalBase clone) { if (!File.Exists(libraryConnectorsFilePath)) return new HashSet(); @@ -90,7 +77,7 @@ public class TrangaSettings })!; } - public HashSet LoadNotificationConnectors(GlobalBase clone) + public static HashSet LoadNotificationConnectors(GlobalBase clone) { if (!File.Exists(notificationConnectorsFilePath)) return new HashSet(); @@ -104,13 +91,13 @@ public class TrangaSettings })!; } - public void UpdateAprilFoolsMode(bool enabled) + public static void UpdateAprilFoolsMode(bool enabled) { - this.aprilFoolsMode = enabled; + TrangaSettings.aprilFoolsMode = enabled; ExportSettings(); } - public void UpdateDownloadLocation(string newPath, bool moveFiles = true) + public static void UpdateDownloadLocation(string newPath, bool moveFiles = true) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) Directory.CreateDirectory(newPath, @@ -118,32 +105,44 @@ public class TrangaSettings else Directory.CreateDirectory(newPath); - if (moveFiles && Directory.Exists(this.downloadLocation)) - Directory.Move(this.downloadLocation, newPath); + if (moveFiles && Directory.Exists(TrangaSettings.downloadLocation)) + Directory.Move(TrangaSettings.downloadLocation, newPath); - this.downloadLocation = newPath; + TrangaSettings.downloadLocation = newPath; ExportSettings(); } - public void UpdateWorkingDirectory(string newPath) + public static void UpdateWorkingDirectory(string newPath) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) Directory.CreateDirectory(newPath, GroupRead | GroupWrite | None | OtherRead | OtherWrite | UserRead | UserWrite); else Directory.CreateDirectory(newPath); - Directory.Move(this.workingDirectory, newPath); - this.workingDirectory = newPath; + Directory.Move(TrangaSettings.workingDirectory, newPath); + TrangaSettings.workingDirectory = newPath; ExportSettings(); } - public void UpdateUserAgent(string? customUserAgent) + public static void UpdateUserAgent(string? customUserAgent) { - this.userAgent = customUserAgent ?? DefaultUserAgent; + TrangaSettings.userAgent = customUserAgent ?? DefaultUserAgent; ExportSettings(); } - public void ExportSettings() + public static void UpdateRateLimit(RequestType requestType, int newLimit) + { + TrangaSettings.requestLimits[requestType] = newLimit; + ExportSettings(); + } + + public static void ResetRateLimits() + { + TrangaSettings.requestLimits = DefaultRequestLimits; + ExportSettings(); + } + + public static void ExportSettings() { if (File.Exists(settingsFilePath)) { @@ -152,22 +151,36 @@ public class TrangaSettings } else Directory.CreateDirectory(new FileInfo(settingsFilePath).DirectoryName!); - File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(this, Formatting.Indented)); + File.WriteAllText(settingsFilePath, Serialize()); } - public string GetFullCoverPath(Manga manga) + public static string Serialize() { - return Path.Join(this.coverImageCache, manga.coverFileNameInCache); + JObject jobj = new JObject(); + jobj.Add("downloadLocation", JToken.FromObject(TrangaSettings.downloadLocation)); + jobj.Add("workingDirectory", JToken.FromObject(TrangaSettings.workingDirectory)); + jobj.Add("apiPortNumber", JToken.FromObject(TrangaSettings.apiPortNumber)); + jobj.Add("userAgent", JToken.FromObject(TrangaSettings.userAgent)); + jobj.Add("aprilFoolsMode", JToken.FromObject(TrangaSettings.aprilFoolsMode)); + jobj.Add("version", JToken.FromObject(TrangaSettings.version)); + jobj.Add("requestLimits", JToken.FromObject(TrangaSettings.requestLimits)); + return jobj.ToString(); } - public override string ToString() + public static void Deserialize(string serialized) { - return $"TrangaSettings:\n" + - $"\tDownloadLocation: {downloadLocation}\n" + - $"\tworkingDirectory: {workingDirectory}\n" + - $"\tjobsFolderPath: {jobsFolderPath}\n" + - $"\tsettingsFilePath: {settingsFilePath}\n" + - $"\t\tnotificationConnectors: {notificationConnectorsFilePath}\n" + - $"\t\tlibraryConnectors: {libraryConnectorsFilePath}\n"; + JObject jobj = JObject.Parse(serialized); + if (jobj.TryGetValue("downloadLocation", out JToken? dl)) + TrangaSettings.downloadLocation = dl.Value()!; + if (jobj.TryGetValue("workingDirectory", out JToken? wd)) + TrangaSettings.workingDirectory = wd.Value()!; + if (jobj.TryGetValue("apiPortNumber", out JToken? apn)) + TrangaSettings.apiPortNumber = apn.Value(); + if (jobj.TryGetValue("userAgent", out JToken? ua)) + TrangaSettings.userAgent = ua.Value()!; + if (jobj.TryGetValue("aprilFoolsMode", out JToken? afm)) + TrangaSettings.aprilFoolsMode = afm.Value()!; + if (jobj.TryGetValue("requestLimits", out JToken? rl)) + TrangaSettings.requestLimits = rl.ToObject>()!; } } \ No newline at end of file From 7b91bb699f8e21ce14545101e3587a9ac60e1b4f Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 26 Aug 2024 13:09:33 +0200 Subject: [PATCH 6/9] Fix Settings not loading on reload --- CLI/Program.cs | 2 ++ Tranga/TrangaArgs.cs | 2 ++ Tranga/TrangaSettings.cs | 11 ++++------- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CLI/Program.cs b/CLI/Program.cs index f927ea2..c349b33 100644 --- a/CLI/Program.cs +++ b/CLI/Program.cs @@ -49,6 +49,8 @@ internal sealed class TrangaCli : Command if(settings.workingDirectory is not null) TrangaSettings.LoadFromWorkingDirectory(settings.workingDirectory); + else + TrangaSettings.CreateOrUpdate(); if(settings.downloadLocation is not null) TrangaSettings.CreateOrUpdate(downloadDirectory: settings.downloadLocation); diff --git a/Tranga/TrangaArgs.cs b/Tranga/TrangaArgs.cs index 77dfea3..f643d4a 100644 --- a/Tranga/TrangaArgs.cs +++ b/Tranga/TrangaArgs.cs @@ -41,6 +41,8 @@ public partial class Tranga : GlobalBase if (wdp) TrangaSettings.LoadFromWorkingDirectory(workingDirectoryPath![0]); + else + TrangaSettings.CreateOrUpdate(); if(dlp) TrangaSettings.CreateOrUpdate(downloadDirectory: downloadLocationPath![0]); diff --git a/Tranga/TrangaSettings.cs b/Tranga/TrangaSettings.cs index e2b9390..ec44ecc 100644 --- a/Tranga/TrangaSettings.cs +++ b/Tranga/TrangaSettings.cs @@ -37,14 +37,9 @@ public static class TrangaSettings public static void LoadFromWorkingDirectory(string directory) { TrangaSettings.workingDirectory = directory; - if (!File.Exists(settingsFilePath)) - { - return; - } - else - { + if(File.Exists(settingsFilePath)) Deserialize(File.ReadAllText(settingsFilePath)); - } + else return; Directory.CreateDirectory(downloadLocation); Directory.CreateDirectory(workingDirectory); @@ -53,6 +48,8 @@ public static class TrangaSettings public static void CreateOrUpdate(string? downloadDirectory = null, string? pWorkingDirectory = null, int? pApiPortNumber = null, string? pUserAgent = null, bool? pAprilFoolsMode = null) { + if(pWorkingDirectory is null && File.Exists(settingsFilePath)) + LoadFromWorkingDirectory(workingDirectory); TrangaSettings.downloadLocation = downloadDirectory ?? TrangaSettings.downloadLocation; TrangaSettings.workingDirectory = pWorkingDirectory ?? TrangaSettings.workingDirectory; TrangaSettings.apiPortNumber = pApiPortNumber ?? TrangaSettings.apiPortNumber; From 6d723b6355c84d39ea4f454a7ce05315bbebd42c Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 26 Aug 2024 12:59:19 +0200 Subject: [PATCH 7/9] Fix Settings not returning as JSON --- Tranga/Server.cs | 2 +- Tranga/TrangaSettings.cs | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Tranga/Server.cs b/Tranga/Server.cs index 95dad91..8ed2e2c 100644 --- a/Tranga/Server.cs +++ b/Tranga/Server.cs @@ -198,7 +198,7 @@ public class Server : GlobalBase SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.Where(jjob => jjob is DownloadNewChapters).OrderBy(jjob => ((DownloadNewChapters)jjob).manga.sortName)); break; case "Settings": - SendResponse(HttpStatusCode.OK, response, TrangaSettings.Serialize()); + SendResponse(HttpStatusCode.OK, response, TrangaSettings.AsJObject()); break; case "Settings/userAgent": SendResponse(HttpStatusCode.OK, response, TrangaSettings.userAgent); diff --git a/Tranga/TrangaSettings.cs b/Tranga/TrangaSettings.cs index ec44ecc..b945fe5 100644 --- a/Tranga/TrangaSettings.cs +++ b/Tranga/TrangaSettings.cs @@ -151,7 +151,7 @@ public static class TrangaSettings File.WriteAllText(settingsFilePath, Serialize()); } - public static string Serialize() + public static JObject AsJObject() { JObject jobj = new JObject(); jobj.Add("downloadLocation", JToken.FromObject(TrangaSettings.downloadLocation)); @@ -161,9 +161,11 @@ public static class TrangaSettings jobj.Add("aprilFoolsMode", JToken.FromObject(TrangaSettings.aprilFoolsMode)); jobj.Add("version", JToken.FromObject(TrangaSettings.version)); jobj.Add("requestLimits", JToken.FromObject(TrangaSettings.requestLimits)); - return jobj.ToString(); + return jobj; } + public static string Serialize() => AsJObject().ToString(); + public static void Deserialize(string serialized) { JObject jobj = JObject.Parse(serialized); From 1bd20791b85bfc255457e2dc22f6f60ff943b859 Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 26 Aug 2024 13:18:48 +0200 Subject: [PATCH 8/9] Add Cache-Control headers --- Tranga/Server.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tranga/Server.cs b/Tranga/Server.cs index 8ed2e2c..78f96de 100644 --- a/Tranga/Server.cs +++ b/Tranga/Server.cs @@ -716,6 +716,7 @@ public class Server : GlobalBase if (content is not Stream) { response.ContentType = "application/json"; + response.AddHeader("Cache-Control", "no-store"); try { response.OutputStream.Write(content is not null @@ -731,6 +732,7 @@ public class Server : GlobalBase else if(content is FileStream stream) { string contentType = stream.Name.Split('.')[^1]; + response.AddHeader("Cache-Control", "max-age=600"); switch (contentType.ToLower()) { case "gif": From dfa8e66f3436327771dd7460c2d05370cafebdfb Mon Sep 17 00:00:00 2001 From: Glax Date: Mon, 26 Aug 2024 13:21:34 +0200 Subject: [PATCH 9/9] Fix try-block in Server.cs --- Tranga/Server.cs | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/Tranga/Server.cs b/Tranga/Server.cs index 78f96de..4e387f1 100644 --- a/Tranga/Server.cs +++ b/Tranga/Server.cs @@ -713,45 +713,46 @@ public class Server : GlobalBase response.AddHeader("Access-Control-Max-Age", "1728000"); response.AppendHeader("Access-Control-Allow-Origin", "*"); - if (content is not Stream) + try { - response.ContentType = "application/json"; - response.AddHeader("Cache-Control", "no-store"); - try + if (content is not Stream) { + response.ContentType = "application/json"; + response.AddHeader("Cache-Control", "no-store"); response.OutputStream.Write(content is not null ? Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(content)) : Array.Empty()); response.OutputStream.Close(); } - catch (HttpListenerException e) + else if (content is FileStream stream) { - Log(e.ToString()); + string contentType = stream.Name.Split('.')[^1]; + response.AddHeader("Cache-Control", "max-age=600"); + switch (contentType.ToLower()) + { + case "gif": + response.ContentType = "image/gif"; + break; + case "png": + response.ContentType = "image/png"; + break; + case "jpg": + case "jpeg": + response.ContentType = "image/jpeg"; + break; + case "log": + response.ContentType = "text/plain"; + break; + } + + stream.CopyTo(response.OutputStream); + response.OutputStream.Close(); + stream.Close(); } } - else if(content is FileStream stream) + catch (HttpListenerException e) { - string contentType = stream.Name.Split('.')[^1]; - response.AddHeader("Cache-Control", "max-age=600"); - switch (contentType.ToLower()) - { - case "gif": - response.ContentType = "image/gif"; - break; - case "png": - response.ContentType = "image/png"; - break; - case "jpg": - case "jpeg": - response.ContentType = "image/jpeg"; - break; - case "log": - response.ContentType = "text/plain"; - break; - } - stream.CopyTo(response.OutputStream); - response.OutputStream.Close(); - stream.Close(); + Log(e.ToString()); } } } \ No newline at end of file