Compare commits

..

7 Commits

Author SHA1 Message Date
ed79ee5d0f Add Manga from Jobs to cachedManga 2023-09-01 23:41:50 +02:00
28e05e549d Added import and export for Jobs
Renamed tasksFilePath -> jobsFilePath and changed to jobs.json
2023-09-01 23:37:50 +02:00
eaab7c5235 Fixed jobs not starting at all 2023-09-01 23:08:31 +02:00
0552b3db82 Fix crash on null Logmessage 2023-09-01 22:53:38 +02:00
c813e1854d Do not add duplicate jobs 2023-09-01 22:39:22 +02:00
32036df057 Added API call to retrieve cover with internalId.
No need to mount imageCache over multiple containers.
2023-09-01 21:40:56 +02:00
394829ee36 Revert "Download Covers only when Downloading Chapters"
This reverts commit e663163d

Covers might be important
2023-09-01 21:17:46 +02:00
14 changed files with 269 additions and 78 deletions

View File

@ -45,14 +45,22 @@ public class MemoryLogger : LoggerBase
public string[] GetNewLines()
{
int logMessageCount = _logMessages.Count;
string[] ret = new string[logMessageCount - _lastLogMessageIndex];
List<string> ret = new();
for (int retIndex = 0; retIndex < ret.Length; retIndex++)
int retIndex = 0;
for (; retIndex < logMessageCount - _lastLogMessageIndex; retIndex++)
{
ret[retIndex] = _logMessages.GetValueAtIndex(_lastLogMessageIndex + retIndex).ToString();
try
{
ret.Add(_logMessages.GetValueAtIndex(_lastLogMessageIndex + retIndex).ToString());
}
catch (NullReferenceException e)//Called when LogMessage has not finished writing
{
break;
}
}
_lastLogMessageIndex = logMessageCount;
return ret;
_lastLogMessageIndex = _lastLogMessageIndex + retIndex;
return ret.ToArray();
}
}

View File

@ -19,6 +19,8 @@ public abstract class Job : GlobalBase
this.recurring = recurring;
if (recurring && recurrenceTime is null)
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;
}

View File

@ -1,4 +1,5 @@
using Tranga.MangaConnectors;
using Newtonsoft.Json;
using Tranga.MangaConnectors;
namespace Tranga.Jobs;
@ -7,16 +8,42 @@ public class JobBoss : GlobalBase
public HashSet<Job> jobs { get; init; }
private Dictionary<MangaConnector, Queue<Job>> mangaConnectorJobQueue { get; init; }
public JobBoss(GlobalBase clone) : base(clone)
public JobBoss(GlobalBase clone, HashSet<MangaConnector> connectors) : base(clone)
{
this.jobs = new();
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();
foreach (DownloadNewChapters ncJob in this.jobs.Where(job => job is DownloadNewChapters))
cachedPublications.Add(ncJob.manga);
this.mangaConnectorJobQueue = new();
}
public void AddJob(Job job)
{
Log($"Added {job}");
this.jobs.Add(job);
if (ContainsJobLike(job))
{
Log($"Already Contains Job {job}");
}
else
{
Log($"Added {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)
@ -110,13 +137,13 @@ public class JobBoss : GlobalBase
foreach (Queue<Job> jobQueue in mangaConnectorJobQueue.Values)
{
Job queueHead = jobQueue.Peek();
if (queueHead.progressToken.state == ProgressToken.State.Complete)
if (queueHead.progressToken.state is ProgressToken.State.Complete)
{
if(queueHead.recurring)
queueHead.Reset();
jobQueue.Dequeue();
}else if(queueHead.progressToken.state is ProgressToken.State.Standby)
AddJobsToQueue(jobQueue.Peek().ExecuteReturnSubTasks());
}
}
}
}

View File

@ -0,0 +1,66 @@
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");
}
}

View File

@ -36,14 +36,14 @@ public struct Manga
private static readonly Regex LegalCharacters = new (@"[A-Z]*[a-z]*[0-9]* *\.*-*,*'*\'*\)*\(*~*!*");
[JsonConstructor]
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)
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)
{
this.sortName = sortName;
this.authors = authors;
this.description = description;
this.altTitles = altTitles;
this.tags = tags;
this.coverFileNameInCache = null;
this.coverFileNameInCache = coverFileNameInCache;
this.coverUrl = coverUrl;
this.links = links ?? new Dictionary<string, string>();
this.year = year;

View File

@ -0,0 +1,49 @@
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");
}
}

View File

@ -102,6 +102,9 @@ public class MangaDex : MangaConnector
authorIds.Add(node!["id"]!.GetValue<string>());
}
string? coverUrl = GetCoverUrl(publicationId, posterId);
string? coverCacheName = null;
if (coverUrl is not null)
coverCacheName = SaveCoverImageToCache(coverUrl, (byte)RequestType.AtHomeServer);
List<string> authors = GetAuthors(authorIds);
@ -132,6 +135,7 @@ public class MangaDex : MangaConnector
altTitlesDict,
tags.ToArray(),
coverUrl,
coverCacheName,
linksDict,
year,
originalLanguage,
@ -227,8 +231,6 @@ public class MangaDex : MangaConnector
string comicInfoPath = Path.GetTempFileName();
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
if (chapterParentManga.coverUrl is not null)
chapterParentManga.coverFileNameInCache = SaveCoverImageToCache(chapterParentManga.coverUrl, (byte)RequestType.AtHomeServer);
//Download Chapter-Images
return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(settings.downloadLocation), (byte)RequestType.AtHomeServer, comicInfoPath, progressToken:progressToken);
}

View File

@ -119,6 +119,8 @@ public class MangaKatana : MangaConnector
string posterUrl = document.DocumentNode.SelectSingleNode("//*[@id='single_book']/div[1]/div").Descendants("img").First()
.GetAttributes().First(a => a.Name == "src").Value;
string coverFileNameInCache = SaveCoverImageToCache(posterUrl, 1);
string description = document.DocumentNode.SelectSingleNode("//*[@id='single_book']/div[3]/p").InnerText;
while (description.StartsWith('\n'))
description = description.Substring(1);
@ -132,7 +134,7 @@ public class MangaKatana : MangaConnector
year = Convert.ToInt32(yearString);
}
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, links,
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
year, originalLanguage, status, publicationId);
}
@ -199,9 +201,6 @@ public class MangaKatana : MangaConnector
string comicInfoPath = Path.GetTempFileName();
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);
}

View File

@ -111,6 +111,8 @@ public class Manganato : MangaConnector
string posterUrl = document.DocumentNode.Descendants("span").First(s => s.HasClass("info-image")).Descendants("img").First()
.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"))
.InnerText.Replace("Description :", "");
while (description.StartsWith('\n'))
@ -120,7 +122,7 @@ public class Manganato : MangaConnector
.First(s => s.HasClass("chapter-time")).InnerText;
int year = Convert.ToInt32(yearString.Split(',')[^1]) + 2000;
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, links,
return new Manga(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
year, originalLanguage, status, publicationId);
}
@ -185,9 +187,6 @@ public class Manganato : MangaConnector
string comicInfoPath = Path.GetTempFileName();
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);
}

View File

@ -133,6 +133,7 @@ public class Mangasee : MangaConnector
HtmlNode posterNode =
document.DocumentNode.Descendants("img").First(img => img.HasClass("img-fluid") && img.HasClass("bottom-5"));
string posterUrl = posterNode.GetAttributeValue("src", "");
string coverFileNameInCache = SaveCoverImageToCache(posterUrl, 1);
HtmlNode attributes = document.DocumentNode.Descendants("div")
.First(div => div.HasClass("col-md-9") && div.HasClass("col-sm-8") && div.HasClass("top-5"))
@ -170,7 +171,7 @@ public class Mangasee : MangaConnector
foreach(string at in a)
altTitles.Add((i++).ToString(), at);
return new Manga(sortName, authors, description, altTitles, tags.ToArray(), posterUrl, links,
return new Manga(sortName, authors, description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
year, originalLanguage, status, publicationId);
}
@ -270,9 +271,6 @@ public class Mangasee : MangaConnector
string comicInfoPath = Path.GetTempFileName();
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 response.Status;

View File

@ -105,68 +105,85 @@ public class Server : GlobalBase
private void HandleGet(HttpListenerRequest request, HttpListenerResponse response)
{
Dictionary<string, string> requestVariables = GetRequestVariables(request.Url!.Query);
string? connectorName, jobId;
MangaConnector connector;
string? connectorName, jobId, internalId;
MangaConnector? connector;
Manga? manga;
string path = Regex.Match(request.Url!.LocalPath, @"[A-z0-9]+(\/[A-z0-9]+)*").Value;
switch (path)
{
case "Connectors":
SendResponse(HttpStatusCode.OK, response, _parent.GetConnectors().Select(con => con.name).ToArray());
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":
if (!requestVariables.TryGetValue("connector", out connectorName) ||
!requestVariables.TryGetValue("title", out string? title) ||
_parent.GetConnector(connectorName) is null)
!_parent.TryGetConnector(connectorName, out connector))
{
SendResponse(HttpStatusCode.BadRequest, response);
break;
}
connector = _parent.GetConnector(connectorName)!;
SendResponse(HttpStatusCode.OK, response, connector.GetPublications(title));
SendResponse(HttpStatusCode.OK, response, connector!.GetPublications(title));
break;
case "Manga/Chapters":
if(!requestVariables.TryGetValue("connector", out connectorName) ||
!requestVariables.TryGetValue("internalId", out string? internalId) ||
_parent.GetConnector(connectorName) is null ||
_parent.GetPublicationById(internalId) is null)
!requestVariables.TryGetValue("internalId", out internalId) ||
!_parent.TryGetConnector(connectorName, out connector) ||
!_parent.TryGetPublicationById(internalId, out manga))
{
SendResponse(HttpStatusCode.BadRequest, response);
break;
}
connector = _parent.GetConnector(connectorName)!;
Manga manga = (Manga)_parent.GetPublicationById(internalId)!;
SendResponse(HttpStatusCode.OK, response, connector.GetChapters(manga));
SendResponse(HttpStatusCode.OK, response, connector!.GetChapters((Manga)manga!));
break;
case "Jobs":
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);
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;
}
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs);
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs);
break;
case "Jobs/Progress":
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);
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;
}
SendResponse(HttpStatusCode.OK, response, _parent._jobBoss.jobs.Select(jjob => jjob.progressToken));
SendResponse(HttpStatusCode.OK, response, _parent.jobBoss.jobs.Select(jjob => jjob.progressToken));
break;
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;
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;
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;
case "Settings":
SendResponse(HttpStatusCode.OK, response, settings);
@ -213,7 +230,7 @@ public class Server : GlobalBase
}
connector = _parent.GetConnector(connectorName)!;
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);
break;
case "Jobs/DownloadNewChapters":
@ -227,17 +244,17 @@ public class Server : GlobalBase
}
connector = _parent.GetConnector(connectorName)!;
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);
break;
case "Jobs/StartNow":
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);
break;
}
_parent._jobBoss.AddJobToQueue(job!);
_parent.jobBoss.AddJobToQueue(job!);
SendResponse(HttpStatusCode.Accepted, response);
break;
case "Settings/UpdateDownloadLocation":
@ -346,12 +363,12 @@ public class Server : GlobalBase
{
case "Jobs":
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);
break;
}
_parent._jobBoss.RemoveJob(job!);
_parent.jobBoss.RemoveJob(job!);
SendResponse(HttpStatusCode.Accepted, response);
break;
case "Jobs/DownloadChapter":
@ -364,7 +381,7 @@ public class Server : GlobalBase
SendResponse(HttpStatusCode.BadRequest, response);
break;
}
_parent._jobBoss.RemoveJobs(_parent._jobBoss.GetJobsLike(connectorName, internalId, chapterNumber));
_parent.jobBoss.RemoveJobs(_parent.jobBoss.GetJobsLike(connectorName, internalId, chapterNumber));
SendResponse(HttpStatusCode.Accepted, response);
break;
case "Jobs/MonitorManga":
@ -378,7 +395,7 @@ public class Server : GlobalBase
}
connector = _parent.GetConnector(connectorName)!;
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);
break;
case "Jobs/DownloadNewChapters":
@ -392,7 +409,7 @@ public class Server : GlobalBase
}
connector = _parent.GetConnector(connectorName)!;
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);
break;
case "NotificationConnectors":
@ -430,17 +447,27 @@ public class Server : GlobalBase
response.AddHeader("Access-Control-Allow-Methods", "GET, POST, DELETE");
response.AddHeader("Access-Control-Max-Age", "1728000");
response.AppendHeader("Access-Control-Allow-Origin", "*");
response.ContentType = "application/json";
try
if (content is not FileStream stream)
{
response.OutputStream.Write(content is not null
? Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(content))
: Array.Empty<byte>());
response.OutputStream.Close();
response.ContentType = "application/json";
try
{
response.OutputStream.Write(content is not null
? Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(content))
: Array.Empty<byte>());
response.OutputStream.Close();
}
catch (HttpListenerException e)
{
Log(e.ToString());
}
}
catch (HttpListenerException e)
else
{
Log(e.ToString());
stream.CopyTo(response.OutputStream);
response.OutputStream.Close();
stream.Close();
}
}
}

View File

@ -7,36 +7,42 @@ namespace Tranga;
public partial class Tranga : GlobalBase
{
public bool keepRunning;
public JobBoss _jobBoss;
private Server server;
private HashSet<MangaConnector> connectors;
public JobBoss jobBoss;
private Server _server;
private HashSet<MangaConnector> _connectors;
public Tranga(Logger? logger, TrangaSettings settings) : base(logger, settings)
{
keepRunning = true;
_jobBoss = new(this);
connectors = new HashSet<MangaConnector>()
_connectors = new HashSet<MangaConnector>()
{
new Manganato(this),
new Mangasee(this),
new MangaDex(this),
new MangaKatana(this)
};
jobBoss = new(this, this._connectors);
StartJobBoss();
this.server = new Server(this);
this._server = new Server(this);
}
public MangaConnector? GetConnector(string name)
{
foreach(MangaConnector mc in connectors)
foreach(MangaConnector mc in _connectors)
if (mc.name.Equals(name, StringComparison.InvariantCultureIgnoreCase))
return mc;
return null;
}
public bool TryGetConnector(string name, out MangaConnector? connector)
{
connector = GetConnector(name);
return connector is not null;
}
public IEnumerable<MangaConnector> GetConnectors()
{
return connectors;
return _connectors;
}
public Manga? GetPublicationById(string internalId)
@ -46,13 +52,19 @@ public partial class Tranga : GlobalBase
return null;
}
public bool TryGetPublicationById(string internalId, out Manga? manga)
{
manga = GetPublicationById(internalId);
return manga is not null;
}
private void StartJobBoss()
{
Thread t = new (() =>
{
while (keepRunning)
{
_jobBoss.CheckJobs();
jobBoss.CheckJobs();
Thread.Sleep(1000);
}
});

View File

@ -14,7 +14,7 @@ public class TrangaSettings
[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 tasksFilePath => Path.Join(workingDirectory, "tasks.json");
[JsonIgnore] public string jobsFilePath => Path.Join(workingDirectory, "jobs.json");
[JsonIgnore] public string coverImageCache => Path.Join(workingDirectory, "imageCache");
public ushort? version { get; set; }
@ -127,4 +127,9 @@ public class TrangaSettings
Directory.CreateDirectory(new FileInfo(settingsFilePath).DirectoryName!);
File.WriteAllText(settingsFilePath, JsonConvert.SerializeObject(this));
}
public string GetFullCoverPath(Manga manga)
{
return Path.Join(this.coverImageCache, manga.coverFileNameInCache);
}
}

View File

@ -4,7 +4,6 @@ services:
image: glax/tranga-api:latest
container_name: tranga-api
volumes:
- ./tranga:/usr/share/Tranga-API #1 when replacing ./tranga replace #2 with same value
- ./Manga:/Manga
ports:
- "6531:6531"
@ -12,8 +11,6 @@ services:
tranga-website:
image: glax/tranga-website:latest
container_name: tranga-website
volumes:
- ./tranga/imageCache:/usr/share/nginx/html/imageCache:ro #2 when replacing Point to same value as #1/imageCache
ports:
- "9555:80"
depends_on: