Compare commits

..

No commits in common. "442d9493719a74b76e9726e2ed756561ba963af3" and "c965bc38d1a24441e8f2acfcd509554e75e51b43" have entirely different histories.

17 changed files with 85 additions and 402 deletions

View File

@ -7,12 +7,12 @@ public class DownloadChapter : Job
{ {
public Chapter chapter { get; init; } public Chapter chapter { get; init; }
public DownloadChapter(GlobalBase clone, MangaConnector connector, Chapter chapter, DateTime lastExecution, string? parentJobId = null) : base(clone, JobType.DownloadChapterJob, connector, lastExecution, parentJobId: parentJobId) public DownloadChapter(GlobalBase clone, MangaConnector connector, Chapter chapter, DateTime lastExecution, string? parentJobId = null) : base(clone, connector, lastExecution, parentJobId: parentJobId)
{ {
this.chapter = chapter; this.chapter = chapter;
} }
public DownloadChapter(GlobalBase clone, MangaConnector connector, Chapter chapter, string? parentJobId = null) : base(clone, JobType.DownloadChapterJob, connector, parentJobId: parentJobId) public DownloadChapter(GlobalBase clone, MangaConnector connector, Chapter chapter, string? parentJobId = null) : base(clone, connector, parentJobId: parentJobId)
{ {
this.chapter = chapter; this.chapter = chapter;
} }
@ -27,7 +27,7 @@ public class DownloadChapter : Job
return $"{id} Chapter: {chapter}"; return $"{id} Chapter: {chapter}";
} }
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss) protected override IEnumerable<Job> ExecuteReturnSubTasksInternal()
{ {
Task downloadTask = new(delegate Task downloadTask = new(delegate
{ {

View File

@ -4,18 +4,18 @@ namespace Tranga.Jobs;
public class DownloadNewChapters : Job public class DownloadNewChapters : Job
{ {
public Manga manga { get; set; } public Manga manga { get; init; }
public string translatedLanguage { get; init; } public string translatedLanguage { get; init; }
public DownloadNewChapters(GlobalBase clone, MangaConnector connector, Manga manga, DateTime lastExecution, public DownloadNewChapters(GlobalBase clone, MangaConnector connector, Manga manga, DateTime lastExecution,
bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base(clone, JobType.DownloadNewChaptersJob, connector, lastExecution, recurring, bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base(clone, connector, lastExecution, recurring,
recurrence, parentJobId) recurrence, parentJobId)
{ {
this.manga = manga; this.manga = manga;
this.translatedLanguage = translatedLanguage; this.translatedLanguage = translatedLanguage;
} }
public DownloadNewChapters(GlobalBase clone, MangaConnector connector, Manga manga, bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base (clone, JobType.DownloadNewChaptersJob, connector, recurring, recurrence, parentJobId) public DownloadNewChapters(GlobalBase clone, MangaConnector connector, Manga manga, bool recurring = false, TimeSpan? recurrence = null, string? parentJobId = null, string translatedLanguage = "en") : base (clone, connector, recurring, recurrence, parentJobId)
{ {
this.manga = manga; this.manga = manga;
this.translatedLanguage = translatedLanguage; this.translatedLanguage = translatedLanguage;
@ -31,9 +31,8 @@ public class DownloadNewChapters : Job
return $"{id} Manga: {manga}"; return $"{id} Manga: {manga}";
} }
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss) protected override IEnumerable<Job> ExecuteReturnSubTasksInternal()
{ {
manga.SaveSeriesInfoJson(settings.downloadLocation);
Chapter[] chapters = mangaConnector.GetNewChapters(manga, this.translatedLanguage); Chapter[] chapters = mangaConnector.GetNewChapters(manga, this.translatedLanguage);
this.progressToken.increments = chapters.Length; this.progressToken.increments = chapters.Length;
List<Job> jobs = new(); List<Job> jobs = new();
@ -43,8 +42,6 @@ public class DownloadNewChapters : Job
DownloadChapter downloadChapterJob = new(this, this.mangaConnector, chapter, parentJobId: this.id); DownloadChapter downloadChapterJob = new(this, this.mangaConnector, chapter, parentJobId: this.id);
jobs.Add(downloadChapterJob); jobs.Add(downloadChapterJob);
} }
UpdateMetadata updateMetadataJob = new(this, this.mangaConnector, this.manga, parentJobId: this.id);
jobs.Add(updateMetadataJob);
progressToken.Complete(); progressToken.Complete();
return jobs; return jobs;
} }

View File

@ -13,13 +13,9 @@ public abstract class Job : GlobalBase
public string id => GetId(); public string id => GetId();
internal IEnumerable<Job>? subJobs { get; private set; } internal IEnumerable<Job>? subJobs { get; private set; }
public string? parentJobId { get; init; } public string? parentJobId { get; init; }
public enum JobType : byte { DownloadChapterJob, DownloadNewChaptersJob, UpdateMetaDataJob }
public JobType jobType; internal Job(GlobalBase clone, MangaConnector connector, bool recurring = false, TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone)
internal Job(GlobalBase clone, JobType jobType, MangaConnector connector, bool recurring = false, TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone)
{ {
this.jobType = jobType;
this.mangaConnector = connector; this.mangaConnector = connector;
this.progressToken = new ProgressToken(0); this.progressToken = new ProgressToken(0);
this.recurring = recurring; this.recurring = recurring;
@ -31,10 +27,9 @@ public abstract class Job : GlobalBase
this.parentJobId = parentJobId; this.parentJobId = parentJobId;
} }
internal Job(GlobalBase clone, JobType jobType, MangaConnector connector, DateTime lastExecution, bool recurring = false, internal Job(GlobalBase clone, MangaConnector connector, DateTime lastExecution, bool recurring = false,
TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone) TimeSpan? recurrenceTime = null, string? parentJobId = null) : base(clone)
{ {
this.jobType = jobType;
this.mangaConnector = connector; this.mangaConnector = connector;
this.progressToken = new ProgressToken(0); this.progressToken = new ProgressToken(0);
this.recurring = recurring; this.recurring = recurring;
@ -86,13 +81,13 @@ public abstract class Job : GlobalBase
subJob.Cancel(); subJob.Cancel();
} }
public IEnumerable<Job> ExecuteReturnSubTasks(JobBoss jobBoss) public IEnumerable<Job> ExecuteReturnSubTasks()
{ {
progressToken.Start(); progressToken.Start();
subJobs = ExecuteReturnSubTasksInternal(jobBoss); subJobs = ExecuteReturnSubTasksInternal();
lastExecution = DateTime.Now; lastExecution = DateTime.Now;
return subJobs; return subJobs;
} }
protected abstract IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss); protected abstract IEnumerable<Job> ExecuteReturnSubTasksInternal();
} }

View File

@ -253,7 +253,7 @@ public class JobBoss : GlobalBase
Log($"Next job in {jobs.MinBy(job => job.nextExecution)?.nextExecution.Subtract(DateTime.Now)} {jobs.MinBy(job => job.nextExecution)?.id}"); Log($"Next job in {jobs.MinBy(job => job.nextExecution)?.nextExecution.Subtract(DateTime.Now)} {jobs.MinBy(job => job.nextExecution)?.id}");
}else if (queueHead.progressToken.state is ProgressToken.State.Standby) }else if (queueHead.progressToken.state is ProgressToken.State.Standby)
{ {
Job[] subJobs = jobQueue.Peek().ExecuteReturnSubTasks(this).ToArray(); Job[] subJobs = jobQueue.Peek().ExecuteReturnSubTasks().ToArray();
AddJobs(subJobs); AddJobs(subJobs);
AddJobsToQueue(subJobs); AddJobsToQueue(subJobs);
}else if (queueHead.progressToken.state is ProgressToken.State.Running && DateTime.Now.Subtract(queueHead.progressToken.lastUpdate) > TimeSpan.FromMinutes(5)) }else if (queueHead.progressToken.state is ProgressToken.State.Running && DateTime.Now.Subtract(queueHead.progressToken.lastUpdate) > TimeSpan.FromMinutes(5))

View File

@ -23,20 +23,7 @@ public class JobJsonConverter : JsonConverter
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{ {
JObject jo = JObject.Load(reader); JObject jo = JObject.Load(reader);
if (jo.ContainsKey("manga"))//DownloadNewChapters
if (jo.ContainsKey("jobType") && jo["jobType"]!.Value<byte>() == (byte)Job.JobType.UpdateMetaDataJob)
{
return new UpdateMetadata(this._clone,
jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings()
{
Converters =
{
this._mangaConnectorJsonConverter
}
}))!,
jo.GetValue("manga")!.ToObject<Manga>(),
jo.GetValue("parentJobId")!.Value<string?>());
}else if ((jo.ContainsKey("jobType") && jo["jobType"]!.Value<byte>() == (byte)Job.JobType.DownloadNewChaptersJob) || jo.ContainsKey("translatedLanguage"))//TODO change to jobType
{ {
return new DownloadNewChapters(this._clone, return new DownloadNewChapters(this._clone,
jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings() jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings()
@ -51,7 +38,9 @@ public class JobJsonConverter : JsonConverter
jo.GetValue("recurring")!.Value<bool>(), jo.GetValue("recurring")!.Value<bool>(),
jo.GetValue("recurrenceTime")!.ToObject<TimeSpan?>(), jo.GetValue("recurrenceTime")!.ToObject<TimeSpan?>(),
jo.GetValue("parentJobId")!.Value<string?>()); jo.GetValue("parentJobId")!.Value<string?>());
}else if ((jo.ContainsKey("jobType") && jo["jobType"]!.Value<byte>() == (byte)Job.JobType.DownloadChapterJob) || jo.ContainsKey("chapter"))//TODO change to jobType }
if (jo.ContainsKey("chapter"))//DownloadChapter
{ {
return new DownloadChapter(this._clone, return new DownloadChapter(this._clone,
jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings() jo.GetValue("mangaConnector")!.ToObject<MangaConnector>(JsonSerializer.Create(new JsonSerializerSettings()

View File

@ -1,50 +0,0 @@
using Tranga.MangaConnectors;
namespace Tranga.Jobs;
public class UpdateMetadata : Job
{
public Manga manga { get; set; }
public UpdateMetadata(GlobalBase clone, MangaConnector connector, Manga manga, string? parentJobId = null) : base(clone, JobType.UpdateMetaDataJob, connector, parentJobId: parentJobId)
{
this.manga = manga;
}
protected override string GetId()
{
return $"{GetType()}-{manga.internalId}";
}
public override string ToString()
{
return $"{id} Manga: {manga}";
}
protected override IEnumerable<Job> ExecuteReturnSubTasksInternal(JobBoss jobBoss)
{
Manga? possibleUpdatedManga = mangaConnector.GetMangaFromId(manga.publicationId);
if (possibleUpdatedManga is { } updatedManga)
{
if(updatedManga.Equals(this.manga))
return Array.Empty<Job>();
this.manga.UpdateMetadata(updatedManga);
this.manga.SaveSeriesInfoJson(settings.downloadLocation, true);
if (parentJobId is not null && jobBoss.GetJobById(this.parentJobId) is DownloadNewChapters dncJob)
{
dncJob.manga = updatedManga;
}
this.progressToken.Complete();
}
else
{
Log($"Could not find Manga {manga}");
this.progressToken.Cancel();
return Array.Empty<Job>();
}
this.progressToken.Cancel();
return Array.Empty<Job>();
}
}

View File

@ -41,34 +41,16 @@ public abstract class LibraryConnector : GlobalBase
Method = HttpMethod.Get, Method = HttpMethod.Get,
RequestUri = new Uri(url) RequestUri = new Uri(url)
}; };
try
{
HttpResponseMessage response = client.Send(requestMessage); HttpResponseMessage response = client.Send(requestMessage);
logger?.WriteLine("LibraryManager.NetClient", logger?.WriteLine("LibraryManager.NetClient", $"GET {url} -> {(int)response.StatusCode}: {response.ReasonPhrase}");
$"GET {url} -> {(int)response.StatusCode}: {response.ReasonPhrase}");
if (response.StatusCode is HttpStatusCode.Unauthorized && if(response.StatusCode is HttpStatusCode.Unauthorized && response.RequestMessage!.RequestUri!.AbsoluteUri != url)
response.RequestMessage!.RequestUri!.AbsoluteUri != url)
return MakeRequest(response.RequestMessage!.RequestUri!.AbsoluteUri, authScheme, auth, logger); return MakeRequest(response.RequestMessage!.RequestUri!.AbsoluteUri, authScheme, auth, logger);
else if (response.IsSuccessStatusCode) else if (response.IsSuccessStatusCode)
return response.Content.ReadAsStream(); return response.Content.ReadAsStream();
else else
return Stream.Null; return Stream.Null;
} }
catch (Exception e)
{
switch (e)
{
case HttpRequestException:
logger?.WriteLine("LibraryManager.NetClient", $"Failed to make Request:\n\r{e}\n\rContinuing.");
break;
default:
throw;
}
return Stream.Null;
}
}
public static bool MakePost(string url, string authScheme, string auth, Logger? logger) public static bool MakePost(string url, string authScheme, string auth, Logger? logger)
{ {

View File

@ -11,32 +11,23 @@ namespace Tranga;
/// </summary> /// </summary>
public struct Manga public struct Manga
{ {
public string sortName { get; private set; } public string sortName { get; }
public List<string> authors { get; } public List<string> authors { get; }
// ReSharper disable once UnusedAutoPropertyAccessor.Global // ReSharper disable once UnusedAutoPropertyAccessor.Global
public Dictionary<string,string> altTitles { get; } public Dictionary<string,string> altTitles { get; }
// ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once MemberCanBePrivate.Global
public string? description { get; private set; } public string? description { get; }
public string[] tags { get; } public string[] tags { get; }
// ReSharper disable once UnusedAutoPropertyAccessor.Global // ReSharper disable once UnusedAutoPropertyAccessor.Global
public string? coverUrl { get; } public string? coverUrl { get; }
public string? coverFileNameInCache { get; } public string? coverFileNameInCache { get; set; }
// ReSharper disable once UnusedAutoPropertyAccessor.Global // ReSharper disable once UnusedAutoPropertyAccessor.Global
public Dictionary<string,string> links { get; } public Dictionary<string,string> links { get; }
// ReSharper disable once MemberCanBePrivate.Global // ReSharper disable once MemberCanBePrivate.Global
public int? year { get; private set; } public int? year { get; }
public string? originalLanguage { get; } public string? originalLanguage { get; }
// ReSharper disable twice MemberCanBePrivate.Global // ReSharper disable twice MemberCanBePrivate.Global
public string status { get; private set; } public string status { get; }
public ReleaseStatusByte releaseStatus { get; }
public enum ReleaseStatusByte : byte
{
Continuing = 0,
Completed = 1,
OnHiatus = 2,
Cancelled = 3,
Unreleased = 4
};
public string folderName { get; private set; } public string folderName { get; private set; }
public string publicationId { get; } public string publicationId { get; }
public string internalId { get; } public string internalId { get; }
@ -47,7 +38,7 @@ 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, ReleaseStatusByte releaseStatus = 0, string? websiteUrl = null, 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.sortName = sortName;
this.authors = authors; this.authors = authors;
@ -69,31 +60,6 @@ public struct Manga
this.ignoreChaptersBelow = ignoreChaptersBelow ?? 0f; this.ignoreChaptersBelow = ignoreChaptersBelow ?? 0f;
this.latestChapterDownloaded = 0; this.latestChapterDownloaded = 0;
this.latestChapterAvailable = 0; this.latestChapterAvailable = 0;
this.releaseStatus = releaseStatus;
}
public void UpdateMetadata(Manga newManga)
{
this.sortName = newManga.sortName;
this.description = newManga.description;
foreach (string author in newManga.authors)
if(this.authors.Contains(author))
this.authors.Add(author);
this.status = newManga.status;
this.year = newManga.year;
}
public override bool Equals(object? obj)
{
if (obj is not Manga compareManga)
return false;
return this.description == compareManga.description &&
this.year == compareManga.year &&
this.status == compareManga.status &&
this.releaseStatus == compareManga.releaseStatus &&
this.sortName == compareManga.sortName &&
this.latestChapterAvailable.Equals(compareManga.latestChapterAvailable) &&
this.tags.Equals(compareManga.tags);
} }
public override string ToString() public override string ToString()
@ -126,11 +92,11 @@ public struct Manga
latestChapterDownloaded = latestChapterDownloaded < chapterNumber ? chapterNumber : latestChapterDownloaded; latestChapterDownloaded = latestChapterDownloaded < chapterNumber ? chapterNumber : latestChapterDownloaded;
} }
public void SaveSeriesInfoJson(string downloadDirectory, bool overwrite = false) public void SaveSeriesInfoJson(string downloadDirectory)
{ {
string publicationFolder = CreatePublicationFolder(downloadDirectory); string publicationFolder = CreatePublicationFolder(downloadDirectory);
string seriesInfoPath = Path.Join(publicationFolder, "series.json"); string seriesInfoPath = Path.Join(publicationFolder, "series.json");
if(overwrite || (!overwrite && !File.Exists(seriesInfoPath))) if(!File.Exists(seriesInfoPath))
File.WriteAllText(seriesInfoPath,this.GetSeriesInfoJson()); File.WriteAllText(seriesInfoPath,this.GetSeriesInfoJson());
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
File.SetUnixFileMode(seriesInfoPath, GroupRead | GroupWrite | OtherRead | OtherWrite | UserRead | UserWrite); File.SetUnixFileMode(seriesInfoPath, GroupRead | GroupWrite | OtherRead | OtherWrite | UserRead | UserWrite);
@ -139,7 +105,7 @@ public struct Manga
/// <returns>Serialized JSON String for series.json</returns> /// <returns>Serialized JSON String for series.json</returns>
private string GetSeriesInfoJson() private string GetSeriesInfoJson()
{ {
SeriesInfo si = new (new Metadata(this)); SeriesInfo si = new (new Metadata(this.sortName, this.year.ToString() ?? string.Empty, this.status, this.description ?? ""));
return System.Text.Json.JsonSerializer.Serialize(si); return System.Text.Json.JsonSerializer.Serialize(si);
} }
@ -185,11 +151,6 @@ public struct Manga
"droppato" "droppato"
}; };
public Metadata(Manga manga) : this(manga.sortName, manga.year.ToString() ?? string.Empty, manga.status, manga.description ?? "")
{
}
public Metadata(string name, string year, string status, string description_text) public Metadata(string name, string year, string status, string description_text)
{ {
this.name = name; this.name = name;

View File

@ -36,11 +36,6 @@ public class Bato : MangaConnector
return publications; return publications;
} }
public override Manga? GetMangaFromId(string publicationId)
{
return GetMangaFromUrl($"https://bato.to/title/{publicationId}");
}
public override Manga? GetMangaFromUrl(string url) public override Manga? GetMangaFromUrl(string url)
{ {
DownloadClient.RequestResult requestResult = DownloadClient.RequestResult requestResult =
@ -107,18 +102,9 @@ public class Bato : MangaConnector
string status = document.DocumentNode.SelectSingleNode("//span[text()='Original Publication:']/..") string status = document.DocumentNode.SelectSingleNode("//span[text()='Original Publication:']/..")
.ChildNodes[2].InnerText; .ChildNodes[2].InnerText;
Manga.ReleaseStatusByte releaseStatus = Manga.ReleaseStatusByte.Unreleased;
switch (status.ToLower())
{
case "ongoing": releaseStatus = Manga.ReleaseStatusByte.Continuing; break;
case "completed": releaseStatus = Manga.ReleaseStatusByte.Completed; break;
case "hiatus": releaseStatus = Manga.ReleaseStatusByte.OnHiatus; break;
case "cancelled": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
case "pending": releaseStatus = Manga.ReleaseStatusByte.Unreleased; break;
}
Manga manga = new (sortName, authors, description, altTitles, tags, posterUrl, coverFileNameInCache, new Dictionary<string, string>(), Manga manga = new (sortName, authors, description, altTitles, tags, posterUrl, coverFileNameInCache, new Dictionary<string, string>(),
year, originalLanguage, status, publicationId, releaseStatus); year, originalLanguage, status, publicationId);
cachedPublications.Add(manga); cachedPublications.Add(manga);
return manga; return manga;
} }

View File

@ -38,8 +38,6 @@ public abstract class MangaConnector : GlobalBase
public abstract Manga? GetMangaFromUrl(string url); public abstract Manga? GetMangaFromUrl(string url);
public abstract Manga? GetMangaFromId(string publicationId);
/// <summary> /// <summary>
/// Returns all Chapters of the publication in the provided language. /// Returns all Chapters of the publication in the provided language.
/// If the language is empty or null, returns all Chapters in all Languages. /// If the language is empty or null, returns all Chapters in all Languages.
@ -150,8 +148,7 @@ public abstract class MangaConnector : GlobalBase
/// Copies the already downloaded cover from cache to downloadLocation /// Copies the already downloaded cover from cache to downloadLocation
/// </summary> /// </summary>
/// <param name="manga">Publication to retrieve Cover for</param> /// <param name="manga">Publication to retrieve Cover for</param>
/// <param name="retries">Number of times to retry to copy the cover (or download it first)</param> public void CopyCoverFromCacheToDownloadLocation(Manga manga)
public void CopyCoverFromCacheToDownloadLocation(Manga manga, int? retries = 1)
{ {
Log($"Copy cover {manga}"); Log($"Copy cover {manga}");
//Check if Publication already has a Folder and cover //Check if Publication already has a Folder and cover
@ -164,18 +161,6 @@ public abstract class MangaConnector : GlobalBase
} }
string fileInCache = Path.Join(settings.coverImageCache, manga.coverFileNameInCache); string fileInCache = Path.Join(settings.coverImageCache, manga.coverFileNameInCache);
if (!File.Exists(fileInCache))
{
Log($"Cloníng cover failed: File missing {fileInCache}.");
if (retries > 0 && manga.coverUrl is not null)
{
Log($"Trying {retries} more times");
SaveCoverImageToCache(manga.coverUrl, 0);
CopyCoverFromCacheToDownloadLocation(manga, --retries);
}
return;
}
string newFilePath = Path.Join(publicationFolder, $"cover.{Path.GetFileName(fileInCache).Split('.')[^1]}" ); string newFilePath = Path.Join(publicationFolder, $"cover.{Path.GetFileName(fileInCache).Split('.')[^1]}" );
Log($"Cloning cover {fileInCache} -> {newFilePath}"); Log($"Cloning cover {fileInCache} -> {newFilePath}");
File.Copy(fileInCache, newFilePath, true); File.Copy(fileInCache, newFilePath, true);

View File

@ -72,10 +72,13 @@ public class MangaDex : MangaConnector
return retManga.ToArray(); return retManga.ToArray();
} }
public override Manga? GetMangaFromId(string publicationId) public override Manga? GetMangaFromUrl(string url)
{ {
Regex idRex = new (@"https:\/\/mangadex.org\/title\/([A-z0-9-]*)\/.*");
string id = idRex.Match(url).Groups[1].Value;
Log($"Got id {id} from {url}");
DownloadClient.RequestResult requestResult = DownloadClient.RequestResult requestResult =
downloadClient.MakeRequest($"https://api.mangadex.org/manga/{publicationId}", (byte)RequestType.Manga); downloadClient.MakeRequest($"https://api.mangadex.org/manga/{id}", (byte)RequestType.Manga);
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300) if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300)
return null; return null;
JsonObject? result = JsonSerializer.Deserialize<JsonObject>(requestResult.result); JsonObject? result = JsonSerializer.Deserialize<JsonObject>(requestResult.result);
@ -84,14 +87,6 @@ public class MangaDex : MangaConnector
return null; return null;
} }
public override Manga? GetMangaFromUrl(string url)
{
Regex idRex = new (@"https:\/\/mangadex.org\/title\/([A-z0-9-]*)\/.*");
string id = idRex.Match(url).Groups[1].Value;
Log($"Got id {id} from {url}");
return GetMangaFromId(id);
}
private Manga? MangaFromJsonObject(JsonObject manga) private Manga? MangaFromJsonObject(JsonObject manga)
{ {
if (!manga.ContainsKey("attributes")) if (!manga.ContainsKey("attributes"))
@ -175,14 +170,6 @@ public class MangaDex : MangaConnector
if(!attributes.ContainsKey("status")) if(!attributes.ContainsKey("status"))
return null; return null;
string status = attributes["status"]!.GetValue<string>(); string status = attributes["status"]!.GetValue<string>();
Manga.ReleaseStatusByte releaseStatus = Manga.ReleaseStatusByte.Unreleased;
switch (status.ToLower())
{
case "ongoing": releaseStatus = Manga.ReleaseStatusByte.Continuing; break;
case "completed": releaseStatus = Manga.ReleaseStatusByte.Completed; break;
case "hiatus": releaseStatus = Manga.ReleaseStatusByte.OnHiatus; break;
case "cancelled": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
}
Manga pub = new( Manga pub = new(
title, title,
@ -196,8 +183,7 @@ public class MangaDex : MangaConnector
year, year,
originalLanguage, originalLanguage,
status, status,
publicationId, publicationId
releaseStatus
); );
cachedPublications.Add(pub); cachedPublications.Add(pub);
return pub; return pub;

View File

@ -39,11 +39,6 @@ public class MangaKatana : MangaConnector
return publications; return publications;
} }
public override Manga? GetMangaFromId(string publicationId)
{
return GetMangaFromUrl($"https://mangakatana.com/manga/{publicationId}");
}
public override Manga? GetMangaFromUrl(string url) public override Manga? GetMangaFromUrl(string url)
{ {
DownloadClient.RequestResult requestResult = DownloadClient.RequestResult requestResult =
@ -92,7 +87,6 @@ public class MangaKatana : MangaConnector
HashSet<string> tags = new(); HashSet<string> tags = new();
string[] authors = Array.Empty<string>(); string[] authors = Array.Empty<string>();
string originalLanguage = ""; string originalLanguage = "";
Manga.ReleaseStatusByte releaseStatus = Manga.ReleaseStatusByte.Unreleased;
HtmlNode infoNode = document.DocumentNode.SelectSingleNode("//*[@id='single_book']"); HtmlNode infoNode = document.DocumentNode.SelectSingleNode("//*[@id='single_book']");
string sortName = infoNode.Descendants("h1").First(n => n.HasClass("heading")).InnerText; string sortName = infoNode.Descendants("h1").First(n => n.HasClass("heading")).InnerText;
@ -116,11 +110,6 @@ public class MangaKatana : MangaConnector
break; break;
case "status": case "status":
status = value; status = value;
switch (status.ToLower())
{
case "ongoing": releaseStatus = Manga.ReleaseStatusByte.Continuing; break;
case "completed": releaseStatus = Manga.ReleaseStatusByte.Completed; break;
}
break; break;
case "genres": case "genres":
tags = row.SelectNodes("div").Last().Descendants("a").Select(a => a.InnerText).ToHashSet(); tags = row.SelectNodes("div").Last().Descendants("a").Select(a => a.InnerText).ToHashSet();
@ -147,7 +136,7 @@ public class MangaKatana : MangaConnector
} }
Manga manga = new (sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, Manga manga = new (sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
year, originalLanguage, status, publicationId, releaseStatus); year, originalLanguage, status, publicationId);
cachedPublications.Add(manga); cachedPublications.Add(manga);
return manga; return manga;
} }

View File

@ -32,11 +32,6 @@ public class MangaLife : MangaConnector
return publications; return publications;
} }
public override Manga? GetMangaFromId(string publicationId)
{
return GetMangaFromUrl($"https://manga4life.com/manga/{publicationId}");
}
public override Manga? GetMangaFromUrl(string url) public override Manga? GetMangaFromUrl(string url)
{ {
Regex publicationIdRex = new(@"https:\/\/manga4life.com\/manga\/(.*)(\/.*)*"); Regex publicationIdRex = new(@"https:\/\/manga4life.com\/manga\/(.*)(\/.*)*");
@ -77,7 +72,6 @@ public class MangaLife : MangaConnector
string originalLanguage = "", status = ""; string originalLanguage = "", status = "";
Dictionary<string, string> altTitles = new(), links = new(); Dictionary<string, string> altTitles = new(), links = new();
HashSet<string> tags = new(); HashSet<string> tags = new();
Manga.ReleaseStatusByte releaseStatus = Manga.ReleaseStatusByte.Unreleased;
HtmlNode posterNode = document.DocumentNode.SelectSingleNode("//div[@class='BoxBody']//div[@class='row']//img"); HtmlNode posterNode = document.DocumentNode.SelectSingleNode("//div[@class='BoxBody']//div[@class='row']//img");
string posterUrl = posterNode.GetAttributeValue("src", ""); string posterUrl = posterNode.GetAttributeValue("src", "");
@ -110,14 +104,6 @@ public class MangaLife : MangaConnector
foreach (HtmlNode statusNode in statusNodes) foreach (HtmlNode statusNode in statusNodes)
if (statusNode.InnerText.Contains("publish", StringComparison.CurrentCultureIgnoreCase)) if (statusNode.InnerText.Contains("publish", StringComparison.CurrentCultureIgnoreCase))
status = statusNode.InnerText.Split(' ')[0]; status = statusNode.InnerText.Split(' ')[0];
switch (status.ToLower())
{
case "cancelled": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
case "hiatus": releaseStatus = Manga.ReleaseStatusByte.OnHiatus; break;
case "discontinued": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
case "complete": releaseStatus = Manga.ReleaseStatusByte.Completed; break;
case "ongoing": releaseStatus = Manga.ReleaseStatusByte.Continuing; break;
}
HtmlNode descriptionNode = document.DocumentNode HtmlNode descriptionNode = document.DocumentNode
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Description:']/..") .SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Description:']/..")
@ -125,7 +111,8 @@ public class MangaLife : MangaConnector
string description = descriptionNode.InnerText; string description = descriptionNode.InnerText;
Manga manga = new(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, Manga manga = new(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl,
coverFileNameInCache, links, year, originalLanguage, status, publicationId, releaseStatus); coverFileNameInCache, links,
year, originalLanguage, status, publicationId);
cachedPublications.Add(manga); cachedPublications.Add(manga);
return manga; return manga;
} }

View File

@ -54,11 +54,6 @@ public class Manganato : MangaConnector
return ret.ToArray(); return ret.ToArray();
} }
public override Manga? GetMangaFromId(string publicationId)
{
return GetMangaFromUrl($"https://chapmanganato.com/{publicationId}");
}
public override Manga? GetMangaFromUrl(string url) public override Manga? GetMangaFromUrl(string url)
{ {
DownloadClient.RequestResult requestResult = DownloadClient.RequestResult requestResult =
@ -79,7 +74,6 @@ public class Manganato : MangaConnector
HashSet<string> tags = new(); HashSet<string> tags = new();
string[] authors = Array.Empty<string>(); string[] authors = Array.Empty<string>();
string originalLanguage = ""; string originalLanguage = "";
Manga.ReleaseStatusByte releaseStatus = Manga.ReleaseStatusByte.Unreleased;
HtmlNode infoNode = document.DocumentNode.Descendants("div").First(d => d.HasClass("story-info-right")); HtmlNode infoNode = document.DocumentNode.Descendants("div").First(d => d.HasClass("story-info-right"));
@ -105,11 +99,6 @@ public class Manganato : MangaConnector
break; break;
case "status": case "status":
status = value; status = value;
switch (status.ToLower())
{
case "ongoing": releaseStatus = Manga.ReleaseStatusByte.Continuing; break;
case "completed": releaseStatus = Manga.ReleaseStatusByte.Completed; break;
}
break; break;
case "genres": case "genres":
string[] genres = value.Split(" - "); string[] genres = value.Split(" - ");
@ -133,7 +122,7 @@ public class Manganato : MangaConnector
int year = Convert.ToInt32(yearString.Split(',')[^1]) + 2000; int year = Convert.ToInt32(yearString.Split(',')[^1]) + 2000;
Manga manga = new (sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, Manga manga = new (sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
year, originalLanguage, status, publicationId, releaseStatus); year, originalLanguage, status, publicationId);
cachedPublications.Add(manga); cachedPublications.Add(manga);
return manga; return manga;
} }
@ -167,18 +156,18 @@ public class Manganato : MangaConnector
HtmlNode chapterList = document.DocumentNode.Descendants("ul").First(l => l.HasClass("row-content-chapter")); HtmlNode chapterList = document.DocumentNode.Descendants("ul").First(l => l.HasClass("row-content-chapter"));
Regex volRex = new(@"Vol\.([0-9]+).*"); Regex volRex = new(@"Vol\.([0-9]+).*");
Regex chapterRex = new(@"https:\/\/chapmanganato.com/manga-[A-z0-9]+\/chapter-([0-9\.]+)"); Regex chapterRex = new(@"Chapter ([0-9]+(\.[0-9]+)*){1}.*");
Regex nameRex = new(@"Chapter ([0-9]+(\.[0-9]+)*){1}:? (.*)"); Regex nameRex = new(@"Chapter ([0-9]+(\.[0-9]+)*){1}:? (.*)");
foreach (HtmlNode chapterInfo in chapterList.Descendants("li")) foreach (HtmlNode chapterInfo in chapterList.Descendants("li"))
{ {
string fullString = chapterInfo.Descendants("a").First(d => d.HasClass("chapter-name")).InnerText; string fullString = chapterInfo.Descendants("a").First(d => d.HasClass("chapter-name")).InnerText;
string? volumeNumber = volRex.IsMatch(fullString) ? volRex.Match(fullString).Groups[1].Value : null;
string chapterNumber = chapterRex.IsMatch(fullString) ? chapterRex.Match(fullString).Groups[1].Value : fullString;
string chapterName = nameRex.Match(fullString).Groups[3].Value;
string url = chapterInfo.Descendants("a").First(d => d.HasClass("chapter-name")) string url = chapterInfo.Descendants("a").First(d => d.HasClass("chapter-name"))
.GetAttributeValue("href", ""); .GetAttributeValue("href", "");
string? volumeNumber = volRex.IsMatch(fullString) ? volRex.Match(fullString).Groups[1].Value : null;
string chapterNumber = chapterRex.Match(url).Groups[1].Value;
string chapterName = nameRex.Match(fullString).Groups[3].Value;
ret.Add(new Chapter(manga, chapterName, volumeNumber, chapterNumber, url)); ret.Add(new Chapter(manga, chapterName, volumeNumber, chapterNumber, url));
} }
ret.Reverse(); ret.Reverse();

View File

@ -1,9 +1,7 @@
using System.Data; using System.Net;
using System.Net;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Xml.Linq; using System.Xml.Linq;
using HtmlAgilityPack; using HtmlAgilityPack;
using Newtonsoft.Json;
using Tranga.Jobs; using Tranga.Jobs;
namespace Tranga.MangaConnectors; namespace Tranga.MangaConnectors;
@ -18,102 +16,21 @@ public class Mangasee : MangaConnector
}); });
} }
private struct SearchResult
{
public string i { get; set; }
public string s { get; set; }
public string[] a { get; set; }
}
public override Manga[] GetManga(string publicationTitle = "") public override Manga[] GetManga(string publicationTitle = "")
{ {
Log($"Searching Publications. Term=\"{publicationTitle}\""); Log($"Searching Publications. Term=\"{publicationTitle}\"");
string requestUrl = "https://mangasee123.com/_search.php"; string sanitizedTitle = WebUtility.UrlEncode(publicationTitle);
string requestUrl = $"https://mangasee123.com/search/?name={sanitizedTitle}";
DownloadClient.RequestResult requestResult = DownloadClient.RequestResult requestResult =
downloadClient.MakeRequest(requestUrl, 1); downloadClient.MakeRequest(requestUrl, 1);
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300) if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300)
{
Log($"Failed to retrieve search: {requestResult.statusCode}");
return Array.Empty<Manga>(); return Array.Empty<Manga>();
}
try if (requestResult.htmlDocument is null)
{
SearchResult[] searchResults = JsonConvert.DeserializeObject<SearchResult[]>(requestResult.htmlDocument!.DocumentNode.InnerText) ??
throw new NoNullAllowedException();
SearchResult[] filteredResults = FilteredResults(publicationTitle, searchResults);
Log($"Total available manga: {searchResults.Length} Filtered down to: {filteredResults.Length}");
/*
Dictionary<SearchResult, int> levenshteinRelation = filteredResults.ToDictionary(result => result,
result =>
{
Log($"Levenshtein {result.s}");
return LevenshteinDistance(publicationTitle.Replace(" ", "").ToLower(), result.s.Replace(" ", "").ToLower());
});
Log($"After levenshtein: {levenshteinRelation.Count}");*/
string[] urls = filteredResults.Select(result => $"https://mangasee123.com/manga/{result.i}").ToArray();
List<Manga> searchResultManga = new();
foreach (string url in urls)
{
Manga? newManga = GetMangaFromUrl(url);
if(newManga is { } manga)
searchResultManga.Add(manga);
}
Log($"Retrieved {searchResultManga.Count} publications. Term=\"{publicationTitle}\"");
return searchResultManga.ToArray();
}
catch (NoNullAllowedException)
{
Log("Failed to retrieve search");
return Array.Empty<Manga>(); return Array.Empty<Manga>();
} Manga[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
} Log($"Retrieved {publications.Length} publications. Term=\"{publicationTitle}\"");
return publications;
private SearchResult[] FilteredResults(string publicationTitle, SearchResult[] unfilteredSearchResults)
{
string[] bannedStrings = {"a", "the", "of", "as", "to", "no", "for", "on", "with", "be", "and", "in", "wa", "at"};
string[] cleanSplitPublicationTitle = publicationTitle.Split(' ')
.Where(part => part.Length > 0 && !bannedStrings.Contains(part.ToLower())).ToArray();
return unfilteredSearchResults.Where(usr =>
{
string cleanSearchResultString = string.Join(' ', usr.s.Split(' ').Where(part => part.Length > 0 && !bannedStrings.Contains(part.ToLower())));
foreach(string splitPublicationTitlePart in cleanSplitPublicationTitle)
if (cleanSearchResultString.Contains(splitPublicationTitlePart, StringComparison.InvariantCultureIgnoreCase) ||
cleanSearchResultString.Contains(splitPublicationTitlePart, StringComparison.InvariantCultureIgnoreCase))
return true;
return false;
}).ToArray();
}
private int LevenshteinDistance(string a, string b)
{
if (b.Length == 0)
return a.Length;
if (a.Length == 0)
return b.Length;
if (a[0] == b[0])
return LevenshteinDistance(a[1..], b[1..]);
int case1 = LevenshteinDistance(a, b[1..]);
int case2 = LevenshteinDistance(a[1..], b[1..]);
int case3 = LevenshteinDistance(a[1..], b);
if (case1 < case2)
{
return 1 + (case1 < case3 ? case1 : case3);
}
else
{
return 1 + (case2 < case3 ? case2 : case3);
}
}
public override Manga? GetMangaFromId(string publicationId)
{
return GetMangaFromUrl($"https://mangasee123.com/manga/{publicationId}");
} }
public override Manga? GetMangaFromUrl(string url) public override Manga? GetMangaFromUrl(string url)
@ -127,12 +44,35 @@ public class Mangasee : MangaConnector
return null; return null;
} }
private Manga[] ParsePublicationsFromHtml(HtmlDocument document)
{
HtmlNode resultsNode = document.DocumentNode.SelectSingleNode("//div[@class='BoxBody']/div[last()]/div[1]/div");
if (resultsNode.Descendants("div").Count() == 1 && resultsNode.Descendants("div").First().HasClass("NoResults"))
{
Log("No results.");
return Array.Empty<Manga>();
}
Log($"{resultsNode.SelectNodes("div").Count} items.");
HashSet<Manga> ret = new();
foreach (HtmlNode resultNode in resultsNode.SelectNodes("div"))
{
string url = resultNode.Descendants().First(d => d.HasClass("SeriesName")).GetAttributeValue("href", "");
Manga? manga = GetMangaFromUrl($"https://mangasee123.com{url}");
if (manga is not null)
ret.Add((Manga)manga);
}
return ret.ToArray();
}
private Manga ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId) private Manga ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId)
{ {
string originalLanguage = "", status = ""; string originalLanguage = "", status = "";
Dictionary<string, string> altTitles = new(), links = new(); Dictionary<string, string> altTitles = new(), links = new();
HashSet<string> tags = new(); HashSet<string> tags = new();
Manga.ReleaseStatusByte releaseStatus = Manga.ReleaseStatusByte.Unreleased;
HtmlNode posterNode = document.DocumentNode.SelectSingleNode("//div[@class='BoxBody']//div[@class='row']//img"); HtmlNode posterNode = document.DocumentNode.SelectSingleNode("//div[@class='BoxBody']//div[@class='row']//img");
string posterUrl = posterNode.GetAttributeValue("src", ""); string posterUrl = posterNode.GetAttributeValue("src", "");
@ -165,14 +105,6 @@ public class Mangasee : MangaConnector
foreach (HtmlNode statusNode in statusNodes) foreach (HtmlNode statusNode in statusNodes)
if (statusNode.InnerText.Contains("publish", StringComparison.CurrentCultureIgnoreCase)) if (statusNode.InnerText.Contains("publish", StringComparison.CurrentCultureIgnoreCase))
status = statusNode.InnerText.Split(' ')[0]; status = statusNode.InnerText.Split(' ')[0];
switch (status.ToLower())
{
case "cancelled": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
case "hiatus": releaseStatus = Manga.ReleaseStatusByte.OnHiatus; break;
case "discontinued": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
case "complete": releaseStatus = Manga.ReleaseStatusByte.Completed; break;
case "ongoing": releaseStatus = Manga.ReleaseStatusByte.Continuing; break;
}
HtmlNode descriptionNode = document.DocumentNode HtmlNode descriptionNode = document.DocumentNode
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Description:']/..") .SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Description:']/..")
@ -181,7 +113,7 @@ public class Mangasee : MangaConnector
Manga manga = new(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, Manga manga = new(sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl,
coverFileNameInCache, links, coverFileNameInCache, links,
year, originalLanguage, status, publicationId, releaseStatus); year, originalLanguage, status, publicationId);
cachedPublications.Add(manga); cachedPublications.Add(manga);
return manga; return manga;
} }
@ -210,7 +142,7 @@ public class Mangasee : MangaConnector
} }
catch (HttpRequestException e) catch (HttpRequestException e)
{ {
Log($"Failed to load https://mangasee123.com/rss/{manga.publicationId}.xml \n\r{e}"); Log($"Failed to load XML\n\r{e}");
return Array.Empty<Chapter>(); return Array.Empty<Chapter>();
} }
} }

View File

@ -54,11 +54,6 @@ public class Mangaworld: MangaConnector
return ret.ToArray(); return ret.ToArray();
} }
public override Manga? GetMangaFromId(string publicationId)
{
return GetMangaFromUrl($"https://www.mangaworld.bz/manga/{publicationId}");
}
public override Manga? GetMangaFromUrl(string url) public override Manga? GetMangaFromUrl(string url)
{ {
DownloadClient.RequestResult requestResult = DownloadClient.RequestResult requestResult =
@ -69,9 +64,7 @@ public class Mangaworld: MangaConnector
if (requestResult.htmlDocument is null) if (requestResult.htmlDocument is null)
return null; return null;
Regex idRex = new (@"https:\/\/www\.mangaworld\.bz\/manga\/([0-9]+\/[0-9A-z\-]+)"); return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^2]);
string id = idRex.Match(url).Groups[1].Value;
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, id);
} }
private Manga ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId) private Manga ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId)
@ -79,7 +72,6 @@ public class Mangaworld: MangaConnector
Dictionary<string, string> altTitles = new(); Dictionary<string, string> altTitles = new();
Dictionary<string, string>? links = null; Dictionary<string, string>? links = null;
string originalLanguage = ""; string originalLanguage = "";
Manga.ReleaseStatusByte releaseStatus = Manga.ReleaseStatusByte.Unreleased;
HtmlNode infoNode = document.DocumentNode.Descendants("div").First(d => d.HasClass("info")); HtmlNode infoNode = document.DocumentNode.Descendants("div").First(d => d.HasClass("info"));
@ -102,15 +94,6 @@ public class Mangaworld: MangaConnector
string[] authors = new[] { authorsNode.SelectNodes("a").First().InnerText }; string[] authors = new[] { authorsNode.SelectNodes("a").First().InnerText };
string status = metadata.SelectSingleNode("//span[text()='Stato: ']/..").SelectNodes("a").First().InnerText; string status = metadata.SelectSingleNode("//span[text()='Stato: ']/..").SelectNodes("a").First().InnerText;
// ReSharper disable 5 times StringLiteralTypo
switch (status.ToLower())
{
case "cancellato": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
case "in pausa": releaseStatus = Manga.ReleaseStatusByte.OnHiatus; break;
case "droppato": releaseStatus = Manga.ReleaseStatusByte.Cancelled; break;
case "finito": releaseStatus = Manga.ReleaseStatusByte.Completed; break;
case "in corso": releaseStatus = Manga.ReleaseStatusByte.Continuing; break;
}
string posterUrl = document.DocumentNode.SelectSingleNode("//img[@class='rounded']").GetAttributeValue("src", ""); string posterUrl = document.DocumentNode.SelectSingleNode("//img[@class='rounded']").GetAttributeValue("src", "");
@ -122,7 +105,7 @@ public class Mangaworld: MangaConnector
int year = Convert.ToInt32(yearString); int year = Convert.ToInt32(yearString);
Manga manga = new (sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links, Manga manga = new (sortName, authors.ToList(), description, altTitles, tags.ToArray(), posterUrl, coverFileNameInCache, links,
year, originalLanguage, status, publicationId, releaseStatus); year, originalLanguage, status, publicationId);
cachedPublications.Add(manga); cachedPublications.Add(manga);
return manga; return manga;
} }

View File

@ -304,34 +304,6 @@ public class Server : GlobalBase
_parent.jobBoss.AddJob(new DownloadNewChapters(this, connector!, manga, false, translatedLanguage: translatedLanguage??"en")); _parent.jobBoss.AddJob(new DownloadNewChapters(this, connector!, manga, false, translatedLanguage: translatedLanguage??"en"));
SendResponse(HttpStatusCode.Accepted, response); SendResponse(HttpStatusCode.Accepted, response);
break; break;
case "Jobs/UpdateMetadata":
if (!requestVariables.TryGetValue("internalId", out internalId))
{
foreach (Job pJob in _parent.jobBoss.jobs.Where(possibleDncJob =>
possibleDncJob.jobType is Job.JobType.DownloadNewChaptersJob).ToArray())//ToArray to avoid modyifying while adding new jobs
{
DownloadNewChapters dncJob = pJob as DownloadNewChapters ??
throw new Exception("Has to be DownloadNewChapters Job");
_parent.jobBoss.AddJob(new UpdateMetadata(this, dncJob.mangaConnector, dncJob.manga));
}
SendResponse(HttpStatusCode.Accepted, response);
}
else
{
Job[] possibleDncJobs = _parent.jobBoss.GetJobsLike(internalId: internalId).ToArray();
switch (possibleDncJobs.Length)
{
case <1: SendResponse(HttpStatusCode.BadRequest, response, "Could not find matching release"); break;
case >1: SendResponse(HttpStatusCode.BadRequest, response, "Multiple releases??"); break;
default:
DownloadNewChapters dncJob = possibleDncJobs[0] as DownloadNewChapters ??
throw new Exception("Has to be DownloadNewChapters Job");
_parent.jobBoss.AddJob(new UpdateMetadata(this, dncJob.mangaConnector, dncJob.manga));
SendResponse(HttpStatusCode.Accepted, response);
break;
}
}
break;
case "Jobs/StartNow": case "Jobs/StartNow":
if (!requestVariables.TryGetValue("jobId", out jobId) || if (!requestVariables.TryGetValue("jobId", out jobId) ||
!_parent.jobBoss.TryGetJobById(jobId, out job)) !_parent.jobBoss.TryGetJobById(jobId, out job))