using System.Net; using dy.net.model.entity; namespace dy.net.service { public sealed class LiveEmailNotificationService { private readonly EmailNotificationSettingsService _settingsService; private readonly IEmailNotificationSender _sender; public LiveEmailNotificationService( EmailNotificationSettingsService settingsService, IEmailNotificationSender sender) { _settingsService = settingsService; _sender = sender; } public Task GetReadinessErrorAsync() => _settingsService.GetReadinessErrorAsync(); public async Task<(bool Sent, string Error)> SendLiveStartedAsync( DouyinFollowed follow, CancellationToken cancellationToken = default) { try { var settings = await _settingsService.GetAsync(); if (!settings.Enabled || !follow.LiveEmailNotificationEnabled) return (false, null); var password = await _settingsService.GetPasswordAsync(settings); var roomUrl = !string.IsNullOrWhiteSpace(follow.LiveWebRid) ? "https://live.douyin.com/" + Uri.EscapeDataString(follow.LiveWebRid) : "https://www.douyin.com/user/" + Uri.EscapeDataString(follow.SecUid ?? string.Empty); var blogger = WebUtility.HtmlEncode(follow.UperName ?? "关注博主"); var title = WebUtility.HtmlEncode(follow.LiveTitle ?? "正在直播"); var safeUrl = WebUtility.HtmlEncode(roomUrl); var subject = $"[dysync.net] {follow.UperName ?? "关注博主"} 开播了"; var body = $"

{blogger} 正在直播

{title}

" + $"

检测时间:{DateTime.Now:yyyy-MM-dd HH:mm:ss}

" + $"

进入直播间

"; await _sender.SendAsync(settings, password, subject, body, cancellationToken); return (true, null); } catch (Exception ex) when (ex is not OperationCanceledException) { Serilog.Log.Warning(ex, "发送开播邮件失败:Blogger={Blogger}", follow.UperName); return (false, SafeError(ex)); } } private static string SafeError(Exception ex) { var message = ex.GetBaseException().Message?.Trim(); if (string.IsNullOrWhiteSpace(message)) return "开播邮件发送失败,请检查邮箱设置"; return message.Length <= 1000 ? message : message[..1000]; } } }