Merge branch 'refs/heads/cuttingedge-merge-ServerV2' into Server-V2
This commit is contained in:
commit
2db85e5070
@ -22,7 +22,7 @@ jobs:
|
|||||||
# https://github.com/marketplace/actions/docker-setup-buildx
|
# https://github.com/marketplace/actions/docker-setup-buildx
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3.6.1
|
uses: docker/setup-buildx-action@v3.7.1
|
||||||
|
|
||||||
# https://github.com/docker/login-action#docker-hub
|
# https://github.com/docker/login-action#docker-hub
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
@ -33,7 +33,7 @@ jobs:
|
|||||||
|
|
||||||
# https://github.com/docker/build-push-action#multi-platform-image
|
# https://github.com/docker/build-push-action#multi-platform-image
|
||||||
- name: Build and push API
|
- name: Build and push API
|
||||||
uses: docker/build-push-action@v6.7.0
|
uses: docker/build-push-action@v6.9.0
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
4
.github/workflows/docker-image-dev.yml
vendored
4
.github/workflows/docker-image-dev.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
# https://github.com/marketplace/actions/docker-setup-buildx
|
# https://github.com/marketplace/actions/docker-setup-buildx
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3.6.1
|
uses: docker/setup-buildx-action@v3.7.1
|
||||||
|
|
||||||
# https://github.com/docker/login-action#docker-hub
|
# https://github.com/docker/login-action#docker-hub
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
@ -33,7 +33,7 @@ jobs:
|
|||||||
|
|
||||||
# https://github.com/docker/build-push-action#multi-platform-image
|
# https://github.com/docker/build-push-action#multi-platform-image
|
||||||
- name: Build and push API
|
- name: Build and push API
|
||||||
uses: docker/build-push-action@v6.7.0
|
uses: docker/build-push-action@v6.9.0
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
4
.github/workflows/docker-image-master.yml
vendored
4
.github/workflows/docker-image-master.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
# https://github.com/marketplace/actions/docker-setup-buildx
|
# https://github.com/marketplace/actions/docker-setup-buildx
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3.6.1
|
uses: docker/setup-buildx-action@v3.7.1
|
||||||
|
|
||||||
# https://github.com/docker/login-action#docker-hub
|
# https://github.com/docker/login-action#docker-hub
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
@ -33,7 +33,7 @@ jobs:
|
|||||||
|
|
||||||
# https://github.com/docker/build-push-action#multi-platform-image
|
# https://github.com/docker/build-push-action#multi-platform-image
|
||||||
- name: Build and push API
|
- name: Build and push API
|
||||||
uses: docker/build-push-action@v6.7.0
|
uses: docker/build-push-action@v6.9.0
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
4
.github/workflows/docker-image-serverv2.yml
vendored
4
.github/workflows/docker-image-serverv2.yml
vendored
@ -22,7 +22,7 @@ jobs:
|
|||||||
# https://github.com/marketplace/actions/docker-setup-buildx
|
# https://github.com/marketplace/actions/docker-setup-buildx
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
id: buildx
|
id: buildx
|
||||||
uses: docker/setup-buildx-action@v3.6.1
|
uses: docker/setup-buildx-action@v3.7.1
|
||||||
|
|
||||||
# https://github.com/docker/login-action#docker-hub
|
# https://github.com/docker/login-action#docker-hub
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
@ -33,7 +33,7 @@ jobs:
|
|||||||
|
|
||||||
# https://github.com/docker/build-push-action#multi-platform-image
|
# https://github.com/docker/build-push-action#multi-platform-image
|
||||||
- name: Build and push API
|
- name: Build and push API
|
||||||
uses: docker/build-push-action@v6.7.0
|
uses: docker/build-push-action@v6.9.0
|
||||||
with:
|
with:
|
||||||
context: ./
|
context: ./
|
||||||
file: ./Dockerfile
|
file: ./Dockerfile
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
using System.Text.RegularExpressions;
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Xml.Linq;
|
using System.Xml.Linq;
|
||||||
|
using static System.IO.UnixFileMode;
|
||||||
|
|
||||||
namespace Tranga;
|
namespace Tranga;
|
||||||
|
|
||||||
@ -17,23 +19,21 @@ public readonly struct Chapter : IComparable
|
|||||||
public string url { get; }
|
public string url { get; }
|
||||||
// ReSharper disable once MemberCanBePrivate.Global
|
// ReSharper disable once MemberCanBePrivate.Global
|
||||||
public string fileName { get; }
|
public string fileName { get; }
|
||||||
|
public string? id { get; }
|
||||||
|
|
||||||
private static readonly Regex LegalCharacters = new (@"([A-z]*[0-9]* *\.*-*,*\]*\[*'*\'*\)*\(*~*!*)*");
|
private static readonly Regex LegalCharacters = new (@"([A-z]*[0-9]* *\.*-*,*\]*\[*'*\'*\)*\(*~*!*)*");
|
||||||
private static readonly Regex IllegalStrings = new(@"(Vol(ume)?|Ch(apter)?)\.?", RegexOptions.IgnoreCase);
|
private static readonly Regex IllegalStrings = new(@"(Vol(ume)?|Ch(apter)?)\.?", RegexOptions.IgnoreCase);
|
||||||
private static readonly Regex Digits = new(@"[0-9\.]*");
|
private static readonly Regex Digits = new(@"[0-9\.]*");
|
||||||
public Chapter(Manga parentManga, string? name, string? volumeNumber, string chapterNumber, string url)
|
public Chapter(Manga parentManga, string? name, string? volumeNumber, string chapterNumber, string url, string? id = null)
|
||||||
{
|
{
|
||||||
this.parentManga = parentManga;
|
this.parentManga = parentManga;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.volumeNumber = volumeNumber is not null ? string.Concat(Digits.Matches(volumeNumber).Select(x => x.Value)) : "0";
|
this.volumeNumber = volumeNumber is not null ? string.Concat(Digits.Matches(volumeNumber).Select(x => x.Value)) : "0";
|
||||||
this.chapterNumber = string.Concat(Digits.Matches(chapterNumber).Select(x => x.Value));
|
this.chapterNumber = string.Concat(Digits.Matches(chapterNumber).Select(x => x.Value));
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
this.id = id;
|
||||||
|
|
||||||
string chapterVolNumStr;
|
string chapterVolNumStr = $"Vol.{this.volumeNumber} Ch.{chapterNumber}";
|
||||||
if (volumeNumber is not null && volumeNumber.Length > 0)
|
|
||||||
chapterVolNumStr = $"Vol.{volumeNumber} Ch.{chapterNumber}";
|
|
||||||
else
|
|
||||||
chapterVolNumStr = $"Ch.{chapterNumber}";
|
|
||||||
|
|
||||||
if (name is not null && name.Length > 0)
|
if (name is not null && name.Length > 0)
|
||||||
{
|
{
|
||||||
@ -87,24 +87,44 @@ public readonly struct Chapter : IComparable
|
|||||||
string mangaDirectory = Path.Join(TrangaSettings.downloadLocation, parentManga.folderName);
|
string mangaDirectory = Path.Join(TrangaSettings.downloadLocation, parentManga.folderName);
|
||||||
if (!Directory.Exists(mangaDirectory))
|
if (!Directory.Exists(mangaDirectory))
|
||||||
return false;
|
return false;
|
||||||
FileInfo[] archives = new DirectoryInfo(mangaDirectory).GetFiles("*.cbz");
|
FileInfo? mangaArchive = null;
|
||||||
Regex volChRex = new(@"(?:Vol(?:ume)?\.([0-9]+)\D*)?Ch(?:apter)?\.([0-9]+(?:\.[0-9]+)*)");
|
string markerPath = Path.Join(mangaDirectory, $".{id}");
|
||||||
|
if (this.id is not null
|
||||||
Chapter t = this;
|
&& File.Exists(markerPath)
|
||||||
string correctPath = GetArchiveFilePath();
|
&& File.Exists(File.ReadAllText(markerPath)))
|
||||||
FileInfo? archive = archives.FirstOrDefault(archive =>
|
|
||||||
{
|
{
|
||||||
Match m = volChRex.Match(archive.Name);
|
mangaArchive = new FileInfo(File.ReadAllText(markerPath));
|
||||||
/*Uncommenting this section will only allow *Version without Volume number* -> *Version with Volume number* but not the other way
|
}
|
||||||
if (m.Groups[1].Success)
|
else
|
||||||
return m.Groups[1].Value == t.volumeNumber && m.Groups[2].Value == t.chapterNumber;
|
{
|
||||||
else*/
|
FileInfo[] archives = new DirectoryInfo(mangaDirectory).GetFiles("*.cbz");
|
||||||
return m.Groups[2].Value == t.chapterNumber;
|
Regex volChRex = new(@"(?:Vol(?:ume)?\.([0-9]+)\D*)?Ch(?:apter)?\.([0-9]+(?:\.[0-9]+)*)");
|
||||||
});
|
|
||||||
if(archive is not null && archive.FullName != correctPath)
|
Chapter t = this;
|
||||||
archive.MoveTo(correctPath, true);
|
mangaArchive = archives.FirstOrDefault(archive =>
|
||||||
return (archive is not null);
|
{
|
||||||
|
Match m = volChRex.Match(archive.Name);
|
||||||
|
if (m.Groups[1].Success)
|
||||||
|
return m.Groups[1].Value == t.volumeNumber && m.Groups[2].Value == t.chapterNumber;
|
||||||
|
else
|
||||||
|
return m.Groups[2].Value == t.chapterNumber;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
string correctPath = GetArchiveFilePath();
|
||||||
|
if(mangaArchive is not null && mangaArchive.FullName != correctPath)
|
||||||
|
mangaArchive.MoveTo(correctPath, true);
|
||||||
|
return (mangaArchive is not null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CreateChapterMarker()
|
||||||
|
{
|
||||||
|
string path = Path.Join(TrangaSettings.downloadLocation, parentManga.folderName, $".{id}");
|
||||||
|
File.WriteAllText(path, GetArchiveFilePath());
|
||||||
|
File.SetAttributes(path, FileAttributes.Hidden);
|
||||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
File.SetUnixFileMode(path, UserRead | UserWrite | UserExecute | GroupRead | GroupWrite | GroupExecute | OtherRead | OtherExecute);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates full file path of chapter-archive
|
/// Creates full file path of chapter-archive
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -150,7 +150,7 @@ public class Bato : MangaConnector
|
|||||||
HtmlNode chapterList =
|
HtmlNode chapterList =
|
||||||
result.htmlDocument.DocumentNode.SelectSingleNode("/html/body/div/main/div[3]/astro-island/div/div[2]/div/div/astro-slot");
|
result.htmlDocument.DocumentNode.SelectSingleNode("/html/body/div/main/div[3]/astro-island/div/div[2]/div/div/astro-slot");
|
||||||
|
|
||||||
Regex numberRex = new(@"\/title\/.+\/[0-9]+(-vol_([0-9]+))?-ch_([0-9\.]+)");
|
Regex numberRex = new(@"\/title\/.+\/([0-9])+(?:-vol_([0-9]+))?-ch_([0-9\.]+)");
|
||||||
|
|
||||||
foreach (HtmlNode chapterInfo in chapterList.SelectNodes("div"))
|
foreach (HtmlNode chapterInfo in chapterList.SelectNodes("div"))
|
||||||
{
|
{
|
||||||
@ -158,6 +158,7 @@ public class Bato : MangaConnector
|
|||||||
string chapterUrl = infoNode.GetAttributeValue("href", "");
|
string chapterUrl = infoNode.GetAttributeValue("href", "");
|
||||||
|
|
||||||
Match match = numberRex.Match(chapterUrl);
|
Match match = numberRex.Match(chapterUrl);
|
||||||
|
string id = match.Groups[1].Value;
|
||||||
string? volumeNumber = match.Groups[2].Success ? match.Groups[2].Value : null;
|
string? volumeNumber = match.Groups[2].Success ? match.Groups[2].Value : null;
|
||||||
string chapterNumber = match.Groups[3].Value;
|
string chapterNumber = match.Groups[3].Value;
|
||||||
string chapterName = chapterNumber;
|
string chapterName = chapterNumber;
|
||||||
@ -189,11 +190,8 @@ public class Bato : MangaConnector
|
|||||||
}
|
}
|
||||||
|
|
||||||
string[] imageUrls = ParseImageUrlsFromHtml(requestUrl);
|
string[] imageUrls = ParseImageUrlsFromHtml(requestUrl);
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
return DownloadChapterImages(imageUrls, chapter, RequestType.MangaImage, progressToken:progressToken);
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] ParseImageUrlsFromHtml(string mangaUrl)
|
private string[] ParseImageUrlsFromHtml(string mangaUrl)
|
||||||
|
@ -216,8 +216,10 @@ public abstract class MangaConnector : GlobalBase
|
|||||||
return requestResult.statusCode;
|
return requestResult.statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpStatusCode DownloadChapterImages(string[] imageUrls, string saveArchiveFilePath, RequestType requestType, string? comicInfoPath = null, string? referrer = null, ProgressToken? progressToken = null)
|
protected HttpStatusCode DownloadChapterImages(string[] imageUrls, Chapter chapter, RequestType requestType, string? referrer = null, ProgressToken? progressToken = null)
|
||||||
{
|
{
|
||||||
|
string saveArchiveFilePath = chapter.GetArchiveFilePath();
|
||||||
|
|
||||||
if (progressToken?.cancellationRequested ?? false)
|
if (progressToken?.cancellationRequested ?? false)
|
||||||
return HttpStatusCode.RequestTimeout;
|
return HttpStatusCode.RequestTimeout;
|
||||||
Log($"Downloading Images for {saveArchiveFilePath}");
|
Log($"Downloading Images for {saveArchiveFilePath}");
|
||||||
@ -241,7 +243,7 @@ public abstract class MangaConnector : GlobalBase
|
|||||||
//Create a temporary folder to store images
|
//Create a temporary folder to store images
|
||||||
string tempFolder = Directory.CreateTempSubdirectory("trangatemp").FullName;
|
string tempFolder = Directory.CreateTempSubdirectory("trangatemp").FullName;
|
||||||
|
|
||||||
int chapter = 0;
|
int chapterNum = 0;
|
||||||
//Download all Images to temporary Folder
|
//Download all Images to temporary Folder
|
||||||
if (imageUrls.Length == 0)
|
if (imageUrls.Length == 0)
|
||||||
{
|
{
|
||||||
@ -255,9 +257,9 @@ public abstract class MangaConnector : GlobalBase
|
|||||||
foreach (string imageUrl in imageUrls)
|
foreach (string imageUrl in imageUrls)
|
||||||
{
|
{
|
||||||
string extension = imageUrl.Split('.')[^1].Split('?')[0];
|
string extension = imageUrl.Split('.')[^1].Split('?')[0];
|
||||||
Log($"Downloading image {chapter + 1:000}/{imageUrls.Length:000}"); //TODO
|
Log($"Downloading image {chapterNum + 1:000}/{imageUrls.Length:000}"); //TODO
|
||||||
HttpStatusCode status = DownloadImage(imageUrl, Path.Join(tempFolder, $"{chapter++}.{extension}"), requestType, referrer);
|
HttpStatusCode status = DownloadImage(imageUrl, Path.Join(tempFolder, $"{chapterNum++}.{extension}"), requestType, referrer);
|
||||||
Log($"{saveArchiveFilePath} {chapter + 1:000}/{imageUrls.Length:000} {status}");
|
Log($"{saveArchiveFilePath} {chapterNum + 1:000}/{imageUrls.Length:000} {status}");
|
||||||
if ((int)status < 200 || (int)status >= 300)
|
if ((int)status < 200 || (int)status >= 300)
|
||||||
{
|
{
|
||||||
progressToken?.Complete();
|
progressToken?.Complete();
|
||||||
@ -271,16 +273,14 @@ public abstract class MangaConnector : GlobalBase
|
|||||||
progressToken?.Increment();
|
progressToken?.Increment();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(comicInfoPath is not null){
|
File.WriteAllText(Path.Join(tempFolder, "ComicInfo.xml"), chapter.GetComicInfoXmlString());
|
||||||
File.Copy(comicInfoPath, Path.Join(tempFolder, "ComicInfo.xml"));
|
|
||||||
File.Delete(comicInfoPath); //Delete tmp-file
|
|
||||||
}
|
|
||||||
|
|
||||||
Log($"Creating archive {saveArchiveFilePath}");
|
Log($"Creating archive {saveArchiveFilePath}");
|
||||||
//ZIP-it and ship-it
|
//ZIP-it and ship-it
|
||||||
ZipFile.CreateFromDirectory(tempFolder, saveArchiveFilePath);
|
ZipFile.CreateFromDirectory(tempFolder, saveArchiveFilePath);
|
||||||
if(RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
chapter.CreateChapterMarker();
|
||||||
File.SetUnixFileMode(saveArchiveFilePath, UserRead | UserWrite | UserExecute | GroupRead | GroupWrite | GroupExecute);
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
|
||||||
|
File.SetUnixFileMode(saveArchiveFilePath, UserRead | UserWrite | UserExecute | GroupRead | GroupWrite | GroupExecute | OtherRead | OtherExecute);
|
||||||
Directory.Delete(tempFolder, true); //Cleanup
|
Directory.Delete(tempFolder, true); //Cleanup
|
||||||
|
|
||||||
progressToken?.Complete();
|
progressToken?.Complete();
|
||||||
|
@ -248,7 +248,7 @@ public class MangaDex : MangaConnector
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(chapterNum is not "null" && !chapters.Any(chp => chp.volumeNumber.Equals(volume) && chp.chapterNumber.Equals(chapterNum)))
|
if(chapterNum is not "null" && !chapters.Any(chp => chp.volumeNumber.Equals(volume) && chp.chapterNumber.Equals(chapterNum)))
|
||||||
chapters.Add(new Chapter(manga, title, volume, chapterNum, chapterId));
|
chapters.Add(new Chapter(manga, title, volume, chapterNum, chapterId, chapterId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,11 +289,8 @@ public class MangaDex : MangaConnector
|
|||||||
HashSet<string> imageUrls = new();
|
HashSet<string> imageUrls = new();
|
||||||
foreach (JsonNode? image in imageFileNames)
|
foreach (JsonNode? image in imageFileNames)
|
||||||
imageUrls.Add($"{baseUrl}/data/{hash}/{image!.GetValue<string>()}");
|
imageUrls.Add($"{baseUrl}/data/{hash}/{image!.GetValue<string>()}");
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
//Download Chapter-Images
|
//Download Chapter-Images
|
||||||
return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken);
|
return DownloadChapterImages(imageUrls.ToArray(), chapter, RequestType.MangaImage, progressToken:progressToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -117,7 +117,7 @@ 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 Array.Empty<Chapter>();
|
return Array.Empty<Chapter>();
|
||||||
|
|
||||||
List<string> urls = requestResult.htmlDocument.DocumentNode.SelectNodes("//div[@id='list-2']/ul//li//a[contains(@href, '/manga/')]")
|
List<string> urls = requestResult.htmlDocument.DocumentNode.SelectNodes("//div[@id='list-1']/ul//li//a[contains(@href, '/manga/')]")
|
||||||
.Select(node => node.GetAttributeValue("href", "")).ToList();
|
.Select(node => node.GetAttributeValue("href", "")).ToList();
|
||||||
Regex chapterRex = new(@".*\/manga\/[a-zA-Z0-9\-\._\~\!\$\&\'\(\)\*\+\,\;\=\:\@]+\/v([0-9(TBD)]+)\/c([0-9\.]+)\/.*");
|
Regex chapterRex = new(@".*\/manga\/[a-zA-Z0-9\-\._\~\!\$\&\'\(\)\*\+\,\;\=\:\@]+\/v([0-9(TBD)]+)\/c([0-9\.]+)\/.*");
|
||||||
|
|
||||||
@ -181,12 +181,9 @@ public class MangaHere : MangaConnector
|
|||||||
}
|
}
|
||||||
} while (downloaded++ <= images);
|
} while (downloaded++ <= images);
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
if (progressToken is not null)
|
if (progressToken is not null)
|
||||||
progressToken.increments = images;//we blip to normal length, in downloadchapterimages it is increasaed by the amount of urls again
|
progressToken.increments = images;//we blip to normal length, in downloadchapterimages it is increasaed by the amount of urls again
|
||||||
return DownloadChapterImages(imageUrls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken);
|
return DownloadChapterImages(imageUrls.ToArray(), chapter, RequestType.MangaImage, progressToken:progressToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] ParseImageUrlsFromHtml(HtmlDocument document)
|
private string[] ParseImageUrlsFromHtml(HtmlDocument document)
|
||||||
|
@ -213,11 +213,8 @@ public class MangaKatana : MangaConnector
|
|||||||
}
|
}
|
||||||
|
|
||||||
string[] imageUrls = ParseImageUrlsFromHtml(requestUrl);
|
string[] imageUrls = ParseImageUrlsFromHtml(requestUrl);
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
return DownloadChapterImages(imageUrls, chapter, RequestType.MangaImage, progressToken:progressToken);
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://mangakatana.com/", progressToken:progressToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] ParseImageUrlsFromHtml(string mangaUrl)
|
private string[] ParseImageUrlsFromHtml(string mangaUrl)
|
||||||
|
@ -194,6 +194,6 @@ public class MangaLife : MangaConnector
|
|||||||
string comicInfoPath = Path.GetTempFileName();
|
string comicInfoPath = Path.GetTempFileName();
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
||||||
|
|
||||||
return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken);
|
return DownloadChapterImages(urls.ToArray(), chapter, RequestType.MangaImage, progressToken:progressToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -214,10 +214,7 @@ public class Manganato : MangaConnector
|
|||||||
|
|
||||||
string[] imageUrls = ParseImageUrlsFromHtml(requestResult.htmlDocument);
|
string[] imageUrls = ParseImageUrlsFromHtml(requestResult.htmlDocument);
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
return DownloadChapterImages(imageUrls, chapter, RequestType.MangaImage, "https://chapmanganato.com/", progressToken:progressToken);
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://chapmanganato.com/", progressToken:progressToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] ParseImageUrlsFromHtml(HtmlDocument document)
|
private string[] ParseImageUrlsFromHtml(HtmlDocument document)
|
||||||
|
@ -220,10 +220,7 @@ public class Mangasee : MangaConnector
|
|||||||
List<string> urls = new();
|
List<string> urls = new();
|
||||||
foreach(HtmlNode galleryImage in images)
|
foreach(HtmlNode galleryImage in images)
|
||||||
urls.Add(galleryImage.GetAttributeValue("src", ""));
|
urls.Add(galleryImage.GetAttributeValue("src", ""));
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken);
|
return DownloadChapterImages(urls.ToArray(), chapter, RequestType.MangaImage, progressToken:progressToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -149,19 +149,21 @@ public class Mangaworld: MangaConnector
|
|||||||
document.DocumentNode.SelectSingleNode(
|
document.DocumentNode.SelectSingleNode(
|
||||||
"//div[contains(concat(' ',normalize-space(@class),' '),'chapters-wrapper')]");
|
"//div[contains(concat(' ',normalize-space(@class),' '),'chapters-wrapper')]");
|
||||||
|
|
||||||
|
Regex volumeRex = new(@"[Vv]olume ([0-9]+).*");
|
||||||
|
Regex chapterRex = new(@"[Cc]apitolo ([0-9]+).*");
|
||||||
|
Regex idRex = new(@".*\/read\/([a-z0-9]+)(?:[?\/].*)?");
|
||||||
if (chaptersWrapper.Descendants("div").Any(descendant => descendant.HasClass("volume-element")))
|
if (chaptersWrapper.Descendants("div").Any(descendant => descendant.HasClass("volume-element")))
|
||||||
{
|
{
|
||||||
foreach (HtmlNode volNode in document.DocumentNode.SelectNodes("//div[contains(concat(' ',normalize-space(@class),' '),'volume-element')]"))
|
foreach (HtmlNode volNode in document.DocumentNode.SelectNodes("//div[contains(concat(' ',normalize-space(@class),' '),'volume-element')]"))
|
||||||
{
|
{
|
||||||
string volume = Regex.Match(volNode.SelectNodes("div").First(node => node.HasClass("volume")).SelectSingleNode("p").InnerText,
|
string volume = volumeRex.Match(volNode.SelectNodes("div").First(node => node.HasClass("volume")).SelectSingleNode("p").InnerText).Groups[1].Value;
|
||||||
@"[Vv]olume ([0-9]+).*").Groups[1].Value;
|
|
||||||
foreach (HtmlNode chNode in volNode.SelectNodes("div").First(node => node.HasClass("volume-chapters")).SelectNodes("div"))
|
foreach (HtmlNode chNode in volNode.SelectNodes("div").First(node => node.HasClass("volume-chapters")).SelectNodes("div"))
|
||||||
{
|
{
|
||||||
|
|
||||||
string number = Regex.Match(chNode.SelectSingleNode("a").SelectSingleNode("span").InnerText,
|
string number = chapterRex.Match(chNode.SelectSingleNode("a").SelectSingleNode("span").InnerText).Groups[1].Value;
|
||||||
@"[Cc]apitolo ([0-9]+).*").Groups[1].Value;
|
|
||||||
string url = chNode.SelectSingleNode("a").GetAttributeValue("href", "");
|
string url = chNode.SelectSingleNode("a").GetAttributeValue("href", "");
|
||||||
ret.Add(new Chapter(manga, null, volume, number, url));
|
string id = idRex.Match(chNode.SelectSingleNode("a").GetAttributeValue("href", "")).Groups[1].Value;
|
||||||
|
ret.Add(new Chapter(manga, null, volume, number, url, id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,10 +171,10 @@ public class Mangaworld: MangaConnector
|
|||||||
{
|
{
|
||||||
foreach (HtmlNode chNode in chaptersWrapper.SelectNodes("div").Where(node => node.HasClass("chapter")))
|
foreach (HtmlNode chNode in chaptersWrapper.SelectNodes("div").Where(node => node.HasClass("chapter")))
|
||||||
{
|
{
|
||||||
string number = Regex.Match(chNode.SelectSingleNode("a").SelectSingleNode("span").InnerText,
|
string number = chapterRex.Match(chNode.SelectSingleNode("a").SelectSingleNode("span").InnerText).Groups[1].Value;
|
||||||
@"[Cc]apitolo ([0-9]+).*").Groups[1].Value;
|
|
||||||
string url = chNode.SelectSingleNode("a").GetAttributeValue("href", "");
|
string url = chNode.SelectSingleNode("a").GetAttributeValue("href", "");
|
||||||
ret.Add(new Chapter(manga, null, null, number, url));
|
string id = idRex.Match(chNode.SelectSingleNode("a").GetAttributeValue("href", "")).Groups[1].Value;
|
||||||
|
ret.Add(new Chapter(manga, null, null, number, url, id));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,10 +209,7 @@ public class Mangaworld: MangaConnector
|
|||||||
|
|
||||||
string[] imageUrls = ParseImageUrlsFromHtml(requestResult.htmlDocument);
|
string[] imageUrls = ParseImageUrlsFromHtml(requestResult.htmlDocument);
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
return DownloadChapterImages(imageUrls, chapter, RequestType.MangaImage,"https://www.mangaworld.bz/", progressToken:progressToken);
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
return DownloadChapterImages(imageUrls, chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, "https://www.mangaworld.bz/", progressToken:progressToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private string[] ParseImageUrlsFromHtml(HtmlDocument document)
|
private string[] ParseImageUrlsFromHtml(HtmlDocument document)
|
||||||
|
@ -189,10 +189,7 @@ public class ManhuaPlus : MangaConnector
|
|||||||
|
|
||||||
HtmlNode[] images = document.DocumentNode.SelectNodes("//a[contains(concat(' ',normalize-space(@class),' '),' readImg ')]/img").ToArray();
|
HtmlNode[] images = document.DocumentNode.SelectNodes("//a[contains(concat(' ',normalize-space(@class),' '),' readImg ')]/img").ToArray();
|
||||||
List<string> urls = images.Select(node => node.GetAttributeValue("src", "")).ToList();
|
List<string> urls = images.Select(node => node.GetAttributeValue("src", "")).ToList();
|
||||||
|
|
||||||
string comicInfoPath = Path.GetTempFileName();
|
|
||||||
File.WriteAllText(comicInfoPath, chapter.GetComicInfoXmlString());
|
|
||||||
|
|
||||||
return DownloadChapterImages(urls.ToArray(), chapter.GetArchiveFilePath(), RequestType.MangaImage, comicInfoPath, progressToken:progressToken);
|
return DownloadChapterImages(urls.ToArray(), chapter, RequestType.MangaImage, progressToken:progressToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user