From 3f5f832617c1daedc8ade509b0b7bd9b16dad6f5 Mon Sep 17 00:00:00 2001 From: nanxun Date: Mon, 27 Apr 2026 23:30:50 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=A2=9E=E5=8A=A0=E9=A1=B5=E9=9D=A2HTML?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E4=BD=9C=E4=B8=BA=E6=8A=96=E9=9F=B3=E7=9B=B4?= =?UTF-8?q?=E6=92=AD=E7=8A=B6=E6=80=81=E6=A3=80=E6=B5=8B=E5=A4=87=E9=80=89?= =?UTF-8?q?=E6=96=B9=E6=A1=88=EF=BC=8C=E9=81=BF=E5=85=8DAPI=E6=A0=BC?= =?UTF-8?q?=E5=BC=8F=E5=8F=98=E5=8C=96=E5=AF=BC=E8=87=B4=E8=AF=AF=E5=88=A4?= =?UTF-8?q?=E6=9C=AA=E7=9B=B4=E6=92=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Platforms/Douyin/DouyinHttpClient.cs | 21 +++++++++++++++ .../Douyin/DouyinLivePlatformAdapter.cs | 26 +++++++++++++++++++ 2 files changed, 47 insertions(+) diff --git a/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinHttpClient.cs b/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinHttpClient.cs index c0c2e67..3814897 100644 --- a/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinHttpClient.cs +++ b/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinHttpClient.cs @@ -61,6 +61,10 @@ public sealed class DouyinHttpClient "\"roomStore\":{[\\s\\S]*?\"roomInfo\":{[\\s\\S]*?\"anchor\":{[\\s\\S]*?\"nickname\":\"(?[\\s\\S]*?)\"", RegexOptions.Compiled | RegexOptions.CultureInvariant); + private static readonly Regex HtmlStatusRegex = new( + "\"roomStore\":{[\\s\\S]*?\"roomInfo\":{[\\s\\S]*?\"room\":{[\\s\\S]*?\"status\":(?\\d+)", + RegexOptions.Compiled | RegexOptions.CultureInvariant); + private readonly PlatformHttpClientFactory _platformHttpClientFactory; private readonly IServiceScopeFactory _serviceScopeFactory; private readonly DouyinXBogusSigner _xBogusSigner; @@ -129,6 +133,23 @@ public sealed class DouyinHttpClient return await JsonDocument.ParseAsync(stream, cancellationToken: cancellationToken); } + public static int? TryExtractLiveStatusIntFromHtml(string? html) + { + var normalized = TryExtractNormalizedStatePayload(html); + if (string.IsNullOrWhiteSpace(normalized)) + { + return null; + } + + var match = HtmlStatusRegex.Match(normalized); + if (match.Success && int.TryParse(match.Groups["status"].Value, out var status)) + { + return status; + } + + return null; + } + public async Task GetStreamInputHeadersAsync(string roomId, CancellationToken cancellationToken = default) { var settings = await GetSystemSettingsAsync(cancellationToken); diff --git a/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinLivePlatformAdapter.cs b/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinLivePlatformAdapter.cs index 7c85022..1e17b20 100644 --- a/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinLivePlatformAdapter.cs +++ b/src/LiveRecorder.Infrastructure/Platforms/Douyin/DouyinLivePlatformAdapter.cs @@ -103,9 +103,35 @@ public sealed class DouyinLivePlatformAdapter : ILivePlatformAdapter var coverUrl = GetCoverUrl(room); var isLive = statusCode == 2 || GetInt(room, "live_status") is 1 or 2; + if (!isLive) + { + var pageStatus = await TryDetectLiveStatusFromPageAsync(roomId, cancellationToken); + if (pageStatus is 1 or 2) + { + isLive = true; + statusCode ??= pageStatus; + } + } + return new LiveStatusSnapshot(isLive, title, anchorName, anchorId, avatarUrl, coverUrl, statusCode, statusCode?.ToString()); } + private async Task TryDetectLiveStatusFromPageAsync(string roomId, CancellationToken cancellationToken) + { + try + { + var (_, html) = await _douyinHttpClient.ResolvePageAsync( + $"https://live.douyin.com/{roomId}", + cancellationToken); + + return DouyinHttpClient.TryExtractLiveStatusIntFromHtml(html); + } + catch + { + return null; + } + } + public async Task GetStreamUrlAsync( string roomId, string? preferredQuality = null,