mirror of
https://github.com/C9Glax/tranga.git
synced 2025-02-23 15:50:13 +01:00
Fix Arrays shall not be added to context
This commit is contained in:
parent
729f018712
commit
60b128fc30
@ -1,10 +1,8 @@
|
|||||||
using API.Schema;
|
using API.Schema;
|
||||||
using API.Schema.Jobs;
|
|
||||||
using API.Schema.MangaConnectors;
|
using API.Schema.MangaConnectors;
|
||||||
using Asp.Versioning;
|
using Asp.Versioning;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Soenneker.Utils.String.NeedlemanWunsch;
|
|
||||||
using static Microsoft.AspNetCore.Http.StatusCodes;
|
using static Microsoft.AspNetCore.Http.StatusCodes;
|
||||||
|
|
||||||
namespace API.Controllers;
|
namespace API.Controllers;
|
||||||
@ -36,21 +34,24 @@ public class ConnectorController(PgsqlContext context) : Controller
|
|||||||
[ProducesResponseType<Manga[]>(Status500InternalServerError)]
|
[ProducesResponseType<Manga[]>(Status500InternalServerError)]
|
||||||
public IActionResult SearchMangaGlobal(string name)
|
public IActionResult SearchMangaGlobal(string name)
|
||||||
{
|
{
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> allManga = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> allManga = new();
|
||||||
foreach (MangaConnector contextMangaConnector in context.MangaConnectors)
|
foreach (MangaConnector contextMangaConnector in context.MangaConnectors)
|
||||||
allManga.AddRange(contextMangaConnector.GetManga(name));
|
allManga.AddRange(contextMangaConnector.GetManga(name));
|
||||||
foreach ((Manga? manga, Author[]? authors, MangaTag[]? tags, Link[]? links, MangaAltTitle[]? altTitles) in allManga)
|
List<Manga> retMangas = new();
|
||||||
|
foreach ((Manga? manga, List<Author>? authors, List<MangaTag>? tags, List<Link>? links, List<MangaAltTitle>? altTitles) in allManga)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
AddMangaToContext(manga, authors, tags, links, altTitles);
|
Manga? add = AddMangaToContext(manga, authors, tags, links, altTitles);
|
||||||
|
if(add is not null)
|
||||||
|
retMangas.Add(add);
|
||||||
}
|
}
|
||||||
catch (DbUpdateException)
|
catch (DbUpdateException)
|
||||||
{
|
{
|
||||||
return StatusCode(500, new ProblemResponse("An error occurred while processing your request."));
|
return StatusCode(500, new ProblemResponse("An error occurred while processing your request."));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Ok(allManga.Select(m => context.Manga.Find(m.Item1.MangaId)).ToArray());
|
return Ok(retMangas.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -68,31 +69,41 @@ public class ConnectorController(PgsqlContext context) : Controller
|
|||||||
MangaConnector? connector = context.MangaConnectors.Find(id);
|
MangaConnector? connector = context.MangaConnectors.Find(id);
|
||||||
if (connector is null)
|
if (connector is null)
|
||||||
return NotFound(new ProblemResponse("Connector not found."));
|
return NotFound(new ProblemResponse("Connector not found."));
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] mangas = connector.GetManga(name);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] mangas = connector.GetManga(name);
|
||||||
foreach ((Manga? manga, Author[]? authors, MangaTag[]? tags, Link[]? links, MangaAltTitle[]? altTitles) in mangas)
|
List<Manga> retMangas = new();
|
||||||
|
foreach ((Manga? manga, List<Author>? authors, List<MangaTag>? tags, List<Link>? links, List<MangaAltTitle>? altTitles) in mangas)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
AddMangaToContext(manga, authors, tags, links, altTitles);
|
Manga? add = AddMangaToContext(manga, authors, tags, links, altTitles);
|
||||||
|
if(add is not null)
|
||||||
|
retMangas.Add(add);
|
||||||
}
|
}
|
||||||
catch (DbUpdateException)
|
catch (DbUpdateException e)
|
||||||
{
|
{
|
||||||
return StatusCode(500, new ProblemResponse("An error occurred while processing your request."));
|
return StatusCode(500, new ProblemResponse("An error occurred while processing your request.", e.Message));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(mangas.Select(m => context.Manga.Find(m.Item1.MangaId)).ToArray());
|
return Ok(retMangas.ToArray());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddMangaToContext(Manga? manga, Author[]? authors, MangaTag[]? tags, Link[]? links,
|
private Manga? AddMangaToContext(Manga? manga, List<Author>? authors, List<MangaTag>? tags, List<Link>? links,
|
||||||
MangaAltTitle[]? altTitles)
|
List<MangaAltTitle>? altTitles)
|
||||||
{
|
{
|
||||||
if (manga is null)
|
if (manga is null)
|
||||||
return;
|
return null;
|
||||||
|
Manga? existing = context.Manga.FirstOrDefault(m => m.ConnectorId == manga.ConnectorId);
|
||||||
|
|
||||||
if (tags is not null)
|
if (tags is not null)
|
||||||
{
|
{
|
||||||
IEnumerable<MangaTag> newTags = tags.Where(mt => context.Tags.All(t => !t.Tag.Equals(mt.Tag)));
|
IEnumerable<MangaTag> mergedTags = tags.Select(mt =>
|
||||||
|
{
|
||||||
|
MangaTag? inDb = context.Tags.FirstOrDefault(t => t.Equals(mt));
|
||||||
|
return inDb ?? mt;
|
||||||
|
});
|
||||||
|
manga.Tags = mergedTags.ToList();
|
||||||
|
IEnumerable<MangaTag> newTags = manga.Tags.Where(mt => !context.Tags.Any(t => t.Tag.Equals(mt.Tag)));
|
||||||
context.Tags.AddRange(newTags);
|
context.Tags.AddRange(newTags);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,22 +111,50 @@ public class ConnectorController(PgsqlContext context) : Controller
|
|||||||
{
|
{
|
||||||
IEnumerable<Author> mergedAuthors = authors.Select(ma =>
|
IEnumerable<Author> mergedAuthors = authors.Select(ma =>
|
||||||
{
|
{
|
||||||
Author? inDb = context.Authors.FirstOrDefault(a => a.Equals(ma));
|
Author? inDb = context.Authors.FirstOrDefault(a => a.AuthorName == ma.AuthorName);
|
||||||
return inDb ?? ma;
|
return inDb ?? ma;
|
||||||
});
|
});
|
||||||
manga.Authors = mergedAuthors.ToArray();
|
manga.Authors = mergedAuthors.ToList();
|
||||||
IEnumerable<Author> newAuthors = authors.Where(ma => context.Authors.All(a => !a.Equals(ma)));
|
IEnumerable<Author> newAuthors = manga.Authors.Where(ma => !context.Authors.Any(a =>
|
||||||
|
a.AuthorName == ma.AuthorName));
|
||||||
context.Authors.AddRange(newAuthors);
|
context.Authors.AddRange(newAuthors);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (links is not null)
|
if (links is not null)
|
||||||
context.Link.AddRange(links);
|
{
|
||||||
|
IEnumerable<Link> mergedLinks = links.Select(ml =>
|
||||||
|
{
|
||||||
|
Link? inDb = context.Link.FirstOrDefault(l =>
|
||||||
|
l.LinkProvider == ml.LinkProvider && l.LinkUrl == ml.LinkUrl);
|
||||||
|
return inDb ?? ml;
|
||||||
|
});
|
||||||
|
manga.Links = mergedLinks.ToList();
|
||||||
|
IEnumerable<Link> newLinks = manga.Links.Where(ml => !context.Link.Any(l =>
|
||||||
|
l.LinkProvider == ml.LinkProvider && l.LinkUrl == ml.LinkUrl));
|
||||||
|
context.Link.AddRange(newLinks);
|
||||||
|
}
|
||||||
|
|
||||||
if(altTitles is not null)
|
if (altTitles is not null)
|
||||||
context.AltTitles.AddRange(altTitles);
|
{
|
||||||
|
IEnumerable<MangaAltTitle> mergedAltTitles = altTitles.Select(mat =>
|
||||||
|
{
|
||||||
|
MangaAltTitle? inDb = context.AltTitles.FirstOrDefault(at =>
|
||||||
|
at.Language == mat.Language && at.Title == mat.Title);
|
||||||
|
return inDb ?? mat;
|
||||||
|
});
|
||||||
|
manga.AltTitles = mergedAltTitles.ToList();
|
||||||
|
IEnumerable<MangaAltTitle> newAltTitles = manga.AltTitles.Where(mat =>
|
||||||
|
!context.AltTitles.Any(at => at.Language == mat.Language && at.Title == mat.Title));
|
||||||
|
context.AltTitles.AddRange(newAltTitles);
|
||||||
|
}
|
||||||
|
|
||||||
|
existing?.UpdateWithInfo(manga);
|
||||||
|
if(existing is not null)
|
||||||
|
context.Manga.Update(existing);
|
||||||
|
else
|
||||||
context.Manga.Add(manga);
|
context.Manga.Add(manga);
|
||||||
|
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
|
return existing ?? manga;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,25 +19,12 @@ public class JobController(PgsqlContext context) : Controller
|
|||||||
/// <returns>Array of Jobs</returns>
|
/// <returns>Array of Jobs</returns>
|
||||||
[HttpPost("WithIDs")]
|
[HttpPost("WithIDs")]
|
||||||
[ProducesResponseType<Job[]>(Status200OK)]
|
[ProducesResponseType<Job[]>(Status200OK)]
|
||||||
public IActionResult GetJobs([FromBody] string[] ids)
|
public IActionResult GetJobs([FromBody]string[] ids)
|
||||||
{
|
{
|
||||||
Job[] ret = context.Jobs.Where(job => ids.Contains(job.JobId)).ToArray();
|
Job[] ret = context.Jobs.Where(job => ids.Contains(job.JobId)).ToArray();
|
||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Get all due Jobs (NextExecution > CurrentTime)
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>Array of Jobs</returns>
|
|
||||||
[HttpGet("Due")]
|
|
||||||
[ProducesResponseType<Job[]>(Status200OK)]
|
|
||||||
public IActionResult GetDueJobs()
|
|
||||||
{
|
|
||||||
DateTime now = DateTime.Now.ToUniversalTime();
|
|
||||||
Job[] dueJobs = context.Jobs.Where(job => job.NextExecution < now && job.state < JobState.Running).ToArray();
|
|
||||||
return Ok(dueJobs);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get all Jobs in requested State
|
/// Get all Jobs in requested State
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -56,7 +43,7 @@ public class JobController(PgsqlContext context) : Controller
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="type">Requested Job-Type</param>
|
/// <param name="type">Requested Job-Type</param>
|
||||||
/// <returns>Array of Jobs</returns>
|
/// <returns>Array of Jobs</returns>
|
||||||
[HttpPost("Type/{type}")]
|
[HttpGet("Type/{type}")]
|
||||||
[ProducesResponseType<Job[]>(Status200OK)]
|
[ProducesResponseType<Job[]>(Status200OK)]
|
||||||
public IActionResult GetJobsOfType(JobType type)
|
public IActionResult GetJobsOfType(JobType type)
|
||||||
{
|
{
|
||||||
@ -83,46 +70,71 @@ public class JobController(PgsqlContext context) : Controller
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the State of a Job
|
/// Create a new CreateNewDownloadChapterJob
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="id">Job-ID</param>
|
/// <param name="request">ID of the Manga, and how often we check again</param>
|
||||||
/// <param name="state">New State</param>
|
|
||||||
/// <returns>Nothing</returns>
|
/// <returns>Nothing</returns>
|
||||||
[HttpPatch("{id}/Status")]
|
[HttpPut("NewDownloadChapterJob/{mangaId}")]
|
||||||
[ProducesResponseType(Status200OK)]
|
[ProducesResponseType(Status201Created)]
|
||||||
[ProducesResponseType<string>(Status404NotFound)]
|
[ProducesResponseType<string>(Status500InternalServerError)]
|
||||||
[ProducesResponseType(Status500InternalServerError)]
|
public IActionResult CreateNewDownloadChapterJob(string mangaId, [FromBody]ulong recurrenceTime)
|
||||||
public IActionResult UpdateJobStatus(string id, [FromBody]JobState state)
|
|
||||||
{
|
{
|
||||||
|
Job job = new DownloadNewChaptersJob(recurrenceTime, mangaId);
|
||||||
|
return AddJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new DownloadSingleChapterJob
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="chapterId">ID of the Chapter</param>
|
||||||
|
/// <returns>Nothing</returns>
|
||||||
|
[HttpPut("DownloadSingleChapterJob/{chapterId}")]
|
||||||
|
[ProducesResponseType(Status201Created)]
|
||||||
|
[ProducesResponseType<string>(Status500InternalServerError)]
|
||||||
|
public IActionResult CreateNewDownloadChapterJob(string chapterId)
|
||||||
|
{
|
||||||
|
Job job = new DownloadSingleChapterJob(chapterId);
|
||||||
|
return AddJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new UpdateMetadataJob
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mangaId">ID of the Manga</param>
|
||||||
|
/// <returns>Nothing</returns>
|
||||||
|
[HttpPut("UpdateMetadataJob/{mangaId}")]
|
||||||
|
[ProducesResponseType(Status201Created)]
|
||||||
|
[ProducesResponseType<string>(Status500InternalServerError)]
|
||||||
|
public IActionResult CreateUpdateMetadataJob(string mangaId)
|
||||||
|
{
|
||||||
|
Job job = new UpdateMetadataJob(0, mangaId);
|
||||||
|
return AddJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Create a new UpdateMetadataJob for all Manga
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Nothing</returns>
|
||||||
|
[HttpPut("UpdateMetadataJob")]
|
||||||
|
[ProducesResponseType(Status201Created)]
|
||||||
|
[ProducesResponseType<string>(Status500InternalServerError)]
|
||||||
|
public IActionResult CreateUpdateAllMetadataJob()
|
||||||
|
{
|
||||||
|
List<string> ids = context.Manga.Select(m => m.MangaId).ToList();
|
||||||
|
List<UpdateMetadataJob> jobs = ids.Select(id => new UpdateMetadataJob(0, id)).ToList();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Job? ret = context.Jobs.Find(id);
|
context.Jobs.AddRange(jobs);
|
||||||
switch (ret is not null)
|
|
||||||
{
|
|
||||||
case true:
|
|
||||||
ret.state = state;
|
|
||||||
context.Update(ret);
|
|
||||||
context.SaveChanges();
|
context.SaveChanges();
|
||||||
return Ok();
|
return Created();
|
||||||
case false: return NotFound();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
return StatusCode(500, e.Message);
|
return StatusCode(500, e.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private IActionResult AddJob(Job job)
|
||||||
/// Create a new Job
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="job">Job</param>
|
|
||||||
/// <returns>Nothing</returns>
|
|
||||||
[HttpPut]
|
|
||||||
[ProducesResponseType(Status201Created)]
|
|
||||||
[ProducesResponseType<string>(Status500InternalServerError)]
|
|
||||||
public IActionResult CreateJob([FromBody]Job job)
|
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -71,59 +71,6 @@ public class MangaController(PgsqlContext context) : Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Create new Manga
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="manga">Manga</param>
|
|
||||||
/// <returns>Nothing</returns>
|
|
||||||
[HttpPut]
|
|
||||||
[ProducesResponseType(Status200OK)]
|
|
||||||
[ProducesResponseType(Status500InternalServerError)]
|
|
||||||
public IActionResult CreateManga([FromBody] Manga manga)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
context.Manga.Add(manga);
|
|
||||||
context.SaveChanges();
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return StatusCode(500, e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Update Manga MetaData
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">Manga-ID</param>
|
|
||||||
/// <param name="manga">New Manga-Info</param>
|
|
||||||
/// <returns>Nothing</returns>
|
|
||||||
[HttpPatch("{id}")]
|
|
||||||
[ProducesResponseType(Status200OK)]
|
|
||||||
[ProducesResponseType(Status404NotFound)]
|
|
||||||
[ProducesResponseType(Status500InternalServerError)]
|
|
||||||
public IActionResult UpdateMangaMetadata(string id, [FromBody]Manga manga)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Manga? ret = context.Manga.Find(id);
|
|
||||||
switch (ret is not null)
|
|
||||||
{
|
|
||||||
case true:
|
|
||||||
ret.UpdateWithInfo(manga);
|
|
||||||
context.Update(ret);
|
|
||||||
context.SaveChanges();
|
|
||||||
return Ok();
|
|
||||||
case false: return NotFound();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return StatusCode(500, e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns URL of Cover of Manga
|
/// Returns URL of Cover of Manga
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -153,37 +100,6 @@ public class MangaController(PgsqlContext context) : Controller
|
|||||||
return Ok(ret);
|
return Ok(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds/Creates new Chapter for Manga
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="id">Manga-ID</param>
|
|
||||||
/// <param name="chapters">Array of Chapters</param>
|
|
||||||
/// <remarks>Manga-ID and all Chapters have to be the same</remarks>
|
|
||||||
/// <returns>Nothing</returns>
|
|
||||||
[HttpPut("{id}")]
|
|
||||||
[ProducesResponseType(Status200OK)]
|
|
||||||
[ProducesResponseType<string>(Status404NotFound)]
|
|
||||||
[ProducesResponseType(Status500InternalServerError)]
|
|
||||||
public IActionResult CreateChapters(string id, [FromBody]Chapter[] chapters)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Manga? ret = context.Manga.Find(id);
|
|
||||||
if(ret is null)
|
|
||||||
return NotFound("Manga could not be found");
|
|
||||||
if(chapters.All(c => c.ParentManga.MangaId == ret.MangaId))
|
|
||||||
return BadRequest("Chapters belong to different Manga.");
|
|
||||||
|
|
||||||
context.Chapters.AddRange(chapters);
|
|
||||||
context.SaveChanges();
|
|
||||||
return Ok();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
return StatusCode(500, e.Message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the latest Chapter of requested Manga
|
/// Returns the latest Chapter of requested Manga
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -9,11 +9,4 @@ public class Author(string authorName)
|
|||||||
[MaxLength(64)]
|
[MaxLength(64)]
|
||||||
public string AuthorId { get; init; } = TokenGen.CreateToken(typeof(Author), 64);
|
public string AuthorId { get; init; } = TokenGen.CreateToken(typeof(Author), 64);
|
||||||
public string AuthorName { get; init; } = authorName;
|
public string AuthorName { get; init; } = authorName;
|
||||||
|
|
||||||
public override bool Equals(object? obj)
|
|
||||||
{
|
|
||||||
if (obj is not Author other)
|
|
||||||
return false;
|
|
||||||
return other.AuthorName == AuthorName;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.ComponentModel.DataAnnotations.Schema;
|
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
using API.Schema.Jobs;
|
using API.Schema.Jobs;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
@ -10,4 +10,11 @@ public class Link(string linkProvider, string linkUrl)
|
|||||||
public string LinkId { get; init; } = TokenGen.CreateToken(typeof(Link), 64);
|
public string LinkId { get; init; } = TokenGen.CreateToken(typeof(Link), 64);
|
||||||
public string LinkProvider { get; init; } = linkProvider;
|
public string LinkProvider { get; init; } = linkProvider;
|
||||||
public string LinkUrl { get; init; } = linkUrl;
|
public string LinkUrl { get; init; } = linkUrl;
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (obj is not Link other)
|
||||||
|
return false;
|
||||||
|
return other.LinkProvider == LinkProvider && other.LinkUrl == LinkUrl;
|
||||||
|
}
|
||||||
}
|
}
|
@ -25,10 +25,10 @@ public class Manga(
|
|||||||
Chapter? latestChapterDownloaded,
|
Chapter? latestChapterDownloaded,
|
||||||
Chapter? latestChapterAvailable,
|
Chapter? latestChapterAvailable,
|
||||||
MangaConnector mangaConnector,
|
MangaConnector mangaConnector,
|
||||||
Author[] authors,
|
ICollection<Author> authors,
|
||||||
MangaTag[] tags,
|
ICollection<MangaTag> tags,
|
||||||
Link[] links,
|
ICollection<Link> links,
|
||||||
MangaAltTitle[] altTitles)
|
ICollection<MangaAltTitle> altTitles)
|
||||||
{
|
{
|
||||||
[MaxLength(64)]
|
[MaxLength(64)]
|
||||||
public string MangaId { get; init; } = TokenGen.CreateToken(typeof(Manga), 64);
|
public string MangaId { get; init; } = TokenGen.CreateToken(typeof(Manga), 64);
|
||||||
@ -57,13 +57,11 @@ public class Manga(
|
|||||||
|
|
||||||
public ICollection<Author> Authors { get; internal set; } = authors;
|
public ICollection<Author> Authors { get; internal set; } = authors;
|
||||||
|
|
||||||
public ICollection<MangaTag> Tags { get; private set; } = tags;
|
public ICollection<MangaTag> Tags { get; internal set; } = tags;
|
||||||
|
|
||||||
[ForeignKey("LinkIds")]
|
public ICollection<Link> Links { get; internal set; } = links;
|
||||||
public ICollection<Link> Links { get; private set; } = links;
|
|
||||||
|
|
||||||
[ForeignKey("AltTitleIds")]
|
public ICollection<MangaAltTitle> AltTitles { get; internal set; } = altTitles;
|
||||||
public ICollection<MangaAltTitle> AltTitles { get; private set; } = altTitles;
|
|
||||||
|
|
||||||
public Manga(string connectorId, string name, string description, string websiteUrl, string coverUrl,
|
public Manga(string connectorId, string name, string description, string websiteUrl, string coverUrl,
|
||||||
string? coverFileNameInCache,
|
string? coverFileNameInCache,
|
||||||
|
@ -12,7 +12,7 @@ public class AsuraToon : MangaConnector
|
|||||||
this.downloadClient = new ChromiumDownloadClient();
|
this.downloadClient = new ChromiumDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
|
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
|
||||||
string requestUrl = $"https://asuracomic.net/series?name={sanitizedTitle}";
|
string requestUrl = $"https://asuracomic.net/series?name={sanitizedTitle}";
|
||||||
@ -26,16 +26,16 @@ public class AsuraToon : MangaConnector
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://asuracomic.net/series/{publicationId}");
|
return GetMangaFromUrl($"https://asuracomic.net/series/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
RequestResult requestResult = downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
RequestResult requestResult = downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
||||||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300)
|
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300)
|
||||||
@ -47,7 +47,7 @@ public class AsuraToon : MangaConnector
|
|||||||
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^1], url);
|
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^1], url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
HtmlNodeCollection mangaList = document.DocumentNode.SelectNodes("//a[starts-with(@href,'series')]");
|
HtmlNodeCollection mangaList = document.DocumentNode.SelectNodes("//a[starts-with(@href,'series')]");
|
||||||
if (mangaList is null || mangaList.Count < 1)
|
if (mangaList is null || mangaList.Count < 1)
|
||||||
@ -55,10 +55,10 @@ public class AsuraToon : MangaConnector
|
|||||||
|
|
||||||
IEnumerable<string> urls = mangaList.Select(a => $"https://asuracomic.net/{a.GetAttributeValue("href", "")}");
|
IEnumerable<string> urls = mangaList.Select(a => $"https://asuracomic.net/{a.GetAttributeValue("href", "")}");
|
||||||
|
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl(url);
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -66,14 +66,14 @@ public class AsuraToon : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
string? originalLanguage = null;
|
string? originalLanguage = null;
|
||||||
Dictionary<string, string> altTitles = new(), links = new();
|
Dictionary<string, string> altTitles = new(), links = new();
|
||||||
|
|
||||||
HtmlNodeCollection genreNodes = document.DocumentNode.SelectNodes("//h3[text()='Genres']/../div/button");
|
HtmlNodeCollection genreNodes = document.DocumentNode.SelectNodes("//h3[text()='Genres']/../div/button");
|
||||||
string[] tags = genreNodes.Select(b => b.InnerText).ToArray();
|
string[] tags = genreNodes.Select(b => b.InnerText).ToArray();
|
||||||
MangaTag[] mangaTags = tags.Select(t => new MangaTag(t)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(t => new MangaTag(t)).ToList();
|
||||||
|
|
||||||
HtmlNode statusNode = document.DocumentNode.SelectSingleNode("//h3[text()='Status']/../h3[2]");
|
HtmlNode statusNode = document.DocumentNode.SelectSingleNode("//h3[text()='Status']/../h3[2]");
|
||||||
MangaReleaseStatus releaseStatus = statusNode.InnerText.ToLower() switch
|
MangaReleaseStatus releaseStatus = statusNode.InnerText.ToLower() switch
|
||||||
@ -104,7 +104,7 @@ public class AsuraToon : MangaConnector
|
|||||||
IEnumerable<string> authorNames = authorNodes is null ? [] : authorNodes.Select(a => a.InnerText);
|
IEnumerable<string> authorNames = authorNodes is null ? [] : authorNodes.Select(a => a.InnerText);
|
||||||
IEnumerable<string> artistNames = artistNodes is null ? [] : artistNodes.Select(a => a.InnerText);
|
IEnumerable<string> artistNames = artistNodes is null ? [] : artistNodes.Select(a => a.InnerText);
|
||||||
List<string> authorStrings = authorNames.Concat(artistNames).ToList();
|
List<string> authorStrings = authorNames.Concat(artistNames).ToList();
|
||||||
Author[] authors = authorStrings.Select(author => new Author(author)).ToArray();
|
List<Author> authors = authorStrings.Select(author => new Author(author)).ToList();
|
||||||
|
|
||||||
HtmlNode? firstChapterNode = document.DocumentNode.SelectSingleNode("//a[contains(@href, 'chapter/1')]/../following-sibling::h3");
|
HtmlNode? firstChapterNode = document.DocumentNode.SelectSingleNode("//a[contains(@href, 'chapter/1')]/../following-sibling::h3");
|
||||||
uint year = uint.Parse(firstChapterNode?.InnerText.Split(' ')[^1] ?? "2000");
|
uint year = uint.Parse(firstChapterNode?.InnerText.Split(' ')[^1] ?? "2000");
|
||||||
|
@ -13,7 +13,7 @@ public class Bato : MangaConnector
|
|||||||
this.downloadClient = new HttpDownloadClient();
|
this.downloadClient = new HttpDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
|
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
|
||||||
string requestUrl = $"https://bato.to/v3x-search?word={sanitizedTitle}&lang=en";
|
string requestUrl = $"https://bato.to/v3x-search?word={sanitizedTitle}&lang=en";
|
||||||
@ -27,16 +27,16 @@ public class Bato : MangaConnector
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://bato.to/title/{publicationId}");
|
return GetMangaFromUrl($"https://bato.to/title/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
RequestResult requestResult = downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
RequestResult requestResult = downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
||||||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300)
|
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300)
|
||||||
@ -48,7 +48,7 @@ public class Bato : MangaConnector
|
|||||||
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^1], url);
|
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^1], url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
HtmlNode mangaList = document.DocumentNode.SelectSingleNode("//div[@data-hk='0-0-2']");
|
HtmlNode mangaList = document.DocumentNode.SelectSingleNode("//div[@data-hk='0-0-2']");
|
||||||
if (!mangaList.ChildNodes.Any(node => node.Name == "div"))
|
if (!mangaList.ChildNodes.Any(node => node.Name == "div"))
|
||||||
@ -57,10 +57,10 @@ public class Bato : MangaConnector
|
|||||||
List<string> urls = mangaList.ChildNodes
|
List<string> urls = mangaList.ChildNodes
|
||||||
.Select(node => $"https://bato.to{node.Descendants("div").First().FirstChild.GetAttributeValue("href", "")}").ToList();
|
.Select(node => $"https://bato.to{node.Descendants("div").First().FirstChild.GetAttributeValue("href", "")}").ToList();
|
||||||
|
|
||||||
HashSet<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
HashSet<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl(url);
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -68,7 +68,7 @@ public class Bato : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
HtmlNode infoNode = document.DocumentNode.SelectSingleNode("/html/body/div/main/div[1]/div[2]");
|
HtmlNode infoNode = document.DocumentNode.SelectSingleNode("/html/body/div/main/div[1]/div[2]");
|
||||||
|
|
||||||
@ -78,18 +78,18 @@ public class Bato : MangaConnector
|
|||||||
|
|
||||||
string[] altTitlesList = infoNode.ChildNodes[1].ChildNodes[2].InnerText.Split('/');
|
string[] altTitlesList = infoNode.ChildNodes[1].ChildNodes[2].InnerText.Split('/');
|
||||||
int i = 0;
|
int i = 0;
|
||||||
MangaAltTitle[] altTitles = altTitlesList.Select(a => new MangaAltTitle(i++.ToString(), a)).ToArray();
|
List<MangaAltTitle> altTitles = altTitlesList.Select(a => new MangaAltTitle(i++.ToString(), a)).ToList();
|
||||||
|
|
||||||
string coverUrl = document.DocumentNode.SelectNodes("//img")
|
string coverUrl = document.DocumentNode.SelectNodes("//img")
|
||||||
.First(child => child.GetAttributeValue("data-hk", "") == "0-1-0").GetAttributeValue("src", "").Replace("&", "&");
|
.First(child => child.GetAttributeValue("data-hk", "") == "0-1-0").GetAttributeValue("src", "").Replace("&", "&");
|
||||||
|
|
||||||
List<HtmlNode> genreNodes = document.DocumentNode.SelectSingleNode("//b[text()='Genres:']/..").SelectNodes("span").ToList();
|
List<HtmlNode> genreNodes = document.DocumentNode.SelectSingleNode("//b[text()='Genres:']/..").SelectNodes("span").ToList();
|
||||||
string[] tags = genreNodes.Select(node => node.FirstChild.InnerText).ToArray();
|
string[] tags = genreNodes.Select(node => node.FirstChild.InnerText).ToArray();
|
||||||
MangaTag[] mangaTags = tags.Select(s => new MangaTag(s)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(s => new MangaTag(s)).ToList();
|
||||||
|
|
||||||
List<HtmlNode> authorsNodes = infoNode.ChildNodes[1].ChildNodes[3].Descendants("a").ToList();
|
List<HtmlNode> authorsNodes = infoNode.ChildNodes[1].ChildNodes[3].Descendants("a").ToList();
|
||||||
List<string> authorNames = authorsNodes.Select(node => node.InnerText.Replace("amp;", "")).ToList();
|
List<string> authorNames = authorsNodes.Select(node => node.InnerText.Replace("amp;", "")).ToList();
|
||||||
Author[] authors = authorNames.Select(n => new Author(n)).ToArray();
|
List<Author> authors = authorNames.Select(n => new Author(n)).ToList();
|
||||||
|
|
||||||
HtmlNode? originalLanguageNode = document.DocumentNode.SelectSingleNode("//span[text()='Tr From']/..");
|
HtmlNode? originalLanguageNode = document.DocumentNode.SelectSingleNode("//span[text()='Tr From']/..");
|
||||||
string originalLanguage = originalLanguageNode is not null ? originalLanguageNode.LastChild.InnerText : "";
|
string originalLanguage = originalLanguageNode is not null ? originalLanguageNode.LastChild.InnerText : "";
|
||||||
|
@ -14,11 +14,11 @@ public abstract class MangaConnector(string name, string[] supportedLanguages, s
|
|||||||
public string[] SupportedLanguages { get; init; } = supportedLanguages;
|
public string[] SupportedLanguages { get; init; } = supportedLanguages;
|
||||||
public string[] BaseUris { get; init; } = baseUris;
|
public string[] BaseUris { get; init; } = baseUris;
|
||||||
|
|
||||||
public abstract (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "");
|
public abstract (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "");
|
||||||
|
|
||||||
public abstract (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url);
|
public abstract (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url);
|
||||||
|
|
||||||
public abstract (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId);
|
public abstract (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId);
|
||||||
|
|
||||||
public abstract Chapter[] GetChapters(Manga manga, string language="en");
|
public abstract Chapter[] GetChapters(Manga manga, string language="en");
|
||||||
|
|
||||||
|
@ -16,12 +16,12 @@ public class MangaDex : MangaConnector
|
|||||||
this.downloadClient = new HttpDownloadClient();
|
this.downloadClient = new HttpDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
const int limit = 100; //How many values we want returned at once
|
const int limit = 100; //How many values we want returned at once
|
||||||
int offset = 0; //"Page"
|
int offset = 0; //"Page"
|
||||||
int total = int.MaxValue; //How many total results are there, is updated on first request
|
int total = int.MaxValue; //How many total results are there, is updated on first request
|
||||||
HashSet<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> retManga = new();
|
HashSet<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> retManga = new();
|
||||||
int loadedPublicationData = 0;
|
int loadedPublicationData = 0;
|
||||||
List<JsonNode> results = new();
|
List<JsonNode> results = new();
|
||||||
|
|
||||||
@ -59,7 +59,7 @@ public class MangaDex : MangaConnector
|
|||||||
return retManga.ToArray();
|
return retManga.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
RequestResult requestResult =
|
RequestResult requestResult =
|
||||||
downloadClient.MakeRequest($"https://api.mangadex.org/manga/{publicationId}?includes%5B%5D=manga&includes%5B%5D=cover_art&includes%5B%5D=author&includes%5B%5D=artist&includes%5B%5D=tag", RequestType.MangaInfo);
|
downloadClient.MakeRequest($"https://api.mangadex.org/manga/{publicationId}?includes%5B%5D=manga&includes%5B%5D=cover_art&includes%5B%5D=author&includes%5B%5D=artist&includes%5B%5D=tag", RequestType.MangaInfo);
|
||||||
@ -71,14 +71,14 @@ public class MangaDex : MangaConnector
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
Regex idRex = new (@"https:\/\/mangadex.org\/title\/([A-z0-9-]*)\/.*");
|
Regex idRex = new (@"https:\/\/mangadex.org\/title\/([A-z0-9-]*)\/.*");
|
||||||
string id = idRex.Match(url).Groups[1].Value;
|
string id = idRex.Match(url).Groups[1].Value;
|
||||||
return GetMangaFromId(id);
|
return GetMangaFromId(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? MangaFromJsonObject(JsonObject manga)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? MangaFromJsonObject(JsonObject manga)
|
||||||
{
|
{
|
||||||
if (!manga.TryGetPropertyValue("id", out JsonNode? idNode))
|
if (!manga.TryGetPropertyValue("id", out JsonNode? idNode))
|
||||||
return null;
|
return null;
|
||||||
@ -105,7 +105,7 @@ public class MangaDex : MangaConnector
|
|||||||
altTitlesDict.TryAdd(altTitleNodeObject.First().Key, altTitleNodeObject.First().Value!.GetValue<string>());
|
altTitlesDict.TryAdd(altTitleNodeObject.First().Key, altTitleNodeObject.First().Value!.GetValue<string>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MangaAltTitle[] altTitles = altTitlesDict.Select(t => new MangaAltTitle(t.Key, t.Value)).ToArray();
|
List<MangaAltTitle> altTitles = altTitlesDict.Select(t => new MangaAltTitle(t.Key, t.Value)).ToList();
|
||||||
|
|
||||||
if (!attributes.TryGetPropertyValue("description", out JsonNode? descriptionNode))
|
if (!attributes.TryGetPropertyValue("description", out JsonNode? descriptionNode))
|
||||||
return null;
|
return null;
|
||||||
@ -119,7 +119,7 @@ public class MangaDex : MangaConnector
|
|||||||
if (attributes.TryGetPropertyValue("links", out JsonNode? linksNode) && linksNode is not null)
|
if (attributes.TryGetPropertyValue("links", out JsonNode? linksNode) && linksNode is not null)
|
||||||
foreach (KeyValuePair<string, JsonNode?> linkKv in linksNode!.AsObject())
|
foreach (KeyValuePair<string, JsonNode?> linkKv in linksNode!.AsObject())
|
||||||
linksDict.TryAdd(linkKv.Key, linkKv.Value.GetValue<string>());
|
linksDict.TryAdd(linkKv.Key, linkKv.Value.GetValue<string>());
|
||||||
Link[] links = linksDict.Select(x => new Link(x.Key, x.Value)).ToArray();
|
List<Link> links = linksDict.Select(x => new Link(x.Key, x.Value)).ToList();
|
||||||
|
|
||||||
string? originalLanguage =
|
string? originalLanguage =
|
||||||
attributes.TryGetPropertyValue("originalLanguage", out JsonNode? originalLanguageNode) switch
|
attributes.TryGetPropertyValue("originalLanguage", out JsonNode? originalLanguageNode) switch
|
||||||
@ -151,7 +151,7 @@ public class MangaDex : MangaConnector
|
|||||||
if (attributes.TryGetPropertyValue("tags", out JsonNode? tagsNode))
|
if (attributes.TryGetPropertyValue("tags", out JsonNode? tagsNode))
|
||||||
foreach (JsonNode? tagNode in tagsNode!.AsArray())
|
foreach (JsonNode? tagNode in tagsNode!.AsArray())
|
||||||
tags.Add(tagNode!["attributes"]!["name"]!["en"]!.GetValue<string>());
|
tags.Add(tagNode!["attributes"]!["name"]!["en"]!.GetValue<string>());
|
||||||
MangaTag[] mangaTags = tags.Select(t => new MangaTag(t)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(t => new MangaTag(t)).ToList();
|
||||||
|
|
||||||
if (!manga.TryGetPropertyValue("relationships", out JsonNode? relationshipsNode))
|
if (!manga.TryGetPropertyValue("relationships", out JsonNode? relationshipsNode))
|
||||||
return null;
|
return null;
|
||||||
@ -172,7 +172,7 @@ public class MangaDex : MangaConnector
|
|||||||
if(!authorNames.Contains(authorName))
|
if(!authorNames.Contains(authorName))
|
||||||
authorNames.Add(authorName);
|
authorNames.Add(authorName);
|
||||||
}
|
}
|
||||||
Author[] authors = authorNames.Select(a => new Author(a)).ToArray();
|
List<Author> authors = authorNames.Select(a => new Author(a)).ToList();
|
||||||
|
|
||||||
Manga pub = new (publicationId, sortName, description, $"https://mangadex.org/title/{publicationId}", coverUrl, null, year,
|
Manga pub = new (publicationId, sortName, description, $"https://mangadex.org/title/{publicationId}", coverUrl, null, year,
|
||||||
originalLanguage, releaseStatus, -1, null, null,
|
originalLanguage, releaseStatus, -1, null, null,
|
||||||
|
@ -11,7 +11,7 @@ public class MangaHere : MangaConnector
|
|||||||
this.downloadClient = new ChromiumDownloadClient();
|
this.downloadClient = new ChromiumDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = string.Join('+', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
string sanitizedTitle = string.Join('+', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
||||||
string requestUrl = $"https://www.mangahere.cc/search?title={sanitizedTitle}";
|
string requestUrl = $"https://www.mangahere.cc/search?title={sanitizedTitle}";
|
||||||
@ -20,11 +20,11 @@ public class MangaHere : MangaConnector
|
|||||||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300 || requestResult.htmlDocument is null)
|
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300 || requestResult.htmlDocument is null)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
if (document.DocumentNode.SelectNodes("//div[contains(concat(' ',normalize-space(@class),' '),' container ')]").Any(node => node.ChildNodes.Any(cNode => cNode.HasClass("search-keywords"))))
|
if (document.DocumentNode.SelectNodes("//div[contains(concat(' ',normalize-space(@class),' '),' container ')]").Any(node => node.ChildNodes.Any(cNode => cNode.HasClass("search-keywords"))))
|
||||||
return [];
|
return [];
|
||||||
@ -33,10 +33,10 @@ public class MangaHere : MangaConnector
|
|||||||
.SelectNodes("//a[contains(@href, '/manga/') and not(contains(@href, '.html'))]")
|
.SelectNodes("//a[contains(@href, '/manga/') and not(contains(@href, '.html'))]")
|
||||||
.Select(thumb => $"https://www.mangahere.cc{thumb.GetAttributeValue("href", "")}").Distinct().ToList();
|
.Select(thumb => $"https://www.mangahere.cc{thumb.GetAttributeValue("href", "")}").Distinct().ToList();
|
||||||
|
|
||||||
HashSet<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
HashSet<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl(url);
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -44,12 +44,12 @@ public class MangaHere : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://www.mangahere.cc/manga/{publicationId}");
|
return GetMangaFromUrl($"https://www.mangahere.cc/manga/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
RequestResult requestResult =
|
RequestResult requestResult =
|
||||||
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
||||||
@ -61,7 +61,7 @@ public class MangaHere : MangaConnector
|
|||||||
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, id, url);
|
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, id, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
string originalLanguage = "", status = "";
|
string originalLanguage = "", status = "";
|
||||||
Dictionary<string, string> altTitles = new(), links = new();
|
Dictionary<string, string> altTitles = new(), links = new();
|
||||||
@ -77,13 +77,13 @@ public class MangaHere : MangaConnector
|
|||||||
.SelectNodes("//p[contains(concat(' ',normalize-space(@class),' '),' detail-info-right-say ')]/a")
|
.SelectNodes("//p[contains(concat(' ',normalize-space(@class),' '),' detail-info-right-say ')]/a")
|
||||||
.Select(node => node.InnerText)
|
.Select(node => node.InnerText)
|
||||||
.ToList();
|
.ToList();
|
||||||
Author[] authors = authorNames.Select(n => new Author(n)).ToArray();
|
List<Author> authors = authorNames.Select(n => new Author(n)).ToList();
|
||||||
|
|
||||||
HashSet<string> tags = document.DocumentNode
|
HashSet<string> tags = document.DocumentNode
|
||||||
.SelectNodes("//p[contains(concat(' ',normalize-space(@class),' '),' detail-info-right-tag-list ')]/a")
|
.SelectNodes("//p[contains(concat(' ',normalize-space(@class),' '),' detail-info-right-tag-list ')]/a")
|
||||||
.Select(node => node.InnerText)
|
.Select(node => node.InnerText)
|
||||||
.ToHashSet();
|
.ToHashSet();
|
||||||
MangaTag[] mangaTags = tags.Select(n => new MangaTag(n)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(n => new MangaTag(n)).ToList();
|
||||||
|
|
||||||
status = document.DocumentNode.SelectSingleNode("//span[contains(concat(' ',normalize-space(@class),' '),' detail-info-right-title-tip ')]").InnerText;
|
status = document.DocumentNode.SelectSingleNode("//span[contains(concat(' ',normalize-space(@class),' '),' detail-info-right-title-tip ')]").InnerText;
|
||||||
switch (status.ToLower())
|
switch (status.ToLower())
|
||||||
|
@ -11,7 +11,7 @@ public class MangaKatana : MangaConnector
|
|||||||
this.downloadClient = new HttpDownloadClient();
|
this.downloadClient = new HttpDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = string.Join("%20", Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
|
string sanitizedTitle = string.Join("%20", Regex.Matches(publicationTitle, "[A-z]*").Where(m => m.Value.Length > 0)).ToLower();
|
||||||
string requestUrl = $"https://mangakatana.com/?search={sanitizedTitle}&search_by=book_name";
|
string requestUrl = $"https://mangakatana.com/?search={sanitizedTitle}&search_by=book_name";
|
||||||
@ -29,16 +29,16 @@ public class MangaKatana : MangaConnector
|
|||||||
return new [] { ParseSinglePublicationFromHtml(requestResult.result, requestResult.redirectedToUrl.Split('/')[^1], requestResult.redirectedToUrl) };
|
return new [] { ParseSinglePublicationFromHtml(requestResult.result, requestResult.redirectedToUrl.Split('/')[^1], requestResult.redirectedToUrl) };
|
||||||
}
|
}
|
||||||
|
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.result);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.result);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://mangakatana.com/manga/{publicationId}");
|
return GetMangaFromUrl($"https://mangakatana.com/manga/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
RequestResult requestResult =
|
RequestResult requestResult =
|
||||||
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
||||||
@ -47,7 +47,7 @@ public class MangaKatana : MangaConnector
|
|||||||
return ParseSinglePublicationFromHtml(requestResult.result, url.Split('/')[^1], url);
|
return ParseSinglePublicationFromHtml(requestResult.result, url.Split('/')[^1], url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(Stream html)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(Stream html)
|
||||||
{
|
{
|
||||||
StreamReader reader = new(html);
|
StreamReader reader = new(html);
|
||||||
string htmlString = reader.ReadToEnd();
|
string htmlString = reader.ReadToEnd();
|
||||||
@ -63,10 +63,10 @@ public class MangaKatana : MangaConnector
|
|||||||
.First(a => a.Name == "href").Value);
|
.First(a => a.Name == "href").Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
HashSet<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
HashSet<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl(url);
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -74,7 +74,7 @@ public class MangaKatana : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(Stream html, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(Stream html, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
StreamReader reader = new(html);
|
StreamReader reader = new(html);
|
||||||
string htmlString = reader.ReadToEnd();
|
string htmlString = reader.ReadToEnd();
|
||||||
@ -135,9 +135,9 @@ public class MangaKatana : MangaConnector
|
|||||||
{
|
{
|
||||||
year = uint.Parse(yearString);
|
year = uint.Parse(yearString);
|
||||||
}
|
}
|
||||||
Author[] authors = authorNames.Select(n => new Author(n)).ToArray();
|
List<Author> authors = authorNames.Select(n => new Author(n)).ToList();
|
||||||
MangaTag[] mangaTags = tags.Select(n => new MangaTag(n)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(n => new MangaTag(n)).ToList();
|
||||||
MangaAltTitle[] altTitles = altTitlesDict.Select(x => new MangaAltTitle(x.Key, x.Value)).ToArray();
|
List<MangaAltTitle> altTitles = altTitlesDict.Select(x => new MangaAltTitle(x.Key, x.Value)).ToList();
|
||||||
|
|
||||||
Manga manga = new (publicationId, sortName, description, websiteUrl, coverUrl, null, year,
|
Manga manga = new (publicationId, sortName, description, websiteUrl, coverUrl, null, year,
|
||||||
originalLanguage, releaseStatus, -1, null, null,
|
originalLanguage, releaseStatus, -1, null, null,
|
||||||
|
@ -12,7 +12,7 @@ public class MangaLife : MangaConnector
|
|||||||
this.downloadClient = new ChromiumDownloadClient();
|
this.downloadClient = new ChromiumDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = WebUtility.UrlEncode(publicationTitle);
|
string sanitizedTitle = WebUtility.UrlEncode(publicationTitle);
|
||||||
string requestUrl = $"https://manga4life.com/search/?name={sanitizedTitle}";
|
string requestUrl = $"https://manga4life.com/search/?name={sanitizedTitle}";
|
||||||
@ -23,16 +23,16 @@ public class MangaLife : MangaConnector
|
|||||||
|
|
||||||
if (requestResult.htmlDocument is null)
|
if (requestResult.htmlDocument is null)
|
||||||
return [];
|
return [];
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://manga4life.com/manga/{publicationId}");
|
return GetMangaFromUrl($"https://manga4life.com/manga/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
Regex publicationIdRex = new(@"https:\/\/(www\.)?manga4life.com\/manga\/(.*)(\/.*)*");
|
Regex publicationIdRex = new(@"https:\/\/(www\.)?manga4life.com\/manga\/(.*)(\/.*)*");
|
||||||
string publicationId = publicationIdRex.Match(url).Groups[2].Value;
|
string publicationId = publicationIdRex.Match(url).Groups[2].Value;
|
||||||
@ -43,7 +43,7 @@ public class MangaLife : MangaConnector
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
HtmlNode resultsNode = document.DocumentNode.SelectSingleNode("//div[@class='BoxBody']/div[last()]/div[1]/div");
|
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"))
|
if (resultsNode.Descendants("div").Count() == 1 && resultsNode.Descendants("div").First().HasClass("NoResults"))
|
||||||
@ -51,12 +51,12 @@ public class MangaLife : MangaConnector
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
|
|
||||||
foreach (HtmlNode resultNode in resultsNode.SelectNodes("div"))
|
foreach (HtmlNode resultNode in resultsNode.SelectNodes("div"))
|
||||||
{
|
{
|
||||||
string url = resultNode.Descendants().First(d => d.HasClass("SeriesName")).GetAttributeValue("href", "");
|
string url = resultNode.Descendants().First(d => d.HasClass("SeriesName")).GetAttributeValue("href", "");
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl($"https://manga4life.com{url}");
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl($"https://manga4life.com{url}");
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -65,7 +65,7 @@ public class MangaLife : MangaConnector
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
string originalLanguage = "", status = "";
|
string originalLanguage = "", status = "";
|
||||||
Dictionary<string, string> altTitles = new(), links = new();
|
Dictionary<string, string> altTitles = new(), links = new();
|
||||||
@ -84,14 +84,14 @@ public class MangaLife : MangaConnector
|
|||||||
List<string> authorNames = new();
|
List<string> authorNames = new();
|
||||||
foreach (HtmlNode authorNode in authorsNodes)
|
foreach (HtmlNode authorNode in authorsNodes)
|
||||||
authorNames.Add(authorNode.InnerText);
|
authorNames.Add(authorNode.InnerText);
|
||||||
Author[] authors = authorNames.Select(a => new Author(a)).ToArray();
|
List<Author> authors = authorNames.Select(a => new Author(a)).ToList();
|
||||||
|
|
||||||
HtmlNode[] genreNodes = document.DocumentNode
|
HtmlNode[] genreNodes = document.DocumentNode
|
||||||
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Genre(s):']/..").Descendants("a")
|
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Genre(s):']/..").Descendants("a")
|
||||||
.ToArray();
|
.ToArray();
|
||||||
foreach (HtmlNode genreNode in genreNodes)
|
foreach (HtmlNode genreNode in genreNodes)
|
||||||
tags.Add(genreNode.InnerText);
|
tags.Add(genreNode.InnerText);
|
||||||
MangaTag[] mangaTags = tags.Select(t => new MangaTag(t)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(t => new MangaTag(t)).ToList();
|
||||||
|
|
||||||
HtmlNode yearNode = document.DocumentNode
|
HtmlNode yearNode = document.DocumentNode
|
||||||
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Released:']/..").Descendants("a")
|
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Released:']/..").Descendants("a")
|
||||||
|
@ -13,7 +13,7 @@ public class Manganato : MangaConnector
|
|||||||
this.downloadClient = new HttpDownloadClient();
|
this.downloadClient = new HttpDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = string.Join('_', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
string sanitizedTitle = string.Join('_', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
||||||
string requestUrl = $"https://manganato.com/search/story/{sanitizedTitle}";
|
string requestUrl = $"https://manganato.com/search/story/{sanitizedTitle}";
|
||||||
@ -21,11 +21,11 @@ public class Manganato : MangaConnector
|
|||||||
downloadClient.MakeRequest(requestUrl, RequestType.Default);
|
downloadClient.MakeRequest(requestUrl, RequestType.Default);
|
||||||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300 ||requestResult.htmlDocument is null)
|
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300 ||requestResult.htmlDocument is null)
|
||||||
return [];
|
return [];
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
List<HtmlNode> searchResults = document.DocumentNode.Descendants("div").Where(n => n.HasClass("search-story-item")).ToList();
|
List<HtmlNode> searchResults = document.DocumentNode.Descendants("div").Where(n => n.HasClass("search-story-item")).ToList();
|
||||||
List<string> urls = new();
|
List<string> urls = new();
|
||||||
@ -35,10 +35,10 @@ public class Manganato : MangaConnector
|
|||||||
.First(a => a.Name == "href").Value);
|
.First(a => a.Name == "href").Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl(url);
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -46,12 +46,12 @@ public class Manganato : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://chapmanganato.com/{publicationId}");
|
return GetMangaFromUrl($"https://chapmanganato.com/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
RequestResult requestResult =
|
RequestResult requestResult =
|
||||||
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
||||||
@ -63,7 +63,7 @@ public class Manganato : MangaConnector
|
|||||||
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^1], url);
|
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, url.Split('/')[^1], url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> altTitlesDict = new();
|
Dictionary<string, string> altTitlesDict = new();
|
||||||
Dictionary<string, string>? links = null;
|
Dictionary<string, string>? links = null;
|
||||||
@ -111,9 +111,9 @@ public class Manganato : MangaConnector
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Author[] authors = authorNames.Select(n => new Author(n)).ToArray();
|
List<Author> authors = authorNames.Select(n => new Author(n)).ToList();
|
||||||
MangaTag[] mangaTags = tags.Select(n => new MangaTag(n)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(n => new MangaTag(n)).ToList();
|
||||||
MangaAltTitle[] mangaAltTitles = altTitlesDict.Select(a => new MangaAltTitle(a.Key, a.Value)).ToArray();
|
List<MangaAltTitle> mangaAltTitles = altTitlesDict.Select(a => new MangaAltTitle(a.Key, a.Value)).ToList();
|
||||||
|
|
||||||
string coverUrl = document.DocumentNode.Descendants("span").First(s => s.HasClass("info-image")).Descendants("img").First()
|
string coverUrl = 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;
|
||||||
|
@ -23,7 +23,7 @@ public class Mangasee : MangaConnector
|
|||||||
public string[] a { get; set; }
|
public string[] a { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string requestUrl = "https://mangasee123.com/_search.php";
|
string requestUrl = "https://mangasee123.com/_search.php";
|
||||||
RequestResult requestResult =
|
RequestResult requestResult =
|
||||||
@ -41,10 +41,10 @@ public class Mangasee : MangaConnector
|
|||||||
|
|
||||||
|
|
||||||
string[] urls = filteredResults.Select(result => $"https://mangasee123.com/manga/{result.i}").ToArray();
|
string[] urls = filteredResults.Select(result => $"https://mangasee123.com/manga/{result.i}").ToArray();
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> searchResultManga = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> searchResultManga = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? newManga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? newManga = GetMangaFromUrl(url);
|
||||||
if(newManga is { } manga)
|
if(newManga is { } manga)
|
||||||
searchResultManga.Add(manga);
|
searchResultManga.Add(manga);
|
||||||
}
|
}
|
||||||
@ -79,12 +79,12 @@ public class Mangasee : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://mangasee123.com/manga/{publicationId}");
|
return GetMangaFromUrl($"https://mangasee123.com/manga/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
Regex publicationIdRex = new(@"https:\/\/mangasee123.com\/manga\/(.*)(\/.*)*");
|
Regex publicationIdRex = new(@"https:\/\/mangasee123.com\/manga\/(.*)(\/.*)*");
|
||||||
string publicationId = publicationIdRex.Match(url).Groups[1].Value;
|
string publicationId = publicationIdRex.Match(url).Groups[1].Value;
|
||||||
@ -95,7 +95,7 @@ public class Mangasee : MangaConnector
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
string originalLanguage = "", status = "";
|
string originalLanguage = "", status = "";
|
||||||
Dictionary<string, string> altTitles = new(), links = new();
|
Dictionary<string, string> altTitles = new(), links = new();
|
||||||
@ -114,14 +114,14 @@ public class Mangasee : MangaConnector
|
|||||||
List<string> authorNames = new();
|
List<string> authorNames = new();
|
||||||
foreach (HtmlNode authorNode in authorsNodes)
|
foreach (HtmlNode authorNode in authorsNodes)
|
||||||
authorNames.Add(authorNode.InnerText);
|
authorNames.Add(authorNode.InnerText);
|
||||||
Author[] authors = authorNames.Select(a => new Author(a)).ToArray();
|
List<Author> authors = authorNames.Select(a => new Author(a)).ToList();
|
||||||
|
|
||||||
HtmlNode[] genreNodes = document.DocumentNode
|
HtmlNode[] genreNodes = document.DocumentNode
|
||||||
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Genre(s):']/..").Descendants("a")
|
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Genre(s):']/..").Descendants("a")
|
||||||
.ToArray();
|
.ToArray();
|
||||||
foreach (HtmlNode genreNode in genreNodes)
|
foreach (HtmlNode genreNode in genreNodes)
|
||||||
tags.Add(genreNode.InnerText);
|
tags.Add(genreNode.InnerText);
|
||||||
MangaTag[] mangaTags = tags.Select(t => new MangaTag(t)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(t => new MangaTag(t)).ToList();
|
||||||
|
|
||||||
HtmlNode yearNode = document.DocumentNode
|
HtmlNode yearNode = document.DocumentNode
|
||||||
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Released:']/..").Descendants("a")
|
.SelectNodes("//div[@class='BoxBody']//div[@class='row']//span[text()='Released:']/..").Descendants("a")
|
||||||
|
@ -12,7 +12,7 @@ public class Mangaworld : MangaConnector
|
|||||||
this.downloadClient = new HttpDownloadClient();
|
this.downloadClient = new HttpDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
||||||
string requestUrl = $"https://www.mangaworld.ac/archive?keyword={sanitizedTitle}";
|
string requestUrl = $"https://www.mangaworld.ac/archive?keyword={sanitizedTitle}";
|
||||||
@ -23,11 +23,11 @@ public class Mangaworld : MangaConnector
|
|||||||
|
|
||||||
if (requestResult.htmlDocument is null)
|
if (requestResult.htmlDocument is null)
|
||||||
return [];
|
return [];
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
if (!document.DocumentNode.SelectSingleNode("//div[@class='comics-grid']").ChildNodes
|
if (!document.DocumentNode.SelectSingleNode("//div[@class='comics-grid']").ChildNodes
|
||||||
.Any(node => node.HasClass("entry")))
|
.Any(node => node.HasClass("entry")))
|
||||||
@ -38,10 +38,10 @@ public class Mangaworld : MangaConnector
|
|||||||
"//div[@class='comics-grid']//div[@class='entry']//a[contains(concat(' ',normalize-space(@class),' '),'thumb')]")
|
"//div[@class='comics-grid']//div[@class='entry']//a[contains(concat(' ',normalize-space(@class),' '),'thumb')]")
|
||||||
.Select(thumb => thumb.GetAttributeValue("href", "")).ToList();
|
.Select(thumb => thumb.GetAttributeValue("href", "")).ToList();
|
||||||
|
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl(url);
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -49,12 +49,12 @@ public class Mangaworld : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://www.mangaworld.ac/manga/{publicationId}");
|
return GetMangaFromUrl($"https://www.mangaworld.ac/manga/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
RequestResult requestResult =
|
RequestResult requestResult =
|
||||||
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
downloadClient.MakeRequest(url, RequestType.MangaInfo);
|
||||||
@ -69,10 +69,9 @@ public class Mangaworld : MangaConnector
|
|||||||
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, id, url);
|
return ParseSinglePublicationFromHtml(requestResult.htmlDocument, id, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
Dictionary<string, string> altTitlesDict = new();
|
Dictionary<string, string> altTitlesDict = new();
|
||||||
Dictionary<string, string>? links = null;
|
|
||||||
string originalLanguage = "";
|
string originalLanguage = "";
|
||||||
MangaReleaseStatus releaseStatus = MangaReleaseStatus.Unreleased;
|
MangaReleaseStatus releaseStatus = MangaReleaseStatus.Unreleased;
|
||||||
|
|
||||||
@ -86,17 +85,17 @@ public class Mangaworld : MangaConnector
|
|||||||
string[] alts = altTitlesNode.InnerText.Split(", ");
|
string[] alts = altTitlesNode.InnerText.Split(", ");
|
||||||
for(int i = 0; i < alts.Length; i++)
|
for(int i = 0; i < alts.Length; i++)
|
||||||
altTitlesDict.Add(i.ToString(), alts[i]);
|
altTitlesDict.Add(i.ToString(), alts[i]);
|
||||||
MangaAltTitle[] altTitles = altTitlesDict.Select(a => new MangaAltTitle(a.Key, a.Value)).ToArray();
|
List<MangaAltTitle> altTitles = altTitlesDict.Select(a => new MangaAltTitle(a.Key, a.Value)).ToList();
|
||||||
|
|
||||||
HtmlNode genresNode =
|
HtmlNode genresNode =
|
||||||
metadata.SelectSingleNode("//span[text()='Generi: ' or text()='Genero: ']/..");
|
metadata.SelectSingleNode("//span[text()='Generi: ' or text()='Genero: ']/..");
|
||||||
HashSet<string> tags = genresNode.SelectNodes("a").Select(node => node.InnerText).ToHashSet();
|
HashSet<string> tags = genresNode.SelectNodes("a").Select(node => node.InnerText).ToHashSet();
|
||||||
MangaTag[] mangaTags = tags.Select(t => new MangaTag(t)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(t => new MangaTag(t)).ToList();
|
||||||
|
|
||||||
HtmlNode authorsNode =
|
HtmlNode authorsNode =
|
||||||
metadata.SelectSingleNode("//span[text()='Autore: ' or text()='Autori: ']/..");
|
metadata.SelectSingleNode("//span[text()='Autore: ' or text()='Autori: ']/..");
|
||||||
string[] authorNames = authorsNode.SelectNodes("a").Select(node => node.InnerText).ToArray();
|
string[] authorNames = authorsNode.SelectNodes("a").Select(node => node.InnerText).ToArray();
|
||||||
Author[] authors = authorNames.Select(n => new Author(n)).ToArray();
|
List<Author> authors = authorNames.Select(n => new Author(n)).ToList();
|
||||||
|
|
||||||
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
|
// ReSharper disable 5 times StringLiteralTypo
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.Net;
|
using System.Text.RegularExpressions;
|
||||||
using System.Text.RegularExpressions;
|
|
||||||
using API.MangaDownloadClients;
|
using API.MangaDownloadClients;
|
||||||
using HtmlAgilityPack;
|
using HtmlAgilityPack;
|
||||||
|
|
||||||
@ -12,7 +11,7 @@ public class ManhuaPlus : MangaConnector
|
|||||||
this.downloadClient = new ChromiumDownloadClient();
|
this.downloadClient = new ChromiumDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
string sanitizedTitle = string.Join(' ', Regex.Matches(publicationTitle, "[A-z]*").Where(str => str.Length > 0)).ToLower();
|
||||||
string requestUrl = $"https://manhuaplus.org/search?keyword={sanitizedTitle}";
|
string requestUrl = $"https://manhuaplus.org/search?keyword={sanitizedTitle}";
|
||||||
@ -21,11 +20,11 @@ public class ManhuaPlus : MangaConnector
|
|||||||
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300 || requestResult.htmlDocument is null)
|
if ((int)requestResult.statusCode < 200 || (int)requestResult.statusCode >= 300 || requestResult.htmlDocument is null)
|
||||||
return [];
|
return [];
|
||||||
|
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] publications = ParsePublicationsFromHtml(requestResult.htmlDocument);
|
||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
if (document.DocumentNode.SelectSingleNode("//h1/../..").ChildNodes//I already want to not.
|
if (document.DocumentNode.SelectSingleNode("//h1/../..").ChildNodes//I already want to not.
|
||||||
.Any(node => node.InnerText.Contains("No manga found")))
|
.Any(node => node.InnerText.Contains("No manga found")))
|
||||||
@ -35,10 +34,10 @@ public class ManhuaPlus : MangaConnector
|
|||||||
.SelectNodes("//h1/../..//a[contains(@href, 'https://manhuaplus.org/manga/') and contains(concat(' ',normalize-space(@class),' '),' clamp ') and not(contains(@href, '/chapter'))]")
|
.SelectNodes("//h1/../..//a[contains(@href, 'https://manhuaplus.org/manga/') and contains(concat(' ',normalize-space(@class),' '),' clamp ') and not(contains(@href, '/chapter'))]")
|
||||||
.Select(mangaNode => mangaNode.GetAttributeValue("href", "")).ToList();
|
.Select(mangaNode => mangaNode.GetAttributeValue("href", "")).ToList();
|
||||||
|
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (string url in urls)
|
foreach (string url in urls)
|
||||||
{
|
{
|
||||||
(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? manga = GetMangaFromUrl(url);
|
(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? manga = GetMangaFromUrl(url);
|
||||||
if (manga is { } x)
|
if (manga is { } x)
|
||||||
ret.Add(x);
|
ret.Add(x);
|
||||||
}
|
}
|
||||||
@ -46,12 +45,12 @@ public class ManhuaPlus : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://manhuaplus.org/manga/{publicationId}");
|
return GetMangaFromUrl($"https://manhuaplus.org/manga/{publicationId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
Regex publicationIdRex = new(@"https:\/\/manhuaplus.org\/manga\/(.*)(\/.*)*");
|
Regex publicationIdRex = new(@"https:\/\/manhuaplus.org\/manga\/(.*)(\/.*)*");
|
||||||
string publicationId = publicationIdRex.Match(url).Groups[1].Value;
|
string publicationId = publicationIdRex.Match(url).Groups[1].Value;
|
||||||
@ -62,7 +61,7 @@ public class ManhuaPlus : MangaConnector
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
string originalLanguage = "", status = "";
|
string originalLanguage = "", status = "";
|
||||||
Dictionary<string, string> altTitles = new(), links = new();
|
Dictionary<string, string> altTitles = new(), links = new();
|
||||||
@ -88,7 +87,7 @@ public class ManhuaPlus : MangaConnector
|
|||||||
catch (ArgumentNullException e)
|
catch (ArgumentNullException e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
Author[] authors = authorNames.Select(a => new Author(a)).ToArray();
|
List<Author> authors = authorNames.Select(a => new Author(a)).ToList();
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -100,7 +99,7 @@ public class ManhuaPlus : MangaConnector
|
|||||||
catch (ArgumentNullException e)
|
catch (ArgumentNullException e)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
MangaTag[] mangaTags = tags.Select(t => new MangaTag(t)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(t => new MangaTag(t)).ToList();
|
||||||
|
|
||||||
Regex yearRex = new(@"(?:[0-9]{1,2}\/){2}([0-9]{2,4}) [0-9]{1,2}:[0-9]{1,2}");
|
Regex yearRex = new(@"(?:[0-9]{1,2}\/){2}([0-9]{2,4}) [0-9]{1,2}:[0-9]{1,2}");
|
||||||
HtmlNode yearNode = document.DocumentNode.SelectSingleNode("//aside//i[contains(concat(' ',normalize-space(@class),' '),' fa-clock ')]/../span");
|
HtmlNode yearNode = document.DocumentNode.SelectSingleNode("//aside//i[contains(concat(' ',normalize-space(@class),' '),' fa-clock ')]/../span");
|
||||||
|
@ -17,7 +17,7 @@ public class Weebcentral : MangaConnector
|
|||||||
downloadClient = new ChromiumDownloadClient();
|
downloadClient = new ChromiumDownloadClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] GetManga(string publicationTitle = "")
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] GetManga(string publicationTitle = "")
|
||||||
{
|
{
|
||||||
const int limit = 32; //How many values we want returned at once
|
const int limit = 32; //How many values we want returned at once
|
||||||
var offset = 0; //"Page"
|
var offset = 0; //"Page"
|
||||||
@ -36,7 +36,7 @@ public class Weebcentral : MangaConnector
|
|||||||
return publications;
|
return publications;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])[] ParsePublicationsFromHtml(HtmlDocument document)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)[] ParsePublicationsFromHtml(HtmlDocument document)
|
||||||
{
|
{
|
||||||
if (document.DocumentNode.SelectNodes("//article") == null)
|
if (document.DocumentNode.SelectNodes("//article") == null)
|
||||||
return [];
|
return [];
|
||||||
@ -44,7 +44,7 @@ public class Weebcentral : MangaConnector
|
|||||||
var urls = document.DocumentNode.SelectNodes("/html/body/article/a[@class='link link-hover']")
|
var urls = document.DocumentNode.SelectNodes("/html/body/article/a[@class='link link-hover']")
|
||||||
.Select(elem => elem.GetAttributeValue("href", "")).ToList();
|
.Select(elem => elem.GetAttributeValue("href", "")).ToList();
|
||||||
|
|
||||||
List<(Manga, Author[], MangaTag[], Link[], MangaAltTitle[])> ret = new();
|
List<(Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)> ret = new();
|
||||||
foreach (var url in urls)
|
foreach (var url in urls)
|
||||||
{
|
{
|
||||||
var manga = GetMangaFromUrl(url);
|
var manga = GetMangaFromUrl(url);
|
||||||
@ -55,7 +55,7 @@ public class Weebcentral : MangaConnector
|
|||||||
return ret.ToArray();
|
return ret.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromUrl(string url)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromUrl(string url)
|
||||||
{
|
{
|
||||||
Regex publicationIdRex = new(@"https:\/\/weebcentral\.com\/series\/(\w*)\/(.*)");
|
Regex publicationIdRex = new(@"https:\/\/weebcentral\.com\/series\/(\w*)\/(.*)");
|
||||||
var publicationId = publicationIdRex.Match(url).Groups[1].Value;
|
var publicationId = publicationIdRex.Match(url).Groups[1].Value;
|
||||||
@ -67,7 +67,7 @@ public class Weebcentral : MangaConnector
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private (Manga, Author[], MangaTag[], Link[], MangaAltTitle[]) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
private (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?) ParseSinglePublicationFromHtml(HtmlDocument document, string publicationId, string websiteUrl)
|
||||||
{
|
{
|
||||||
var posterNode =
|
var posterNode =
|
||||||
document.DocumentNode.SelectSingleNode("//section[@class='flex items-center justify-center']/picture/img");
|
document.DocumentNode.SelectSingleNode("//section[@class='flex items-center justify-center']/picture/img");
|
||||||
@ -79,12 +79,12 @@ public class Weebcentral : MangaConnector
|
|||||||
HtmlNode[] authorsNodes =
|
HtmlNode[] authorsNodes =
|
||||||
document.DocumentNode.SelectNodes("//ul/li[strong/text() = 'Author(s): ']/span")?.ToArray() ?? [];
|
document.DocumentNode.SelectNodes("//ul/li[strong/text() = 'Author(s): ']/span")?.ToArray() ?? [];
|
||||||
var authorNames = authorsNodes.Select(n => n.InnerText).ToList();
|
var authorNames = authorsNodes.Select(n => n.InnerText).ToList();
|
||||||
Author[] authors = authorNames.Select(n => new Author(n)).ToArray();
|
List<Author> authors = authorNames.Select(n => new Author(n)).ToList();
|
||||||
|
|
||||||
HtmlNode[] genreNodes =
|
HtmlNode[] genreNodes =
|
||||||
document.DocumentNode.SelectNodes("//ul/li[strong/text() = 'Tags(s): ']/span")?.ToArray() ?? [];
|
document.DocumentNode.SelectNodes("//ul/li[strong/text() = 'Tags(s): ']/span")?.ToArray() ?? [];
|
||||||
HashSet<string> tags = genreNodes.Select(n => n.InnerText).ToHashSet();
|
HashSet<string> tags = genreNodes.Select(n => n.InnerText).ToHashSet();
|
||||||
MangaTag[] mangaTags = tags.Select(t => new MangaTag(t)).ToArray();
|
List<MangaTag> mangaTags = tags.Select(t => new MangaTag(t)).ToList();
|
||||||
|
|
||||||
var statusNode = document.DocumentNode.SelectSingleNode("//ul/li[strong/text() = 'Status: ']/a");
|
var statusNode = document.DocumentNode.SelectSingleNode("//ul/li[strong/text() = 'Status: ']/a");
|
||||||
var status = statusNode?.InnerText ?? "";
|
var status = statusNode?.InnerText ?? "";
|
||||||
@ -108,7 +108,7 @@ public class Weebcentral : MangaConnector
|
|||||||
Dictionary<string, string> altTitlesDict = new(), links = new();
|
Dictionary<string, string> altTitlesDict = new(), links = new();
|
||||||
for (var i = 0; i < altTitleNodes.Length; i++)
|
for (var i = 0; i < altTitleNodes.Length; i++)
|
||||||
altTitlesDict.Add(i.ToString(), altTitleNodes[i].InnerText);
|
altTitlesDict.Add(i.ToString(), altTitleNodes[i].InnerText);
|
||||||
MangaAltTitle[] altTitles = altTitlesDict.Select(a => new MangaAltTitle(a.Key, a.Value)).ToArray();
|
List<MangaAltTitle> altTitles = altTitlesDict.Select(a => new MangaAltTitle(a.Key, a.Value)).ToList();
|
||||||
|
|
||||||
var originalLanguage = "";
|
var originalLanguage = "";
|
||||||
|
|
||||||
@ -123,7 +123,7 @@ public class Weebcentral : MangaConnector
|
|||||||
return (manga, authors, mangaTags, [], altTitles);
|
return (manga, authors, mangaTags, [], altTitles);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override (Manga, Author[], MangaTag[], Link[], MangaAltTitle[])? GetMangaFromId(string publicationId)
|
public override (Manga, List<Author>?, List<MangaTag>?, List<Link>?, List<MangaAltTitle>?)? GetMangaFromId(string publicationId)
|
||||||
{
|
{
|
||||||
return GetMangaFromUrl($"https://weebcentral.com/series/{publicationId}");
|
return GetMangaFromUrl($"https://weebcentral.com/series/{publicationId}");
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
using System.ComponentModel.DataAnnotations.Schema;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore;
|
|
||||||
|
|
||||||
namespace API.Schema;
|
namespace API.Schema;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user