fix: 修复文件列表为空时的返回值处理并添加图像处理相关依赖

This commit is contained in:
Megghy
2025-09-29 13:41:32 +08:00
parent 7abe753401
commit 360cc79e18
12 changed files with 1913 additions and 0 deletions

View File

@@ -0,0 +1,136 @@
using MegghysAPI.Modules;
using Microsoft.AspNetCore.Mvc;
using System.Text.Json;
using System.Text.Json.Nodes;
namespace MegghysAPI.Controllers
{
[Route("api/bili")]
[ApiController]
public class BiliController : MControllerBase
{
[HttpGet("test-cap")]
public async Task<IActionResult> TestCap([FromQuery] string gt, [FromQuery] string challenge)
{
var solution = await CapResolver.SolveGeetestAsync("https://www.bilibili.com", gt, challenge);
return Ok(ResponseOK(solution));
}
[HttpGet("resolve-grisk-id")]
public async Task<IActionResult> ResolveGriskId([FromQuery] string v_voucher, [FromQuery] string? csrf)
{
if (string.IsNullOrEmpty(v_voucher))
{
return BadRequest(ResponseBadRequest("v_voucher 不能为空"));
}
try
{
// 1. 调用B站注册接口获取 gt, challenge, token
var (gt, challenge, token) = await RegisterFromVVoucher(v_voucher, csrf);
// 2. 使用 CapResolver 解决验证码, 获取 validate
var solution = await CapResolver.SolveGeetestAsync("https://live.bilibili.com", gt, challenge);
if (solution == null)
{
throw new Exception("从 CapSolver 获取 validate 失败");
}
string validate = solution.Validate;
// 3. 调用B站验证接口获取 grisk_id
var griskId = await ValidateToGriskId(challenge, token, validate, csrf);
return Ok(ResponseOK(new { grisk_id = griskId }));
}
catch (Exception ex)
{
Logs.Error($"ResolveGriskId 失败: {ex.Message}");
return StatusCode(500, ResponseInternalError(ex.Message));
}
}
public const string FirstHost = "https://i.ukamnads.icu/api-bilibili/";
public const string SecondHost = "https://api.bilibili.com/";
private static readonly string[] PreferredHosts = { FirstHost, SecondHost };
private async Task<(string gt, string challenge, string token)> RegisterFromVVoucher(string vVoucher, string? csrf)
{
var path = "x/gaia-vgate/v1/register";
var payload = new Dictionary<string, string> { { "v_voucher", vVoucher } };
if (!string.IsNullOrEmpty(csrf))
{
payload["csrf"] = csrf;
}
var root = await PostFormWithFailoverAsync(path, payload, "注册接口");
var data = root["data"] ?? throw new Exception("注册接口返回缺少 data 字段");
var geetest = data["geetest"] ?? throw new Exception("注册返回缺少 geetest 字段");
var gt = (string?)geetest["gt"] ?? throw new Exception("注册返回缺少 gt 字段");
var challenge = (string?)geetest["challenge"] ?? throw new Exception("注册返回缺少 challenge 字段");
var apiToken = (string?)data["token"] ?? throw new Exception("注册返回缺少 token 字段");
return (gt, challenge, apiToken);
}
private async Task<string> ValidateToGriskId(string challenge, string token, string validate, string? csrf)
{
var path = "x/gaia-vgate/v1/validate";
var seccode = $"{validate}|jordan";
var payload = new Dictionary<string, string>
{
{ "challenge", challenge },
{ "token", token },
{ "validate", validate },
{ "seccode", seccode },
};
if (!string.IsNullOrEmpty(csrf))
{
payload["csrf"] = csrf;
}
var root = await PostFormWithFailoverAsync(path, payload, "验证接口");
var data = root["data"] ?? throw new Exception("验证接口返回缺少 data 字段");
var isValid = (int?)data["is_valid"];
var griskId = (string?)data["grisk_id"];
if (isValid != 1 || string.IsNullOrEmpty(griskId))
{
throw new Exception($"验证失败或缺少 grisk_id: is_valid={isValid} grisk_id={griskId}");
}
return griskId;
}
private async Task<JsonNode> PostFormWithFailoverAsync(string path, Dictionary<string, string> payload, string operation)
{
Exception? lastException = null;
foreach (var host in PreferredHosts)
{
try
{
using var content = new FormUrlEncodedContent(payload);
var response = await Utils._client.PostAsync($"{host}{path}", content);
response.EnsureSuccessStatusCode();
var json = await response.Content.ReadAsStringAsync();
return JsonNode.Parse(json) ?? throw new Exception($"{operation} 返回内容解析失败");
}
catch (Exception ex)
{
lastException = ex;
if (host == FirstHost)
{
Logs.Warn($"{operation} 使用 FirstHost 调用失败: {ex.Message}");
}
else
{
Logs.Error($"{operation} 使用 SecondHost 调用失败: {ex.Message}");
}
}
}
throw new Exception($"{operation} 调用失败: {lastException?.Message}", lastException);
}
}
}