diff --git a/Tranga/Connector.cs b/Tranga/Connector.cs
index 24bd845..51be4dd 100644
--- a/Tranga/Connector.cs
+++ b/Tranga/Connector.cs
@@ -62,6 +62,12 @@ public abstract class Connector
File.WriteAllText(seriesInfoPath,publication.GetSeriesInfo());
}
+ ///
+ /// Downloads Image from URL and saves it to the given path(incl. fileName)
+ ///
+ ///
+ ///
+ /// DownloadClient of the connector
protected static void DownloadImage(string imageUrl, string fullPath, DownloadClient downloadClient)
{
DownloadClient.RequestResult requestResult = downloadClient.MakeRequest(imageUrl);
@@ -70,22 +76,31 @@ public abstract class Connector
File.WriteAllBytes(fullPath, buffer);
}
+ ///
+ /// Downloads all Images from URLs, Compresses to zip(cbz) and saves.
+ ///
+ /// List of URLs to download Images from
+ /// Full path to save archive to (without file ending .cbz)
+ /// DownloadClient of the connector
protected static void DownloadChapterImages(string[] imageUrls, string saveArchiveFilePath, DownloadClient downloadClient)
{
+ //Check if Publication Directory already exists
string[] splitPath = saveArchiveFilePath.Split(Path.DirectorySeparatorChar);
string directoryPath = Path.Combine(splitPath.Take(splitPath.Length - 1).ToArray());
if (!Directory.Exists(directoryPath))
Directory.CreateDirectory(directoryPath);
string fullPath = $"{saveArchiveFilePath}.cbz";
- if (File.Exists(fullPath))
+ if (File.Exists(fullPath)) //Don't download twice.
return;
+ //Create a temporary folder to store images
string tempFolder = Path.GetTempFileName();
File.Delete(tempFolder);
Directory.CreateDirectory(tempFolder);
int chapter = 0;
+ //Download all Images to temporary Folder
foreach (string imageUrl in imageUrls)
{
string[] split = imageUrl.Split('.');
@@ -93,10 +108,10 @@ public abstract class Connector
DownloadImage(imageUrl, Path.Join(tempFolder, $"{chapter++}.{extension}"), downloadClient);
}
+ //ZIP-it and ship-it
ZipFile.CreateFromDirectory(tempFolder, fullPath);
Directory.Delete(tempFolder); //Cleanup
}
-
protected class DownloadClient
{
@@ -104,12 +119,21 @@ public abstract class Connector
private DateTime _lastRequest;
private static readonly HttpClient Client = new();
+ ///
+ /// Creates a httpClient
+ ///
+ /// minimum delay between requests (to avoid spam)
public DownloadClient(uint delay)
{
_requestSpeed = TimeSpan.FromMilliseconds(delay);
_lastRequest = DateTime.Now.Subtract(_requestSpeed);
}
+ ///
+ /// Request Webpage
+ ///
+ ///
+ /// RequestResult with StatusCode and Stream of received data
public RequestResult MakeRequest(string url)
{
while((DateTime.Now - _lastRequest) < _requestSpeed)
diff --git a/Tranga/Connectors/MangaDex.cs b/Tranga/Connectors/MangaDex.cs
index 351f45d..5cd2662 100644
--- a/Tranga/Connectors/MangaDex.cs
+++ b/Tranga/Connectors/MangaDex.cs
@@ -20,24 +20,28 @@ public class MangaDex : Connector
public override Publication[] GetPublications(string publicationTitle = "")
{
- const int limit = 100;
- int offset = 0;
- int total = int.MaxValue;
+ const int limit = 100; //How many values we want returned at once
+ int offset = 0; //"Page"
+ int total = int.MaxValue; //How many total results are there, is updated on first request
HashSet publications = new();
- while (offset < total)
+ while (offset < total) //As long as we haven't requested all "Pages"
{
+ //Request next Page
DownloadClient.RequestResult requestResult =
downloadClient.MakeRequest(
$"https://api.mangadex.org/manga?limit={limit}&title={publicationTitle}&offset={offset}");
if (requestResult.statusCode != HttpStatusCode.OK)
break;
JsonObject? result = JsonSerializer.Deserialize(requestResult.result);
+
offset += limit;
if (result is null)
break;
- total = result["total"]!.GetValue();
- JsonArray mangaInResult = result["data"]!.AsArray();
+ total = result["total"]!.GetValue(); //Update the total number of Publications
+
+ JsonArray mangaInResult = result["data"]!.AsArray(); //Manga-data-Array
+ //Loop each Manga and extract information from JSON
foreach (JsonNode? mangeNode in mangaInResult)
{
JsonObject manga = (JsonObject)mangeNode!;
@@ -113,7 +117,7 @@ public class MangaDex : Connector
status,
manga["id"]!.GetValue()
);
- publications.Add(pub);
+ publications.Add(pub); //Add Publication (Manga) to result
}
}
@@ -122,16 +126,17 @@ public class MangaDex : Connector
public override Chapter[] GetChapters(Publication publication, string language = "")
{
- const int limit = 100;
- int offset = 0;
- string id = publication.downloadUrl;
- int total = int.MaxValue;
+ const int limit = 100; //How many values we want returned at once
+ int offset = 0; //"Page"
+ int total = int.MaxValue; //How many total results are there, is updated on first request
List chapters = new();
+ //As long as we haven't requested all "Pages"
while (offset < total)
{
+ //Request next "Page"
DownloadClient.RequestResult requestResult =
downloadClient.MakeRequest(
- $"https://api.mangadex.org/manga/{id}/feed?limit={limit}&offset={offset}&translatedLanguage%5B%5D={language}");
+ $"https://api.mangadex.org/manga/{publication.downloadUrl}/feed?limit={limit}&offset={offset}&translatedLanguage%5B%5D={language}");
if (requestResult.statusCode != HttpStatusCode.OK)
break;
JsonObject? result = JsonSerializer.Deserialize(requestResult.result);
@@ -142,6 +147,7 @@ public class MangaDex : Connector
total = result["total"]!.GetValue();
JsonArray chaptersInResult = result["data"]!.AsArray();
+ //Loop through all Chapters in result and extract information from JSON
foreach (JsonNode? jsonNode in chaptersInResult)
{
JsonObject chapter = (JsonObject)jsonNode!;
@@ -164,6 +170,7 @@ public class MangaDex : Connector
}
}
+ //Return Chapters ordered by Chapter-Number
NumberFormatInfo chapterNumberFormatInfo = new()
{
NumberDecimalSeparator = "."
@@ -173,6 +180,7 @@ public class MangaDex : Connector
public override void DownloadChapter(Publication publication, Chapter chapter)
{
+ //Request URLs for Chapter-Images
DownloadClient.RequestResult requestResult =
downloadClient.MakeRequest($"https://api.mangadex.org/at-home/server/{chapter.url}?forcePort443=false'");
if (requestResult.statusCode != HttpStatusCode.OK)
@@ -184,22 +192,26 @@ public class MangaDex : Connector
string baseUrl = result["baseUrl"]!.GetValue();
string hash = result["chapter"]!["hash"]!.GetValue();
JsonArray imageFileNames = result["chapter"]!["data"]!.AsArray();
+ //Loop through all imageNames and construct urls (imageUrl)
HashSet imageUrls = new();
foreach (JsonNode? image in imageFileNames)
imageUrls.Add($"{baseUrl}/data/{hash}/{image!.GetValue()}");
+ //Download Chapter-Images
DownloadChapterImages(imageUrls.ToArray(), Path.Join(downloadLocation, publication.folderName, chapter.fileName), this.downloadClient);
}
public override void DownloadCover(Publication publication)
{
- string publicationPath = Path.Join(downloadLocation, publication.folderName);
- Directory.CreateDirectory(publicationPath);
- DirectoryInfo dirInfo = new (publicationPath);
+ //Check if Publication already has a Folder and cover
+ string publicationFolder = Path.Join(downloadLocation, publication.folderName);
+ Directory.CreateDirectory(publicationFolder);
+ DirectoryInfo dirInfo = new (publicationFolder);
foreach(FileInfo fileInfo in dirInfo.EnumerateFiles())
if (fileInfo.Name.Contains("cover."))
return;
+ //Request information where to download Cover
DownloadClient.RequestResult requestResult =
downloadClient.MakeRequest($"https://api.mangadex.org/cover/{publication.posterUrl}");
if (requestResult.statusCode != HttpStatusCode.OK)
@@ -211,11 +223,15 @@ public class MangaDex : Connector
string fileName = result!["data"]!["attributes"]!["fileName"]!.GetValue();
string coverUrl = $"https://uploads.mangadex.org/covers/{publication.downloadUrl}/{fileName}";
+
+ //Get file-extension (jpg, png)
string[] split = coverUrl.Split('.');
string extension = split[split.Length - 1];
string outFolderPath = Path.Join(downloadLocation, publication.folderName);
Directory.CreateDirectory(outFolderPath);
+
+ //Download cover-Image
DownloadImage(coverUrl, Path.Join(downloadLocation, publication.folderName, $"cover.{extension}"), this.downloadClient);
}
}
\ No newline at end of file
diff --git a/Tranga/TaskExecutor.cs b/Tranga/TaskExecutor.cs
index 4f55ef3..c4b0ff2 100644
--- a/Tranga/TaskExecutor.cs
+++ b/Tranga/TaskExecutor.cs
@@ -17,6 +17,7 @@ public static class TaskExecutor
/// Is thrown when there is no Connector available with the name of the TrangaTask.connectorName
public static void Execute(Connector[] connectors, TrangaTask trangaTask, Dictionary> chapterCollection)
{
+ //Get Connector from list of available Connectors and the required Connector of the TrangaTask
Connector? connector = connectors.FirstOrDefault(c => c.name == trangaTask.connectorName);
if (connector is null)
throw new ArgumentException($"Connector {trangaTask.connectorName} is not a known connector.");
@@ -26,6 +27,7 @@ public static class TaskExecutor
trangaTask.isBeingExecuted = true;
trangaTask.lastExecuted = DateTime.Now;
+ //Call appropriate Method based on TrangaTask.Task
switch (trangaTask.task)
{
case TrangaTask.Task.DownloadNewChapters:
@@ -42,6 +44,11 @@ public static class TaskExecutor
trangaTask.isBeingExecuted = false;
}
+ ///
+ /// Updates the available Publications from a Connector (all of them)
+ ///
+ /// Connector to receive Publications from
+ ///
private static void UpdatePublications(Connector connector, Dictionary> chapterCollection)
{
Publication[] publications = connector.GetPublications();
@@ -49,6 +56,14 @@ public static class TaskExecutor
chapterCollection.TryAdd(publication, new List());
}
+ ///
+ /// Checks for new Chapters and Downloads new ones.
+ /// If no Chapters had been downloaded previously, download also cover and create series.json
+ ///
+ /// Connector to use
+ /// Publication to check
+ /// Language to receive chapters for
+ ///
private static void DownloadNewChapters(Connector connector, Publication publication, string language, Dictionary> chapterCollection)
{
List newChapters = UpdateChapters(connector, publication, language, chapterCollection);
@@ -58,6 +73,14 @@ public static class TaskExecutor
connector.SaveSeriesInfo(publication);
}
+ ///
+ /// Updates the available Chapters of a Publication
+ ///
+ /// Connector to use
+ /// Publication to check
+ /// Language to receive chapters for
+ ///
+ /// List of Chapters that were previously not in collection
private static List UpdateChapters(Connector connector, Publication publication, string language, Dictionary> chapterCollection)
{
List newChaptersList = new();
diff --git a/Tranga/TaskManager.cs b/Tranga/TaskManager.cs
index 6a510e1..9a94866 100644
--- a/Tranga/TaskManager.cs
+++ b/Tranga/TaskManager.cs
@@ -70,10 +70,12 @@ public class TaskManager
public void AddTask(TrangaTask.Task task, string connectorName, Publication? publication, TimeSpan reoccurrence,
string language = "")
{
+ //Get appropriate Connector from available Connectors for TrangaTask
Connector? connector = connectors.FirstOrDefault(c => c.name == connectorName);
if (connector is null)
throw new ArgumentException($"Connector {connectorName} is not a known connector.");
+ //Check if same task already exists
if (!_allTasks.Any(trangaTask => trangaTask.task != task && trangaTask.connectorName != connector.name &&
trangaTask.publication?.downloadUrl != publication?.downloadUrl))
{
@@ -142,7 +144,7 @@ public class TaskManager
//Wait for tasks to finish
while(_allTasks.Any(task => task.isBeingExecuted))
Thread.Sleep(10);
-
+ Environment.Exit(0);
}
private HashSet ImportTasks(string importFolderPath)