using System; using System.Collections.Generic; using System.Text.RegularExpressions; using JetBrains.Annotations; using Kyoo.Controllers; using Kyoo.Models.Attributes; namespace Kyoo.Models { /// /// A class to represent a single show's episode. /// This is also used internally for movies (their number is juste set to -1). /// public class Episode : IResource, IOnMerge { /// public int ID { get; set; } /// public string Slug { get => GetSlug(ShowSlug, SeasonNumber, EpisodeNumber, AbsoluteNumber); set { Match match = Regex.Match(value, @"(?.*)-s(?\d*)e(?\d*)"); if (match.Success) { ShowSlug = match.Groups["show"].Value; SeasonNumber = int.Parse(match.Groups["season"].Value); EpisodeNumber = int.Parse(match.Groups["episode"].Value); } else { match = Regex.Match(value, @"(?.*)-(?\d*)"); if (match.Success) { ShowSlug = match.Groups["Show"].Value; AbsoluteNumber = int.Parse(match.Groups["absolute"].Value); } else ShowSlug = value; SeasonNumber = -1; EpisodeNumber = -1; } } } /// /// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed. /// [SerializeIgnore] public string ShowSlug { private get; set; } /// /// The ID of the Show containing this episode. This value is only set when the has been loaded. /// [SerializeIgnore] public int ShowID { get; set; } /// /// The show that contains this episode. This must be explicitly loaded via a call to . /// [LoadableRelation(nameof(ShowID))] public Show Show { get; set; } /// /// The ID of the Season containing this episode. This value is only set when the has been loaded. /// [SerializeIgnore] public int? SeasonID { get; set; } /// /// The season that contains this episode. This must be explicitly loaded via a call to . /// This can be null if the season is unknown and the episode is only identified by it's . /// [LoadableRelation(nameof(SeasonID))] public Season Season { get; set; } /// /// The season in witch this episode is in. This defaults to -1 if not specified. /// public int SeasonNumber { get; set; } = -1; /// /// The number of this episode is it's season. This defaults to -1 if not specified. /// public int EpisodeNumber { get; set; } = -1; /// /// The absolute number of this episode. It's an episode number that is not reset to 1 after a new season. /// This defaults to -1 if not specified. /// public int AbsoluteNumber { get; set; } = -1; /// /// The path of the video file for this episode. Any format supported by a is allowed. /// [SerializeIgnore] public string Path { get; set; } /// /// The path of this episode's thumbnail. /// By default, the http path for the thumbnail is returned from the public API. /// This can be disabled using the internal query flag. /// [SerializeAs("{HOST}/api/episodes/{Slug}/thumb")] public string Thumb { get; set; } /// /// The title of this episode. /// public string Title { get; set; } /// /// The overview of this episode. /// public string Overview { get; set; } /// /// The release date of this episode. It can be null if unknown. /// public DateTime? ReleaseDate { get; set; } /// /// The link to metadata providers that this episode has. See for more information. /// [EditableRelation] [LoadableRelation] public ICollection> ExternalIDs { get; set; } /// /// The list of tracks this episode has. This lists video, audio and subtitles available. /// [EditableRelation] [LoadableRelation] public ICollection Tracks { get; set; } /// /// Get the slug of an episode. /// /// The slug of the show. It can't be null. /// /// The season in which the episode is. /// If this is a movie or if the episode should be referred by it's absolute number, set this to -1. /// /// /// The number of the episode in it's season. /// If this is a movie or if the episode should be referred by it's absolute number, set this to -1. /// /// /// The absolute number of this show. /// If you don't know it or this is a movie, use -1 /// /// The slug corresponding to the given arguments /// The given show slug was null. public static string GetSlug([NotNull] string showSlug, int seasonNumber = -1, int episodeNumber = -1, int absoluteNumber = -1) { if (showSlug == null) throw new ArgumentNullException(nameof(showSlug)); return seasonNumber switch { -1 when absoluteNumber == -1 => showSlug, -1 => $"{showSlug}-{absoluteNumber}", _ => $"{showSlug}-s{seasonNumber}e{episodeNumber}" }; } /// public void OnMerge(object merged) { Episode other = (Episode)merged; if (SeasonNumber == -1 && other.SeasonNumber != -1) SeasonNumber = other.SeasonNumber; if (EpisodeNumber == -1 && other.EpisodeNumber != -1) EpisodeNumber = other.EpisodeNumber; if (AbsoluteNumber == -1 && other.AbsoluteNumber != -1) AbsoluteNumber = other.AbsoluteNumber; } } }