feat: expand platform adapters and preview tooling
This commit is contained in:
@@ -21,4 +21,7 @@ public sealed class LiveDanmakuAdapterFactory : ILiveDanmakuAdapterFactory
|
||||
|
||||
return adapter;
|
||||
}
|
||||
|
||||
public ILiveDanmakuAdapter? TryGetByPlatform(LivePlatformType platformType) =>
|
||||
_adapterByPlatform.TryGetValue(platformType, out var adapter) ? adapter : null;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,14 @@ public sealed class LiveRoomService
|
||||
"""^(?:(?:https?:\/\/)?live\.bilibili\.com\/(?:blanc\/|h5\/)?)?(?<id>\d+)\/?(?:[#\?].*)?$""",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
private static readonly Regex YouTubeVideoIdRegex = new(
|
||||
@"[A-Za-z0-9_-]{11}",
|
||||
RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
||||
|
||||
private static readonly Regex TikTokHandleRegex = new(
|
||||
@"@(?<handle>[A-Za-z0-9._-]{2,})",
|
||||
RegexOptions.Compiled | RegexOptions.CultureInvariant);
|
||||
|
||||
private readonly ILiveRoomRepository _liveRoomRepository;
|
||||
private readonly IRecordSessionRepository _recordSessionRepository;
|
||||
private readonly ILivePlatformAdapterFactory _livePlatformAdapterFactory;
|
||||
@@ -507,6 +515,15 @@ public sealed class LiveRoomService
|
||||
{
|
||||
LivePlatformType.Douyin => ParseDouyinRoomLocally(input),
|
||||
LivePlatformType.Bilibili => ParseBilibiliRoomLocally(input),
|
||||
LivePlatformType.Huya => ParsePathRoomLocally(input, platform, "https://www.huya.com/"),
|
||||
LivePlatformType.Douyu => ParsePathRoomLocally(input, platform, "https://www.douyu.com/"),
|
||||
LivePlatformType.Kuaishou => ParsePathRoomLocally(input, platform, "https://live.kuaishou.com/"),
|
||||
LivePlatformType.TikTok => ParseTikTokRoomLocally(input),
|
||||
LivePlatformType.Xiaohongshu => ParsePathRoomLocally(input, platform, "https://www.xiaohongshu.com/"),
|
||||
LivePlatformType.YouTube => ParseYouTubeRoomLocally(input),
|
||||
LivePlatformType.Twitch => ParseTwitchRoomLocally(input),
|
||||
LivePlatformType.PandaTV => ParsePathRoomLocally(input, platform, "https://www.pandalive.co.kr/"),
|
||||
LivePlatformType.Migu => ParsePathRoomLocally(input, platform, "https://www.miguvideo.com/"),
|
||||
_ => throw new NotSupportedException(
|
||||
"This platform still requires live room detection during import. Please enable detection or choose a supported platform.")
|
||||
};
|
||||
@@ -530,6 +547,53 @@ public sealed class LiveRoomService
|
||||
return LivePlatformType.Bilibili;
|
||||
}
|
||||
|
||||
if (input.Contains("huya.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.Huya;
|
||||
}
|
||||
|
||||
if (input.Contains("douyu.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.Douyu;
|
||||
}
|
||||
|
||||
if (input.Contains("kuaishou.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.Kuaishou;
|
||||
}
|
||||
|
||||
if (input.Contains("tiktok.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.TikTok;
|
||||
}
|
||||
|
||||
if (input.Contains("xiaohongshu.com", StringComparison.OrdinalIgnoreCase) ||
|
||||
input.Contains("xhslink.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.Xiaohongshu;
|
||||
}
|
||||
|
||||
if (input.Contains("youtube.com", StringComparison.OrdinalIgnoreCase) ||
|
||||
input.Contains("youtu.be", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.YouTube;
|
||||
}
|
||||
|
||||
if (input.Contains("twitch.tv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.Twitch;
|
||||
}
|
||||
|
||||
if (input.Contains("pandalive.co.kr", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.PandaTV;
|
||||
}
|
||||
|
||||
if (input.Contains("miguvideo.com", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return LivePlatformType.Migu;
|
||||
}
|
||||
|
||||
throw new NotSupportedException(
|
||||
"Unable to infer the platform without detection. Please specify a platform override or keep detection enabled.");
|
||||
}
|
||||
@@ -566,6 +630,74 @@ public sealed class LiveRoomService
|
||||
$"https://live.bilibili.com/{roomId}");
|
||||
}
|
||||
|
||||
private static ParsedLiveRoom ParsePathRoomLocally(string input, LivePlatformType platformType, string rootUrl)
|
||||
{
|
||||
if (!TryExtractPathBasedRoomId(input, out var roomId))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to extract the {platformType} room id locally. Please keep detection enabled for this link.");
|
||||
}
|
||||
|
||||
return new ParsedLiveRoom(
|
||||
platformType,
|
||||
roomId,
|
||||
input.Trim(),
|
||||
$"{rootUrl.TrimEnd('/')}/{roomId}");
|
||||
}
|
||||
|
||||
private static ParsedLiveRoom ParseTikTokRoomLocally(string input)
|
||||
{
|
||||
var match = TikTokHandleRegex.Match(input.Trim());
|
||||
if (!match.Success)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Unable to extract the TikTok handle locally. Please keep detection enabled for this link.");
|
||||
}
|
||||
|
||||
var handle = match.Groups["handle"].Value;
|
||||
return new ParsedLiveRoom(
|
||||
LivePlatformType.TikTok,
|
||||
handle,
|
||||
input.Trim(),
|
||||
$"https://www.tiktok.com/@{handle}/live");
|
||||
}
|
||||
|
||||
private static ParsedLiveRoom ParseYouTubeRoomLocally(string input)
|
||||
{
|
||||
var roomId = ExtractYouTubeVideoId(input);
|
||||
if (string.IsNullOrWhiteSpace(roomId))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Unable to extract the YouTube video id locally. Please keep detection enabled for this link.");
|
||||
}
|
||||
|
||||
return new ParsedLiveRoom(
|
||||
LivePlatformType.YouTube,
|
||||
roomId,
|
||||
input.Trim(),
|
||||
$"https://www.youtube.com/watch?v={roomId}");
|
||||
}
|
||||
|
||||
private static ParsedLiveRoom ParseTwitchRoomLocally(string input)
|
||||
{
|
||||
if (!TryExtractPathBasedRoomId(input, out var roomId))
|
||||
{
|
||||
roomId = input.Trim().Trim('/');
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(roomId))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"Unable to extract the Twitch channel login locally. Please keep detection enabled for this link.");
|
||||
}
|
||||
|
||||
return new ParsedLiveRoom(
|
||||
LivePlatformType.Twitch,
|
||||
roomId,
|
||||
input.Trim(),
|
||||
$"https://www.twitch.tv/{roomId}");
|
||||
}
|
||||
|
||||
private static string? ExtractDouyinRoomId(string input)
|
||||
{
|
||||
var trimmedInput = input.Trim();
|
||||
@@ -593,6 +725,56 @@ public sealed class LiveRoomService
|
||||
.FirstOrDefault(static item => !string.IsNullOrWhiteSpace(item) && item.All(char.IsDigit));
|
||||
}
|
||||
|
||||
private static string? ExtractYouTubeVideoId(string input)
|
||||
{
|
||||
var trimmedInput = input.Trim();
|
||||
var directMatch = YouTubeVideoIdRegex.Match(trimmedInput);
|
||||
if (directMatch.Success && directMatch.Index == 0 && directMatch.Length == trimmedInput.Length)
|
||||
{
|
||||
return directMatch.Value;
|
||||
}
|
||||
|
||||
if (Uri.TryCreate(trimmedInput, UriKind.Absolute, out var uri))
|
||||
{
|
||||
var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(uri.Query);
|
||||
if (query.TryGetValue("v", out var videoId) &&
|
||||
!string.IsNullOrWhiteSpace(videoId.ToString()) &&
|
||||
YouTubeVideoIdRegex.IsMatch(videoId.ToString()))
|
||||
{
|
||||
return videoId.ToString();
|
||||
}
|
||||
|
||||
var segment = uri.Segments
|
||||
.Select(static item => item.Trim('/'))
|
||||
.FirstOrDefault(static item => !string.IsNullOrWhiteSpace(item) && YouTubeVideoIdRegex.IsMatch(item));
|
||||
if (!string.IsNullOrWhiteSpace(segment))
|
||||
{
|
||||
return segment;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool TryExtractPathBasedRoomId(string input, out string roomId)
|
||||
{
|
||||
roomId = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(input))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var trimmedInput = input.Trim().Trim('/');
|
||||
if (!Uri.TryCreate(trimmedInput, UriKind.Absolute, out var uri))
|
||||
{
|
||||
roomId = trimmedInput;
|
||||
return !string.IsNullOrWhiteSpace(roomId);
|
||||
}
|
||||
|
||||
roomId = uri.AbsolutePath.Trim('/');
|
||||
return !string.IsNullOrWhiteSpace(roomId);
|
||||
}
|
||||
|
||||
private async Task<Dictionary<Guid, RecordingExecutionSettings>> BuildEffectiveSettingsLookupAsync(
|
||||
IReadOnlyCollection<LiveRoom> rooms,
|
||||
CancellationToken cancellationToken)
|
||||
|
||||
@@ -60,9 +60,15 @@ public sealed class LiveRoomStatusService
|
||||
return;
|
||||
}
|
||||
|
||||
await _emailNotificationService.SendLiveStartedAsync(liveRoom, cancellationToken);
|
||||
await _webhookNotificationService.SendLiveStartedAsync(liveRoom, cancellationToken);
|
||||
await _eventScriptService.RunLiveStartedAsync(liveRoom, observedAt, cancellationToken);
|
||||
var eventScriptResult = await _eventScriptService.RunLiveStartedAsync(liveRoom, observedAt, cancellationToken);
|
||||
await _emailNotificationService.SendLiveStartedAsync(
|
||||
liveRoom,
|
||||
cancellationToken,
|
||||
eventScriptOutput: eventScriptResult?.CustomLogOutput);
|
||||
await _webhookNotificationService.SendLiveStartedAsync(
|
||||
liveRoom,
|
||||
cancellationToken,
|
||||
eventScriptOutput: eventScriptResult?.CustomLogOutput);
|
||||
liveRoom.MarkLiveNotificationSent(observedAt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using LiveRecorder.Application.Abstractions.Persistence;
|
||||
using LiveRecorder.Application.Abstractions.Settings;
|
||||
using LiveRecorder.Application.Common;
|
||||
using LiveRecorder.Application.Models.Cleanup;
|
||||
using LiveRecorder.Application.Models.Settings;
|
||||
using LiveRecorder.Domain.Entities;
|
||||
@@ -154,21 +155,7 @@ public sealed class SystemSettingsService : ISystemSettingsService
|
||||
UploadTarget = Enum.TryParse(GetValue(lookup, UploadTargetKey, "None"), true, out UploadTargetType uploadTarget)
|
||||
? uploadTarget
|
||||
: UploadTargetType.None,
|
||||
DouyinProxy = new PlatformProxySettingsDto
|
||||
{
|
||||
Enabled = bool.TryParse(GetValue(lookup, DouyinProxyEnabledKey, "false"), out var douyinProxyEnabled) && douyinProxyEnabled,
|
||||
ProxyUrl = GetValue(lookup, DouyinProxyUrlKey, string.Empty)
|
||||
},
|
||||
BilibiliProxy = new PlatformProxySettingsDto
|
||||
{
|
||||
Enabled = bool.TryParse(GetValue(lookup, BilibiliProxyEnabledKey, "false"), out var bilibiliProxyEnabled) && bilibiliProxyEnabled,
|
||||
ProxyUrl = GetValue(lookup, BilibiliProxyUrlKey, string.Empty)
|
||||
},
|
||||
HuyaProxy = new PlatformProxySettingsDto
|
||||
{
|
||||
Enabled = bool.TryParse(GetValue(lookup, HuyaProxyEnabledKey, "false"), out var huyaProxyEnabled) && huyaProxyEnabled,
|
||||
ProxyUrl = GetValue(lookup, HuyaProxyUrlKey, string.Empty)
|
||||
},
|
||||
PlatformRequestSettings = BuildPlatformRequestSettingsMap(lookup),
|
||||
WebDavUpload = new WebDavUploadSettingsDto
|
||||
{
|
||||
Endpoint = GetValue(lookup, WebDavEndpointKey, string.Empty),
|
||||
@@ -274,13 +261,7 @@ public sealed class SystemSettingsService : ISystemSettingsService
|
||||
WebhookBodyTemplate = GetValue(lookup, WebhookBodyTemplateKey, string.Empty),
|
||||
WebhookTimeoutSeconds = GetIntValue(lookup, WebhookTimeoutSecondsKey, 15, 1, 300),
|
||||
NotifyWebhookOnLiveStarted = bool.TryParse(GetValue(lookup, NotifyWebhookOnLiveStartedKey, "true"), out var notifyWebhookOnLiveStarted) && notifyWebhookOnLiveStarted,
|
||||
NotifyWebhookOnException = bool.TryParse(GetValue(lookup, NotifyWebhookOnExceptionKey, "true"), out var notifyWebhookOnException) && notifyWebhookOnException,
|
||||
DouyinUserAgent = GetValue(
|
||||
lookup,
|
||||
DouyinUserAgentKey,
|
||||
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36"),
|
||||
DouyinReferer = GetValue(lookup, DouyinRefererKey, "https://live.douyin.com/"),
|
||||
DouyinCookie = GetValue(lookup, DouyinCookieKey, string.Empty)
|
||||
NotifyWebhookOnException = bool.TryParse(GetValue(lookup, NotifyWebhookOnExceptionKey, "true"), out var notifyWebhookOnException) && notifyWebhookOnException
|
||||
};
|
||||
}
|
||||
|
||||
@@ -289,9 +270,6 @@ public sealed class SystemSettingsService : ISystemSettingsService
|
||||
ArgumentNullException.ThrowIfNull(request);
|
||||
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
var douyinProxy = request.DouyinProxy ?? new PlatformProxySettingsDto();
|
||||
var bilibiliProxy = request.BilibiliProxy ?? new PlatformProxySettingsDto();
|
||||
var huyaProxy = request.HuyaProxy ?? new PlatformProxySettingsDto();
|
||||
var webDavUpload = request.WebDavUpload ?? new WebDavUploadSettingsDto();
|
||||
var s3Upload = request.S3Upload ?? new S3UploadSettingsDto();
|
||||
|
||||
@@ -351,12 +329,15 @@ public sealed class SystemSettingsService : ISystemSettingsService
|
||||
await UpsertAsync(S3SecretKeyKey, s3Upload.SecretKey, now, cancellationToken);
|
||||
await UpsertAsync(S3PrefixKey, s3Upload.Prefix.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(S3ForcePathStyleKey, s3Upload.ForcePathStyle.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(DouyinProxyEnabledKey, douyinProxy.Enabled.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(DouyinProxyUrlKey, douyinProxy.ProxyUrl.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(BilibiliProxyEnabledKey, bilibiliProxy.Enabled.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(BilibiliProxyUrlKey, bilibiliProxy.ProxyUrl.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(HuyaProxyEnabledKey, huyaProxy.Enabled.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(HuyaProxyUrlKey, huyaProxy.ProxyUrl.Trim(), now, cancellationToken);
|
||||
foreach (var platformDefinition in LivePlatformCatalog.All)
|
||||
{
|
||||
var platformRequestSettings = request.GetPlatformRequestSettings(platformDefinition.Type);
|
||||
await UpsertAsync(GetPlatformProxyEnabledKey(platformDefinition.Key), platformRequestSettings.Proxy.Enabled.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(GetPlatformProxyUrlKey(platformDefinition.Key), platformRequestSettings.Proxy.ProxyUrl.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(GetPlatformUserAgentKey(platformDefinition.Key), platformRequestSettings.UserAgent.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(GetPlatformRefererKey(platformDefinition.Key), platformRequestSettings.Referer.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(GetPlatformCookieKey(platformDefinition.Key), platformRequestSettings.Cookie.Trim(), now, cancellationToken);
|
||||
}
|
||||
await UpsertAsync(EnableEventScriptsKey, request.EnableEventScripts.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(EnableLiveStartedScriptKey, request.EnableLiveStartedScript.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(LiveStartedScriptModeKey, NormalizeEventScriptMode(request.LiveStartedScriptMode), now, cancellationToken);
|
||||
@@ -398,14 +379,50 @@ public sealed class SystemSettingsService : ISystemSettingsService
|
||||
await UpsertAsync(WebhookTimeoutSecondsKey, Math.Clamp(request.WebhookTimeoutSeconds, 1, 300).ToString(), now, cancellationToken);
|
||||
await UpsertAsync(NotifyWebhookOnLiveStartedKey, request.NotifyWebhookOnLiveStarted.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(NotifyWebhookOnExceptionKey, request.NotifyWebhookOnException.ToString(), now, cancellationToken);
|
||||
await UpsertAsync(DouyinUserAgentKey, request.DouyinUserAgent.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(DouyinRefererKey, request.DouyinReferer.Trim(), now, cancellationToken);
|
||||
await UpsertAsync(DouyinCookieKey, request.DouyinCookie.Trim(), now, cancellationToken);
|
||||
|
||||
await _unitOfWork.SaveChangesAsync(cancellationToken);
|
||||
return await GetAsync(cancellationToken);
|
||||
}
|
||||
|
||||
private static Dictionary<string, PlatformRequestSettingsDto> BuildPlatformRequestSettingsMap(
|
||||
IReadOnlyDictionary<string, string> lookup)
|
||||
{
|
||||
var result = SystemSettingsDto.CreatePlatformRequestSettingsMap();
|
||||
|
||||
foreach (var platformDefinition in LivePlatformCatalog.All)
|
||||
{
|
||||
var settings = result[platformDefinition.Key];
|
||||
settings.Proxy.Enabled = bool.TryParse(
|
||||
GetPlatformValue(
|
||||
lookup,
|
||||
GetPlatformProxyEnabledKey(platformDefinition.Key),
|
||||
GetLegacyProxyEnabledKey(platformDefinition.Type),
|
||||
"false"),
|
||||
out var proxyEnabled) && proxyEnabled;
|
||||
settings.Proxy.ProxyUrl = GetPlatformValue(
|
||||
lookup,
|
||||
GetPlatformProxyUrlKey(platformDefinition.Key),
|
||||
GetLegacyProxyUrlKey(platformDefinition.Type),
|
||||
string.Empty);
|
||||
settings.UserAgent = GetPlatformValue(
|
||||
lookup,
|
||||
GetPlatformUserAgentKey(platformDefinition.Key),
|
||||
GetLegacyUserAgentKey(platformDefinition.Type),
|
||||
platformDefinition.DefaultUserAgent);
|
||||
settings.Referer = GetPlatformValue(
|
||||
lookup,
|
||||
GetPlatformRefererKey(platformDefinition.Key),
|
||||
GetLegacyRefererKey(platformDefinition.Type),
|
||||
platformDefinition.DefaultReferer);
|
||||
settings.Cookie = GetPlatformValue(
|
||||
lookup,
|
||||
GetPlatformCookieKey(platformDefinition.Key),
|
||||
GetLegacyCookieKey(platformDefinition.Type),
|
||||
string.Empty);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static string GetValue(IReadOnlyDictionary<string, string> lookup, string key, string fallback) =>
|
||||
lookup.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value) ? value : fallback;
|
||||
|
||||
@@ -498,6 +515,69 @@ public sealed class SystemSettingsService : ISystemSettingsService
|
||||
.OrderBy(static item => item)
|
||||
.ToArray());
|
||||
|
||||
private static string GetPlatformProxyEnabledKey(string platformKey) =>
|
||||
$"platform_request.{platformKey}.proxy.enabled";
|
||||
|
||||
private static string GetPlatformProxyUrlKey(string platformKey) =>
|
||||
$"platform_request.{platformKey}.proxy.url";
|
||||
|
||||
private static string GetPlatformUserAgentKey(string platformKey) =>
|
||||
$"platform_request.{platformKey}.user_agent";
|
||||
|
||||
private static string GetPlatformRefererKey(string platformKey) =>
|
||||
$"platform_request.{platformKey}.referer";
|
||||
|
||||
private static string GetPlatformCookieKey(string platformKey) =>
|
||||
$"platform_request.{platformKey}.cookie";
|
||||
|
||||
private static string? GetLegacyProxyEnabledKey(LivePlatformType platformType) =>
|
||||
platformType switch
|
||||
{
|
||||
LivePlatformType.Douyin => DouyinProxyEnabledKey,
|
||||
LivePlatformType.Bilibili => BilibiliProxyEnabledKey,
|
||||
LivePlatformType.Huya => HuyaProxyEnabledKey,
|
||||
_ => null
|
||||
};
|
||||
|
||||
private static string? GetLegacyProxyUrlKey(LivePlatformType platformType) =>
|
||||
platformType switch
|
||||
{
|
||||
LivePlatformType.Douyin => DouyinProxyUrlKey,
|
||||
LivePlatformType.Bilibili => BilibiliProxyUrlKey,
|
||||
LivePlatformType.Huya => HuyaProxyUrlKey,
|
||||
_ => null
|
||||
};
|
||||
|
||||
private static string? GetLegacyUserAgentKey(LivePlatformType platformType) =>
|
||||
platformType == LivePlatformType.Douyin ? DouyinUserAgentKey : null;
|
||||
|
||||
private static string? GetLegacyRefererKey(LivePlatformType platformType) =>
|
||||
platformType == LivePlatformType.Douyin ? DouyinRefererKey : null;
|
||||
|
||||
private static string? GetLegacyCookieKey(LivePlatformType platformType) =>
|
||||
platformType == LivePlatformType.Douyin ? DouyinCookieKey : null;
|
||||
|
||||
private static string GetPlatformValue(
|
||||
IReadOnlyDictionary<string, string> lookup,
|
||||
string key,
|
||||
string? legacyKey,
|
||||
string fallback)
|
||||
{
|
||||
if (lookup.TryGetValue(key, out var value) && !string.IsNullOrWhiteSpace(value))
|
||||
{
|
||||
return value.Trim();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(legacyKey) &&
|
||||
lookup.TryGetValue(legacyKey, out var legacyValue) &&
|
||||
!string.IsNullOrWhiteSpace(legacyValue))
|
||||
{
|
||||
return legacyValue.Trim();
|
||||
}
|
||||
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private async Task UpsertAsync(string key, string value, DateTimeOffset updatedAt, CancellationToken cancellationToken)
|
||||
{
|
||||
var existing = await _appSettingRepository.GetByKeyAsync(key, cancellationToken);
|
||||
|
||||
Reference in New Issue
Block a user