namespace YoutubeSummarizer.Models; /// /// Metadata returned from the YouTube Data API for a single video. /// This is a slim projection — the API returns far more fields, but we /// only bind what we actually need for the summarization workflow. /// public sealed class VideoMetadata { /// The 11-character YouTube video ID parsed from the URL. public required string VideoId { get; init; } /// Full video title as shown on YouTube. public required string Title { get; init; } /// Channel that published the video. public required string ChannelTitle { get; init; } /// UTC publish date of the video. public DateTimeOffset PublishedAt { get; init; } /// /// Video duration in ISO 8601 format (e.g. "PT1H4M32S"). /// We store it raw and parse it for display purposes. /// public string? Duration { get; init; } /// First 5000 characters of the video description (API cap). public string? Description { get; init; } /// Human-readable duration parsed from . public string FormattedDuration => Duration is null ? "Unknown" : System.Xml.XmlConvert.ToTimeSpan(Duration).ToString(@"hh\:mm\:ss").TrimStart('0', ':'); } /// /// Represents a single caption track available for a video. /// YouTube can provide multiple tracks (languages, auto-generated vs. manual). /// public sealed class CaptionTrack { public required string TrackId { get; init; } public required string Language { get; init; } // BCP-47, e.g. "en" public required string TrackKind { get; init; } // "standard", "asr" (auto), "forced" public required string Name { get; init; } // Display name from YouTube /// /// True when the track was automatically generated by YouTube's ASR system. /// ASR captions are less reliable — typos, missing punctuation, run-on sentences. /// public bool IsAutoGenerated => TrackKind.Equals("asr", StringComparison.OrdinalIgnoreCase); } /// /// The full textual transcript assembled from caption data, /// along with provenance information about how it was obtained. /// public sealed class VideoTranscript { public required string VideoId { get; init; } /// The concatenated, cleaned transcript text. public required string Text { get; init; } /// The caption track this text came from, if available. public CaptionTrack? SourceTrack { get; init; } /// /// How the transcript was obtained. This is important context for /// interpreting the quality of the summary. /// public TranscriptSource Source { get; init; } /// /// Individual timestamped segments from the caption track. /// Empty when timestamps are not available (e.g. metadata-only transcripts). /// public IReadOnlyList Segments { get; init; } = Array.Empty(); /// Approximate word count of the raw transcript. public int WordCount => Text.Split(' ', StringSplitOptions.RemoveEmptyEntries).Length; } /// /// A single timestamped segment from a caption track. /// Used when saving the transcript to a file with timestamp formatting. /// public sealed class TimestampedSegment { /// Start time offset from the beginning of the video. public TimeSpan Start { get; init; } /// Duration of this caption segment. public TimeSpan Duration { get; init; } /// The caption text for this segment. public required string Text { get; init; } /// Formats the start time as [HH:MM:SS] or [MM:SS] for display. public string FormattedTimestamp => Start.TotalHours >= 1 ? Start.ToString(@"hh\:mm\:ss") : Start.ToString(@"mm\:ss"); } /// /// Describes how a transcript was obtained, ordered from most to least reliable. /// This maps directly to the caption quality transparency layer discussed in LIKA. /// public enum TranscriptSource { /// Human-reviewed caption track provided by the video owner. OwnerPublished, /// Community-contributed captions (YouTube retired this but tracks may exist). CommunityContributed, /// YouTube's automatic speech recognition — less reliable. AutoGenerated, /// No captions available; summary based on metadata/description only. MetadataOnly } /// /// Controls which summarization prompt style is used. /// public enum SummaryMode { /// Default detailed summary with bullet points and takeaways. Standard, /// /// Personal Information Filter — brief 1–2 sentence summary, relevance /// evaluation against personal priorities (time, finances, health, family, /// service to others), and a single-word verdict: ACT, MONITOR, or IGNORE. /// PersonalFilter } /// /// The final deliverable: a structured summary of a YouTube video. /// public sealed class VideoSummary { public required VideoMetadata Metadata { get; init; } public required string SummaryText { get; init; } public required TranscriptSource TranscriptSource { get; init; } /// /// Warning shown when the summary is based on low-quality or missing transcript data. /// Null when the source is reliable. /// public string? QualityWarning { get; init; } /// Model used to generate this summary. public required string ModelUsed { get; init; } public DateTimeOffset GeneratedAt { get; init; } = DateTimeOffset.UtcNow; }