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;
}