From a43bfc1fb4ffdd8fc337bc9710064669efd8607c Mon Sep 17 00:00:00 2001 From: Misaka-L Date: Sun, 28 Jul 2024 00:32:32 +0800 Subject: [PATCH] feat: bililive url --- .../Controllers/BiliLiveController.cs | 36 ++++++++++++++++++ MisakaBiliApi/Program.cs | 23 ++++++++++++ .../Models/BiliApi/BiliLiveQuality.cs | 8 ++++ .../Models/BiliApi/BiliLiveUrlResponse.cs | 37 +++++++++++++++++++ MisakaBiliCore/Models/LiveStreamType.cs | 7 ++++ .../Services/BiliApi/IBiliLiveApiService.cs | 13 +++++++ 6 files changed, 124 insertions(+) create mode 100644 MisakaBiliApi/Controllers/BiliLiveController.cs create mode 100644 MisakaBiliCore/Models/BiliApi/BiliLiveQuality.cs create mode 100644 MisakaBiliCore/Models/BiliApi/BiliLiveUrlResponse.cs create mode 100644 MisakaBiliCore/Models/LiveStreamType.cs create mode 100644 MisakaBiliCore/Services/BiliApi/IBiliLiveApiService.cs diff --git a/MisakaBiliApi/Controllers/BiliLiveController.cs b/MisakaBiliApi/Controllers/BiliLiveController.cs new file mode 100644 index 0000000..247bae2 --- /dev/null +++ b/MisakaBiliApi/Controllers/BiliLiveController.cs @@ -0,0 +1,36 @@ +using Microsoft.AspNetCore.Mvc; +using MisakaBiliApi.Models.ApiResponse; +using MisakaBiliCore.Models; +using MisakaBiliCore.Models.BiliApi; +using MisakaBiliCore.Services.BiliApi; + +namespace MisakaBiliApi.Controllers; + +[ApiController] +[Route("live")] +public class BiliLiveController(IBiliLiveApiService biliLiveApiService) : ControllerBase +{ + [HttpGet("url")] + [ProducesResponseType(StatusCodes.Status400BadRequest)] + [ProducesResponseType(StatusCodes.Status200OK)] + [ProducesResponseType(StatusCodes.Status302Found)] + [Produces("application/json")] + public async Task GetLiveUrl(string cid, LiveStreamType streamType = LiveStreamType.M3U8, + bool redirect = false) + { + var liveUrlResponse = + await biliLiveApiService.GetLiveUrlByRoomId(cid, streamType == LiveStreamType.Flv ? "web" : "h5"); + + var liveUrl = liveUrlResponse.Data.Durl.First(); + + if (redirect) + return Redirect(liveUrl.Url.ToString()); + + return Ok(new MisakaVideoUrlResponse( + Url: liveUrl.Url.ToString(), + Format: streamType.ToString(), + TimeLength: liveUrl.Length, + Quality: BiliVideoQuality.R1080P + )); + } +} diff --git a/MisakaBiliApi/Program.cs b/MisakaBiliApi/Program.cs index 2756758..83f2bda 100644 --- a/MisakaBiliApi/Program.cs +++ b/MisakaBiliApi/Program.cs @@ -78,6 +78,10 @@ builder.Services.AddHostedService(); +#region HttpClient & Refit + +#region HttpClient + builder.Services.AddHttpClient("biliapi", client => { foreach (var (headerName, value) in defaultRequestHeader) @@ -106,9 +110,26 @@ CookieContainer = services.GetRequiredService().CookieContainer }); +#endregion + builder.Services.AddRefitClient(null, httpClientName: "biliapi") .AddHttpMessageHandler(); +builder.Services.AddRefitClient() + .ConfigureHttpClient(client => + { + foreach (var (headerName, value) in defaultRequestHeader) + { + client.DefaultRequestHeaders.Add(headerName, value); + } + + client.BaseAddress = new Uri("https://api.live.bilibili.com"); + }).ConfigurePrimaryHttpMessageHandler(services => new SocketsHttpHandler + { + AutomaticDecompression = DecompressionMethods.All, + CookieContainer = services.GetRequiredService().CookieContainer + }); + builder.Services.AddRefitClient() .ConfigureHttpClient(client => { @@ -124,6 +145,8 @@ CookieContainer = services.GetRequiredService().CookieContainer }); +#endregion + builder.Services.AddControllers(); builder.Host.UseSerilog(); diff --git a/MisakaBiliCore/Models/BiliApi/BiliLiveQuality.cs b/MisakaBiliCore/Models/BiliApi/BiliLiveQuality.cs new file mode 100644 index 0000000..049553d --- /dev/null +++ b/MisakaBiliCore/Models/BiliApi/BiliLiveQuality.cs @@ -0,0 +1,8 @@ +namespace MisakaBiliCore.Models.BiliApi; + +public enum BiliLiveQuality +{ + Smooth = 2, + High = 3, + Original = 4 +} diff --git a/MisakaBiliCore/Models/BiliApi/BiliLiveUrlResponse.cs b/MisakaBiliCore/Models/BiliApi/BiliLiveUrlResponse.cs new file mode 100644 index 0000000..c889bf0 --- /dev/null +++ b/MisakaBiliCore/Models/BiliApi/BiliLiveUrlResponse.cs @@ -0,0 +1,37 @@ +using System.Text.Json.Serialization; + +namespace MisakaBiliCore.Models.BiliApi; + +public class BiliLiveUrlResponse +{ + [JsonPropertyName("current_quality")] public long CurrentQuality { get; set; } + + [JsonPropertyName("accept_quality")] public string[] AcceptQuality { get; set; } + + [JsonPropertyName("current_qn")] public long CurrentQn { get; set; } + + [JsonPropertyName("quality_description")] + public QualityDescription[] QualityDescription { get; set; } + + [JsonPropertyName("durl")] public Durl[] Durl { get; set; } +} + +public class Durl +{ + [JsonPropertyName("url")] public Uri Url { get; set; } + + [JsonPropertyName("length")] public long Length { get; set; } + + [JsonPropertyName("order")] public long Order { get; set; } + + [JsonPropertyName("stream_type")] public long StreamType { get; set; } + + [JsonPropertyName("p2p_type")] public long P2PType { get; set; } +} + +public class QualityDescription +{ + [JsonPropertyName("qn")] public long Qn { get; set; } + + [JsonPropertyName("desc")] public string Desc { get; set; } +} diff --git a/MisakaBiliCore/Models/LiveStreamType.cs b/MisakaBiliCore/Models/LiveStreamType.cs new file mode 100644 index 0000000..e1d210f --- /dev/null +++ b/MisakaBiliCore/Models/LiveStreamType.cs @@ -0,0 +1,7 @@ +namespace MisakaBiliCore.Models; + +public enum LiveStreamType +{ + M3U8, + Flv +} diff --git a/MisakaBiliCore/Services/BiliApi/IBiliLiveApiService.cs b/MisakaBiliCore/Services/BiliApi/IBiliLiveApiService.cs new file mode 100644 index 0000000..874dce2 --- /dev/null +++ b/MisakaBiliCore/Services/BiliApi/IBiliLiveApiService.cs @@ -0,0 +1,13 @@ +using MisakaBiliCore.Models.BiliApi; +using Refit; + +namespace MisakaBiliCore.Services.BiliApi; + +public interface IBiliLiveApiService +{ + [Get("/room/v1/Room/playUrl")] + public Task> GetLiveUrlByRoomId( + [AliasAs("cid")] string cid, + [AliasAs("platform")] string platform = "web", + [AliasAs("quality")] int quality = (int)BiliLiveQuality.Original); +}