Initial commit to new repository
This commit is contained in:
178
.decompiledproj/AxCopilot/Handlers/BookmarkHandler.cs
Normal file
178
.decompiledproj/AxCopilot/Handlers/BookmarkHandler.cs
Normal file
@@ -0,0 +1,178 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using AxCopilot.SDK;
|
||||
using AxCopilot.Services;
|
||||
|
||||
namespace AxCopilot.Handlers;
|
||||
|
||||
public class BookmarkHandler : IActionHandler
|
||||
{
|
||||
private record BookmarkEntry(string Name, string? Url);
|
||||
|
||||
private List<BookmarkEntry>? _cache;
|
||||
|
||||
private DateTime _cacheTime = DateTime.MinValue;
|
||||
|
||||
private static readonly TimeSpan CacheTtl = TimeSpan.FromMinutes(5.0);
|
||||
|
||||
public string? Prefix => null;
|
||||
|
||||
public PluginMetadata Metadata => new PluginMetadata("Bookmarks", "Chrome / Edge 북마크 검색", "1.0", "AX");
|
||||
|
||||
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(query))
|
||||
{
|
||||
return Task.FromResult((IEnumerable<LauncherItem>)Array.Empty<LauncherItem>());
|
||||
}
|
||||
RefreshCacheIfNeeded();
|
||||
if (_cache == null || _cache.Count == 0)
|
||||
{
|
||||
return Task.FromResult((IEnumerable<LauncherItem>)Array.Empty<LauncherItem>());
|
||||
}
|
||||
string q = query.Trim().ToLowerInvariant();
|
||||
List<LauncherItem> result = (from b in _cache.Where((BookmarkEntry b) => b.Name.ToLowerInvariant().Contains(q) || (b.Url?.ToLowerInvariant().Contains(q) ?? false)).Take(8)
|
||||
select new LauncherItem(b.Name, b.Url ?? "", null, b.Url, null, "\ue774")).ToList();
|
||||
return Task.FromResult((IEnumerable<LauncherItem>)result);
|
||||
}
|
||||
|
||||
public Task ExecuteAsync(LauncherItem item, CancellationToken ct)
|
||||
{
|
||||
if (item.Data is string text && !string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
try
|
||||
{
|
||||
Process.Start(new ProcessStartInfo(text)
|
||||
{
|
||||
UseShellExecute = true
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("북마크 열기 실패: " + ex.Message);
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void RefreshCacheIfNeeded()
|
||||
{
|
||||
if (_cache != null && DateTime.Now - _cacheTime < CacheTtl)
|
||||
{
|
||||
return;
|
||||
}
|
||||
List<BookmarkEntry> list = new List<BookmarkEntry>();
|
||||
foreach (string bookmarkFile in GetBookmarkFiles())
|
||||
{
|
||||
try
|
||||
{
|
||||
string json = File.ReadAllText(bookmarkFile);
|
||||
ParseChromeBookmarks(json, list);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogService.Warn("북마크 파일 읽기 실패: " + bookmarkFile + " — " + ex.Message);
|
||||
}
|
||||
}
|
||||
_cache = list;
|
||||
_cacheTime = DateTime.Now;
|
||||
LogService.Info($"북마크 로드 완료: {list.Count}개");
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetBookmarkFiles()
|
||||
{
|
||||
string localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
string[] chromePaths = new string[4]
|
||||
{
|
||||
Path.Combine(localAppData, "Google", "Chrome", "User Data"),
|
||||
Path.Combine(localAppData, "Google", "Chrome Beta", "User Data"),
|
||||
Path.Combine(localAppData, "Google", "Chrome Dev", "User Data"),
|
||||
Path.Combine(localAppData, "Google", "Chrome SxS", "User Data")
|
||||
};
|
||||
string[] edgePaths = new string[4]
|
||||
{
|
||||
Path.Combine(localAppData, "Microsoft", "Edge", "User Data"),
|
||||
Path.Combine(localAppData, "Microsoft", "Edge Beta", "User Data"),
|
||||
Path.Combine(localAppData, "Microsoft", "Edge Dev", "User Data"),
|
||||
Path.Combine(localAppData, "Microsoft", "Edge Canary", "User Data")
|
||||
};
|
||||
foreach (string profileRoot in chromePaths.Concat(edgePaths))
|
||||
{
|
||||
if (!Directory.Exists(profileRoot))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
string defaultBookmark = Path.Combine(profileRoot, "Default", "Bookmarks");
|
||||
if (File.Exists(defaultBookmark))
|
||||
{
|
||||
yield return defaultBookmark;
|
||||
}
|
||||
string[] directories = Directory.GetDirectories(profileRoot, "Profile *");
|
||||
foreach (string dir in directories)
|
||||
{
|
||||
string f = Path.Combine(dir, "Bookmarks");
|
||||
if (File.Exists(f))
|
||||
{
|
||||
yield return f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParseChromeBookmarks(string json, List<BookmarkEntry> result)
|
||||
{
|
||||
JsonNode jsonNode = JsonNode.Parse(json)?["roots"];
|
||||
if (jsonNode == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
string[] array = new string[3] { "bookmark_bar", "other", "synced" };
|
||||
foreach (string propertyName in array)
|
||||
{
|
||||
JsonNode jsonNode2 = jsonNode[propertyName];
|
||||
if (jsonNode2 != null)
|
||||
{
|
||||
WalkNode(jsonNode2, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void WalkNode(JsonNode node, List<BookmarkEntry> result)
|
||||
{
|
||||
string text = node["type"]?.GetValue<string>();
|
||||
if (text == "url")
|
||||
{
|
||||
string text2 = node["name"]?.GetValue<string>() ?? "";
|
||||
string text3 = node["url"]?.GetValue<string>() ?? "";
|
||||
if (!string.IsNullOrWhiteSpace(text2) && !string.IsNullOrWhiteSpace(text3))
|
||||
{
|
||||
result.Add(new BookmarkEntry(text2, text3));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(text == "folder"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
JsonArray jsonArray = node["children"]?.AsArray();
|
||||
if (jsonArray == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
foreach (JsonNode item in jsonArray)
|
||||
{
|
||||
if (item != null)
|
||||
{
|
||||
WalkNode(item, result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user