Skip to content

Commit f79c7e4

Browse files
author
OnlyFart
committed
1 parent 78c06f0 commit f79c7e4

6 files changed

Lines changed: 155 additions & 8 deletions

File tree

Core/Core.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<TargetFramework>net9.0</TargetFramework>
55
<LangVersion>latestmajor</LangVersion>
66
<PackageId>Core</PackageId>
7-
<Version>2.6.5</Version>
7+
<Version>2.7.0</Version>
88
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
99
</PropertyGroup>
1010

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Net.Http;
5+
using System.Text.Json;
6+
using System.Text.RegularExpressions;
7+
using System.Threading.Tasks;
8+
using Core.Configs;
9+
using Core.Extensions;
10+
using Core.Types.Book;
11+
using Core.Types.Common;
12+
using Core.Types.Librebook;
13+
using HtmlAgilityPack;
14+
using HtmlAgilityPack.CssSelectors.NetCore;
15+
using Microsoft.Extensions.Logging;
16+
17+
namespace Core.Logic.Getters;
18+
19+
public class LibrebookGetter(BookGetterConfig config) : GetterBase(config) {
20+
protected override Uri SystemUrl => new("https://librebook.me/");
21+
22+
public override bool IsSameUrl(Uri url) {
23+
return SystemUrl.IsSameSubDomain(SystemUrl);
24+
}
25+
26+
protected override string GetId(Uri url) {
27+
return url.GetSegment(1);
28+
}
29+
30+
public override async Task Init() {
31+
await base.Init();
32+
Config.Client.DefaultRequestHeaders.Add("Referer", SystemUrl.ToString());
33+
}
34+
35+
public override async Task Authorize() {
36+
if (!Config.HasCredentials) {
37+
return;
38+
}
39+
40+
var loginPage = "https://1.grouple.co/internal/auth/login?siteId=6&targetUri=%2Flogin%2FcontinueSso%3FsiteId%3D6%26targetUri%3D%252F".AsUri();
41+
var doc = await Config.Client.GetHtmlDocWithTriesAsync(loginPage);
42+
43+
var formUrl = loginPage.MakeRelativeUri(doc.QuerySelector("form")?.Attributes["action"]?.Value);
44+
doc = await Config.Client.PostHtmlDocWithTriesAsync(formUrl, GenerateAuthData());
45+
46+
var noty = Regex.Match(doc.ParsedText, @"showNoty\((.*?)\)");
47+
var result = JsonSerializer.Deserialize<LibrebookAuthResponse>(noty.Groups[1].Value);
48+
if (result.Type == "success") {
49+
Config.Logger.LogInformation("Успешно авторизовались");
50+
} else {
51+
throw new Exception($"Не удалось авторизоваться. {result.Text}");
52+
}
53+
}
54+
55+
private FormUrlEncodedContent GenerateAuthData() {
56+
var payload = new Dictionary<string, string> {
57+
{ "targetUri", "/login/continueSso?siteId=6&targetUri=%2F" },
58+
{ "username", Config.Options.Login },
59+
{ "password", Config.Options.Password },
60+
{ "remember_me", "true" },
61+
{ "_remember_me_yes", string.Empty },
62+
{ "remember_me_yes", "on" },
63+
};
64+
65+
return new FormUrlEncodedContent(payload);
66+
}
67+
68+
public override async Task<Book> Get(Uri url) {
69+
url = SystemUrl.MakeRelativeUri(GetId(url)).ReplaceHost(url.Host);
70+
var doc = await Config.Client.GetHtmlDocWithTriesAsync(url);
71+
72+
var chapterLink = doc.QuerySelector("a.chapter-link");
73+
if (chapterLink == default) {
74+
throw new Exception("Книга недоступна для чтения. Возможно, нужна авторизация.");
75+
}
76+
77+
var startUrl = url.MakeRelativeUri(chapterLink.Attributes["href"].Value);
78+
var book = new Book(url) {
79+
Cover = await GetCover(doc, url),
80+
Chapters = await FillChapters(startUrl),
81+
Title = doc.GetTextBySelector("h1.names > span.name"),
82+
Author = GetAuthor(doc, url),
83+
Annotation = doc.QuerySelector("div.manga-description > div")?.InnerHtml
84+
};
85+
86+
return book;
87+
}
88+
89+
private Author GetAuthor(HtmlDocument doc, Uri bookUrl) {
90+
var a = doc.QuerySelector("span.elem_author a");
91+
return a == default ? new Author("Librebook") : new Author(a.GetText(), bookUrl.MakeRelativeUri(a.Attributes["href"].Value));
92+
}
93+
94+
private async Task<IEnumerable<Chapter>> FillChapters(Uri startUrl) {
95+
var result = new List<Chapter>();
96+
if (Config.Options.NoChapters) {
97+
return result;
98+
}
99+
100+
foreach (var urlChapter in await GetToc(startUrl)) {
101+
Config.Logger.LogInformation($"Загружаю главу {urlChapter.Title.CoverQuotes()}");
102+
var chapter = new Chapter {
103+
Title = urlChapter.Title
104+
};
105+
106+
var chapterDoc = await GetChapter(urlChapter);
107+
108+
if (chapterDoc != default) {
109+
chapter.Images = await GetImages(chapterDoc, SystemUrl);
110+
chapter.Content = chapterDoc.DocumentNode.InnerHtml;
111+
}
112+
113+
result.Add(chapter);
114+
}
115+
116+
return result;
117+
}
118+
119+
private async Task<IEnumerable<UrlChapter>> GetToc(Uri startUrl) {
120+
var doc = await Config.Client.GetHtmlDocWithTriesAsync(startUrl);
121+
var result = doc
122+
.QuerySelectorAll("#chapters-list a.chapter-link")
123+
.Select(a => new UrlChapter(SystemUrl.MakeRelativeUri(a.Attributes["href"].Value), a.GetText().ReplaceNewLine()))
124+
.ToList();
125+
126+
return SliceToc(result, c => c.Title);
127+
}
128+
129+
private async Task<HtmlDocument> GetChapter(UrlChapter urlChapter) {
130+
var doc = await Config.Client.GetHtmlDocWithTriesAsync(urlChapter.Url);
131+
return doc.QuerySelector("div.b-chapter").InnerHtml.AsHtmlDoc();
132+
}
133+
134+
private Task<TempFile> GetCover(HtmlDocument doc, Uri bookUri) {
135+
var imagePath = doc.QuerySelector("img.fotorama__img")?.Attributes["src"]?.Value;
136+
return !string.IsNullOrWhiteSpace(imagePath) ? SaveImage(bookUri.MakeRelativeUri(imagePath)) : Task.FromResult(default(TempFile));
137+
}
138+
}

Core/Logic/Getters/MangaMammyGetter.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Text;
5-
using System.Text.Json.Nodes;
6-
using System.Text.RegularExpressions;
75
using System.Threading.Tasks;
86
using Core.Configs;
97
using Core.Extensions;
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Core.Types.Librebook;
4+
5+
public class LibrebookAuthResponse {
6+
[JsonPropertyName("type")]
7+
public string Type { get; set; }
8+
9+
[JsonPropertyName("text")]
10+
public string Text { get; set; }
11+
}

Elib2EbookCli/Program.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.Diagnostics;
2-
using System.Reflection;
1+
using System.Reflection;
32
using System.Text;
43
using CommandLine;
54
using CommandLine.Text;
@@ -26,9 +25,9 @@ private static async Task Main(string[] args) {
2625

2726
await parserResult
2827
.WithNotParsed(errs => {
29-
var title = AppDomain.CurrentDomain.FriendlyName;
30-
var coreAssembly = typeof(BookGetterConfig).Assembly;
31-
var version = coreAssembly.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? string.Empty;
28+
var title = AppDomain.CurrentDomain.FriendlyName;
29+
var coreAssembly = typeof(BookGetterConfig).Assembly;
30+
var version = coreAssembly.GetCustomAttribute<AssemblyFileVersionAttribute>()?.Version ?? string.Empty;
3231

3332
var heading = new HeadingInfo(title, version);
3433

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
* https://ladylib.top/
4646
* https://lanovels.com/
4747
* https://libbox.ru/
48+
* https://librebook.me/
4849
* https://libst.ru/
4950
* https://lightnoveldaily.com/
5051
* https://litgorod.ru/

0 commit comments

Comments
 (0)