using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BetterGenshinImpact.GameTask.UseRedeemCode.Model;
using BetterGenshinImpact.Helpers.Http;
using Newtonsoft.Json.Linq;
namespace BetterGenshinImpact.GameTask.UseRedeemCode;
///
/// 获取直播的前瞻兑换码
///
public class GetLiveRedeemCode
{
private static readonly string BBS_URL = "https://bbs-api.mihoyo.com";
private readonly HttpClient _httpClient = HttpClientFactory.GetCommonSendClient();
private readonly Dictionary _url = new()
{
{ "act_id_1", $"{BBS_URL}/painter/api/user_instant/list?offset=0&size=20&uid=75276539" },
{ "act_id_2", $"{BBS_URL}/painter/api/user_instant/list?offset=0&size=20&uid=75276550" },
{ "index", "https://api-takumi.mihoyo.com/event/miyolive/index" },
{ "code", "https://api-takumi-static.mihoyo.com/event/miyolive/refreshCode" }
};
private async Task GetDataAsync(string type, Dictionary? data = null)
{
try
{
HttpResponseMessage res;
var request = new HttpRequestMessage(HttpMethod.Get, _url[type]);
// 为所有需要的请求添加 act_id header
if ((type == "index" || type == "code") && data != null && data.TryGetValue("actId", out var actId))
{
request.Headers.Add("x-rpc-act_id", actId);
}
// 为code类型添加查询参数
if (type == "code" && data != null)
{
var uriBuilder = new UriBuilder(_url[type]);
var query = System.Web.HttpUtility.ParseQueryString(uriBuilder.Query);
query["version"] = data.GetValueOrDefault("version", "");
query["time"] = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
uriBuilder.Query = query.ToString();
request.RequestUri = uriBuilder.Uri;
}
res = await _httpClient.SendAsync(request);
var content = await res.Content.ReadAsStringAsync();
return JObject.Parse(content);
}
catch (Exception e)
{
return JObject.Parse($"{{\"error\":\"[{e.GetType().Name}] {type} 接口请求错误\",\"retcode\":1}}");
}
}
private async Task GetActIdAsync(string id)
{
var ret = await GetDataAsync($"act_id_{id}");
if (ret == null) return "";
// 检查error或retcode != 0
if (ret["error"] != null || ret["retcode"]?.Value() != 0)
return "";
string actId = "";
var keywords = new List { "前瞻特别节目" };
var list = ret["data"]?["list"] as JArray;
if (list == null) return "";
foreach (var p in list)
{
var post = p["post"]?["post"];
if (post == null) continue;
var subject = post["subject"]?.Value();
if (string.IsNullOrEmpty(subject)) continue;
bool containsAll = keywords.All(word => subject.Contains(word));
if (!containsAll) continue;
var structContent = post["structured_content"]?.Value();
if (string.IsNullOrEmpty(structContent)) continue;
var segments = JArray.Parse(structContent);
foreach (var segment in segments)
{
var link = segment["attributes"]?["link"]?.Value() ?? "";
// 优化:安全获取insert字段值
string insert = "";
var insertToken = segment["insert"];
if (insertToken != null)
{
if (insertToken.Type == JTokenType.String)
{
insert = insertToken.Value() ?? "";
}
else if (insertToken.Type == JTokenType.Object)
{
// 如果是对象,尝试转换为字符串
insert = insertToken.ToString();
}
}
if ((insert.Contains("观看") || insert.Contains("米游社直播间")) && !string.IsNullOrEmpty(link))
{
var match = Regex.Match(link, @"act_id=(.*?)\&");
if (match.Success)
actId = match.Groups[1].Value;
}
}
if (!string.IsNullOrEmpty(actId)) break;
}
return actId;
}
private async Task<(string codeVer, string title)> GetLiveDataAsync(string actId)
{
var ret = await GetDataAsync("index", new Dictionary { { "actId", actId } });
if (ret == null || ret["error"] != null || ret["retcode"]?.Value() != 0)
return (null, null);
var liveRaw = ret["data"]?["live"];
if (liveRaw == null) return (null, null);
string codeVer = liveRaw["code_ver"]?.Value();
string title = liveRaw["title"]?.Value();
return (codeVer, title);
}
private async Task> GetCodeAsync(string version, string actId)
{
var ret = await GetDataAsync("code", new Dictionary { { "version", version }, { "actId", actId } });
var result = new List();
if (ret == null || ret["error"] != null || ret["retcode"]?.Value() != 0)
return result;
var removeTag = new Regex("<.*?>", RegexOptions.Compiled);
var codeList = ret["data"]?["code_list"] as JArray;
if (codeList == null) return result;
foreach (var codeInfo in codeList)
{
string items = removeTag.Replace(codeInfo["title"]?.Value() ?? "", "");
string code = codeInfo["code"]?.Value();
if (!string.IsNullOrEmpty(code))
result.Add(new RedeemCode(code, items));
}
return result;
}
///
/// 获取前瞻直播兑换码信息。返回格式:List[("奖励内容", "兑换码")]
///
public async Task> GetCodeMsgAsync()
{
string actId = await GetActIdAsync("1");
if (string.IsNullOrEmpty(actId))
{
actId = await GetActIdAsync("2");
if (string.IsNullOrEmpty(actId))
throw new Exception("暂无前瞻直播资讯!");
}
var (codeVer, title) = await GetLiveDataAsync(actId);
if (string.IsNullOrEmpty(codeVer))
throw new Exception("前瞻直播数据异常");
var codeList = await GetCodeAsync(codeVer, actId);
return codeList;
}
}