using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; namespace MediaBrowser.Controller.Entities.TV { /// /// Class Episode /// public class Episode : Video, IHasTrailers, IHasLookupInfo, IHasSeries { public Episode() { RemoteTrailers = new List(); LocalTrailerIds = new List(); RemoteTrailerIds = new List(); } public List LocalTrailerIds { get; set; } public List RemoteTrailerIds { get; set; } public List RemoteTrailers { get; set; } /// /// Gets the season in which it aired. /// /// The aired season. public int? AirsBeforeSeasonNumber { get; set; } public int? AirsAfterSeasonNumber { get; set; } public int? AirsBeforeEpisodeNumber { get; set; } /// /// Gets or sets the DVD season number. /// /// The DVD season number. public int? DvdSeasonNumber { get; set; } /// /// Gets or sets the DVD episode number. /// /// The DVD episode number. public float? DvdEpisodeNumber { get; set; } /// /// Gets or sets the absolute episode number. /// /// The absolute episode number. public int? AbsoluteEpisodeNumber { get; set; } /// /// This is the ending episode number for double episodes. /// /// The index number. public int? IndexNumberEnd { get; set; } [IgnoreDataMember] public string SeriesSortName { get; set; } public string FindSeriesSortName() { var series = Series; return series == null ? SeriesSortName : series.SortName; } [IgnoreDataMember] protected override bool SupportsOwnedItems { get { return IsStacked || MediaSourceCount > 1; } } [IgnoreDataMember] public int? AiredSeasonNumber { get { return AirsAfterSeasonNumber ?? AirsBeforeSeasonNumber ?? ParentIndexNumber; } } [IgnoreDataMember] public override Folder LatestItemsIndexContainer { get { return Series; } } [IgnoreDataMember] public override Guid? DisplayParentId { get { return SeasonId; } } [IgnoreDataMember] protected override bool EnableDefaultVideoUserDataKeys { get { return false; } } public override List GetUserDataKeys() { var list = base.GetUserDataKeys(); var series = Series; if (series != null && ParentIndexNumber.HasValue && IndexNumber.HasValue) { var seriesUserDataKeys = series.GetUserDataKeys(); var take = seriesUserDataKeys.Count; if (seriesUserDataKeys.Count > 1) { take--; } list.InsertRange(0, seriesUserDataKeys.Take(take).Select(i => i + ParentIndexNumber.Value.ToString("000") + IndexNumber.Value.ToString("000"))); } return list; } /// /// This Episode's Series Instance /// /// The series. [IgnoreDataMember] public Series Series { get { return FindParent(); } } [IgnoreDataMember] public Season Season { get { var season = FindParent(); // Episodes directly in series folder if (season == null) { var series = Series; if (series != null && ParentIndexNumber.HasValue) { var findNumber = ParentIndexNumber.Value; season = series.Children .OfType() .FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == findNumber); } } return season; } } [IgnoreDataMember] public bool IsInSeasonFolder { get { return FindParent() != null; } } [IgnoreDataMember] public string SeriesName { get; set; } [IgnoreDataMember] public string SeasonName { get; set; } public string FindSeasonName() { var season = Season; return season == null ? SeasonName : season.Name; } public string FindSeriesName() { var series = Series; return series == null ? SeriesName : series.Name; } public Guid? FindSeasonId() { var season = Season; return season == null ? (Guid?)null : season.Id; } /// /// Creates the name of the sort. /// /// System.String. protected override string CreateSortName() { return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("000 - ") : "") + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name; } /// /// Determines whether [contains episode number] [the specified number]. /// /// The number. /// true if [contains episode number] [the specified number]; otherwise, false. public bool ContainsEpisodeNumber(int number) { if (IndexNumber.HasValue) { if (IndexNumberEnd.HasValue) { return number >= IndexNumber.Value && number <= IndexNumberEnd.Value; } return IndexNumber.Value == number; } return false; } [IgnoreDataMember] public override bool SupportsRemoteImageDownloading { get { if (IsMissingEpisode) { return false; } return true; } } [IgnoreDataMember] public bool IsMissingEpisode { get { return LocationType == LocationType.Virtual && !IsUnaired; } } [IgnoreDataMember] public bool IsVirtualUnaired { get { return LocationType == LocationType.Virtual && IsUnaired; } } [IgnoreDataMember] public Guid? SeasonId { get; set; } [IgnoreDataMember] public Guid? SeriesId { get; set; } public Guid? FindSeriesId() { var series = Series; return series == null ? (Guid?)null : series.Id; } public override IEnumerable GetAncestorIds() { var list = base.GetAncestorIds().ToList(); var seasonId = SeasonId; if (seasonId.HasValue && !list.Contains(seasonId.Value)) { list.Add(seasonId.Value); } return list; } public override IEnumerable GetDeletePaths() { return new[] { Path }; } public override UnratedItem GetBlockUnratedType() { return UnratedItem.Series; } public EpisodeInfo GetLookupInfo() { var id = GetItemLookupInfo(); var series = Series; if (series != null) { id.SeriesProviderIds = series.ProviderIds; id.AnimeSeriesIndex = series.AnimeSeriesIndex; } id.IsMissingEpisode = IsMissingEpisode; id.IndexNumberEnd = IndexNumberEnd; id.IsVirtualUnaired = IsVirtualUnaired; return id; } public override bool BeforeMetadataRefresh() { var hasChanges = base.BeforeMetadataRefresh(); try { if (LibraryManager.FillMissingEpisodeNumbersFromPath(this)) { hasChanges = true; } } catch (Exception ex) { Logger.ErrorException("Error in FillMissingEpisodeNumbersFromPath. Episode: {0}", ex, Path ?? Name ?? Id.ToString()); } if (!ParentIndexNumber.HasValue) { var season = Season; if (season != null) { if (season.ParentIndexNumber.HasValue) { ParentIndexNumber = season.ParentIndexNumber; hasChanges = true; } } } return hasChanges; } } }