|
9 | 9 | using ModBot.Core;
|
10 | 10 | using FreneticUtilities.FreneticExtensions;
|
11 | 11 | using System.Collections.Concurrent;
|
| 12 | +using FreneticUtilities.FreneticToolkit; |
12 | 13 |
|
13 | 14 | namespace ModBot.WarningHandlers
|
14 | 15 | {
|
@@ -94,56 +95,57 @@ public static WarnableUser GetWarnableUser(ulong guildId, ulong id)
|
94 | 95 | /// <summary>Words that mean "permanent" that a user might try.</summary>
|
95 | 96 | public static HashSet<string> PermanentWords = new() { "permanent", "permanently", "indefinite", "indefinitely", "forever" };
|
96 | 97 |
|
97 |
| - /// <summary>Parses duration text into a valid TimeSpan, or null.</summary> |
98 |
| - public static TimeSpan? ParseShortDuration(string durationText) |
| 98 | + /// <summary>Helper to separate digits from letters, for <see cref="ParseDuration(string, bool)"/>.</summary> |
| 99 | + public static AsciiMatcher DigitMatcher = new(AsciiMatcher.Digits); |
| 100 | + |
| 101 | + /// <summary>Helper to identify timespan suffix keywords, for <see cref="ParseDuration(string, bool)"/>.</summary> |
| 102 | + public static Dictionary<string, string> TimespanSuffixRemapper = new(); |
| 103 | + static WarningUtilities() |
99 | 104 | {
|
100 |
| - durationText = durationText.ToLowerFast(); |
101 |
| - if (durationText == "0") |
102 |
| - { |
103 |
| - return TimeSpan.Zero; |
104 |
| - } |
105 |
| - if (durationText.EndsWith('m') && double.TryParse(durationText.Before('m'), out double minutes)) |
| 105 | + static void Add(string realKey, params string[] keys) |
106 | 106 | {
|
107 |
| - return TimeSpan.FromMinutes(minutes); |
108 |
| - } |
109 |
| - else if (durationText.EndsWith('h') && double.TryParse(durationText.Before('h'), out double hours)) |
110 |
| - { |
111 |
| - return TimeSpan.FromHours(hours); |
112 |
| - } |
113 |
| - else if (durationText.EndsWith('d') && double.TryParse(durationText.Before('d'), out double days)) |
114 |
| - { |
115 |
| - return TimeSpan.FromDays(days); |
| 107 | + foreach (string key in keys) |
| 108 | + { |
| 109 | + TimespanSuffixRemapper.Add(key, realKey); |
| 110 | + } |
| 111 | + TimespanSuffixRemapper.Add(realKey, realKey); |
116 | 112 | }
|
117 |
| - return null; |
| 113 | + Add("seconds", "s", "sec", "secs", "second"); |
| 114 | + Add("minutes", "min", "mins", "minute"); |
| 115 | + Add("hours", "h", "hr", "hrs", "hour"); |
| 116 | + Add("days", "d", "day"); |
| 117 | + Add("weeks", "w", "week"); |
| 118 | + Add("months", "mo", "mon", "mons", "month"); |
| 119 | + Add("years", "y", "yr", "yrs", "year"); |
118 | 120 | }
|
119 | 121 |
|
120 | 122 | /// <summary>Parses duration text into a valid TimeSpan, or null.</summary>
|
121 |
| - public static TimeSpan? ParseDuration(string durationText) |
| 123 | + public static TimeSpan? ParseDuration(string durationText, bool mForMinutes = false) |
122 | 124 | {
|
123 | 125 | durationText = durationText.ToLowerFast();
|
124 | 126 | if (PermanentWords.Contains(durationText))
|
125 | 127 | {
|
126 | 128 | return TimeSpan.FromDays(100 * 365);
|
127 | 129 | }
|
128 |
| - if (durationText.EndsWith('h') && double.TryParse(durationText.Before('h'), out double hours)) |
129 |
| - { |
130 |
| - return TimeSpan.FromHours(hours); |
131 |
| - } |
132 |
| - else if (durationText.EndsWith('d') && double.TryParse(durationText.Before('d'), out double days)) |
133 |
| - { |
134 |
| - return TimeSpan.FromDays(days); |
135 |
| - } |
136 |
| - else if (durationText.EndsWith('w') && double.TryParse(durationText.Before('w'), out double weeks)) |
137 |
| - { |
138 |
| - return TimeSpan.FromDays(weeks * 7); |
139 |
| - } |
140 |
| - else if (durationText.EndsWith('m') && double.TryParse(durationText.Before('m'), out double months)) |
| 130 | + int endOfNumber = DigitMatcher.FirstNonMatchingIndex(durationText); |
| 131 | + string numberText = durationText[..endOfNumber]; |
| 132 | + string suffixText = durationText[endOfNumber..].ToLowerFast(); |
| 133 | + if (suffixText == "m") |
141 | 134 | {
|
142 |
| - return TimeSpan.FromDays(months * 31); |
| 135 | + suffixText = mForMinutes ? "minutes" : "months"; |
143 | 136 | }
|
144 |
| - else if (durationText.EndsWith('y') && double.TryParse(durationText.Before('y'), out double years)) |
| 137 | + if (TimespanSuffixRemapper.TryGetValue(suffixText, out string formatText) && double.TryParse(numberText, out double numVal)) |
145 | 138 | {
|
146 |
| - return TimeSpan.FromDays(years * 365); |
| 139 | + switch (formatText) |
| 140 | + { |
| 141 | + case "seconds": return TimeSpan.FromSeconds(numVal); |
| 142 | + case "minutes": return TimeSpan.FromMinutes(numVal); |
| 143 | + case "hours": return TimeSpan.FromHours(numVal); |
| 144 | + case "days": return TimeSpan.FromDays(numVal); |
| 145 | + case "weeks": return TimeSpan.FromDays(numVal * 7); |
| 146 | + case "months": return TimeSpan.FromDays(numVal * 31); |
| 147 | + case "years": return TimeSpan.FromDays(numVal * 365); |
| 148 | + } |
147 | 149 | }
|
148 | 150 | return null;
|
149 | 151 | }
|
|
0 commit comments