Skip to content

Commit 099e7b2

Browse files
committed
Added GitHub support for easy sorting by repositories and more.
1 parent a2ab465 commit 099e7b2

9 files changed

Lines changed: 678 additions & 131 deletions

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,3 +368,5 @@ Recap.Tests/
368368
/poe.json
369369
TestApp/vec0.dll
370370
TestApp/TestApp.csproj
371+
.history/
372+
.TestAppConsole/

Recap/Resources/AdvancedSettingsForm.cs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Data;
33
using System.Drawing;
4+
using System.Linq;
45
using System.Threading.Tasks;
56
using System.Windows.Forms;
67

@@ -94,10 +95,16 @@ private void InitializeComponent()
9495
btnRepairTimeline.Size = new System.Drawing.Size(120, 30);
9596
btnRepairTimeline.Click += OnRepairTimelineClick;
9697

98+
var btnMigrateApps = new Button();
99+
btnMigrateApps.Text = "Migrate Old Names";
100+
btnMigrateApps.Size = new System.Drawing.Size(120, 30);
101+
btnMigrateApps.Click += OnMigrateAppsClick;
102+
97103
panelButtons.Controls.Add(_btnCancel);
98104
panelButtons.Controls.Add(_btnSave);
99105
panelButtons.Controls.Add(_btnRebuildIndex);
100106
panelButtons.Controls.Add(btnRepairTimeline);
107+
panelButtons.Controls.Add(btnMigrateApps);
101108

102109
_tabSettings.Controls.Add(_propertyGrid);
103110
_tabSettings.Controls.Add(panelButtons);
@@ -315,5 +322,82 @@ private void ExecuteSql()
315322
MessageBox.Show(ex.Message, "SQL Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
316323
}
317324
}
325+
326+
private async void OnMigrateAppsClick(object sender, EventArgs e)
327+
{
328+
if (_ocrDb == null)
329+
{
330+
MessageBox.Show("Database not initialized.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
331+
return;
332+
}
333+
334+
var confirmResult = MessageBox.Show(
335+
"This will scan the database for old flat records and upgrade them to the new hierarchical format. Continue?",
336+
"Confirm Migration",
337+
MessageBoxButtons.YesNo,
338+
MessageBoxIcon.Question);
339+
340+
if (confirmResult != DialogResult.Yes)
341+
return;
342+
343+
Button btn = sender as Button;
344+
if (btn != null) btn.Enabled = false;
345+
346+
try
347+
{
348+
int updatedCount = 0;
349+
await Task.Run(() =>
350+
{
351+
var legacyNames = _ocrDb.GetLegacyAppNames();
352+
foreach (var oldName in legacyNames)
353+
{
354+
var parts = oldName.Split('|');
355+
if (parts.Length < 2) continue;
356+
357+
string processName = parts[0];
358+
string procLower = processName.ToLower();
359+
360+
bool isBrowser = procLower.Contains("chrome") || procLower.Contains("msedge") || procLower.Contains("brave") || procLower.Contains("opera");
361+
string newName = oldName;
362+
363+
if (isBrowser)
364+
{
365+
if (parts.Length >= 3)
366+
{
367+
string domain = parts[1];
368+
string title = string.Join("|", parts.Skip(2));
369+
newName = Utilities.AppNameParser.ParseWindowName(processName, domain, title);
370+
}
371+
}
372+
else
373+
{
374+
if (parts.Length >= 2)
375+
{
376+
string title = string.Join("|", parts.Skip(1));
377+
newName = Utilities.AppNameParser.ParseWindowName(processName, "", title);
378+
}
379+
}
380+
381+
if (newName != oldName && newName.Contains("|"))
382+
{
383+
_ocrDb.RenameApp(oldName, newName);
384+
updatedCount++;
385+
}
386+
}
387+
388+
_ocrDb.RepairNullAppIds();
389+
});
390+
391+
MessageBox.Show($"Migration completed successfully.\nUpdated {updatedCount} applications to the new format.\n\nNote: Please RESTART the application to load the new data into the timeline cache.", "Migration Complete", MessageBoxButtons.OK, MessageBoxIcon.Information);
392+
}
393+
catch (Exception ex)
394+
{
395+
MessageBox.Show($"Error during migration: {ex.Message}", "Migration Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
396+
}
397+
finally
398+
{
399+
if (btn != null) btn.Enabled = true;
400+
}
401+
}
318402
}
319403
}

Recap/Resources/AppFilterController.cs

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,8 @@ private class ParsedAppInfo
166166
public string EffectiveExe;
167167
public string GroupKey;
168168
public string DetailKey;
169+
public string SubDetailKey;
170+
public string ExtraDetailKey;
169171
public bool IsVideo;
170172
public string VideoId;
171173
}
@@ -318,6 +320,28 @@ private void RebuildStats()
318320
detailNode.IsVideoNode = true;
319321
detailNode.VideoId = info.VideoId;
320322
}
323+
324+
if (info.SubDetailKey != null)
325+
{
326+
if (!detailNode.Children.TryGetValue(info.SubDetailKey, out var subDetailNode))
327+
{
328+
subDetailNode = new NodeData();
329+
detailNode.Children[info.SubDetailKey] = subDetailNode;
330+
}
331+
subDetailNode.TotalMs += duration;
332+
subDetailNode.FrameCount++;
333+
334+
if (info.ExtraDetailKey != null)
335+
{
336+
if (!subDetailNode.Children.TryGetValue(info.ExtraDetailKey, out var extraDetailNode))
337+
{
338+
extraDetailNode = new NodeData();
339+
subDetailNode.Children[info.ExtraDetailKey] = extraDetailNode;
340+
}
341+
extraDetailNode.TotalMs += duration;
342+
extraDetailNode.FrameCount++;
343+
}
344+
}
321345
}
322346
}
323347
}
@@ -399,6 +423,26 @@ private void ProcessFrameForStats(MiniFrame f, long duration, Dictionary<string,
399423
detailNode.IsVideoNode = true;
400424
detailNode.VideoId = info.VideoId;
401425
}
426+
427+
if (info.SubDetailKey != null)
428+
{
429+
if (!detailNode.Children.ContainsKey(info.SubDetailKey))
430+
detailNode.Children[info.SubDetailKey] = new NodeData();
431+
432+
var subDetailNode = detailNode.Children[info.SubDetailKey];
433+
subDetailNode.TotalMs += duration;
434+
subDetailNode.FrameCount++;
435+
436+
if (info.ExtraDetailKey != null)
437+
{
438+
if (!subDetailNode.Children.ContainsKey(info.ExtraDetailKey))
439+
subDetailNode.Children[info.ExtraDetailKey] = new NodeData();
440+
441+
var extraDetailNode = subDetailNode.Children[info.ExtraDetailKey];
442+
extraDetailNode.TotalMs += duration;
443+
extraDetailNode.FrameCount++;
444+
}
445+
}
402446
}
403447
}
404448
}
@@ -432,6 +476,20 @@ private ParsedAppInfo ParseAppInfo(string currentAppName)
432476
{
433477
info.GroupKey = rest.Substring(0, pipeIndex);
434478
info.DetailKey = rest.Substring(pipeIndex + 1);
479+
480+
int secondPipeIndex = info.DetailKey.IndexOf('|');
481+
if (secondPipeIndex > 0)
482+
{
483+
info.SubDetailKey = info.DetailKey.Substring(secondPipeIndex + 1);
484+
info.DetailKey = info.DetailKey.Substring(0, secondPipeIndex);
485+
486+
int thirdPipeIndex = info.SubDetailKey.IndexOf('|');
487+
if (thirdPipeIndex > 0)
488+
{
489+
info.ExtraDetailKey = info.SubDetailKey.Substring(thirdPipeIndex + 1);
490+
info.SubDetailKey = info.SubDetailKey.Substring(0, thirdPipeIndex);
491+
}
492+
}
435493
}
436494
else if (isYouTube)
437495
{
@@ -525,6 +583,22 @@ private void RebuildAggregatedStats()
525583
aggGrand.IsVideoNode = true;
526584
aggGrand.VideoId = grandKvp.Value.VideoId;
527585
}
586+
587+
foreach (var greatGrandKvp in grandKvp.Value.Children)
588+
{
589+
if (!aggGrand.Children.ContainsKey(greatGrandKvp.Key)) aggGrand.Children[greatGrandKvp.Key] = new NodeData();
590+
var aggGreatGrand = aggGrand.Children[greatGrandKvp.Key];
591+
aggGreatGrand.TotalMs += greatGrandKvp.Value.TotalMs;
592+
aggGreatGrand.FrameCount += greatGrandKvp.Value.FrameCount;
593+
594+
foreach (var extraKvp in greatGrandKvp.Value.Children)
595+
{
596+
if (!aggGreatGrand.Children.ContainsKey(extraKvp.Key)) aggGreatGrand.Children[extraKvp.Key] = new NodeData();
597+
var aggExtra = aggGreatGrand.Children[extraKvp.Key];
598+
aggExtra.TotalMs += extraKvp.Value.TotalMs;
599+
aggExtra.FrameCount += extraKvp.Value.FrameCount;
600+
}
601+
}
528602
}
529603
}
530604
}
@@ -749,11 +823,18 @@ private void RenderChildren(NodeData parentNode, string parentRaw, string parent
749823

750824
bool isGroupExpanded = _expandedGroups.Contains(fullGroupKey) || isSearch;
751825

826+
string displayChildName = childName;
827+
if (level == 2 && parentRaw != null && parentRaw.Contains("|github.com") && childName.Contains("/") && childName.Split('/').Length == 2)
828+
{
829+
string[] splitRepo = childName.Split('/');
830+
displayChildName = $"{splitRepo[1]} - {splitRepo[0]}";
831+
}
832+
752833
var childItem = new FilterItem
753834
{
754835
RawName = fullGroupKey,
755836
RawNames = new List<string> { $"{parentRaw}|{childName}" },
756-
DisplayName = childName,
837+
DisplayName = displayChildName,
757838
DurationMs = childNode.TotalMs,
758839
FrameCount = childNode.FrameCount,
759840
Level = level,

Recap/Resources/CaptureController.cs

Lines changed: 5 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -112,134 +112,10 @@ private async void OnTimerTick(object sender, EventArgs e)
112112
IntPtr realHwnd = ActiveWindowHelper.GetRealWindow(hWnd);
113113

114114
string processName = ActiveWindowHelper.GetProcessNameFromHwnd(realHwnd);
115-
string finalAppName = processName;
116-
string procLower = processName.ToLower();
117-
118-
if (procLower.Contains("chrome") ||
119-
procLower.Contains("msedge") ||
120-
procLower.Contains("brave") ||
121-
procLower.Contains("opera"))
122-
{
123-
string domain = _browserTracker.CurrentDomain;
124-
if (!string.IsNullOrEmpty(domain))
125-
{
126-
string title = ActiveWindowHelper.GetWindowTitleFromHwnd(hWnd);
127-
title = CleanupBrowserSuffixes(title);
128-
129-
if (domain.Contains("kick.com"))
130-
{
131-
string clean = CleanupTitle(title, new[] { " - Kick", " | Kick" });
132-
if (!string.IsNullOrEmpty(clean))
133-
{
134-
finalAppName = $"{processName}|kick.com|{clean}";
135-
}
136-
else
137-
{
138-
finalAppName = $"{processName}|kick.com|Stream";
139-
}
140-
}
141-
else if (domain.Contains("aistudio.google.com"))
142-
{
143-
string clean = CleanupTitle(title, new[] { " - Google AI Studio", " | Google AI Studio" });
144-
if (!string.IsNullOrEmpty(clean))
145-
{
146-
finalAppName = $"{processName}|aistudio.google.com|{clean}";
147-
}
148-
else
149-
{
150-
finalAppName = $"{processName}|aistudio.google.com|Prompt";
151-
}
152-
}
153-
else
154-
{
155-
finalAppName = $"{processName}|{domain}";
156-
}
157-
}
158-
}
159-
else if (procLower.Contains("code"))
160-
{
161-
string title = ActiveWindowHelper.GetWindowTitleFromHwnd(hWnd);
162-
if (title.StartsWith("● ")) title = title.Substring(2);
163-
164-
string project = CleanupTitle(title, new[] { " - Visual Studio Code" });
165-
166-
if (!string.IsNullOrEmpty(project))
167-
{
168-
int lastDash = project.LastIndexOf(" - ");
169-
if (lastDash >= 0 && lastDash < project.Length - 3)
170-
{
171-
string projName = project.Substring(lastDash + 3);
172-
string fileName = project.Substring(0, lastDash);
173-
finalAppName = $"{processName}|{projName}|{fileName}";
174-
}
175-
else
176-
{
177-
finalAppName = $"{processName}|{project}";
178-
}
179-
}
180-
}
181-
else if (procLower.Contains("devenv"))
182-
{
183-
string title = ActiveWindowHelper.GetWindowTitleFromHwnd(hWnd);
184-
string solution = CleanupTitle(title, new[] { " - Microsoft Visual Studio", " - Visual Studio" });
185-
186-
if (!string.IsNullOrEmpty(solution))
187-
{
188-
int lastDash = solution.LastIndexOf(" - ");
189-
if (lastDash >= 0 && lastDash < solution.Length - 3)
190-
{
191-
string solName = solution.Substring(0, lastDash);
192-
string fileName = solution.Substring(lastDash + 3);
193-
194-
fileName = fileName.TrimEnd('*');
195-
fileName = Regex.Replace(fileName, @"\s\([^\)]+\)$", "");
196-
finalAppName = $"{processName}|{solName}|{fileName}";
197-
}
198-
else
199-
{
200-
solution = solution.TrimEnd('*');
201-
solution = Regex.Replace(solution, @"\s\([^\)]+\)$", "");
202-
finalAppName = $"{processName}|{solution}";
203-
}
204-
}
205-
}
206-
else if (procLower.Contains("antigravity"))
207-
{
208-
string title = ActiveWindowHelper.GetWindowTitleFromHwnd(hWnd);
209-
if (title.StartsWith("● ")) title = title.Substring(2);
210-
211-
string[] parts = title.Split(new[] { " - Antigravity - " }, StringSplitOptions.None);
212-
if (parts.Length == 2)
213-
{
214-
string projName = parts[0].Trim();
215-
string fileName = parts[1].Trim();
216-
finalAppName = $"{processName}|{projName}|{fileName}";
217-
}
218-
else
219-
{
220-
string clean = CleanupTitle(title, new[] { " - Antigravity" });
221-
finalAppName = $"{processName}|{clean}";
222-
}
223-
}
224-
else if (procLower.Contains("telegram") || procLower.Contains("ayugram") || procLower.Contains("kotatogram"))
225-
{
226-
string title = ActiveWindowHelper.GetWindowTitleFromHwnd(hWnd);
227-
228-
if (!string.IsNullOrWhiteSpace(title))
229-
{
230-
string chatName = title;
231-
232-
chatName = Regex.Replace(chatName, @"[\d\(\)]", "");
233-
234-
chatName = chatName.Trim();
235-
if (!string.IsNullOrEmpty(chatName) &&
236-
!chatName.Equals("Telegram", StringComparison.OrdinalIgnoreCase) &&
237-
!chatName.Equals("AyuGram", StringComparison.OrdinalIgnoreCase))
238-
{
239-
finalAppName = $"{processName}|{chatName}";
240-
}
241-
}
242-
}
115+
string title = ActiveWindowHelper.GetWindowTitleFromHwnd(hWnd);
116+
string domain = _browserTracker.CurrentDomain;
117+
118+
string finalAppName = Utilities.AppNameParser.ParseWindowName(processName, domain, title);
243119

244120
bool isBlacklisted = false;
245121
if (_settings.OcrBlacklist != null && _settings.OcrBlacklist.Count > 0)
@@ -378,4 +254,4 @@ public void Dispose()
378254
}
379255
}
380256
}
381-
257+

0 commit comments

Comments
 (0)