namespace Evergreen.Health.Application.Health.Sleep; public sealed record GuidanceClip(string Key, string Title, string? Url, double? DurationSeconds) { public bool Playable => DurationSeconds is > 0 && double.IsFinite(DurationSeconds.Value) && Uri.TryCreate(Url, UriKind.Absolute, out var uri) && uri.Scheme is "http" or "https"; } /// 假数据仅是目录元数据,没有伪造 OSS 地址或播放成功状态。 public sealed class GuidanceCatalog { public GuidanceCatalog(GuidanceClip? initialRelaxation = null) => InitialRelaxation = initialRelaxation ?? new("initial-relaxation", "首次上床放松引导(待上传)", null, null); public GuidanceClip InitialRelaxation { get; } public GuidanceClip AnomalyReminder { get; } = new("anomaly-reminder", "睡眠状态语音提醒(预留)", null, null); } public sealed record GuidancePlaybackResult(bool Completed, string Message); public interface IGuidancePlayer { Task PlayAsync(GuidanceClip clip, int volumePercent, CancellationToken cancellationToken); } public sealed class ReservedGuidancePlayer : IGuidancePlayer { public Task PlayAsync(GuidanceClip clip, int volumePercent, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return Task.FromResult(new GuidancePlaybackResult(false, "引导音频尚未接入,本版不执行播放")); } }