support grouping behind boxsets

pull/702/head
Luke Pulverenti 11 years ago
parent 02bfc112ce
commit d55af4f529

@ -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")] [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; } 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> /// <summary>
@ -315,6 +318,11 @@ namespace MediaBrowser.Api.UserLibrary
items = items.AsEnumerable(); items = items.AsEnumerable();
if (request.CollapseBoxSetItems)
{
items = CollapseItemsWithinBoxSets(items, user);
}
items = ApplySortOrder(request, items, user, _libraryManager); items = ApplySortOrder(request, items, user, _libraryManager);
// This must be the last filter // This must be the last filter
@ -1218,6 +1226,41 @@ namespace MediaBrowser.Api.UserLibrary
return false; 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) internal static IEnumerable<BaseItem> FilterForAdjacency(IEnumerable<BaseItem> items, string adjacentToId)
{ {
var list = items.ToList(); var list = items.ToList();

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

@ -1,25 +1,97 @@
 using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using System.Xml.Serialization;
namespace MediaBrowser.Controller.Dlna namespace MediaBrowser.Controller.Dlna
{ {
public class DirectPlayProfile public class DirectPlayProfile
{ {
public string[] Containers { get; set; } public string Container { get; set; }
public string[] AudioCodecs { get; set; } public string AudioCodec { get; set; }
public string[] VideoCodecs { 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 string MimeType { get; set; }
public DlnaProfileType Type { get; set; } public DlnaProfileType Type { get; set; }
public List<ProfileCondition> Conditions { get; set; }
public DirectPlayProfile() public DirectPlayProfile()
{ {
Containers = new string[] { }; Conditions = new List<ProfileCondition>();
AudioCodecs = new string[] { };
VideoCodecs = new string[] { };
} }
} }
public class ProfileCondition
{
public ProfileConditionType Condition { get; set; }
public ProfileConditionValue Value { get; set; }
}
public enum DlnaProfileType public enum DlnaProfileType
{ {
Audio = 0, Audio = 0,
Video = 1 Video = 1
} }
public enum ProfileConditionType
{
Equals = 0,
NotEquals = 1,
LessThanEqual = 2,
GreaterThanEqual = 3
}
public enum ProfileConditionValue
{
AudioChannels,
AudioBitrate,
Filesize,
VideoWidth,
VideoHeight,
VideoBitrate,
VideoFramerate
}
} }

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

@ -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; }
}
}

@ -1,11 +1,11 @@
using MediaBrowser.Controller.Library; using MediaBrowser.Controller.Providers;
using MediaBrowser.Controller.Providers;
using MediaBrowser.Model.Configuration; using MediaBrowser.Model.Configuration;
using MediaBrowser.Model.Entities; using MediaBrowser.Model.Entities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Runtime.Serialization;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -14,7 +14,7 @@ namespace MediaBrowser.Controller.Entities.Movies
/// <summary> /// <summary>
/// Class Movie /// Class Movie
/// </summary> /// </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; } public List<Guid> SpecialFeatureIds { get; set; }
@ -23,6 +23,12 @@ namespace MediaBrowser.Controller.Entities.Movies
public List<Guid> ThemeSongIds { get; set; } public List<Guid> ThemeSongIds { get; set; }
public List<Guid> ThemeVideoIds { 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> /// <summary>
/// Gets or sets the preferred metadata country code. /// Gets or sets the preferred metadata country code.
/// </summary> /// </summary>
@ -39,6 +45,7 @@ namespace MediaBrowser.Controller.Entities.Movies
LocalTrailerIds = new List<Guid>(); LocalTrailerIds = new List<Guid>();
ThemeSongIds = new List<Guid>(); ThemeSongIds = new List<Guid>();
ThemeVideoIds = new List<Guid>(); ThemeVideoIds = new List<Guid>();
BoxSetIdList = new List<Guid>();
Taglines = new List<string>(); Taglines = new List<string>();
Keywords = new List<string>(); Keywords = new List<string>();
} }

@ -75,7 +75,7 @@
<Compile Include="Collections\ICollectionManager.cs" /> <Compile Include="Collections\ICollectionManager.cs" />
<Compile Include="Dlna\DirectPlayProfile.cs" /> <Compile Include="Dlna\DirectPlayProfile.cs" />
<Compile Include="Dlna\IDlnaManager.cs" /> <Compile Include="Dlna\IDlnaManager.cs" />
<Compile Include="Dlna\DlnaProfile.cs" /> <Compile Include="Dlna\DeviceProfile.cs" />
<Compile Include="Dlna\TranscodingProfile.cs" /> <Compile Include="Dlna\TranscodingProfile.cs" />
<Compile Include="Drawing\IImageProcessor.cs" /> <Compile Include="Drawing\IImageProcessor.cs" />
<Compile Include="Drawing\ImageFormat.cs" /> <Compile Include="Drawing\ImageFormat.cs" />
@ -114,6 +114,7 @@
<Compile Include="Entities\ILibraryItem.cs" /> <Compile Include="Entities\ILibraryItem.cs" />
<Compile Include="Entities\ImageSourceInfo.cs" /> <Compile Include="Entities\ImageSourceInfo.cs" />
<Compile Include="Entities\IMetadataContainer.cs" /> <Compile Include="Entities\IMetadataContainer.cs" />
<Compile Include="Entities\ISupportsBoxSetGrouping.cs" />
<Compile Include="Entities\ISupportsPlaceHolders.cs" /> <Compile Include="Entities\ISupportsPlaceHolders.cs" />
<Compile Include="Entities\ItemImageInfo.cs" /> <Compile Include="Entities\ItemImageInfo.cs" />
<Compile Include="Entities\LinkedChild.cs" /> <Compile Include="Entities\LinkedChild.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.Collections.Generic;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
@ -6,11 +9,23 @@ namespace MediaBrowser.Dlna
{ {
public class DlnaManager : IDlnaManager 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)", Name = "Samsung TV (B Series)",
ClientType = "DLNA", ClientType = "DLNA",
@ -59,7 +74,7 @@ namespace MediaBrowser.Dlna
} }
}); });
list.Add(new DlnaProfile list.Add(new DeviceProfile
{ {
Name = "Samsung TV (E/F-series)", Name = "Samsung TV (E/F-series)",
ClientType = "DLNA", ClientType = "DLNA",
@ -107,7 +122,7 @@ namespace MediaBrowser.Dlna
} }
}); });
list.Add(new DlnaProfile list.Add(new DeviceProfile
{ {
Name = "Samsung TV (C/D-series)", Name = "Samsung TV (C/D-series)",
ClientType = "DLNA", ClientType = "DLNA",
@ -154,7 +169,7 @@ namespace MediaBrowser.Dlna
} }
}); });
list.Add(new DlnaProfile list.Add(new DeviceProfile
{ {
Name = "Xbox 360", Name = "Xbox 360",
ClientType = "DLNA", ClientType = "DLNA",
@ -189,7 +204,7 @@ namespace MediaBrowser.Dlna
} }
}); });
list.Add(new DlnaProfile list.Add(new DeviceProfile
{ {
Name = "Xbox One", Name = "Xbox One",
ModelName = "Xbox One", ModelName = "Xbox One",
@ -225,7 +240,7 @@ namespace MediaBrowser.Dlna
} }
}); });
list.Add(new DlnaProfile list.Add(new DeviceProfile
{ {
Name = "Sony Bravia (2012)", Name = "Sony Bravia (2012)",
ClientType = "DLNA", ClientType = "DLNA",
@ -262,7 +277,7 @@ namespace MediaBrowser.Dlna
}); });
//WDTV does not need any transcoding of the formats we support statically //WDTV does not need any transcoding of the formats we support statically
list.Add(new DlnaProfile list.Add(new DeviceProfile
{ {
Name = "WDTV Live", Name = "WDTV Live",
ClientType = "DLNA", 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 //Linksys DMA2100us does not need any transcoding of the formats we support statically
Name = "Linksys DMA2100", 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; return list;
} }
public DlnaProfile GetDefaultProfile() public DeviceProfile GetDefaultProfile()
{ {
return new DlnaProfile return new DeviceProfile
{ {
TranscodingProfiles = new[] 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()) foreach (var profile in GetProfiles())
{ {

@ -31,7 +31,7 @@ namespace MediaBrowser.Dlna.PlayTo
public long StartPositionTicks { get; set; } 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 var playlistItem = new PlaylistItem
{ {
@ -92,7 +92,7 @@ namespace MediaBrowser.Dlna.PlayTo
return true; 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 // Placeholder for future conditions
return true; return true;

@ -126,6 +126,18 @@ namespace MediaBrowser.Server.Implementations.Collections
ItemType = item.GetType().Name, ItemType = item.GetType().Name,
Type = LinkedChildType.Manual 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); collection.LinkedChildren.AddRange(list);
@ -156,6 +168,16 @@ namespace MediaBrowser.Server.Implementations.Collections
} }
list.Add(child); 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 var shortcutFiles = Directory

@ -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);
}
}
}

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

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

Loading…
Cancel
Save