-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDictionaryService.cs
More file actions
170 lines (144 loc) · 5.9 KB
/
Copy pathDictionaryService.cs
File metadata and controls
170 lines (144 loc) · 5.9 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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace GameSnapPlugin
{
/// <summary>
/// Manages dictionary.txt with blocks [GameName] and aliases below.
/// Format:
/// [Cyberpunk 2077]
/// Cyberpunk2077
/// cyberpunk
/// </summary>
public class DictionaryService
{
private readonly string _dictionaryPath;
public DictionaryService(string pluginDataPath)
{
_dictionaryPath = Path.Combine(pluginDataPath, "dictionary.txt");
}
public string DictionaryPath => _dictionaryPath;
/// <summary>
/// Loads dictionary: key = normalized alias, value = game name.
/// </summary>
public Dictionary<string, string> Load()
{
var dict = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
if (!File.Exists(_dictionaryPath))
return dict;
string? currentGame = null;
foreach (var rawLine in File.ReadAllLines(_dictionaryPath, Encoding.UTF8))
{
var line = rawLine.Trim();
if (string.IsNullOrEmpty(line) || line.StartsWith("#"))
continue;
if (line.StartsWith("[") && line.EndsWith("]"))
{
currentGame = line.Substring(1, line.Length - 2).Trim();
// Also map the game name itself as an alias
var normGame = Normalize(currentGame);
if (!string.IsNullOrEmpty(normGame) && !dict.ContainsKey(normGame))
dict[normGame] = currentGame;
continue;
}
if (currentGame != null && !string.IsNullOrEmpty(line))
{
var key = Normalize(line);
if (!string.IsNullOrEmpty(key) && !dict.ContainsKey(key))
dict[key] = currentGame;
}
}
return dict;
}
/// <summary>
/// Saves a learned alias to dictionary.txt.
/// Creates the file with a header if it does not exist.
/// </summary>
// Prefixo válido: só letras, dígitos e alguns caracteres especiais seguros.
// Rejeita: datas (2026-05-30), timestamps (%t ...), nomes muito curtos.
private static bool IsValidPrefix(string prefix)
{
if (string.IsNullOrWhiteSpace(prefix)) return false;
if (prefix.Length < 2) return false;
// Rejeita se começa com % (artefatos do ShareX como %t, %d)
if (prefix.StartsWith("%")) return false;
// Rejeita se parece uma data (4 dígitos + traço)
if (prefix.Length >= 4 && char.IsDigit(prefix[0]) && char.IsDigit(prefix[1]) &&
char.IsDigit(prefix[2]) && char.IsDigit(prefix[3]))
return false;
// Rejeita se tem mais de 60 caracteres (provavelmente nome de arquivo completo)
if (prefix.Length > 60) return false;
return true;
}
public void SaveAlias(string prefix, string gameName)
{
if (string.IsNullOrWhiteSpace(prefix) || string.IsNullOrWhiteSpace(gameName))
return;
prefix = prefix.Trim();
gameName = gameName.Trim();
// Rejeita prefixos inválidos (datas, artefatos do ShareX, etc.)
if (!IsValidPrefix(prefix)) return;
// Don't save if already known
var existing = Load();
if (existing.TryGetValue(Normalize(prefix), out var known) &&
string.Equals(known, gameName, StringComparison.OrdinalIgnoreCase))
return;
// Create file with header if missing
if (!File.Exists(_dictionaryPath))
{
File.WriteAllText(_dictionaryPath,
"# GameSnap Dictionary\n" +
"# Format:\n" +
"# [Game Name]\n" +
"# alias1\n" +
"# alias2\n\n",
Encoding.UTF8);
}
var lines = new List<string>(File.ReadAllLines(_dictionaryPath, Encoding.UTF8));
var header = $"[{gameName}]";
int blockIdx = -1;
// Find existing block for this game
for (int i = 0; i < lines.Count; i++)
{
if (string.Equals(lines[i].Trim(), header, StringComparison.OrdinalIgnoreCase))
{
blockIdx = i;
break;
}
}
if (blockIdx >= 0)
{
// Check if alias already exists in the block
int j = blockIdx + 1;
while (j < lines.Count &&
!(lines[j].Trim().StartsWith("[") && lines[j].Trim().EndsWith("]")))
{
if (string.Equals(lines[j].Trim(), prefix, StringComparison.OrdinalIgnoreCase))
return; // already there
j++;
}
// Insert alias right after the block header
lines.Insert(blockIdx + 1, prefix);
}
else
{
// Add new block at the end
if (lines.Count > 0 && !string.IsNullOrEmpty(lines[lines.Count - 1]))
lines.Add("");
lines.Add(header);
lines.Add(prefix);
}
File.WriteAllLines(_dictionaryPath, lines, Encoding.UTF8);
}
public static string Normalize(string text)
{
if (string.IsNullOrEmpty(text)) return "";
var result = new StringBuilder();
foreach (var c in text.ToLowerInvariant())
if (char.IsLetterOrDigit(c) || c == ' ')
result.Append(c);
return result.ToString().Trim();
}
}
}