using System.Collections; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Resolvers; using MediaBrowser.Model.Entities; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.Serialization; using System.Threading; using System.Threading.Tasks; namespace MediaBrowser.Controller.Entities { /// /// Class Video /// public class Video : BaseItem, IHasMediaStreams { public bool IsMultiPart { get; set; } public List AdditionalPartIds { get; set; } public Video() { MediaStreams = new List(); Chapters = new List(); PlayableStreamFileNames = new List(); AdditionalPartIds = new List(); } /// /// Gets or sets the type of the video. /// /// The type of the video. public VideoType VideoType { get; set; } /// /// Gets or sets the type of the iso. /// /// The type of the iso. public IsoType? IsoType { get; set; } /// /// Gets or sets the format of the video. /// /// The format of the video. public VideoFormat VideoFormat { get; set; } /// /// Gets or sets the media streams. /// /// The media streams. public List MediaStreams { get; set; } /// /// Gets or sets the chapters. /// /// The chapters. public List Chapters { get; set; } /// /// If the video is a folder-rip, this will hold the file list for the largest playlist /// public List PlayableStreamFileNames { get; set; } /// /// Gets the playable stream files. /// /// List{System.String}. public List GetPlayableStreamFiles() { return GetPlayableStreamFiles(Path); } /// /// Gets the playable stream files. /// /// The root path. /// List{System.String}. public List GetPlayableStreamFiles(string rootPath) { if (PlayableStreamFileNames == null) { return null; } var allFiles = Directory.EnumerateFiles(rootPath, "*", SearchOption.AllDirectories).ToList(); return PlayableStreamFileNames.Select(name => allFiles.FirstOrDefault(f => string.Equals(System.IO.Path.GetFileName(f), name, StringComparison.OrdinalIgnoreCase))) .Where(f => !string.IsNullOrEmpty(f)) .ToList(); } /// /// The default video stream for this video. Use this to determine media info for this item. /// /// The default video stream. [IgnoreDataMember] public MediaStream DefaultVideoStream { get { return MediaStreams != null ? MediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video) : null; } } /// /// Gets a value indicating whether [is3 D]. /// /// true if [is3 D]; otherwise, false. [IgnoreDataMember] public bool Is3D { get { return VideoFormat > 0; } } /// /// Gets the type of the media. /// /// The type of the media. public override string MediaType { get { return Model.Entities.MediaType.Video; } } /// /// Overrides the base implementation to refresh metadata for local trailers /// /// The cancellation token. /// if set to true [is new item]. /// if set to true [force]. /// if set to true [allow slow providers]. /// true if a provider reports we changed public override async Task RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true) { // Kick off a task to refresh the main item var result = await base.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false); var additionalPartsChanged = false; // Must have a parent to have additional parts // In other words, it must be part of the Parent/Child tree // The additional parts won't have additional parts themselves if (IsMultiPart && LocationType == LocationType.FileSystem && Parent != null) { try { additionalPartsChanged = await RefreshAdditionalParts(cancellationToken, forceSave, forceRefresh, allowSlowProviders).ConfigureAwait(false); } catch (IOException ex) { Logger.ErrorException("Error loading additional parts for {0}.", ex, Name); } } return additionalPartsChanged || result; } /// /// Refreshes the additional parts. /// /// The cancellation token. /// if set to true [force save]. /// if set to true [force refresh]. /// if set to true [allow slow providers]. /// Task{System.Boolean}. private async Task RefreshAdditionalParts(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true) { var newItems = LoadAdditionalParts().ToList(); var newItemIds = newItems.Select(i => i.Id).ToList(); var itemsChanged = !AdditionalPartIds.SequenceEqual(newItemIds); var tasks = newItems.Select(i => i.RefreshMetadata(cancellationToken, forceSave, forceRefresh, allowSlowProviders)); var results = await Task.WhenAll(tasks).ConfigureAwait(false); AdditionalPartIds = newItemIds; return itemsChanged || results.Contains(true); } /// /// Loads the additional parts. /// /// IEnumerable{Video}. private IEnumerable