using Hangfire;
using Masuit.MyBlogs.Core.Configs;
using Masuit.Tools.Html;
using Masuit.Tools.Logging;
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using System.Web;
namespace Masuit.MyBlogs.Core.Common
{
///
/// 图床客户端
///
public sealed class ImagebedClient
{
private readonly HttpClient _httpClient;
private readonly IConfiguration _config;
///
/// 图床客户端
///
///
///
public ImagebedClient(HttpClient httpClient, IConfiguration config)
{
_config = config;
_httpClient = httpClient;
}
private readonly List _failedList = new();
///
/// 上传图片
///
///
///
///
public Task<(string url, bool success)> UploadImage(Stream stream, string file, CancellationToken cancellationToken)
{
if (stream.Length < 51200)
{
return Task.FromResult<(string, bool)>((null, false));
}
file = Regex.Replace(Path.GetFileName(file), @"\p{P}|\p{S}", "");
var gitlabs = AppConfig.GitlabConfigs.Where(c => c.FileLimitSize >= stream.Length && !_failedList.Contains(c.ApiUrl)).OrderByRandom().ToList();
if (gitlabs.Count > 0)
{
var gitlab = gitlabs[0];
if (gitlab.ApiUrl.Contains("api.github.com"))
{
return UploadGithub(gitlab, stream, file, cancellationToken);
}
return UploadGitlab(gitlab, stream, file, cancellationToken);
}
return Task.FromResult<(string, bool)>((null, false));
}
///
/// github图床
///
///
///
///
///
private Task<(string url, bool success)> UploadGithub(GitlabConfig config, Stream stream, string file, CancellationToken cancellationToken)
{
var path = $"{DateTime.Now:yyyy\\/MM\\/dd}/{file}";
_httpClient.DefaultRequestHeaders.UserAgent.Add(ProductInfoHeaderValue.Parse("Awesome-Octocat-App"));
_httpClient.DefaultRequestHeaders.Authorization = AuthenticationHeaderValue.Parse("token " + config.AccessToken);
return _httpClient.PutAsJsonAsync(config.ApiUrl + HttpUtility.UrlEncode(path), new
{
message = SnowFlake.NewId,
committer = new
{
name = SnowFlake.NewId,
email = "1@1.cn"
},
content = Convert.ToBase64String(stream.ToArray())
}, cancellationToken).ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
{
using var resp = t.Result;
using var content = resp.Content;
if (resp.IsSuccessStatusCode)
{
return (config.RawUrl.Split(',').OrderByRandom().FirstOrDefault() + path, true);
}
}
LogManager.Info("图片上传到gitee失败。");
return (null, false);
});
}
///
/// github图床
///
///
///
///
///
private Task<(string url, bool success)> UploadGitlab(GitlabConfig config, Stream stream, string file, CancellationToken cancellationToken)
{
var path = $"{DateTime.Now:yyyy\\/MM\\/dd}/{file}";
_httpClient.DefaultRequestHeaders.Add("PRIVATE-TOKEN", config.AccessToken);
return _httpClient.PostAsJsonAsync(config.ApiUrl.Contains("/v3/") ? config.ApiUrl : config.ApiUrl + HttpUtility.UrlEncode(path), new
{
file_path = path,
branch_name = config.Branch,
branch = config.Branch,
author_email = CommonHelper.SystemSettings["ReceiveEmail"],
author_name = SnowFlake.NewId,
encoding = "base64",
content = Convert.ToBase64String(stream.ToArray()),
commit_message = SnowFlake.NewId
}, cancellationToken).ContinueWith(t =>
{
if (t.IsCompletedSuccessfully)
{
using var resp = t.Result;
using var content = resp.Content;
if (resp.IsSuccessStatusCode || content.ReadAsStringAsync().Result.Contains("already exists"))
{
return (config.RawUrl + path, true);
}
}
LogManager.Info($"图片上传到gitlab({config.ApiUrl})失败。");
_failedList.Add(config.ApiUrl);
return (null, false);
});
}
///
/// 替换img标签的src属性
///
///
///
public async Task ReplaceImgSrc(string content, CancellationToken cancellationToken)
{
if (bool.TryParse(_config["Imgbed:EnableLocalStorage"], out var b) && b)
{
return content;
}
var srcs = content.MatchImgSrcs();
foreach (var src in srcs)
{
if (src.StartsWith("http"))
{
continue;
}
var path = Path.Combine(AppContext.BaseDirectory + "wwwroot", src.Replace("/", @"\")[1..]);
if (!File.Exists(path))
{
continue;
}
await using var stream = File.OpenRead(path);
var (url, success) = await UploadImage(stream, path, cancellationToken);
if (success)
{
content = content.Replace(src, url);
BackgroundJob.Enqueue(() => File.Delete(path));
}
}
return content;
}
}
}