XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEToolBox

【WPF】XFE工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using System.Net.Http;
using XFEExtension.NetCore.XFETransform.Json;

namespace XFEToolBox.Client.Utilities.Helpers;

public sealed record BilibiliVideoInfo(string Bvid, string PictureUrl, string Title);

public static class BilibiliHelper
{
    public const string CreatorMid = "200494622";
    public const string CSharpSeasonId = "3641758";

    private static readonly HttpClient HttpClient = CreateHttpClient();

    public static Task<IReadOnlyList<BilibiliVideoInfo>> GetPopularVideoListAsync(
        int pageSize = 6,
        CancellationToken cancellationToken = default)
    {
        pageSize = Math.Clamp(pageSize, 1, 50);
        var requestUri = $"https://api.bilibili.com/x/web-interface/popular?pn=1&ps={pageSize}";
        return GetVideoListAsync(requestUri, static root => root["data"]?["list"], cancellationToken);
    }

    public static Task<IReadOnlyList<BilibiliVideoInfo>> GetLatestCreatorVideoListAsync(
        int pageSize = 6,
        CancellationToken cancellationToken = default)
    {
        pageSize = Math.Clamp(pageSize, 1, 50);
        var requestUri = $"https://api.bilibili.com/x/space/arc/list?mid={CreatorMid}&pn=1&ps={pageSize}&order=pubdate";
        return GetVideoListAsync(requestUri, static root => root["data"]?["archives"], cancellationToken);
    }

    public static Task<IReadOnlyList<BilibiliVideoInfo>> GetSeasonVideoListAsync(
        string seasonId = CSharpSeasonId,
        int pageSize = 10,
        CancellationToken cancellationToken = default)
    {
        pageSize = Math.Clamp(pageSize, 1, 30);
        var requestUri = $"https://api.bilibili.com/x/polymer/web-space/seasons_archives_list?mid={CreatorMid}&season_id={Uri.EscapeDataString(seasonId)}&sort_reverse=false&page_size={pageSize}&page_num=1&web_location=333.1387";
        return GetVideoListAsync(requestUri, static root => root["data"]?["archives"], cancellationToken);
    }

    public static Task<byte[]> GetImageBytesAsync(string imageUrl, CancellationToken cancellationToken = default) =>
        HttpClient.GetByteArrayAsync(imageUrl, cancellationToken);

    private static async Task<IReadOnlyList<BilibiliVideoInfo>> GetVideoListAsync(
        string requestUri,
        Func<XFEJsonNode, XFEJsonNode?> selectItems,
        CancellationToken cancellationToken)
    {
        var responseContent = await HttpClient.GetStringAsync(requestUri, cancellationToken);
        XFEJsonNode root = responseContent;

        if (root["code"]?.GetInt32() != 0)
        {
            var message = root["message"]?.GetString() ?? "未知错误";
            throw new HttpRequestException($"Bilibili 接口返回异常:{message}");
        }

        var items = selectItems(root);
        if (items is null)
            return [];

        var videos = new List<BilibiliVideoInfo>();
        foreach (var item in items.EnumerateArray())
        {
            var bvid = item["bvid"]?.GetString()?.Trim();
            var pictureUrl = item["pic"]?.GetString()?.Trim();
            var title = item["title"]?.GetString()?.Trim();
            if (string.IsNullOrWhiteSpace(bvid) ||
                string.IsNullOrWhiteSpace(pictureUrl) ||
                string.IsNullOrWhiteSpace(title))
                continue;

            videos.Add(new BilibiliVideoInfo(bvid, NormalizePictureUrl(pictureUrl), title));
        }

        return videos;
    }

    private static string NormalizePictureUrl(string pictureUrl)
    {
        if (pictureUrl.StartsWith("//", StringComparison.Ordinal))
            return $"https:{pictureUrl}";
        if (pictureUrl.StartsWith("http://", StringComparison.OrdinalIgnoreCase))
            return $"https://{pictureUrl[7..]}";
        return pictureUrl;
    }

    private static HttpClient CreateHttpClient()
    {
        var client = new HttpClient
        {
            Timeout = TimeSpan.FromSeconds(12)
        };
        client.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/145.0.0.0 Safari/537.36");
        client.DefaultRequestHeaders.Referrer = new Uri($"https://space.bilibili.com/{CreatorMid}/");
        client.DefaultRequestHeaders.Accept.ParseAdd("application/json,image/avif,image/webp,image/apng,image/*,*/*;q=0.8");
        return client;
    }
}