diff --git a/CLI/Program.cs b/CLI/Program.cs index ec21751..c349b33 100644 --- a/CLI/Program.cs +++ b/CLI/Program.cs @@ -47,37 +47,18 @@ 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); - } + if(settings.workingDirectory is not null) + TrangaSettings.LoadFromWorkingDirectory(settings.workingDirectory); else - { - trangaSettings = new TrangaSettings(); - } - - Directory.CreateDirectory(trangaSettings.downloadLocation); - Directory.CreateDirectory(trangaSettings.workingDirectory); + TrangaSettings.CreateOrUpdate(); + 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 +101,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 0843e32..2fc3dbe 100644 --- a/Tranga/GlobalBase.cs +++ b/Tranga/GlobalBase.cs @@ -14,7 +14,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; } @@ -25,19 +24,17 @@ 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; this._connectors = clone._connectors; } - 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(); this._connectors = new(); } @@ -132,20 +129,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() @@ -160,20 +157,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/JobBoss.cs b/Tranga/Jobs/JobBoss.cs index c288c14..e0acf10 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), @@ -192,7 +192,7 @@ public class JobBoss : GlobalBase foreach (string internalId in extraneousIds) RemoveMangaFromCache(internalId); - 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); string[] mangaFiles = Directory.GetFiles(settings.mangaCacheFolderPath); @@ -202,7 +202,7 @@ public class JobBoss : GlobalBase 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)) { @@ -249,7 +249,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/Manga.cs b/Tranga/Manga.cs index df63df6..9deefb3 100644 --- a/Tranga/Manga.cs +++ b/Tranga/Manga.cs @@ -137,9 +137,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 79fc4d6..e502ffa 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/ChromiumDownloadClient.cs b/Tranga/MangaConnectors/ChromiumDownloadClient.cs index 8ddf850..d7e6523 100644 --- a/Tranga/MangaConnectors/ChromiumDownloadClient.cs +++ b/Tranga/MangaConnectors/ChromiumDownloadClient.cs @@ -1,8 +1,8 @@ using System.Net; using System.Text; +using System.Text.RegularExpressions; using HtmlAgilityPack; using PuppeteerSharp; -using PuppeteerSharp.Input; namespace Tranga.MangaConnectors; @@ -11,10 +11,11 @@ internal class ChromiumDownloadClient : DownloadClient private IBrowser browser { get; set; } private const string ChromiumVersion = "1154303"; private const int StartTimeoutMs = 30000; + private readonly 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 +59,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..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)); @@ -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 diff --git a/Tranga/MangaConnectors/HttpDownloadClient.cs b/Tranga/MangaConnectors/HttpDownloadClient.cs index 46a0008..238306b 100644 --- a/Tranga/MangaConnectors/HttpDownloadClient.cs +++ b/Tranga/MangaConnectors/HttpDownloadClient.cs @@ -13,10 +13,10 @@ internal class HttpDownloadClient : DownloadClient public HttpDownloadClient(GlobalBase clone) : base(clone) { - Client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", settings.userAgent); + Client.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", TrangaSettings.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."); 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 2dc0a5b..217a2c4 100644 --- a/Tranga/MangaConnectors/MangaDex.cs +++ b/Tranga/MangaConnectors/MangaDex.cs @@ -291,6 +291,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 49a0d55..585cc91 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 6f3ac9a..551c5bf 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 faf3daa..6c55865 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 84f9e21..67e62a4 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 277b089..b725b91 100644 --- a/Tranga/MangaConnectors/Mangasee.cs +++ b/Tranga/MangaConnectors/Mangasee.cs @@ -61,21 +61,27 @@ 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) == false)); 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(); + return ret.ToArray(); } public override Manga? GetMangaFromId(string publicationId) @@ -218,6 +224,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 774b77d..bb15907 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 8ae3641..0d30fd2 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/Tranga.cs b/Tranga/Tranga.cs index f2ff481..9493311 100644 --- a/Tranga/Tranga.cs +++ b/Tranga/Tranga.cs @@ -10,10 +10,9 @@ public partial class Tranga : GlobalBase public JobBoss jobBoss; private Server.Server _server; - 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() { @@ -69,7 +68,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 c1743a6..f643d4a 100644 --- a/Tranga/TrangaArgs.cs +++ b/Tranga/TrangaArgs.cs @@ -36,34 +36,16 @@ 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(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(workingDirectory: workingDirectoryPath![0]); - else - settings = new TrangaSettings(settings.downloadLocation, workingDirectoryPath![0]); - } + if (wdp) + TrangaSettings.LoadFromWorkingDirectory(workingDirectoryPath![0]); else - { - settings = new TrangaSettings(); - } - - Directory.CreateDirectory(settings.downloadLocation);//TODO validate path - Directory.CreateDirectory(settings.workingDirectory);//TODO validate path + TrangaSettings.CreateOrUpdate(); + 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 7047006..b945fe5 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,21 +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 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; - 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}, @@ -34,50 +32,35 @@ 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(); - } - else - {//Settingsfile is locked - this.requestLimits = DefaultRequestLimits; - this.userAgent = DefaultUserAgent; - this.apiPortNumber = apiPortNumber!.Value; - this.downloadLocation = downloadLocation!; - this.workingDirectory = workingDirectory!; - } - UpdateDownloadLocation(this.downloadLocation, false); + TrangaSettings.workingDirectory = directory; + if(File.Exists(settingsFilePath)) + Deserialize(File.ReadAllText(settingsFilePath)); + else return; + + 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) + { + if(pWorkingDirectory is null && File.Exists(settingsFilePath)) + LoadFromWorkingDirectory(workingDirectory); + 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(); @@ -91,7 +74,7 @@ public class TrangaSettings })!; } - public HashSet LoadNotificationConnectors(GlobalBase clone) + public static HashSet LoadNotificationConnectors(GlobalBase clone) { if (!File.Exists(notificationConnectorsFilePath)) return new HashSet(); @@ -105,13 +88,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, @@ -119,32 +102,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)) { @@ -153,22 +148,38 @@ 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 JObject AsJObject() { - 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; } - public override string ToString() + public static string Serialize() => AsJObject().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