Initial commit to new repository

This commit is contained in:
2026-04-03 18:22:19 +09:00
commit 4458bb0f52
7672 changed files with 452440 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
namespace AxCopilot.Services;
public static class FaviconService
{
private static readonly string CacheDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "AxCopilot", "favicons");
private static readonly ConcurrentDictionary<string, BitmapImage?> _memCache = new ConcurrentDictionary<string, BitmapImage>();
private static readonly HttpClient _http = new HttpClient
{
Timeout = TimeSpan.FromSeconds(5.0)
};
public static BitmapImage? GetFavicon(string url, Action? onLoaded = null)
{
string text = ExtractDomain(url);
if (string.IsNullOrEmpty(text))
{
return null;
}
if (_memCache.TryGetValue(text, out BitmapImage value))
{
return value;
}
string text2 = Path.Combine(CacheDir, text + ".png");
if (File.Exists(text2))
{
try
{
BitmapImage bitmapImage = LoadFromDisk(text2);
_memCache[text] = bitmapImage;
return bitmapImage;
}
catch
{
}
}
_memCache[text] = null;
DownloadAsync(text, text2, onLoaded);
return null;
}
private static async Task DownloadAsync(string domain, string diskPath, Action? onLoaded)
{
try
{
string faviconUrl = "https://www.google.com/s2/favicons?domain=" + Uri.EscapeDataString(domain) + "&sz=32";
byte[] bytes = await _http.GetByteArrayAsync(faviconUrl).ConfigureAwait(continueOnCapturedContext: false);
if (bytes.Length < 100)
{
return;
}
Directory.CreateDirectory(CacheDir);
await File.WriteAllBytesAsync(diskPath, bytes).ConfigureAwait(continueOnCapturedContext: false);
Application current = Application.Current;
if (current == null)
{
return;
}
((DispatcherObject)current).Dispatcher.Invoke((Action)delegate
{
try
{
BitmapImage value = LoadFromDisk(diskPath);
_memCache[domain] = value;
onLoaded?.Invoke();
}
catch
{
}
});
}
catch (Exception ex)
{
Exception ex2 = ex;
LogService.Warn("Favicon 다운로드 실패: " + domain + " — " + ex2.Message);
}
}
private static BitmapImage LoadFromDisk(string path)
{
BitmapImage bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.UriSource = new Uri(path, UriKind.Absolute);
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.DecodePixelWidth = 32;
bitmapImage.EndInit();
((Freezable)bitmapImage).Freeze();
return bitmapImage;
}
private static string? ExtractDomain(string url)
{
try
{
if (!url.StartsWith("http", StringComparison.OrdinalIgnoreCase))
{
url = "https://" + url;
}
return new Uri(url).Host.ToLowerInvariant();
}
catch
{
return null;
}
}
}