Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
117 changes: 65 additions & 52 deletions Scripts/WikiUpdater.cs
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,27 @@ private static HashSet<string> LoadGameTranslationKeys()
return result;
}

/// <summary>
/// Converts formatted HTML text into BBCode.
/// </summary>
private static string ConvertTextToBbcode(string paragraph)
{
return paragraph
.Replace("\n", string.Empty)
.Replace("<b>", "[b]")
.Replace("</b>", "[/b]")
.Replace("<i>", "[i]")
.Replace("</i>", "[/i]")
.Replace("<u>", "[u]")
.Replace("</u>", "[/u]")
.Replace("<code>", "[code]")
.Replace("</code>", "[/code]")
.Replace("<pre>", "[code]")
.Replace("</pre>", "[/code]")
.Replace("<br>", "\n")
.Replace("\"", "\\\"");
}

/// <summary>
/// Fetches a page from the online wiki
/// </summary>
Expand Down Expand Up @@ -528,49 +549,44 @@ private Stage[] StageStringToEnumValues(string rawStageStrings)
private List<GameWiki.Page.Section> GetMainBodySections(IHtmlElement body)
{
var sections = new List<GameWiki.Page.Section> { new(null, string.Empty) };

var children = body.QuerySelector(".mw-parser-output")!.Children;
var text = new StringBuilder();
foreach (var child in children)
{
if (child.TagName == "H2")
{
// Complete the previous section and start a new one with this heading
sections.Add(new GameWiki.Page.Section(child.TextContent, string.Empty));
continue;
}

string text;
switch (child.TagName)
{
case "H2":
// Complete the previous section
sections[^1].SectionBody = text.ToString().Trim();

// and start a new one with this heading
sections.Add(new GameWiki.Page.Section(child.TextContent, string.Empty));
text = new StringBuilder();
continue;
case "P":
text = ConvertParagraphToBbcode(child) + "\n\n";
text = ConvertParagraphToBbcode(child, text);
break;
case "UL":

// TODO: switch to the Godot 4 way to handle this:
// https://github.com/Revolutionary-Games/Thrive/issues/5511
// Godot 3 does not support lists in BBCode, so use custom formatting
text = child.Children
.Where(c => c.TagName == "LI")
.Select(l => $"[indent]— {ConvertParagraphToBbcode(l)}[/indent]")
.Aggregate((a, b) => a + "\n" + b) + "\n\n";
text = ConvertListToBbcode(child, text);
break;
case "H3":
var headline = child.Children
.First(c => c.ClassList.Contains("mw-headline"));

text = $"[b][u]{headline.TextContent}[/u][/b]\n\n";
text = text.Append($"[b][u]{headline.TextContent}[/u][/b]");
break;
default:
// Ignore all other tag types
continue;
}

// Concatenate this tag with the rest of the section so far
sections[^1] = new GameWiki.Page.Section(sections[^1].SectionHeading, sections[^1].SectionBody + text);
text.Append("\n\n");
}

return sections.Select(s => new GameWiki.Page.Section(s.SectionHeading, s.SectionBody.Trim())).ToList();
// ensuring sections have their SectionBody
sections[^1].SectionBody = text.ToString().Trim();

return sections;
}

/// <summary>
Expand All @@ -586,18 +602,34 @@ private GameWiki.Page.Section UntranslateSection(GameWiki.Page.Section section,
return new GameWiki.Page.Section(heading, body);
}

/// <summary>
/// Converts HTML for a single paragraph into BBCode. Paragraph must not contain lists, headings, etc.
/// </summary>
private string ConvertParagraphToBbcode(IElement paragraph)
private StringBuilder ConvertListToBbcode(IElement list, StringBuilder builder)
{
var bbcode = new StringBuilder();
switch (list)
{
case IHtmlUnorderedListElement:
builder.Append("[ul bullet=— ]");
foreach (var item in list.Children)
{
ConvertListToBbcode(item, builder);
builder.Append('\n');
}

builder.Append("[/ul]");
break;
case IHtmlListItemElement:
ConvertParagraphToBbcode(list, builder);
break;

ConvertParagraphToBbcode(paragraph, bbcode);
return bbcode.ToString();
// ordered lists have not been required so far and other tags are invalid in the context of a list
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be fine to for now just make ordered lists also use the same code as unordered lists so that this doesn't blow up unexpectedly some time in the future.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you accidentally still left this comment here that should be removed.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it is literally just switching to use [ol] instead of [ul], I've now covered a proper implementation for ordered lists.

}

return builder;
}

private void ConvertParagraphToBbcode(INode paragraph, StringBuilder result)
/// <summary>
/// Converts HTML for a single paragraph into BBCode. Paragraph must not contain lists, headings, etc.
/// </summary>
private StringBuilder ConvertParagraphToBbcode(INode paragraph, StringBuilder result)
{
var children = paragraph.ChildNodes;
foreach (var child in children)
Expand Down Expand Up @@ -629,7 +661,7 @@ private void ConvertParagraphToBbcode(INode paragraph, StringBuilder result)
case IElement { TagName: "B", Children.Length: > 0 } element:
// Deal with items inside bold tags, e.g. links
result.Append("[b]");
result.Append(ConvertParagraphToBbcode(element));
ConvertParagraphToBbcode(element, result);
result.Append("[/b]");
continue;
case IElement element:
Expand All @@ -640,6 +672,8 @@ private void ConvertParagraphToBbcode(INode paragraph, StringBuilder result)
break;
}
}

return result;
}

/// <summary>
Expand Down Expand Up @@ -718,27 +752,6 @@ private bool IsThriveIcon(string? iconName)
return EmbeddedThriveIconExtensions.TryGetIcon(iconName, out _);
}

/// <summary>
/// Converts formatted HTML text into BBCode.
/// </summary>
private string ConvertTextToBbcode(string paragraph)
{
return paragraph
.Replace("\n", string.Empty)
.Replace("<b>", "[b]")
.Replace("</b>", "[/b]")
.Replace("<i>", "[i]")
.Replace("</i>", "[/i]")
.Replace("<u>", "[u]")
.Replace("</u>", "[/u]")
.Replace("<code>", "[code]")
.Replace("</code>", "[/code]")
.Replace("<pre>", "[code]")
.Replace("</pre>", "[/code]")
.Replace("<br>", "\n")
.Replace("\"", "\\\"");
}

/// <summary>
/// Inserts into en.po the English translations for all the translation keys in a list of wiki pages.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion Thrive.csproj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Godot.NET.Sdk/4.6.0">
<Project Sdk="Godot.NET.Sdk/4.6.2">
<PropertyGroup>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<TargetFramework>net10.0</TargetFramework>
Expand Down