diff options
| -rw-r--r-- | MediaBrowser.Api/UserLibrary/ItemsService.cs | 43 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Dlna/DeviceProfile.cs (renamed from MediaBrowser.Controller/Dlna/DlnaProfile.cs) | 4 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Dlna/DirectPlayProfile.cs | 86 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Dlna/IDlnaManager.cs | 6 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs | 19 | ||||
| -rw-r--r-- | MediaBrowser.Controller/Entities/Movies/Movie.cs | 13 | ||||
| -rw-r--r-- | MediaBrowser.Controller/MediaBrowser.Controller.csproj | 3 | ||||
| -rw-r--r-- | MediaBrowser.Dlna/DlnaManager.cs | 48 | ||||
| -rw-r--r-- | MediaBrowser.Dlna/PlayTo/PlaylistItem.cs | 4 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Collections/CollectionManager.cs | 22 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs | 50 | ||||
| -rw-r--r-- | MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj | 1 | ||||
| -rw-r--r-- | MediaBrowser.ServerApplication/ApplicationHost.cs | 2 |
13 files changed, 268 insertions, 33 deletions
diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index b040d3dd8..ec00be988 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/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(); diff --git a/MediaBrowser.Controller/Dlna/DlnaProfile.cs b/MediaBrowser.Controller/Dlna/DeviceProfile.cs index 33f95b794..3fecf957b 100644 --- a/MediaBrowser.Controller/Dlna/DlnaProfile.cs +++ b/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[] { }; diff --git a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs b/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs index f1922dd32..8c35b52a8 100644 --- a/MediaBrowser.Controller/Dlna/DirectPlayProfile.cs +++ b/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 + } } diff --git a/MediaBrowser.Controller/Dlna/IDlnaManager.cs b/MediaBrowser.Controller/Dlna/IDlnaManager.cs index 017dbc874..04f658805 100644 --- a/MediaBrowser.Controller/Dlna/IDlnaManager.cs +++ b/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); } } diff --git a/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs b/MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs new file mode 100644 index 000000000..0fd463155 --- /dev/null +++ b/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; } + } +} diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index 9858dd5a9..f53b67610 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/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; } @@ -24,6 +24,12 @@ namespace MediaBrowser.Controller.Entities.Movies 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> /// <value>The preferred metadata country code.</value> @@ -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>(); } diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj index 21a501b08..7e5e6d9b0 100644 --- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj +++ b/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" /> diff --git a/MediaBrowser.Dlna/DlnaManager.cs b/MediaBrowser.Dlna/DlnaManager.cs index 1c9cba2be..91d205b47 100644 --- a/MediaBrowser.Dlna/DlnaManager.cs +++ b/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()) { diff --git a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs b/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs index cfb2c7d1c..4f776807e 100644 --- a/MediaBrowser.Dlna/PlayTo/PlaylistItem.cs +++ b/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; diff --git a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs b/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs index 9a196cc47..8e70c1d3d 100644 --- a/MediaBrowser.Server.Implementations/Collections/CollectionManager.cs +++ b/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 diff --git a/MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs b/MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs new file mode 100644 index 000000000..f02c907c6 --- /dev/null +++ b/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); + } + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index c44b60845..871565133 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/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" /> diff --git a/MediaBrowser.ServerApplication/ApplicationHost.cs b/MediaBrowser.ServerApplication/ApplicationHost.cs index 32932fe0b..f55f18cc3 100644 --- a/MediaBrowser.ServerApplication/ApplicationHost.cs +++ b/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); |
