support grouping behind boxsets
This commit is contained in:
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")]
|
||||
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();
|
||||
|
|
|
@ -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[] { };
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs
Normal file
19
MediaBrowser.Controller/Entities/ISupportsBoxSetGrouping.cs
Normal file
|
@ -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.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>();
|
||||
}
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
var list = new List<DlnaProfile>();
|
||||
private IApplicationPaths _appPaths;
|
||||
private readonly IXmlSerializer _xmlSerializer;
|
||||
private readonly IFileSystem _fileSystem;
|
||||
|
||||
list.Add(new DlnaProfile
|
||||
public DlnaManager(IXmlSerializer xmlSerializer, IFileSystem fileSystem)
|
||||
{
|
||||
_xmlSerializer = xmlSerializer;
|
||||
_fileSystem = fileSystem;
|
||||
|
||||
//GetProfiles();
|
||||
}
|
||||
|
||||
public IEnumerable<DeviceProfile> GetProfiles()
|
||||
{
|
||||
var list = new List<DeviceProfile>();
|
||||
|
||||
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())
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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\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" />
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user