[FA-5] Adds image support with proper S3 upload and replacement after upload

This commit is contained in:
gamer147
2025-11-23 21:16:26 -05:00
parent 573a0f6e3f
commit 16ed16ff62
33 changed files with 1321 additions and 267 deletions

View File

@@ -8,5 +8,5 @@ public interface ISourceAdapter
public SourceDescriptor SourceDescriptor { get; }
public Task<bool> CanProcessNovel(string url);
public Task<NovelMetadata> GetMetadata(string novelUrl);
public Task<string> GetRawChapter(string chapterUrl);
public Task<ChapterFetchResult> GetRawChapter(string chapterUrl);
}

View File

@@ -81,6 +81,21 @@ public class NovelpiaAdapter : ISourceAdapter
novel.AuthorName = authorMatch.Groups[2].Value;
novel.AuthorUrl = authorMatch.Groups[2].Value;
// Cover image URL
var coverMatch = Regex.Match(novelData, @"href=""(//images\.novelpia\.com/imagebox/cover/.+?\.file)""");
string coverImageUrl = coverMatch.Groups[1].Value;
if (string.IsNullOrEmpty(coverImageUrl))
{
coverMatch = Regex.Match(novelData, @"src=""(//images\.novelpia\.com/imagebox/cover/.+?\.file)""");
coverImageUrl = coverMatch.Groups[1].Value;
}
novel.CoverImage = new ImageData()
{
Url = coverImageUrl,
Data = await GetImageData(coverImageUrl),
};
// Some badge info
var badgeSet = Regex.Match(novelData, @"(?s)<p\s+class=""in-badge"">(.*?)<\/p>");
var badgeMatches = Regex.Matches(badgeSet.Groups[1].Value, @"<span[^>]*>(.*?)<\/span>");
@@ -160,7 +175,7 @@ public class NovelpiaAdapter : ISourceAdapter
return novel;
}
public async Task<string> GetRawChapter(string chapterUrl)
public async Task<ChapterFetchResult> GetRawChapter(string chapterUrl)
{
var chapterId = uint.Parse(Regex.Match(chapterUrl, ChapterIdRegex).Groups[1].Value);
var endpoint = ChapterDownloadEndpoint + chapterId;
@@ -171,6 +186,11 @@ public class NovelpiaAdapter : ISourceAdapter
{
throw new Exception();
}
var fetchResult = new ChapterFetchResult()
{
ImageData = new List<ImageData>()
};
StringBuilder builder = new StringBuilder();
using var doc = JsonDocument.Parse(responseContent);
@@ -182,10 +202,20 @@ public class NovelpiaAdapter : ISourceAdapter
foreach (JsonElement item in sArray.EnumerateArray())
{
string text = item.GetProperty("text").GetString();
var imageMatch = Regex.Match(text, @"<img.+?src=\""(.+?)\"".+?>");
if (text.Contains("cover-wrapper"))
{
continue;
}
if (imageMatch.Success)
{
var url = imageMatch.Groups[1].Value;
fetchResult.ImageData.Add(new ImageData()
{
Url = url,
Data = await GetImageData(url)
});
}
if (text.Contains("opacity: 0"))
{
continue;
@@ -193,8 +223,24 @@ public class NovelpiaAdapter : ISourceAdapter
builder.Append(WebUtility.HtmlDecode(text));
}
fetchResult.Text = builder.ToString();
return builder.ToString();
return fetchResult;
}
private async Task<byte[]> GetImageData(string url)
{
if (!url.StartsWith("http"))
{
url = "https:" + url;
}
var image = await _httpClient.GetAsync(url);
if (!image.IsSuccessStatusCode)
{
_logger.LogError("Attempting to fetch image with url {imgUrl} returned status code {code}.", url, image.StatusCode);
throw new Exception();
}
return await image.Content.ReadAsByteArrayAsync();
}
}

View File

@@ -52,10 +52,15 @@ public class NovelpiaAuthMessageHandler : DelegatingHandler
var response = await _httpClient.SendAsync(loginMessage);
using (var streamReader = new StreamReader(response.Content.ReadAsStream()))
{
if (streamReader.ReadToEnd().Contains(LoginSuccessMessage))
var message = await streamReader.ReadToEndAsync();
if (message.Contains(LoginSuccessMessage))
{
_cache.Set(CacheKey, loginKey);
}
else
{
throw new Exception("An error occured while retrieving the login key. Message: " + message);
}
}
}