Files
AX-Copilot-Codex/.decompiledproj/AxCopilot/Handlers/WebSearchHandler.cs

164 lines
6.1 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using AxCopilot.SDK;
using AxCopilot.Services;
namespace AxCopilot.Handlers;
public class WebSearchHandler : IActionHandler
{
private readonly SettingsService _settings;
private static readonly string _iconDir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? ".", "Assets", "SearchEngines");
private static readonly Dictionary<string, (string Name, string UrlTemplate, string Icon)> _engines = new Dictionary<string, (string, string, string)>
{
["g"] = ("Google", "https://www.google.com/search?q={0}", "google"),
["n"] = ("Naver", "https://search.naver.com/search.naver?query={0}", "naver"),
["y"] = ("YouTube", "https://www.youtube.com/results?search_query={0}", "youtube"),
["gh"] = ("GitHub", "https://github.com/search?q={0}", "github"),
["d"] = ("DuckDuckGo", "https://duckduckgo.com/?q={0}", "duckduckgo"),
["w"] = ("Wikipedia", "https://ko.wikipedia.org/w/index.php?search={0}", "wikipedia"),
["nm"] = ("Naver Map", "https://map.naver.com/p/search/{0}", "navermap"),
["nw"] = ("나무위키", "https://namu.wiki/Special:Search?query={0}", "namuwiki"),
["ni"] = ("Naver 이미지", "https://search.naver.com/search.naver?where=image&query={0}", "naver"),
["gi"] = ("Google 이미지", "https://www.google.com/search?tbm=isch&q={0}", "google")
};
private const string SecurityWarn = "⚠ 검색어가 외부로 전송됩니다 — 기밀 데이터 입력 금지";
public string? Prefix => "?";
public PluginMetadata Metadata => new PluginMetadata("WebSearch", "웹 검색 — ? 뒤에 검색어 또는 URL 입력", "1.0", "AX");
private string DefaultEngineKey => _settings.Settings.Launcher.WebSearchEngine ?? "g";
private (string Name, string UrlTemplate, string Icon) DefaultEngine
{
get
{
(string, string, string) value;
return _engines.TryGetValue(DefaultEngineKey, out value) ? value : _engines["g"];
}
}
public WebSearchHandler(SettingsService settings)
{
_settings = settings;
}
private static string? GetIconPath(string engineKey)
{
if (!_engines.TryGetValue(engineKey, out (string, string, string) value))
{
return null;
}
string text = Path.Combine(_iconDir, value.Item3 + ".png");
return File.Exists(text) ? text : null;
}
public Task<IEnumerable<LauncherItem>> GetItemsAsync(string query, CancellationToken ct)
{
if (string.IsNullOrWhiteSpace(query))
{
string iconPath = GetIconPath(DefaultEngineKey);
return Task.FromResult((IEnumerable<LauncherItem>)new _003C_003Ez__ReadOnlySingleElementList<LauncherItem>(new LauncherItem("검색어를 입력하세요", "예: ? 오늘 날씨 · ?g python · ?y 음악 · ?n 뉴스 | ⚠ 검색어가 외부로 전송됩니다 — 기밀 데이터 입력 금지", iconPath, null, null, "\ue774")));
}
List<LauncherItem> list = new List<LauncherItem>();
string text = query.Trim();
if (IsUrl(text))
{
string text2 = (text.StartsWith("http", StringComparison.OrdinalIgnoreCase) ? text : ("https://" + text));
string faviconPathForUrl = GetFaviconPathForUrl(text2);
list.Add(new LauncherItem("열기: " + text, text2 + " | ⚠ 검색어가 외부로 전송됩니다 — 기밀 데이터 입력 금지", faviconPathForUrl, text2, null, "\ue774"));
return Task.FromResult((IEnumerable<LauncherItem>)list);
}
string[] array = text.Split(' ', 2);
string text3 = array[0].ToLowerInvariant();
if (array.Length == 2 && _engines.TryGetValue(text3, out (string, string, string) value))
{
string text4 = array[1].Trim();
if (!string.IsNullOrWhiteSpace(text4))
{
string data = string.Format(value.Item2, Uri.EscapeDataString(text4));
list.Add(new LauncherItem(value.Item1 + "에서 '" + text4 + "' 검색", "⚠ 검색어가 외부로 전송됩니다 — 기밀 데이터 입력 금지", GetIconPath(text3), data, null, "\ue774"));
}
}
string defaultEngineKey = DefaultEngineKey;
(string, string, string) defaultEngine = DefaultEngine;
string data2 = string.Format(defaultEngine.Item2, Uri.EscapeDataString(text));
list.Add(new LauncherItem(defaultEngine.Item1 + "에서 '" + text + "' 검색", "⚠ 검색어가 외부로 전송됩니다 — 기밀 데이터 입력 금지", GetIconPath(defaultEngineKey), data2, null, "\ue774"));
if (text.Length <= 2)
{
foreach (var (text6, tuple2) in _engines)
{
list.Add(new LauncherItem("?" + text6 + " — " + tuple2.Item1, $"예: ?{text6} {text} | {" "}", GetIconPath(text6), null, null, "\ue774"));
}
}
return Task.FromResult((IEnumerable<LauncherItem>)list);
}
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 static bool IsUrl(string input)
{
if (input.StartsWith("http://", StringComparison.OrdinalIgnoreCase) || input.StartsWith("https://", StringComparison.OrdinalIgnoreCase))
{
return true;
}
if (!input.Contains(' ') && input.Contains('.') && input.Length > 3)
{
string text = input.Split('/')[0];
string[] array = text.Split('.');
return array.Length >= 2 && array[^1].Length >= 2 && array[^1].Length <= 6 && array[^1].All(char.IsLetter);
}
return false;
}
private static string? GetFaviconPathForUrl(string url)
{
try
{
if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
url = "https://" + url;
}
string text = new Uri(url).Host.ToLowerInvariant();
string text2 = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "favicons", text + ".png");
if (File.Exists(text2))
{
return text2;
}
FaviconService.GetFavicon(url);
return null;
}
catch
{
return null;
}
}
}