2024-03-17 18:37:06 -07:00
|
|
|
|
using System;
|
2024-02-05 23:08:37 -08:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
using Avalonia.Media.Imaging;
|
|
|
|
|
using Avalonia.Threading;
|
|
|
|
|
|
|
|
|
|
namespace SourceGit.Models
|
|
|
|
|
{
|
|
|
|
|
public interface IAvatarHost
|
|
|
|
|
{
|
2024-02-22 19:39:05 -08:00
|
|
|
|
void OnAvatarResourceChanged(string md5);
|
2024-02-05 23:08:37 -08:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public static class AvatarManager
|
|
|
|
|
{
|
|
|
|
|
public static string SelectedServer
|
|
|
|
|
{
|
2024-02-22 19:39:05 -08:00
|
|
|
|
get;
|
|
|
|
|
set;
|
|
|
|
|
} = "https://www.gravatar.com/avatar/";
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
static AvatarManager()
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_storePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "SourceGit", "avatars");
|
|
|
|
|
if (!Directory.Exists(_storePath)) Directory.CreateDirectory(_storePath);
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
Task.Run(() =>
|
|
|
|
|
{
|
|
|
|
|
while (true)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
var md5 = null as string;
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
lock (_synclock)
|
|
|
|
|
{
|
|
|
|
|
foreach (var one in _requesting)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
md5 = one;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (md5 == null)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
Thread.Sleep(100);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var localFile = Path.Combine(_storePath, md5);
|
|
|
|
|
var img = null as Bitmap;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
try
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
var client = new HttpClient() { Timeout = TimeSpan.FromSeconds(2) };
|
2024-02-22 19:39:05 -08:00
|
|
|
|
var task = client.GetAsync($"{SelectedServer}{md5}?d=404");
|
2024-02-05 23:08:37 -08:00
|
|
|
|
task.Wait();
|
|
|
|
|
|
|
|
|
|
var rsp = task.Result;
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (rsp.IsSuccessStatusCode)
|
|
|
|
|
{
|
|
|
|
|
using (var stream = rsp.Content.ReadAsStream())
|
|
|
|
|
{
|
|
|
|
|
using (var writer = File.OpenWrite(localFile))
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
stream.CopyTo(writer);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
using (var reader = File.OpenRead(localFile))
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
img = Bitmap.DecodeToWidth(reader, 128);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
catch { }
|
2024-02-05 23:08:37 -08:00
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
lock (_synclock)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
_requesting.Remove(md5);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
Dispatcher.UIThread.InvokeAsync(() =>
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
if (_resources.ContainsKey(md5)) _resources[md5] = img;
|
|
|
|
|
else _resources.Add(md5, img);
|
2024-02-22 19:39:05 -08:00
|
|
|
|
NotifyResourceChanged(md5);
|
2024-02-05 23:08:37 -08:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public static void Subscribe(IAvatarHost host)
|
|
|
|
|
{
|
2024-02-22 19:39:05 -08:00
|
|
|
|
_avatars.Add(host);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public static void Unsubscribe(IAvatarHost host)
|
|
|
|
|
{
|
2024-02-22 19:39:05 -08:00
|
|
|
|
_avatars.Remove(host);
|
2024-02-05 23:08:37 -08:00
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
public static Bitmap Request(string md5, bool forceRefetch = false)
|
|
|
|
|
{
|
|
|
|
|
if (forceRefetch)
|
|
|
|
|
{
|
2024-02-22 19:39:05 -08:00
|
|
|
|
if (_resources.ContainsKey(md5)) _resources.Remove(md5);
|
|
|
|
|
|
|
|
|
|
var localFile = Path.Combine(_storePath, md5);
|
|
|
|
|
if (File.Exists(localFile)) File.Delete(localFile);
|
|
|
|
|
|
|
|
|
|
NotifyResourceChanged(md5);
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
if (_resources.ContainsKey(md5)) return _resources[md5];
|
|
|
|
|
|
|
|
|
|
var localFile = Path.Combine(_storePath, md5);
|
2024-03-17 18:37:06 -07:00
|
|
|
|
if (File.Exists(localFile))
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
using (var stream = File.OpenRead(localFile))
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
var img = Bitmap.DecodeToWidth(stream, 128);
|
|
|
|
|
_resources.Add(md5, img);
|
|
|
|
|
return img;
|
|
|
|
|
}
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|
|
|
|
|
catch { }
|
2024-02-05 23:08:37 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
lock (_synclock)
|
|
|
|
|
{
|
2024-02-05 23:08:37 -08:00
|
|
|
|
if (!_requesting.Contains(md5)) _requesting.Add(md5);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private static void NotifyResourceChanged(string md5)
|
|
|
|
|
{
|
|
|
|
|
foreach (var avatar in _avatars)
|
|
|
|
|
{
|
2024-02-22 19:39:05 -08:00
|
|
|
|
avatar.OnAvatarResourceChanged(md5);
|
2024-02-05 23:08:37 -08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-17 18:37:06 -07:00
|
|
|
|
private static readonly object _synclock = new object();
|
|
|
|
|
private static readonly string _storePath = string.Empty;
|
|
|
|
|
private static readonly List<IAvatarHost> _avatars = new List<IAvatarHost>();
|
|
|
|
|
private static readonly Dictionary<string, Bitmap> _resources = new Dictionary<string, Bitmap>();
|
|
|
|
|
private static readonly HashSet<string> _requesting = new HashSet<string>();
|
2024-02-05 23:08:37 -08:00
|
|
|
|
}
|
2024-03-17 18:37:06 -07:00
|
|
|
|
}
|