namespace ytLive.Models; public class YouTubeChannel { public string ChannelId { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; public string ProfileImageUrl { get; set; } = string.Empty; public string AccessToken { get; set; } = string.Empty; public string RefreshToken { get; set; } = string.Empty; public DateTime TokenExpiry { get; set; } } /// The channel's reusable live stream (TASK 5): created once, cached, /// rebound to every broadcast. The RTMP URL the encoder pushes to is the /// ingestion address + "/" + stream name. public record ReusableStream(string Id, string IngestionAddress, string StreamName) { public string RtmpUrl => $"{IngestionAddress}/{StreamName}"; } public class ChatMessage { public string Id { get; init; } = Guid.NewGuid().ToString(); public string AuthorName { get; set; } = string.Empty; public string AuthorChannelId { get; set; } = string.Empty; public string AuthorImageUrl { get; set; } = string.Empty; public string Message { get; set; } = string.Empty; public DateTime Timestamp { get; set; } public bool IsSuperChat { get; set; } public double SuperChatAmount { get; set; } public string? SuperChatCurrency { get; set; } public bool IsMember { get; set; } public string? MembershipLevel { get; set; } }