fix: 增加页面HTML解析作为抖音直播状态检测备选方案,避免API格式变化导致误判未直播

This commit is contained in:
2026-04-27 23:30:50 +08:00
parent 9c4f22ff97
commit 3f5f832617
2 changed files with 47 additions and 0 deletions
@@ -61,6 +61,10 @@ public sealed class DouyinHttpClient
"\"roomStore\":{[\\s\\S]*?\"roomInfo\":{[\\s\\S]*?\"anchor\":{[\\s\\S]*?\"nickname\":\"(?<nickname>[\\s\\S]*?)\"",
RegexOptions.Compiled | RegexOptions.CultureInvariant);
private static readonly Regex HtmlStatusRegex = new(
"\"roomStore\":{[\\s\\S]*?\"roomInfo\":{[\\s\\S]*?\"room\":{[\\s\\S]*?\"status\":(?<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<StreamInputHeaders> GetStreamInputHeadersAsync(string roomId, CancellationToken cancellationToken = default)
{
var settings = await GetSystemSettingsAsync(cancellationToken);
@@ -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<int?> 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<StreamUrlResult> GetStreamUrlAsync(
string roomId,
string? preferredQuality = null,