-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathProfile.cs
More file actions
111 lines (100 loc) · 4.22 KB
/
Profile.cs
File metadata and controls
111 lines (100 loc) · 4.22 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
using System;
using System.Text;
using System.Text.Json.Serialization;
using HtmlAgilityPack;
namespace CheatEngineForumScraper
{
public class Profile
{
[JsonPropertyName("id")]
public int Id { get; set; }
[JsonPropertyName("user_name")]
public string UserName { get; set; } = string.Empty;
[JsonPropertyName("email")]
public string Email { get; set; } = string.Empty;
[JsonPropertyName("joined")]
public DateOnly DateJoined { get; set; }
[JsonPropertyName("posts")]
public int TotalPosts { get; set; }
static StringBuilder _defaultBuilder = new();
private static string ClouldFlareDecodeEmail(string encodedString)
{
_defaultBuilder.Clear();
if (string.IsNullOrWhiteSpace(encodedString)) return string.Empty;
byte[] hexValue = Convert.FromHexString(encodedString);
for (int i = 1; i < hexValue.Length; i++)
_defaultBuilder.Append((char)(hexValue[i] ^ hexValue[0]));
return _defaultBuilder.ToString();
}
public static Profile? FromHtml(HtmlNode root)
{
const string XFORUM_LINE = "/html/body/table/tr/td/table[3]";
const string USER_NAME = "tr[2]/td[2]/b/span"; // "All about {USER_NAME}"
const string JOIN_DATE = "tr[3]/td[2]/table/tr[1]/td[2]/b/span";
const string POST_COUNT = "tr[3]/td[2]/table/tr[2]/td[2]/b/span";
const string EMAIL_URI = "tr[5]/td/table/tr[1]/td[2]/b/span/a";
const string USER_NAME_PREFIX = "All about ";
var infoTable = root.SelectSingleNode(XFORUM_LINE);
if (infoTable is null) return null;
HtmlNode? userNode = infoTable.SelectSingleNode(USER_NAME);
if (userNode is null) return null;
string username, email;
if (userNode.ChildNodes.Count > 1)
{
username = string.Empty;
// User signup using email as username
HtmlNode? emailNode = userNode.ChildNodes.FindFirst("a");
if (emailNode is not null)
{
string emailEncrypted = emailNode.GetAttributeValue("data-cfemail", string.Empty);
email = ClouldFlareDecodeEmail(emailEncrypted);
}
else
{
email = string.Empty;
}
}
else
{
username = userNode.InnerText.Substring(USER_NAME_PREFIX.Length) ?? string.Empty;
var emailNode = infoTable.SelectSingleNode(EMAIL_URI);
if (emailNode is not null)
{
email = emailNode.GetAttributeValue("href", string.Empty);
if (string.IsNullOrEmpty(email)) return null;
email = ClouldFlareDecodeEmail(email.Substring(email.IndexOf('#') + 1));
}
else
{
email = string.Empty;
}
}
bool parseSuccess = DateOnly.TryParse(infoTable.SelectSingleNode(JOIN_DATE)?.InnerText, out DateOnly joinDate);
if (!parseSuccess) return null;
parseSuccess = int.TryParse(infoTable.SelectSingleNode(POST_COUNT)?.InnerText, out int postCount);
if (!parseSuccess) return null;
return new Profile()
{
UserName = username,
DateJoined = joinDate,
TotalPosts = postCount,
Email = email,
};
}
public void Log()
{
Console.Write($"{Id}:[");
WriteToConsole(UserName, ConsoleColor.Blue);
WriteToConsole(Email, ConsoleColor.Yellow);
WriteToConsole(DateJoined.ToString("MM-yyyy"), ConsoleColor.Cyan);
WriteToConsole(TotalPosts.ToString(), ConsoleColor.Gray, "]\n");
Console.ResetColor();
}
private static void WriteToConsole(string str, ConsoleColor fgColor, string delimiter = ", ")
{
if (string.IsNullOrEmpty(str)) return;
Console.ForegroundColor = fgColor;
Console.Write(str + delimiter);
}
}
}