Forráskód Böngészése

support grouping behind boxsets

Luke Pulverenti 11 éve
szülő
commit
d55af4f529

+ 43 - 0
MediaBrowser.Api/UserLibrary/ItemsService.cs

@@ -238,6 +238,9 @@ namespace MediaBrowser.Api.UserLibrary
 
         [ApiMember(Name = "HasOfficialRating", Description = "Optional filter by items that have official ratings", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
         public bool? HasOfficialRating { get; set; }
+
+        [ApiMember(Name = "CollapseBoxSetItems", Description = "Whether or not to hide items behind their boxsets.", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")]
+        public bool CollapseBoxSetItems { get; set; }
     }
 
     /// <summary>
@@ -315,6 +318,11 @@ namespace MediaBrowser.Api.UserLibrary
 
             items = items.AsEnumerable();
 
+            if (request.CollapseBoxSetItems)
+            {
+                items = CollapseItemsWithinBoxSets(items, user);
+            }
+
             items = ApplySortOrder(request, items, user, _libraryManager);
 
             // This must be the last filter
@@ -1218,6 +1226,41 @@ namespace MediaBrowser.Api.UserLibrary
             return false;
         }
 
+        private IEnumerable<BaseItem> CollapseItemsWithinBoxSets(IEnumerable<BaseItem> items, User user)
+        {
+            var itemsToCollapse = new List<ISupportsBoxSetGrouping>();
+            var boxsets = new List<BaseItem>();
+
+            var list = items.ToList();
+
+            foreach (var item in list.OfType<ISupportsBoxSetGrouping>())
+            {
+                var currentBoxSets = item.BoxSetIdList
+                    .Select(i => _libraryManager.GetItemById(i))
+                    .Where(i => i != null && i.IsVisible(user))
+                    .ToList();
+
+                if (currentBoxSets.Count > 0)
+                {
+                    itemsToCollapse.Add(item);
+                    boxsets.AddRange(currentBoxSets);
+                }
+            }
+
+            return list.Except(itemsToCollapse.Cast<BaseItem>()).Concat(boxsets).Distinct();
+        }
+
+        private bool AllowBoxSetCollapsing(GetItems request)
+        {
+            // Only allow when using default sort order
+            if (!string.IsNullOrEmpty(request.SortBy) && !string.Equals(request.SortBy, "SortName", StringComparison.OrdinalIgnoreCase))
+            {
+                return false;
+            }
+
+            return true;
+        }
+
         internal static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
         {
             var list = items.ToList();

+ 2 - 2
MediaBrowser.Controller/Dlna/DlnaProfile.cs → MediaBrowser.Controller/Dlna/DeviceProfile.cs

@@ -1,7 +1,7 @@
 
 namespace MediaBrowser.Controller.Dlna
 {
-    public class DlnaProfile
+    public class DeviceProfile
     {
         /// <summary>
         /// Gets or sets the name.
@@ -45,7 +45,7 @@ namespace MediaBrowser.Controller.Dlna
         /// <value>The direct play profiles.</value>
         public DirectPlayProfile[] DirectPlayProfiles { get; set; }
 
-        public DlnaProfile()
+        public DeviceProfile()
         {
             DirectPlayProfiles = new DirectPlayProfile[] { };
             TranscodingProfiles = new TranscodingProfile[] { };

+ 79 - 7
MediaBrowser.Controller/Dlna/DirectPlayProfile.cs

@@ -1,25 +1,97 @@
-
+using System;
+using System.Collections.Generic;
+using System.Runtime.Serialization;
+using System.Xml.Serialization;
+
 namespace MediaBrowser.Controller.Dlna
 {
     public class DirectPlayProfile
     {
-        public string[] Containers { get; set; }
-        public string[] AudioCodecs { get; set; }
-        public string[] VideoCodecs { get; set; }
+        public string Container { get; set; }
+        public string AudioCodec { get; set; }
+        public string VideoCodec { get; set; }
+
+        [IgnoreDataMember]
+        [XmlIgnore]
+        public string[] Containers
+        {
+            get
+            {
+                return (Container ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+            }
+            set
+            {
+                Container = value == null ? null : string.Join(",", value);
+            }
+        }
+
+        [IgnoreDataMember]
+        [XmlIgnore]
+        public string[] AudioCodecs
+        {
+            get
+            {
+                return (AudioCodec ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+            }
+            set
+            {
+                AudioCodec = value == null ? null : string.Join(",", value);
+            }
+        }
+
+        [IgnoreDataMember]
+        [XmlIgnore]
+        public string[] VideoCodecs
+        {
+            get
+            {
+                return (VideoCodec ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+            }
+            set
+            {
+                VideoCodec = value == null ? null : string.Join(",", value);
+            }
+        }
+
         public string MimeType { get; set; }
         public DlnaProfileType Type { get; set; }
 
+        public List<ProfileCondition> Conditions { get; set; }
+
         public DirectPlayProfile()
         {
-            Containers = new string[] { };
-            AudioCodecs = new string[] { };
-            VideoCodecs = new string[] { };
+            Conditions = new List<ProfileCondition>();
         }
     }
 
+    public class ProfileCondition
+    {
+        public ProfileConditionType Condition { get; set; }
+        public ProfileConditionValue Value { get; set; }
+    }
+
     public enum DlnaProfileType
     {
         Audio = 0,
         Video = 1
     }
+
+    public enum ProfileConditionType
+    {
+        Equals = 0,
+        NotEquals = 1,
+        LessThanEqual = 2,
+        GreaterThanEqual = 3
+    }
+
+    public enum ProfileConditionValue
+    {
+        AudioChannels,
+        AudioBitrate,
+        Filesize,
+        VideoWidth,
+        VideoHeight,
+        VideoBitrate,
+        VideoFramerate
+    }
 }

+ 3 - 3
MediaBrowser.Controller/Dlna/IDlnaManager.cs

@@ -8,13 +8,13 @@ namespace MediaBrowser.Controller.Dlna
         /// Gets the dlna profiles.
         /// </summary>
         /// <returns>IEnumerable{DlnaProfile}.</returns>
-        IEnumerable<DlnaProfile> GetProfiles();
+        IEnumerable<DeviceProfile> GetProfiles();
 
         /// <summary>
         /// Gets the default profile.
         /// </summary>
         /// <returns>DlnaProfile.</returns>
-        DlnaProfile GetDefaultProfile();
+        DeviceProfile GetDefaultProfile();
 
         /// <summary>
         /// Gets the profile.
@@ -23,6 +23,6 @@ namespace MediaBrowser.Controller.Dlna
         /// <param name="modelName">Name of the model.</param>
         /// <param name="modelNumber">The model number.</param>
         /// <returns>DlnaProfile.</returns>
-        DlnaProfile GetProfile(string friendlyName, string modelName, string modelNumber);
+        DeviceProfile GetProfile(string friendlyName, string modelName, string modelNumber);
     }
 }

+ 19 - 0
MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs

@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+
+namespace MediaBrowser.Controller.Entities
+{
+    /// <summary>
+    /// Marker interface to denote a class that supports being hidden underneath it's boxset.
+    /// Just about anything can be placed into a boxset, 
+    /// but movies should also only appear underneath and not outside separately (subject to configuration).
+    /// </summary>
+    public interface ISupportsBoxSetGrouping
+    {
+        /// <summary>
+        /// Gets or sets the box set identifier list.
+        /// </summary>
+        /// <value>The box set identifier list.</value>
+        List<Guid> BoxSetIdList { get; set; }
+    }
+}

+ 10 - 3
MediaBrowser.Controller/Entities/Movies/Movie.cs

@@ -1,11 +1,11 @@
-using MediaBrowser.Controller.Library;
-using MediaBrowser.Controller.Providers;
+using MediaBrowser.Controller.Providers;
 using MediaBrowser.Model.Configuration;
 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;
 
@@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities.Movies
     /// <summary>
     /// Class Movie
     /// </summary>
-    public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasPreferredMetadataLanguage, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>
+    public class Movie : Video, IHasCriticRating, IHasSoundtracks, IHasBudget, IHasKeywords, IHasTrailers, IHasThemeMedia, IHasTaglines, IHasPreferredMetadataLanguage, IHasAwards, IHasMetascore, IHasLookupInfo<MovieInfo>, ISupportsBoxSetGrouping
     {
         public List<Guid> SpecialFeatureIds { get; set; }
 
@@ -23,6 +23,12 @@ namespace MediaBrowser.Controller.Entities.Movies
         public List<Guid> ThemeSongIds { get; set; }
         public List<Guid> ThemeVideoIds { get; set; }
 
+        /// <summary>
+        /// This is just a cache to enable quick access by Id
+        /// </summary>
+        [IgnoreDataMember]
+        public List<Guid> BoxSetIdList { get; set; }
+
         /// <summary>
         /// Gets or sets the preferred metadata country code.
         /// </summary>
@@ -39,6 +45,7 @@ namespace MediaBrowser.Controller.Entities.Movies
             LocalTrailerIds = new List<Guid>();
             ThemeSongIds = new List<Guid>();
             ThemeVideoIds = new List<Guid>();
+            BoxSetIdList = new List<Guid>();
             Taglines = new List<string>();
             Keywords = new List<string>();
         }

+ 2 - 1
MediaBrowser.Controller/MediaBrowser.Controller.csproj

@@ -75,7 +75,7 @@
     <Compile Include="Collections\ICollectionManager.cs" />
     <Compile Include="Dlna\DirectPlayProfile.cs" />
     <Compile Include="Dlna\IDlnaManager.cs" />
-    <Compile Include="Dlna\DlnaProfile.cs" />
+    <Compile Include="Dlna\DeviceProfile.cs" />
     <Compile Include="Dlna\TranscodingProfile.cs" />
     <Compile Include="Drawing\IImageProcessor.cs" />
     <Compile Include="Drawing\ImageFormat.cs" />
@@ -114,6 +114,7 @@
     <Compile Include="Entities\ILibraryItem.cs" />
     <Compile Include="Entities\ImageSourceInfo.cs" />
     <Compile Include="Entities\IMetadataContainer.cs" />
+    <Compile Include="Entities\ISupportsBoxSetGrouping.cs" />
     <Compile Include="Entities\ISupportsPlaceHolders.cs" />
     <Compile Include="Entities\ItemImageInfo.cs" />
     <Compile Include="Entities\LinkedChild.cs" />

+ 34 - 14
MediaBrowser.Dlna/DlnaManager.cs

@@ -1,4 +1,7 @@
-using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Common.Configuration;
+using MediaBrowser.Common.IO;
+using MediaBrowser.Controller.Dlna;
+using MediaBrowser.Model.Serialization;
 using System.Collections.Generic;
 using System.Text.RegularExpressions;
 
@@ -6,11 +9,23 @@ namespace MediaBrowser.Dlna
 {
     public class DlnaManager : IDlnaManager
     {
-        public IEnumerable<DlnaProfile> GetProfiles()
+        private IApplicationPaths _appPaths;
+        private readonly IXmlSerializer _xmlSerializer;
+        private readonly IFileSystem _fileSystem;
+
+        public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem)
+        {
+            _xmlSerializer = xmlSerializer;
+            _fileSystem = fileSystem;
+
+            //GetProfiles();
+        }
+
+        public IEnumerable<DeviceProfile> GetProfiles()
         {
-            var list = new List<DlnaProfile>();
+            var list = new List<DeviceProfile>();
 
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 Name = "Samsung TV (B Series)",
                 ClientType = "DLNA",
@@ -59,7 +74,7 @@ namespace MediaBrowser.Dlna
                 }
             });
 
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 Name = "Samsung TV (E/F-series)",
                 ClientType = "DLNA",
@@ -107,7 +122,7 @@ namespace MediaBrowser.Dlna
                 }
             });
 
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 Name = "Samsung TV (C/D-series)",
                 ClientType = "DLNA",
@@ -154,7 +169,7 @@ namespace MediaBrowser.Dlna
                 }
             });
 
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 Name = "Xbox 360",
                 ClientType = "DLNA",
@@ -189,7 +204,7 @@ namespace MediaBrowser.Dlna
                 }
             });
 
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 Name = "Xbox One",
                 ModelName = "Xbox One",
@@ -225,7 +240,7 @@ namespace MediaBrowser.Dlna
                 }
             });
 
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 Name = "Sony Bravia (2012)",
                 ClientType = "DLNA",
@@ -262,7 +277,7 @@ namespace MediaBrowser.Dlna
             });
 
             //WDTV does not need any transcoding of the formats we support statically
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 Name = "WDTV Live",
                 ClientType = "DLNA",
@@ -284,7 +299,7 @@ namespace MediaBrowser.Dlna
                 }
             });
 
-            list.Add(new DlnaProfile
+            list.Add(new DeviceProfile
             {
                 //Linksys DMA2100us does not need any transcoding of the formats we support statically
                 Name = "Linksys DMA2100",
@@ -307,12 +322,17 @@ namespace MediaBrowser.Dlna
                 }
             });
 
+            foreach (var item in list)
+            {
+                //_xmlSerializer.SerializeToFile(item, "d:\\" + _fileSystem.GetValidFilename(item.Name));
+            }
+
             return list;
         }
 
-        public DlnaProfile GetDefaultProfile()
+        public DeviceProfile GetDefaultProfile()
         {
-            return new DlnaProfile
+            return new DeviceProfile
             {
                 TranscodingProfiles = new[]
                 {
@@ -345,7 +365,7 @@ namespace MediaBrowser.Dlna
             };
         }
 
-        public DlnaProfile GetProfile(string friendlyName, string modelName, string modelNumber)
+        public DeviceProfile GetProfile(string friendlyName, string modelName, string modelNumber)
         {
             foreach (var profile in GetProfiles())
             {

+ 2 - 2
MediaBrowser.Dlna/PlayTo/PlaylistItem.cs

@@ -31,7 +31,7 @@ namespace MediaBrowser.Dlna.PlayTo
 
         public long StartPositionTicks { get; set; }
 
-        public static PlaylistItem Create(BaseItem item, DlnaProfile profile)
+        public static PlaylistItem Create(BaseItem item, DeviceProfile profile)
         {
             var playlistItem = new PlaylistItem
             {
@@ -92,7 +92,7 @@ namespace MediaBrowser.Dlna.PlayTo
             return true;
         }
 
-        private static bool IsSupported(DlnaProfile profile, TranscodingProfile transcodingProfile, string path)
+        private static bool IsSupported(DeviceProfile profile, TranscodingProfile transcodingProfile, string path)
         {
             // Placeholder for future conditions
             return true;

+ 22 - 0
MediaBrowser.Server.Implementations/Collections/CollectionManager.cs

@@ -126,6 +126,18 @@ namespace MediaBrowser.Server.Implementations.Collections
                     ItemType = item.GetType().Name,
                     Type = LinkedChildType.Manual
                 });
+
+                var supportsGrouping = item as ISupportsBoxSetGrouping;
+
+                if (supportsGrouping != null)
+                {
+                    var boxsetIdList = supportsGrouping.BoxSetIdList.ToList();
+                    if (!boxsetIdList.Contains(collectionId))
+                    {
+                        boxsetIdList.Add(collectionId);
+                    }
+                    supportsGrouping.BoxSetIdList = boxsetIdList;
+                }
             }
 
             collection.LinkedChildren.AddRange(list);
@@ -156,6 +168,16 @@ namespace MediaBrowser.Server.Implementations.Collections
                 }
 
                 list.Add(child);
+
+                var childItem = _libraryManager.GetItemById(itemId);
+                var supportsGrouping = childItem as ISupportsBoxSetGrouping;
+
+                if (supportsGrouping != null)
+                {
+                    var boxsetIdList = supportsGrouping.BoxSetIdList.ToList();
+                    boxsetIdList.Remove(collectionId);
+                    supportsGrouping.BoxSetIdList = boxsetIdList;
+                }
             }
 
             var shortcutFiles = Directory

+ 50 - 0
MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs

@@ -0,0 +1,50 @@
+using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities.Movies;
+using MediaBrowser.Controller.Library;
+using System;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace MediaBrowser.Server.Implementations.Library.Validators
+{
+    public class BoxSetPostScanTask : ILibraryPostScanTask
+    {
+        private readonly ILibraryManager _libraryManager;
+
+        public BoxSetPostScanTask(ILibraryManager libraryManager)
+        {
+            _libraryManager = libraryManager;
+        }
+
+        public Task Run(IProgress<double> progress, CancellationToken cancellationToken)
+        {
+            var items = _libraryManager.RootFolder.RecursiveChildren.ToList();
+
+            var boxsets = items.OfType<BoxSet>().ToList();
+
+            var numComplete = 0;
+
+            foreach (var boxset in boxsets)
+            {
+                foreach (var child in boxset.GetLinkedChildren().OfType<ISupportsBoxSetGrouping>())
+                {
+                    var boxsetIdList = child.BoxSetIdList.ToList();
+                    if (!boxsetIdList.Contains(boxset.Id))
+                    {
+                        boxsetIdList.Add(boxset.Id);
+                    }
+                    child.BoxSetIdList = boxsetIdList;
+                }
+
+                numComplete++;
+                double percent = numComplete;
+                percent /= boxsets.Count;
+                progress.Report(percent * 100);
+            }
+
+            progress.Report(100);
+            return Task.FromResult(true);
+        }
+    }
+}

+ 1 - 0
MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj

@@ -165,6 +165,7 @@
     <Compile Include="Library\UserManager.cs" />
     <Compile Include="Library\Validators\ArtistsPostScanTask.cs" />
     <Compile Include="Library\Validators\ArtistsValidator.cs" />
+    <Compile Include="Library\Validators\BoxSetPostScanTask.cs" />
     <Compile Include="Library\Validators\CountHelpers.cs" />
     <Compile Include="Library\Validators\GameGenresPostScanTask.cs" />
     <Compile Include="Library\Validators\GameGenresValidator.cs" />

+ 1 - 1
MediaBrowser.ServerApplication/ApplicationHost.cs

@@ -492,7 +492,7 @@ namespace MediaBrowser.ServerApplication
             var appThemeManager = new AppThemeManager(ApplicationPaths, FileSystemManager, JsonSerializer, Logger);
             RegisterSingleInstance<IAppThemeManager>(appThemeManager);
 
-            var dlnaManager = new DlnaManager();
+            var dlnaManager = new DlnaManager(XmlSerializer, FileSystemManager);
             RegisterSingleInstance<IDlnaManager>(dlnaManager);
 
             var collectionManager = new CollectionManager(LibraryManager, FileSystemManager, LibraryMonitor);