Add basic HTML parsing

This commit is contained in:
Saphire committed 2022-02-19 23:51:04 +07:00
1 parent 387909b0c6
commit a7250ceacf
14 files changed
+627 -100

No files matched your search

+47
View File
@@ -0,0 +1,47 @@
namespace QuestReader.Models;
using System.Text.Json.Serialization;
using QuestReader.Models.ParsedContent;
public record ThreadPost
{
public int Id { get; set; }
public string Author { get; set; }
public string Uid { get; set; }
public string RawHtml { get; set; }
public ParsedContent.ParsedContent? ParsedContent { get; set; }
public string? File { get; set; }
public string? Filename { get; set; }
public string? Title { get; set; }
public string? Tripcode { get; set; }
public DateTime Date { get; set; }
[JsonIgnore]
public bool IsChapterAnnounce { get; set; } = false;
public ChapterMetadata? Chapter { get; set; }
public List<int>? RepliesTo { get; set; }
}
public record Metadata
{
public string Name { get; set; }
public string Author { get; set; }
public Uri AuthorPage { get; set; }
public string? AuthorTwitter { get; set; }
public string? Description { get; set; }
public Uri AssetsBaseUrl { get; set; }
public string SocialPreview { get; set; }
public List<int> Threads { get; set; }
public List<ChapterMetadata> Chapters { get; set; }
public override string ToString() => $"\"{Name}\" by {Author}";
}
public record ChapterMetadata
{
public int Id { get; set; }
public string Name { get; set; }
public string Subtitle { get; set; }
public int Start { get; set; }
public int? Announce { get; set; }
public int End { get; set; }
}
+123
View File
@@ -0,0 +1,123 @@
using System.Linq.Expressions;
using System.Runtime.Serialization;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Web;
namespace QuestReader.Models.ParsedContent;
public class ParsedContent
{
public Version Version { get; set; }
public IList<ContentNode> Nodes { get; set; }
}
class ContentConverter : JsonConverter<ContentNode>
{
public override ContentNode Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options
)
{
throw new NotImplementedException();
}
public override void Write(
Utf8JsonWriter writer,
ContentNode value,
JsonSerializerOptions options)
{
switch (value)
{
case null:
JsonSerializer.Serialize(writer, null as ContentNode, options);
break;
default:
{
if (value is RootNode)
throw new InvalidDataContractException("RootNode must not be used");
var type = value.GetType();
JsonSerializer.Serialize(writer, value, type, options);
break;
}
}
}
}
[JsonConverter(typeof(ContentConverter))]
public abstract class ContentNode
{
public string Type { get => GetType().Name.Replace("Node", ""); }
public virtual string Render(TemplateModel model)
{
throw new NotImplementedException("Rendering is not supported for this node type");
}
}
public class TextNode : ContentNode
{
public string Text { get; set; }
public override string ToString() => $"\"{Text}\"";
public override string Render(TemplateModel model) => HttpUtility.HtmlEncode(Text);
}
public class NewlineNode : ContentNode
{
public override string ToString() => $"<br>";
public override string Render(TemplateModel model) => "<br>";
}
public class ReferenceNode : ContentNode
{
public int PostId { get; set; }
public int ThreadId { get; set; }
public ReferenceType ReferenceType { get; set; }
public bool LongReference { get; set; }
}
public enum ReferenceType
{
QuestActive,
QuestArchive,
QuestDiscussion
}
public abstract class ContainerNode : ContentNode
{
public IList<ContentNode> Nodes { get; set; }
public override string ToString() => $"{Type} [ {string.Join(",\n", Nodes)} ]";
}
// A temporary container to recursively parse everything of a note before bailing and MUST NOT BE USED NORMALLY
public class RootNode : ContainerNode
{
public override string ToString() => throw new InvalidDataContractException("RootNode must not be used");
public override string Render(TemplateModel model) => throw new InvalidDataContractException("RootNode must not be used");
}
public class QuoteNode : ContainerNode { };
public class BoldNode : ContainerNode { };
public class ItalicsNode : ContainerNode { };
public class StrikeoutNode : ContainerNode { };
public class SpoilerNode : ContainerNode { };
public class InlineCodeNode : ContainerNode { };
public class UnderlineNode : ContainerNode { };
public class ExternalLinkNode : ContainerNode
{
public string Destination { get; set; }
}
+11
View File
@@ -0,0 +1,11 @@
namespace QuestReader.Models;
public class TemplateModel
{
public Metadata Metadata { get; set; }
public DateTime Now { get; set; }
public List<ThreadPost> Posts { get; set; }
public List<ThreadPost> AllPosts { get; set; }
public string BaseUrl { get; set; }
public string ToolVersion { get; set; }
}