fix: 增加页面HTML解析作为抖音直播状态检测备选方案,避免API格式变化导致误判未直播
This commit is contained in:
@@ -61,6 +61,10 @@ public sealed class DouyinHttpClient
|
|||||||
"\"roomStore\":{[\\s\\S]*?\"roomInfo\":{[\\s\\S]*?\"anchor\":{[\\s\\S]*?\"nickname\":\"(?<nickname>[\\s\\S]*?)\"",
|
"\"roomStore\":{[\\s\\S]*?\"roomInfo\":{[\\s\\S]*?\"anchor\":{[\\s\\S]*?\"nickname\":\"(?<nickname>[\\s\\S]*?)\"",
|
||||||
RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
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 PlatformHttpClientFactory _platformHttpClientFactory;
|
||||||
private readonly IServiceScopeFactory _serviceScopeFactory;
|
private readonly IServiceScopeFactory _serviceScopeFactory;
|
||||||
private readonly DouyinXBogusSigner _xBogusSigner;
|
private readonly DouyinXBogusSigner _xBogusSigner;
|
||||||
@@ -129,6 +133,23 @@ public sealed class DouyinHttpClient
|
|||||||
return await JsonDocument.ParseAsync(stream, cancellationToken: cancellationToken);
|
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)
|
public async Task<StreamInputHeaders> GetStreamInputHeadersAsync(string roomId, CancellationToken cancellationToken = default)
|
||||||
{
|
{
|
||||||
var settings = await GetSystemSettingsAsync(cancellationToken);
|
var settings = await GetSystemSettingsAsync(cancellationToken);
|
||||||
|
|||||||
@@ -103,9 +103,35 @@ public sealed class DouyinLivePlatformAdapter : ILivePlatformAdapter
|
|||||||
var coverUrl = GetCoverUrl(room);
|
var coverUrl = GetCoverUrl(room);
|
||||||
|
|
||||||
var isLive = statusCode == 2 || GetInt(room, "live_status") is 1 or 2;
|
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());
|
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(
|
public async Task<StreamUrlResult> GetStreamUrlAsync(
|
||||||
string roomId,
|
string roomId,
|
||||||
string? preferredQuality = null,
|
string? preferredQuality = null,
|
||||||
|
|||||||
Reference in New Issue
Block a user