mirror of
				https://github.com/jellyfin/jellyfin.git
				synced 2025-11-03 19:17:24 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			329 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			329 lines
		
	
	
		
			9.5 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
using System;
 | 
						|
using System.Collections.Generic;
 | 
						|
using System.Globalization;
 | 
						|
using System.Linq;
 | 
						|
using System.Text.Json.Serialization;
 | 
						|
using Jellyfin.Data.Enums;
 | 
						|
using MediaBrowser.Controller.Providers;
 | 
						|
using MediaBrowser.Model.Entities;
 | 
						|
using MediaBrowser.Model.IO;
 | 
						|
using Microsoft.Extensions.Logging;
 | 
						|
 | 
						|
namespace MediaBrowser.Controller.Entities.TV
 | 
						|
{
 | 
						|
    /// <summary>
 | 
						|
    /// Class Episode
 | 
						|
    /// </summary>
 | 
						|
    public class Episode : Video, IHasTrailers, IHasLookupInfo<EpisodeInfo>, IHasSeries
 | 
						|
    {
 | 
						|
        public Episode()
 | 
						|
        {
 | 
						|
            RemoteTrailers = Array.Empty<MediaUrl>();
 | 
						|
            LocalTrailerIds = Array.Empty<Guid>();
 | 
						|
            RemoteTrailerIds = Array.Empty<Guid>();
 | 
						|
        }
 | 
						|
 | 
						|
        /// <inheritdoc />
 | 
						|
        public IReadOnlyList<Guid> LocalTrailerIds { get; set; }
 | 
						|
 | 
						|
        /// <inheritdoc />
 | 
						|
        public IReadOnlyList<Guid> RemoteTrailerIds { get; set; }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Gets the season in which it aired.
 | 
						|
        /// </summary>
 | 
						|
        /// <value>The aired season.</value>
 | 
						|
        public int? AirsBeforeSeasonNumber { get; set; }
 | 
						|
        public int? AirsAfterSeasonNumber { get; set; }
 | 
						|
        public int? AirsBeforeEpisodeNumber { get; set; }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// This is the ending episode number for double episodes.
 | 
						|
        /// </summary>
 | 
						|
        /// <value>The index number.</value>
 | 
						|
        public int? IndexNumberEnd { get; set; }
 | 
						|
 | 
						|
        public string FindSeriesSortName()
 | 
						|
        {
 | 
						|
            var series = Series;
 | 
						|
            return series == null ? SeriesName : series.SortName;
 | 
						|
        }
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        protected override bool SupportsOwnedItems => IsStacked || MediaSourceCount > 1;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public override bool SupportsInheritedParentImages => true;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public override bool SupportsPeople => true;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public int? AiredSeasonNumber => AirsAfterSeasonNumber ?? AirsBeforeSeasonNumber ?? ParentIndexNumber;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public override Folder LatestItemsIndexContainer => Series;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public override Guid DisplayParentId => SeasonId;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        protected override bool EnableDefaultVideoUserDataKeys => false;
 | 
						|
 | 
						|
        public override double GetDefaultPrimaryImageAspectRatio()
 | 
						|
        {
 | 
						|
            // hack for tv plugins
 | 
						|
            if (SourceType == SourceType.Channel)
 | 
						|
            {
 | 
						|
                return 0;
 | 
						|
            }
 | 
						|
 | 
						|
            return 16.0 / 9;
 | 
						|
        }
 | 
						|
 | 
						|
        public override List<string> 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;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// This Episode's Series Instance
 | 
						|
        /// </summary>
 | 
						|
        /// <value>The series.</value>
 | 
						|
        [JsonIgnore]
 | 
						|
        public Series Series
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                var seriesId = SeriesId;
 | 
						|
                if (seriesId.Equals(Guid.Empty))
 | 
						|
                {
 | 
						|
                    seriesId = FindSeriesId();
 | 
						|
                }
 | 
						|
                return !seriesId.Equals(Guid.Empty) ? (LibraryManager.GetItemById(seriesId) as Series) : null;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public Season Season
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                var seasonId = SeasonId;
 | 
						|
                if (seasonId.Equals(Guid.Empty))
 | 
						|
                {
 | 
						|
                    seasonId = FindSeasonId();
 | 
						|
                }
 | 
						|
                return !seasonId.Equals(Guid.Empty) ? (LibraryManager.GetItemById(seasonId) as Season) : null;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public bool IsInSeasonFolder => FindParent<Season>() != null;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public string SeriesPresentationUniqueKey { get; set; }
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public string SeriesName { get; set; }
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public string SeasonName { get; set; }
 | 
						|
 | 
						|
        public string FindSeriesPresentationUniqueKey()
 | 
						|
        {
 | 
						|
            var series = Series;
 | 
						|
            return series == null ? null : series.PresentationUniqueKey;
 | 
						|
        }
 | 
						|
 | 
						|
        public string FindSeasonName()
 | 
						|
        {
 | 
						|
            var season = Season;
 | 
						|
 | 
						|
            if (season == null)
 | 
						|
            {
 | 
						|
                if (ParentIndexNumber.HasValue)
 | 
						|
                {
 | 
						|
                    return "Season " + ParentIndexNumber.Value.ToString(CultureInfo.InvariantCulture);
 | 
						|
                }
 | 
						|
                return "Season Unknown";
 | 
						|
            }
 | 
						|
 | 
						|
            return season.Name;
 | 
						|
        }
 | 
						|
 | 
						|
        public string FindSeriesName()
 | 
						|
        {
 | 
						|
            var series = Series;
 | 
						|
            return series == null ? SeriesName : series.Name;
 | 
						|
        }
 | 
						|
 | 
						|
        public Guid FindSeasonId()
 | 
						|
        {
 | 
						|
            var season = FindParent<Season>();
 | 
						|
 | 
						|
            // Episodes directly in series folder
 | 
						|
            if (season == null)
 | 
						|
            {
 | 
						|
                var series = Series;
 | 
						|
 | 
						|
                if (series != null && ParentIndexNumber.HasValue)
 | 
						|
                {
 | 
						|
                    var findNumber = ParentIndexNumber.Value;
 | 
						|
 | 
						|
                    season = series.Children
 | 
						|
                        .OfType<Season>()
 | 
						|
                        .FirstOrDefault(i => i.IndexNumber.HasValue && i.IndexNumber.Value == findNumber);
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return season == null ? Guid.Empty : season.Id;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Creates the name of the sort.
 | 
						|
        /// </summary>
 | 
						|
        /// <returns>System.String.</returns>
 | 
						|
        protected override string CreateSortName()
 | 
						|
        {
 | 
						|
            return (ParentIndexNumber != null ? ParentIndexNumber.Value.ToString("000 - ") : "")
 | 
						|
                    + (IndexNumber != null ? IndexNumber.Value.ToString("0000 - ") : "") + Name;
 | 
						|
        }
 | 
						|
 | 
						|
        /// <summary>
 | 
						|
        /// Determines whether [contains episode number] [the specified number].
 | 
						|
        /// </summary>
 | 
						|
        /// <param name="number">The number.</param>
 | 
						|
        /// <returns><c>true</c> if [contains episode number] [the specified number]; otherwise, <c>false</c>.</returns>
 | 
						|
        public bool ContainsEpisodeNumber(int number)
 | 
						|
        {
 | 
						|
            if (IndexNumber.HasValue)
 | 
						|
            {
 | 
						|
                if (IndexNumberEnd.HasValue)
 | 
						|
                {
 | 
						|
                    return number >= IndexNumber.Value && number <= IndexNumberEnd.Value;
 | 
						|
                }
 | 
						|
 | 
						|
                return IndexNumber.Value == number;
 | 
						|
            }
 | 
						|
 | 
						|
            return false;
 | 
						|
        }
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public override bool SupportsRemoteImageDownloading
 | 
						|
        {
 | 
						|
            get
 | 
						|
            {
 | 
						|
                if (IsMissingEpisode)
 | 
						|
                {
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
 | 
						|
                return true;
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public bool IsMissingEpisode => LocationType == LocationType.Virtual;
 | 
						|
 | 
						|
        [JsonIgnore]
 | 
						|
        public Guid SeasonId { get; set; }
 | 
						|
        [JsonIgnore]
 | 
						|
        public Guid SeriesId { get; set; }
 | 
						|
 | 
						|
        public Guid FindSeriesId()
 | 
						|
        {
 | 
						|
            var series = FindParent<Series>();
 | 
						|
            return series == null ? Guid.Empty : series.Id;
 | 
						|
        }
 | 
						|
 | 
						|
        public override IEnumerable<Guid> GetAncestorIds()
 | 
						|
        {
 | 
						|
            var list = base.GetAncestorIds().ToList();
 | 
						|
 | 
						|
            var seasonId = SeasonId;
 | 
						|
 | 
						|
            if (!seasonId.Equals(Guid.Empty) && !list.Contains(seasonId))
 | 
						|
            {
 | 
						|
                list.Add(seasonId);
 | 
						|
            }
 | 
						|
 | 
						|
            return list;
 | 
						|
        }
 | 
						|
 | 
						|
        public override IEnumerable<FileSystemMetadata> GetDeletePaths()
 | 
						|
        {
 | 
						|
            return new[] {
 | 
						|
                new FileSystemMetadata
 | 
						|
                {
 | 
						|
                    FullName = Path,
 | 
						|
                    IsDirectory = IsFolder
 | 
						|
                }
 | 
						|
            }.Concat(GetLocalMetadataFilesToDelete());
 | 
						|
        }
 | 
						|
 | 
						|
        public override UnratedItem GetBlockUnratedType()
 | 
						|
        {
 | 
						|
            return UnratedItem.Series;
 | 
						|
        }
 | 
						|
 | 
						|
        public EpisodeInfo GetLookupInfo()
 | 
						|
        {
 | 
						|
            var id = GetItemLookupInfo<EpisodeInfo>();
 | 
						|
 | 
						|
            var series = Series;
 | 
						|
 | 
						|
            if (series != null)
 | 
						|
            {
 | 
						|
                id.SeriesProviderIds = series.ProviderIds;
 | 
						|
                id.SeriesDisplayOrder = series.DisplayOrder;
 | 
						|
            }
 | 
						|
 | 
						|
            id.IsMissingEpisode = IsMissingEpisode;
 | 
						|
            id.IndexNumberEnd = IndexNumberEnd;
 | 
						|
 | 
						|
            return id;
 | 
						|
        }
 | 
						|
 | 
						|
        public override bool BeforeMetadataRefresh(bool replaceAllMetdata)
 | 
						|
        {
 | 
						|
            var hasChanges = base.BeforeMetadataRefresh(replaceAllMetdata);
 | 
						|
 | 
						|
            if (!IsLocked)
 | 
						|
            {
 | 
						|
                if (SourceType == SourceType.Library)
 | 
						|
                {
 | 
						|
                    try
 | 
						|
                    {
 | 
						|
                        if (LibraryManager.FillMissingEpisodeNumbersFromPath(this, replaceAllMetdata))
 | 
						|
                        {
 | 
						|
                            hasChanges = true;
 | 
						|
                        }
 | 
						|
                    }
 | 
						|
                    catch (Exception ex)
 | 
						|
                    {
 | 
						|
                        Logger.LogError(ex, "Error in FillMissingEpisodeNumbersFromPath. Episode: {Episode}", Path ?? Name ?? Id.ToString());
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            return hasChanges;
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |