Compare commits
No commits in common. "ed79ee5d0f320e38e0af82f81ebb817496fda1ad" and "2a389f1edeff5544fa017194ac825a62cb797660" have entirely different histories.
ed79ee5d0f
...
2a389f1ede
@ -45,22 +45,14 @@ public class MemoryLogger : LoggerBase
|
|||||||
public string[] GetNewLines()
|
public string[] GetNewLines()
|
||||||
{
|
{
|
||||||
int logMessageCount = _logMessages.Count;
|
int logMessageCount = _logMessages.Count;
|
||||||
List<string> ret = new();
|
string[] ret = new string[logMessageCount - _lastLogMessageIndex];
|
||||||
|
|
||||||
int retIndex = 0;
|
for (int retIndex = 0; retIndex < ret.Length; retIndex++)
|
||||||
for (; retIndex < logMessageCount - _lastLogMessageIndex; retIndex++)
|
|
||||||
{
|
{
|
||||||
try
|
ret[retIndex] = _logMessages.GetValueAtIndex(_lastLogMessageIndex + retIndex).ToString();
|
||||||
{
|
|
||||||
ret.Add(_logMessages.GetValueAtIndex(_lastLogMessageIndex + retIndex).ToString());
|
|
||||||
}
|
|
||||||
catch (NullReferenceException e)//Called when LogMessage has not finished writing
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastLogMessageIndex = _lastLogMessageIndex + retIndex;
|
_lastLogMessageIndex = logMessageCount;
|
||||||
return ret.ToArray();
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,8 +19,6 @@ public abstract class Job : GlobalBase
|
|||||||
this.recurring = recurring;
|
this.recurring = recurring;
|
||||||
if (recurring && recurrenceTime is null)
|
if (recurring && recurrenceTime is null)
|
||||||
throw new ArgumentException("If recurrence is set to true, a recurrence time has to be provided.");
|
throw new ArgumentException("If recurrence is set to true, a recurrence time has to be provided.");
|
||||||
else if(recurring && recurrenceTime is not null)
|
|
||||||
this.lastExecution = DateTime.Now.Subtract((TimeSpan)recurrenceTime);
|
|
||||||
this.recurrenceTime = recurrenceTime;
|
this.recurrenceTime = recurrenceTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using Newtonsoft.Json;
|
using Tranga.MangaConnectors;
|
||||||
using Tranga.MangaConnectors;
|
|
||||||
|
|
||||||
namespace Tranga.Jobs;
|
namespace Tranga.Jobs;
|
||||||
|
|
||||||
@ -8,42 +7,16 @@ public class JobBoss : GlobalBase
|
|||||||
public HashSet<Job> jobs { get; init; }
|
public HashSet<Job> jobs { get; init; }
|
||||||
private Dictionary<MangaConnector, Queue<Job>> mangaConnectorJobQueue { get; init; }
|
private Dictionary<MangaConnector, Queue<Job>> mangaConnectorJobQueue { get; init; }
|
||||||
|
|
||||||
public JobBoss(GlobalBase clone, HashSet<MangaConnector> connectors) : base(clone)
|
public JobBoss(GlobalBase clone) : base(clone)
|
||||||
{
|
{
|
||||||
if (File.Exists(settings.jobsFilePath))
|
|
||||||
this.jobs = JsonConvert.DeserializeObject<HashSet<Job>>(File.ReadAllText(settings.jobsFilePath), new JobJsonConverter(this, new MangaConnectorJsonConverter(this, connectors)))!;
|
|
||||||
else
|
|
||||||
this.jobs = new();
|
this.jobs = new();
|
||||||
foreach (DownloadNewChapters ncJob in this.jobs.Where(job => job is DownloadNewChapters))
|
|
||||||
cachedPublications.Add(ncJob.manga);
|
|
||||||
this.mangaConnectorJobQueue = new();
|
this.mangaConnectorJobQueue = new();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddJob(Job job)
|
public void AddJob(Job job)
|
||||||
{
|
|
||||||
if (ContainsJobLike(job))
|
|
||||||
{
|
|
||||||
Log($"Already Contains Job {job}");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
Log($"Added {job}");
|
Log($"Added {job}");
|
||||||
this.jobs.Add(job);
|
this.jobs.Add(job);
|
||||||
File.WriteAllText(settings.jobsFilePath, JsonConvert.SerializeObject(this.jobs));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ContainsJobLike(Job job)
|
|
||||||
{
|
|
||||||
if (job is DownloadChapter dcJob)
|
|
||||||
{
|
|
||||||
return this.GetJobsLike(dcJob.mangaConnector, chapter: dcJob.chapter).Any();
|
|
||||||
}else if (job is DownloadNewChapters ncJob)
|
|
||||||
{
|
|
||||||
return this.GetJobsLike(ncJob.mangaConnector, ncJob.manga).Any();
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveJob(Job job)
|
public void RemoveJob(Job job)
|
||||||
@ -137,13 +110,13 @@ public class JobBoss : GlobalBase
|
|||||||
foreach (Queue<Job> jobQueue in mangaConnectorJobQueue.Values)
|
foreach (Queue<Job> jobQueue in mangaConnectorJobQueue.Values)
|
||||||
{
|
{
|
||||||
Job queueHead = jobQueue.Peek();
|
Job queueHead = jobQueue.Peek();
|
||||||
if (queueHead.progressToken.state is ProgressToken.State.Complete)
|
if (queueHead.progressToken.state == ProgressToken.State.Complete)
|
||||||
{
|
{
|
||||||
if(queueHead.recurring)
|
if(queueHead.recurring)
|
||||||
queueHead.Reset();
|
queueHead.Reset();
|
||||||
jobQueue.Dequeue();
|
jobQueue.Dequeue();
|
||||||
}else if(queueHead.progressToken.state is ProgressToken.State.Standby)
|
|
||||||
AddJobsToQueue(jobQueue.Peek().ExecuteReturnSubTasks());
|
AddJobsToQueue(jobQueue.Peek().ExecuteReturnSubTasks());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
@ -1,66 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
using Tranga.MangaConnectors;
|
|
||||||
|
|
||||||
namespace Tranga.Jobs;
|
|
||||||
|
|
||||||
public class JobJsonConverter : JsonConverter
|
|
||||||
{
|
|
||||||
private GlobalBase _clone;
|
|
||||||
private MangaConnectorJsonConverter _mangaConnectorJsonConverter;
|
|
||||||
|
|
||||||
internal JobJsonConverter(GlobalBase clone, MangaConnectorJsonConverter mangaConnectorJsonConverter)
|
|
||||||
{
|
|
||||||
this._clone = clone;
|
|
||||||
this._mangaConnectorJsonConverter = mangaConnectorJsonConverter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanConvert(Type objectType)
|
|
||||||
{
|
|
||||||
return (objectType == typeof(Job));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
JObject jo = JObject.Load(reader);
|
|
||||||
if (jo.ContainsKey("manga"))//DownloadNewChapters
|
|
||||||
{
|
|
||||||
return new DownloadNewChapters(this._clone,
|
|
||||||
jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings()
|
|
||||||
{
|
|
||||||
Converters =
|
|
||||||
{
|
|
||||||
this._mangaConnectorJsonConverter
|
|
||||||
}
|
|
||||||
}))!,
|
|
||||||
jo.GetValue("manga")!.ToObject<Manga>(),
|
|
||||||
jo.GetValue("recurring")!.Value<bool>(),
|
|
||||||
jo.GetValue("recurrenceTime")!.ToObject<TimeSpan?>());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (jo.ContainsKey("chapter"))//DownloadChapter
|
|
||||||
{
|
|
||||||
return new DownloadChapter(this._clone,
|
|
||||||
jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings()
|
|
||||||
{
|
|
||||||
Converters =
|
|
||||||
{
|
|
||||||
this._mangaConnectorJsonConverter
|
|
||||||
}
|
|
||||||
}))!,
|
|
||||||
jo.GetValue("chapter")!.ToObject<Chapter>());
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Don't call this
|
|
||||||
/// </summary>
|
|
||||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
throw new Exception("Dont call this");
|
|
||||||
}
|
|
||||||
}
|
|
@ -36,14 +36,14 @@ public struct Manga
|
|||||||
private static readonly Regex LegalCharacters = new (@"[A-Z]*[a-z]*[0-9]* *\.*-*,*'*\'*\)*\(*~*!*");
|
private static readonly Regex LegalCharacters = new (@"[A-Z]*[a-z]*[0-9]* *\.*-*,*'*\'*\)*\(*~*!*");
|
||||||
|
|
||||||
[JsonConstructor]
|
[JsonConstructor]
|
||||||
public Manga(string sortName, List<string> authors, string? description, Dictionary<string,string> altTitles, string[] tags, string? coverUrl, string? coverFileNameInCache, Dictionary<string,string>? links, int? year, string? originalLanguage, string status, string publicationId, string? folderName = null, float? ignoreChaptersBelow = 0)
|
public Manga(string sortName, List<string> authors, string? description, Dictionary<string,string> altTitles, string[] tags, string? coverUrl, Dictionary<string,string>? links, int? year, string? originalLanguage, string status, string publicationId, string? folderName = null, float? ignoreChaptersBelow = 0)
|
||||||
{
|
{
|
||||||
this.sortName = sortName;
|
this.sortName = sortName;
|
||||||
this.authors = authors;
|
this.authors = authors;
|
||||||
this.description = description;
|
this.description = description;
|
||||||
this.altTitles = altTitles;
|
this.altTitles = altTitles;
|
||||||
this.tags = tags;
|
this.tags = tags;
|
||||||
this.coverFileNameInCache = coverFileNameInCache;
|
this.coverFileNameInCache = null;
|
||||||
this.coverUrl = coverUrl;
|
this.coverUrl = coverUrl;
|
||||||
this.links = links ?? new Dictionary<string, string>();
|
this.links = links ?? new Dictionary<string, string>();
|
||||||
this.year = year;
|
this.year = year;
|
||||||
|
@ -1,49 +0,0 @@
|
|||||||
using Newtonsoft.Json;
|
|
||||||
using Newtonsoft.Json.Linq;
|
|
||||||
|
|
||||||
namespace Tranga.MangaConnectors;
|
|
||||||
|
|
||||||
public class MangaConnectorJsonConverter : JsonConverter
|
|
||||||
{
|
|
||||||
private GlobalBase _clone;
|
|
||||||
private HashSet<MangaConnector> connectors;
|
|
||||||
|
|
||||||
internal MangaConnectorJsonConverter(GlobalBase clone, HashSet<MangaConnector> connectors)
|
|
||||||
{
|
|
||||||
this._clone = clone;
|
|
||||||
this.connectors = connectors;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanConvert(Type objectType)
|
|
||||||
{
|
|
||||||
return (objectType == typeof(MangaConnector));
|
|
||||||
}
|
|
||||||
|
|
||||||
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
JObject jo = JObject.Load(reader);
|
|
||||||
switch (jo.GetValue("name")!.Value<string>()!)
|
|
||||||
{
|
|
||||||
case "MangaDex":
|
|
||||||
return this.connectors.First(c => c is MangaDex);
|
|
||||||
case "Manganato":
|
|
||||||
return this.connectors.First(c => c is Manganato);
|
|
||||||
case "MangaKatana":
|
|
||||||
return this.connectors.First(c => c is MangaKatana);
|
|
||||||
case "Mangasee":
|
|
||||||
return this.connectors.First(c => c is Mangasee);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Exception();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool CanWrite => false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Don't call this
|
|
||||||
/// </summary>
|
|
||||||
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
|
|
||||||
{
|
|
||||||
throw new Exception("Dont call this");
|
|
||||||
}
|
|
||||||
}
|
|
@ -102,9 +102,6 @@ public class MangaDex : MangaConnector
|
|||||||
authorIds.Add(node!["id"]!.GetValue<string>());
|
authorIds.Add(node!["id"]!.GetValue<string>());
|
||||||
}
|
}
|
||||||
string? coverUrl = GetCoverUrl(publicationId, posterId);
|
string? coverUrl = GetCoverUrl(publicationId, posterId);
|
||||||
string? coverCacheName = null;
|
|
||||||
if (coverUrl is not null)
|
|
||||||
coverCacheName = SaveCoverImageToCache(coverUrl, (byte)RequestType.AtHomeServer);
|
|
||||||
|
|
||||||
List<string> authors = GetAuthors(authorIds);
|
List<string> authors = GetAuthors(authorIds);
|
||||||
|
|
||||||
@ -135,7 +132,6 @@ public class MangaDex : MangaConnector
|
|||||||
altTitlesDict,
|
altTitlesDict,
|
||||||
tags.ToArray(),
|
tags.ToArray(),
|
||||||
coverUrl,
|
coverUrl,
|
||||||
coverCacheName,
|
|
||||||
linksDict,
|
linksDict,
|
||||||
year,
|
year,
|
||||||
originalLanguage,
|
originalLanguage,
|
||||||
@ -231,6 +227,8 @@ public class MangaDex : MangaConnector
|
|||||||
string comicInfoPath = Path.GetTempFileName();
|
string comicInfoPath = Path.GetTempFileName();
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
||||||
|
|
||||||
|
if (chapterParentManga.coverUrl is not null)
|
||||||
|
chapterParentManga.coverFileNameInCache = SaveCoverImageToCache(chapterParentManga.coverUrl, (byte)RequestType.AtHomeServer);
|
||||||
//Download Chapter-Images
|
//Download Chapter-Images
|
||||||
return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), (byte)RequestType.AtHomeServer, comicInfoPath, progressToken:progressToken);
|
return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), (byte)RequestType.AtHomeServer, comicInfoPath, progressToken:progressToken);
|
||||||
}
|
}
|
||||||
|
@ -119,8 +119,6 @@ public class MangaKatana : MangaConnector
|
|||||||
string posterUrl = document.DocumentNode.SelectSingleNode("//*[@id='single_book']/div[1]/div").Descendants("img").First()
|
string posterUrl = document.DocumentNode.SelectSingleNode("//*[@id='single_book']/div[1]/div").Descendants("img").First()
|
||||||
.GetAttributes().First(a => a.Name == "src").Value;
|
.GetAttributes().First(a => a.Name == "src").Value;
|
||||||
|
|
||||||
string coverFileNameInCache = SaveCoverImageToCache(posterUrl, 1);
|
|
||||||
|
|
||||||
string description = document.DocumentNode.SelectSingleNode("//*[@id='single_book']/div[3]/p").InnerText;
|
string description = document.DocumentNode.SelectSingleNode("//*[@id='single_book']/div[3]/p").InnerText;
|
||||||
while (description.StartsWith('\n'))
|
while (description.StartsWith('\n'))
|
||||||
description = description.Substring(1);
|
description = description.Substring(1);
|
||||||
@ -134,7 +132,7 @@ public class MangaKatana : MangaConnector
|
|||||||
year = Convert.ToInt32(yearString);
|
year = Convert.ToInt32(yearString);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, links,
|
||||||
year, originalLanguage, status, publicationId);
|
year, originalLanguage, status, publicationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,6 +199,9 @@ public class MangaKatana : MangaConnector
|
|||||||
string comicInfoPath = Path.GetTempFileName();
|
string comicInfoPath = Path.GetTempFileName();
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
||||||
|
|
||||||
|
if (chapterParentManga.coverUrl is not null)
|
||||||
|
chapterParentManga.coverFileNameInCache = SaveCoverImageToCache(chapterParentManga.coverUrl, 1);
|
||||||
|
|
||||||
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), 1, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken);
|
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), 1, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,8 +111,6 @@ public class Manganato : MangaConnector
|
|||||||
string posterUrl = document.DocumentNode.Descendants("span").First(s => s.HasClass("info-image")).Descendants("img").First()
|
string posterUrl = document.DocumentNode.Descendants("span").First(s => s.HasClass("info-image")).Descendants("img").First()
|
||||||
.GetAttributes().First(a => a.Name == "src").Value;
|
.GetAttributes().First(a => a.Name == "src").Value;
|
||||||
|
|
||||||
string coverFileNameInCache = SaveCoverImageToCache(posterUrl, 1);
|
|
||||||
|
|
||||||
string description = document.DocumentNode.Descendants("div").First(d => d.HasClass("panel-story-info-description"))
|
string description = document.DocumentNode.Descendants("div").First(d => d.HasClass("panel-story-info-description"))
|
||||||
.InnerText.Replace("Description :", "");
|
.InnerText.Replace("Description :", "");
|
||||||
while (description.StartsWith('\n'))
|
while (description.StartsWith('\n'))
|
||||||
@ -122,7 +120,7 @@ public class Manganato : MangaConnector
|
|||||||
.First(s => s.HasClass("chapter-time")).InnerText;
|
.First(s => s.HasClass("chapter-time")).InnerText;
|
||||||
int year = Convert.ToInt32(yearString.Split(',')[^1]) + 2000;
|
int year = Convert.ToInt32(yearString.Split(',')[^1]) + 2000;
|
||||||
|
|
||||||
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, links,
|
||||||
year, originalLanguage, status, publicationId);
|
year, originalLanguage, status, publicationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,6 +185,9 @@ public class Manganato : MangaConnector
|
|||||||
string comicInfoPath = Path.GetTempFileName();
|
string comicInfoPath = Path.GetTempFileName();
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
||||||
|
|
||||||
|
if (chapterParentManga.coverUrl is not null)
|
||||||
|
chapterParentManga.coverFileNameInCache = SaveCoverImageToCache(chapterParentManga.coverUrl, 1);
|
||||||
|
|
||||||
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), 1, comicInfoPath, "https://chapmanganato.com/", progressToken:progressToken);
|
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(settings.downloadLocation), 1, comicInfoPath, "https://chapmanganato.com/", progressToken:progressToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +133,6 @@ public class Mangasee : MangaConnector
|
|||||||
HtmlNode posterNode =
|
HtmlNode posterNode =
|
||||||
document.DocumentNode.Descendants("img").First(img => img.HasClass("img-fluid") && img.HasClass("bottom-5"));
|
document.DocumentNode.Descendants("img").First(img => img.HasClass("img-fluid") && img.HasClass("bottom-5"));
|
||||||
string posterUrl = posterNode.GetAttributeValue("src", "");
|
string posterUrl = posterNode.GetAttributeValue("src", "");
|
||||||
string coverFileNameInCache = SaveCoverImageToCache(posterUrl, 1);
|
|
||||||
|
|
||||||
HtmlNode attributes = document.DocumentNode.Descendants("div")
|
HtmlNode attributes = document.DocumentNode.Descendants("div")
|
||||||
.First(div => div.HasClass("col-md-9") && div.HasClass("col-sm-8") && div.HasClass("top-5"))
|
.First(div => div.HasClass("col-md-9") && div.HasClass("col-sm-8") && div.HasClass("top-5"))
|
||||||
@ -171,7 +170,7 @@ public class Mangasee : MangaConnector
|
|||||||
foreach(string at in a)
|
foreach(string at in a)
|
||||||
altTitles.Add((i++).ToString(), at);
|
altTitles.Add((i++).ToString(), at);
|
||||||
|
|
||||||
return new Manga(sortName, authors, description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
|
return new Manga(sortName, authors, description, altTitles, tags.ToArray(), posterUrl, links,
|
||||||
year, originalLanguage, status, publicationId);
|
year, originalLanguage, status, publicationId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,6 +270,9 @@ public class Mangasee : MangaConnector
|
|||||||
string comicInfoPath = Path.GetTempFileName();
|
string comicInfoPath = Path.GetTempFileName();
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
||||||
|
|
||||||
|
if (chapterParentManga.coverUrl is not null)
|
||||||
|
chapterParentManga.coverFileNameInCache = SaveCoverImageToCache(chapterParentManga.coverUrl, 1);
|
||||||
|
|
||||||
return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), 1, comicInfoPath, progressToken:progressToken);
|
return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), 1, comicInfoPath, progressToken:progressToken);
|
||||||
}
|
}
|
||||||
return response.Status;
|
return response.Status;
|
||||||
|
@ -105,85 +105,68 @@ public class Server : GlobalBase
|
|||||||
private void HandleGet(HttpListenerRequest request, HttpListenerResponse response)
|
private void HandleGet(HttpListenerRequest request, HttpListenerResponse response)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> requestVariables = GetRequestVariables(request.Url!.Query);
|
Dictionary<string, string> requestVariables = GetRequestVariables(request.Url!.Query);
|
||||||
string? connectorName, jobId, internalId;
|
string? connectorName, jobId;
|
||||||
MangaConnector? connector;
|
MangaConnector connector;
|
||||||
Manga? manga;
|
|
||||||
string path = Regex.Match(request.Url!.LocalPath, @"[A-z0-9]+(\/[A-z0-9]+)*").Value;
|
string path = Regex.Match(request.Url!.LocalPath, @"[A-z0-9]+(\/[A-z0-9]+)*").Value;
|
||||||
switch (path)
|
switch (path)
|
||||||
{
|
{
|
||||||
case "Connectors":
|
case "Connectors":
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.GetConnectors().Select(con => con.name).ToArray());
|
SendResponse(HttpStatusCode.OK, response, _parent.GetConnectors().Select(con => con.name).ToArray());
|
||||||
break;
|
break;
|
||||||
case "Manga/Cover":
|
|
||||||
if (!requestVariables.TryGetValue("internalId", out internalId) ||
|
|
||||||
!_parent.TryGetPublicationById(internalId, out manga))
|
|
||||||
{
|
|
||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
string filePath = settings.GetFullCoverPath((Manga)manga!);
|
|
||||||
if (File.Exists(filePath))
|
|
||||||
{
|
|
||||||
FileStream coverStream = new(filePath, FileMode.Open);
|
|
||||||
SendResponse(HttpStatusCode.OK, response, coverStream);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SendResponse(HttpStatusCode.NotFound, response);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "Manga/FromConnector":
|
case "Manga/FromConnector":
|
||||||
if (!requestVariables.TryGetValue("connector", out connectorName) ||
|
if (!requestVariables.TryGetValue("connector", out connectorName) ||
|
||||||
!requestVariables.TryGetValue("title", out string? title) ||
|
!requestVariables.TryGetValue("title", out string? title) ||
|
||||||
!_parent.TryGetConnector(connectorName, out connector))
|
_parent.GetConnector(connectorName) is null)
|
||||||
{
|
{
|
||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
SendResponse(HttpStatusCode.BadRequest, response);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SendResponse(HttpStatusCode.OK, response, connector!.GetPublications(title));
|
connector = _parent.GetConnector(connectorName)!;
|
||||||
|
SendResponse(HttpStatusCode.OK, response, connector.GetPublications(title));
|
||||||
break;
|
break;
|
||||||
case "Manga/Chapters":
|
case "Manga/Chapters":
|
||||||
if(!requestVariables.TryGetValue("connector", out connectorName) ||
|
if(!requestVariables.TryGetValue("connector", out connectorName) ||
|
||||||
!requestVariables.TryGetValue("internalId", out internalId) ||
|
!requestVariables.TryGetValue("internalId", out string? internalId) ||
|
||||||
!_parent.TryGetConnector(connectorName, out connector) ||
|
_parent.GetConnector(connectorName) is null ||
|
||||||
!_parent.TryGetPublicationById(internalId, out manga))
|
_parent.GetPublicationById(internalId) is null)
|
||||||
{
|
{
|
||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
SendResponse(HttpStatusCode.BadRequest, response);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SendResponse(HttpStatusCode.OK, response, connector!.GetChapters((Manga)manga!));
|
connector = _parent.GetConnector(connectorName)!;
|
||||||
|
Manga manga = (Manga)_parent.GetPublicationById(internalId)!;
|
||||||
|
SendResponse(HttpStatusCode.OK, response, connector.GetChapters(manga));
|
||||||
break;
|
break;
|
||||||
case "Jobs":
|
case "Jobs":
|
||||||
if (!requestVariables.TryGetValue("jobId", out jobId))
|
if (!requestVariables.TryGetValue("jobId", out jobId))
|
||||||
{
|
{
|
||||||
if(!_parent.jobBoss.jobs.Any(jjob => jjob.id == jobId))
|
if(!_parent._jobBoss.jobs.Any(jjob => jjob.id == jobId))
|
||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
SendResponse(HttpStatusCode.BadRequest, response);
|
||||||
else
|
else
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.First(jjob => jjob.id == jobId));
|
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs.First(jjob => jjob.id == jobId));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs);
|
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs);
|
||||||
break;
|
break;
|
||||||
case "Jobs/Progress":
|
case "Jobs/Progress":
|
||||||
if (!requestVariables.TryGetValue("jobId", out jobId))
|
if (!requestVariables.TryGetValue("jobId", out jobId))
|
||||||
{
|
{
|
||||||
if(!_parent.jobBoss.jobs.Any(jjob => jjob.id == jobId))
|
if(!_parent._jobBoss.jobs.Any(jjob => jjob.id == jobId))
|
||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
SendResponse(HttpStatusCode.BadRequest, response);
|
||||||
else
|
else
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.First(jjob => jjob.id == jobId).progressToken);
|
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs.First(jjob => jjob.id == jobId).progressToken);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.Select(jjob => jjob.progressToken));
|
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs.Select(jjob => jjob.progressToken));
|
||||||
break;
|
break;
|
||||||
case "Jobs/Running":
|
case "Jobs/Running":
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.Where(jjob => jjob.progressToken.state is ProgressToken.State.Running));
|
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs.Where(jjob => jjob.progressToken.state is ProgressToken.State.Running));
|
||||||
break;
|
break;
|
||||||
case "Jobs/Waiting":
|
case "Jobs/Waiting":
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.Where(jjob => jjob.progressToken.state is ProgressToken.State.Standby));
|
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs.Where(jjob => jjob.progressToken.state is ProgressToken.State.Standby));
|
||||||
break;
|
break;
|
||||||
case "Jobs/MonitorJobs":
|
case "Jobs/MonitorJobs":
|
||||||
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.Where(jjob => jjob is DownloadNewChapters));
|
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs.Where(jjob => jjob is DownloadNewChapters));
|
||||||
break;
|
break;
|
||||||
case "Settings":
|
case "Settings":
|
||||||
SendResponse(HttpStatusCode.OK, response, settings);
|
SendResponse(HttpStatusCode.OK, response, settings);
|
||||||
@ -230,7 +213,7 @@ public class Server : GlobalBase
|
|||||||
}
|
}
|
||||||
connector = _parent.GetConnector(connectorName)!;
|
connector = _parent.GetConnector(connectorName)!;
|
||||||
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
||||||
_parent.jobBoss.AddJob(new DownloadNewChapters(this, connector, manga, true, interval));
|
_parent._jobBoss.AddJob(new DownloadNewChapters(this, connector, manga, true, interval));
|
||||||
SendResponse(HttpStatusCode.Accepted, response);
|
SendResponse(HttpStatusCode.Accepted, response);
|
||||||
break;
|
break;
|
||||||
case "Jobs/DownloadNewChapters":
|
case "Jobs/DownloadNewChapters":
|
||||||
@ -244,17 +227,17 @@ public class Server : GlobalBase
|
|||||||
}
|
}
|
||||||
connector = _parent.GetConnector(connectorName)!;
|
connector = _parent.GetConnector(connectorName)!;
|
||||||
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
||||||
_parent.jobBoss.AddJob(new DownloadNewChapters(this, connector, manga, false));
|
_parent._jobBoss.AddJob(new DownloadNewChapters(this, connector, manga, false));
|
||||||
SendResponse(HttpStatusCode.Accepted, response);
|
SendResponse(HttpStatusCode.Accepted, response);
|
||||||
break;
|
break;
|
||||||
case "Jobs/StartNow":
|
case "Jobs/StartNow":
|
||||||
if (!requestVariables.TryGetValue("jobId", out string? jobId) ||
|
if (!requestVariables.TryGetValue("jobId", out string? jobId) ||
|
||||||
!_parent.jobBoss.TryGetJobById(jobId, out Job? job))
|
!_parent._jobBoss.TryGetJobById(jobId, out Job? job))
|
||||||
{
|
{
|
||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
SendResponse(HttpStatusCode.BadRequest, response);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_parent.jobBoss.AddJobToQueue(job!);
|
_parent._jobBoss.AddJobToQueue(job!);
|
||||||
SendResponse(HttpStatusCode.Accepted, response);
|
SendResponse(HttpStatusCode.Accepted, response);
|
||||||
break;
|
break;
|
||||||
case "Settings/UpdateDownloadLocation":
|
case "Settings/UpdateDownloadLocation":
|
||||||
@ -363,12 +346,12 @@ public class Server : GlobalBase
|
|||||||
{
|
{
|
||||||
case "Jobs":
|
case "Jobs":
|
||||||
if (!requestVariables.TryGetValue("jobID", out string? jobId) ||
|
if (!requestVariables.TryGetValue("jobID", out string? jobId) ||
|
||||||
!_parent.jobBoss.TryGetJobById(jobId, out Job? job))
|
!_parent._jobBoss.TryGetJobById(jobId, out Job? job))
|
||||||
{
|
{
|
||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
SendResponse(HttpStatusCode.BadRequest, response);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_parent.jobBoss.RemoveJob(job!);
|
_parent._jobBoss.RemoveJob(job!);
|
||||||
SendResponse(HttpStatusCode.Accepted, response);
|
SendResponse(HttpStatusCode.Accepted, response);
|
||||||
break;
|
break;
|
||||||
case "Jobs/DownloadChapter":
|
case "Jobs/DownloadChapter":
|
||||||
@ -381,7 +364,7 @@ public class Server : GlobalBase
|
|||||||
SendResponse(HttpStatusCode.BadRequest, response);
|
SendResponse(HttpStatusCode.BadRequest, response);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
_parent.jobBoss.RemoveJobs(_parent.jobBoss.GetJobsLike(connectorName, internalId, chapterNumber));
|
_parent._jobBoss.RemoveJobs(_parent._jobBoss.GetJobsLike(connectorName, internalId, chapterNumber));
|
||||||
SendResponse(HttpStatusCode.Accepted, response);
|
SendResponse(HttpStatusCode.Accepted, response);
|
||||||
break;
|
break;
|
||||||
case "Jobs/MonitorManga":
|
case "Jobs/MonitorManga":
|
||||||
@ -395,7 +378,7 @@ public class Server : GlobalBase
|
|||||||
}
|
}
|
||||||
connector = _parent.GetConnector(connectorName)!;
|
connector = _parent.GetConnector(connectorName)!;
|
||||||
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
||||||
_parent.jobBoss.RemoveJobs(_parent.jobBoss.GetJobsLike(connector, manga));
|
_parent._jobBoss.RemoveJobs(_parent._jobBoss.GetJobsLike(connector, manga));
|
||||||
SendResponse(HttpStatusCode.Accepted, response);
|
SendResponse(HttpStatusCode.Accepted, response);
|
||||||
break;
|
break;
|
||||||
case "Jobs/DownloadNewChapters":
|
case "Jobs/DownloadNewChapters":
|
||||||
@ -409,7 +392,7 @@ public class Server : GlobalBase
|
|||||||
}
|
}
|
||||||
connector = _parent.GetConnector(connectorName)!;
|
connector = _parent.GetConnector(connectorName)!;
|
||||||
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
manga = (Manga)_parent.GetPublicationById(internalId)!;
|
||||||
_parent.jobBoss.RemoveJobs(_parent.jobBoss.GetJobsLike(connector, manga));
|
_parent._jobBoss.RemoveJobs(_parent._jobBoss.GetJobsLike(connector, manga));
|
||||||
SendResponse(HttpStatusCode.Accepted, response);
|
SendResponse(HttpStatusCode.Accepted, response);
|
||||||
break;
|
break;
|
||||||
case "NotificationConnectors":
|
case "NotificationConnectors":
|
||||||
@ -447,9 +430,6 @@ public class Server : GlobalBase
|
|||||||
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, DELETE");
|
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, DELETE");
|
||||||
response.AddHeader("Access-Control-Max-Age", "1728000");
|
response.AddHeader("Access-Control-Max-Age", "1728000");
|
||||||
response.AppendHeader("Access-Control-Allow-Origin", "*");
|
response.AppendHeader("Access-Control-Allow-Origin", "*");
|
||||||
|
|
||||||
if (content is not FileStream stream)
|
|
||||||
{
|
|
||||||
response.ContentType = "application/json";
|
response.ContentType = "application/json";
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -463,11 +443,4 @@ public class Server : GlobalBase
|
|||||||
Log(e.ToString());
|
Log(e.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
stream.CopyTo(response.OutputStream);
|
|
||||||
response.OutputStream.Close();
|
|
||||||
stream.Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -7,42 +7,36 @@ namespace Tranga;
|
|||||||
public partial class Tranga : GlobalBase
|
public partial class Tranga : GlobalBase
|
||||||
{
|
{
|
||||||
public bool keepRunning;
|
public bool keepRunning;
|
||||||
public JobBoss jobBoss;
|
public JobBoss _jobBoss;
|
||||||
private Server _server;
|
private Server server;
|
||||||
private HashSet<MangaConnector> _connectors;
|
private HashSet<MangaConnector> connectors;
|
||||||
|
|
||||||
public Tranga(Logger? logger, TrangaSettings settings) : base(logger, settings)
|
public Tranga(Logger? logger, TrangaSettings settings) : base(logger, settings)
|
||||||
{
|
{
|
||||||
keepRunning = true;
|
keepRunning = true;
|
||||||
_connectors = new HashSet<MangaConnector>()
|
_jobBoss = new(this);
|
||||||
|
connectors = new HashSet<MangaConnector>()
|
||||||
{
|
{
|
||||||
new Manganato(this),
|
new Manganato(this),
|
||||||
new Mangasee(this),
|
new Mangasee(this),
|
||||||
new MangaDex(this),
|
new MangaDex(this),
|
||||||
new MangaKatana(this)
|
new MangaKatana(this)
|
||||||
};
|
};
|
||||||
jobBoss = new(this, this._connectors);
|
|
||||||
StartJobBoss();
|
StartJobBoss();
|
||||||
this._server = new Server(this);
|
this.server = new Server(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MangaConnector? GetConnector(string name)
|
public MangaConnector? GetConnector(string name)
|
||||||
{
|
{
|
||||||
foreach(MangaConnector mc in _connectors)
|
foreach(MangaConnector mc in connectors)
|
||||||
if (mc.name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
if (mc.name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
|
||||||
return mc;
|
return mc;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetConnector(string name, out MangaConnector? connector)
|
|
||||||
{
|
|
||||||
connector = GetConnector(name);
|
|
||||||
return connector is not null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IEnumerable<MangaConnector> GetConnectors()
|
public IEnumerable<MangaConnector> GetConnectors()
|
||||||
{
|
{
|
||||||
return _connectors;
|
return connectors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Manga? GetPublicationById(string internalId)
|
public Manga? GetPublicationById(string internalId)
|
||||||
@ -52,19 +46,13 @@ public partial class Tranga : GlobalBase
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetPublicationById(string internalId, out Manga? manga)
|
|
||||||
{
|
|
||||||
manga = GetPublicationById(internalId);
|
|
||||||
return manga is not null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartJobBoss()
|
private void StartJobBoss()
|
||||||
{
|
{
|
||||||
Thread t = new (() =>
|
Thread t = new (() =>
|
||||||
{
|
{
|
||||||
while (keepRunning)
|
while (keepRunning)
|
||||||
{
|
{
|
||||||
jobBoss.CheckJobs();
|
_jobBoss.CheckJobs();
|
||||||
Thread.Sleep(1000);
|
Thread.Sleep(1000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -14,7 +14,7 @@ public class TrangaSettings
|
|||||||
[JsonIgnore] public string settingsFilePath => Path.Join(workingDirectory, "settings.json");
|
[JsonIgnore] public string settingsFilePath => Path.Join(workingDirectory, "settings.json");
|
||||||
[JsonIgnore] public string libraryConnectorsFilePath => Path.Join(workingDirectory, "libraryConnectors.json");
|
[JsonIgnore] public string libraryConnectorsFilePath => Path.Join(workingDirectory, "libraryConnectors.json");
|
||||||
[JsonIgnore] public string notificationConnectorsFilePath => Path.Join(workingDirectory, "notificationConnectors.json");
|
[JsonIgnore] public string notificationConnectorsFilePath => Path.Join(workingDirectory, "notificationConnectors.json");
|
||||||
[JsonIgnore] public string jobsFilePath => Path.Join(workingDirectory, "jobs.json");
|
[JsonIgnore] public string tasksFilePath => Path.Join(workingDirectory, "tasks.json");
|
||||||
[JsonIgnore] public string coverImageCache => Path.Join(workingDirectory, "imageCache");
|
[JsonIgnore] public string coverImageCache => Path.Join(workingDirectory, "imageCache");
|
||||||
public ushort? version { get; set; }
|
public ushort? version { get; set; }
|
||||||
|
|
||||||
@ -127,9 +127,4 @@ public class TrangaSettings
|
|||||||
Directory.CreateDirectory(new FileInfo(settingsFilePath).DirectoryName!);
|
Directory.CreateDirectory(new FileInfo(settingsFilePath).DirectoryName!);
|
||||||
File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(this));
|
File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetFullCoverPath(Manga manga)
|
|
||||||
{
|
|
||||||
return Path.Join(this.coverImageCache, manga.coverFileNameInCache);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -4,6 +4,7 @@ services:
|
|||||||
image: glax/tranga-api:latest
|
image: glax/tranga-api:latest
|
||||||
container_name: tranga-api
|
container_name: tranga-api
|
||||||
volumes:
|
volumes:
|
||||||
|
- ./tranga:/usr/share/Tranga-API #1 when replacing ./tranga replace #2 with same value
|
||||||
- ./Manga:/Manga
|
- ./Manga:/Manga
|
||||||
ports:
|
ports:
|
||||||
- "6531:6531"
|
- "6531:6531"
|
||||||
@ -11,6 +12,8 @@ services:
|
|||||||
tranga-website:
|
tranga-website:
|
||||||
image: glax/tranga-website:latest
|
image: glax/tranga-website:latest
|
||||||
container_name: tranga-website
|
container_name: tranga-website
|
||||||
|
volumes:
|
||||||
|
- ./tranga/imageCache:/usr/share/nginx/html/imageCache:ro #2 when replacing Point to same value as #1/imageCache
|
||||||
ports:
|
ports:
|
||||||
- "9555:80"
|
- "9555:80"
|
||||||
depends_on:
|
depends_on:
|
||||||
|
Loading…
Reference in New Issue
Block a user