117 lines
2.8 KiB
C#
117 lines
2.8 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|