| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206 | using MediaBrowser.Common.Extensions;using MediaBrowser.Model.Entities;using MoreLinq;using System.Collections.Concurrent;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.Threading;using System.Threading.Tasks;namespace MediaBrowser.Controller.Entities{    /// <summary>    /// Class IndexFolder    /// </summary>    public class IndexFolder : Folder    {        /// <summary>        /// Initializes a new instance of the <see cref="IndexFolder" /> class.        /// </summary>        /// <param name="parent">The parent.</param>        /// <param name="shadow">The shadow.</param>        /// <param name="children">The children.</param>        /// <param name="indexName">Name of the index.</param>        /// <param name="groupContents">if set to <c>true</c> [group contents].</param>        public IndexFolder(Folder parent, BaseItem shadow, IEnumerable<BaseItem> children, string indexName, bool groupContents = true)        {            ChildSource = children;            ShadowItem = shadow;            GroupContents = groupContents;            if (shadow == null)            {                Name = ForcedSortName = "<Unknown>";            }            else            {                SetShadowValues();            }            Id = (parent.Id.ToString() + Name).GetMBId(typeof(IndexFolder));            IndexName = indexName;            Parent = parent;        }        /// <summary>        /// Resets the parent.        /// </summary>        /// <param name="parent">The parent.</param>        public void ResetParent(Folder parent)        {            Parent = parent;            Id = (parent.Id.ToString() + Name).GetMBId(typeof(IndexFolder));        }        /// <summary>        /// Override this to true if class should be grouped under a container in indicies        /// The container class should be defined via IndexContainer        /// </summary>        /// <value><c>true</c> if [group in index]; otherwise, <c>false</c>.</value>        [IgnoreDataMember]        public override bool GroupInIndex        {            get            {                return ShadowItem != null && ShadowItem.GroupInIndex;            }        }        public override LocationType LocationType        {            get            {                return LocationType.Virtual;            }        }        /// <summary>        /// Override this to return the folder that should be used to construct a container        /// for this item in an index.  GroupInIndex should be true as well.        /// </summary>        /// <value>The index container.</value>        [IgnoreDataMember]        public override Folder IndexContainer        {            get { return ShadowItem != null ? ShadowItem.IndexContainer : new IndexFolder(this, null, null, "<Unknown>", false); }        }        /// <summary>        /// Gets or sets a value indicating whether [group contents].        /// </summary>        /// <value><c>true</c> if [group contents]; otherwise, <c>false</c>.</value>        protected bool GroupContents { get; set; }        /// <summary>        /// Gets or sets the child source.        /// </summary>        /// <value>The child source.</value>        protected IEnumerable<BaseItem> ChildSource { get; set; }        /// <summary>        /// Gets or sets our children.        /// </summary>        /// <value>Our children.</value>        protected ConcurrentBag<BaseItem> OurChildren { get; set; }        /// <summary>        /// Gets the name of the index.        /// </summary>        /// <value>The name of the index.</value>        public string IndexName { get; private set; }        /// <summary>        /// Override to return the children defined to us when we were created        /// </summary>        /// <value>The actual children.</value>        protected override IEnumerable<BaseItem> LoadChildren()        {            var originalChildSource = ChildSource.ToList();            var kids = originalChildSource;            if (GroupContents)            {                // Recursively group up the chain                var group = true;                var isSubsequentLoop = false;                while (group)                {                    kids = isSubsequentLoop || kids.Any(i => i.GroupInIndex)                               ? GroupedSource(kids).ToList()                               : originalChildSource;                    group = kids.Any(i => i.GroupInIndex);                    isSubsequentLoop = true;                }            }            // Now - since we built the index grouping from the bottom up - we now need to properly set Parents from the top down            SetParents(this, kids.OfType<IndexFolder>());            return kids.DistinctBy(i => i.Id);        }        /// <summary>        /// Sets the parents.        /// </summary>        /// <param name="parent">The parent.</param>        /// <param name="kids">The kids.</param>        private void SetParents(Folder parent, IEnumerable<IndexFolder> kids)        {            foreach (var child in kids)            {                child.ResetParent(parent);                child.SetParents(child, child.Children.OfType<IndexFolder>());            }        }        /// <summary>        /// Groupeds the source.        /// </summary>        /// <param name="source">The source.</param>        /// <returns>IEnumerable{BaseItem}.</returns>        protected IEnumerable<BaseItem> GroupedSource(IEnumerable<BaseItem> source)        {            return source.GroupBy(i => i.IndexContainer).Select(container => new IndexFolder(this, container.Key, container, null, false));        }        /// <summary>        /// The item we are shadowing as a folder (Genre, Actor, etc.)        /// We inherit the images and other meta from this item        /// </summary>        /// <value>The shadow item.</value>        protected BaseItem ShadowItem { get; set; }        /// <summary>        /// Sets the shadow values.        /// </summary>        protected void SetShadowValues()        {            if (ShadowItem != null)            {                Name = ShadowItem.Name;                ForcedSortName = ShadowItem.SortName;                Genres = ShadowItem.Genres;                Studios = ShadowItem.Studios;                OfficialRating = ShadowItem.OfficialRatingForComparison;                BackdropImagePaths = ShadowItem.BackdropImagePaths;                Images = ShadowItem.Images;                Overview = ShadowItem.Overview;                DisplayMediaType = ShadowItem.GetType().Name;            }        }        /// <summary>        /// Overrides the base implementation to refresh metadata for local trailers        /// </summary>        /// <param name="cancellationToken">The cancellation token.</param>        /// <param name="forceSave">if set to <c>true</c> [is new item].</param>        /// <param name="forceRefresh">if set to <c>true</c> [force].</param>        /// <param name="allowSlowProviders">if set to <c>true</c> [allow slow providers].</param>        /// <param name="resetResolveArgs">if set to <c>true</c> [reset resolve args].</param>        /// <returns>Task{System.Boolean}.</returns>        public override Task<bool> RefreshMetadata(CancellationToken cancellationToken, bool forceSave = false, bool forceRefresh = false, bool allowSlowProviders = true, bool resetResolveArgs = true)        {            // We should never get in here since these are not part of the library            return Task.FromResult(false);        }    }}
 |