From d55af4f5292236317f572e0bddfe9575a21c4662 Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 15 Mar 2014 00:14:07 -0400 Subject: support grouping behind boxsets --- .../Library/Validators/BoxSetPostScanTask.cs | 50 ++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 MediaBrowser.Server.Implementations/Library/Validators/BoxSetPostScanTask.cs (limited to 'MediaBrowser.Server.Implementations/Library') 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 progress, CancellationToken cancellationToken) + { + var items = _libraryManager.RootFolder.RecursiveChildren.ToList(); + + var boxsets = items.OfType().ToList(); + + var numComplete = 0; + + foreach (var boxset in boxsets) + { + foreach (var child in boxset.GetLinkedChildren().OfType()) + { + 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); + } + } +} -- cgit v1.2.3 From bf30936550a0b9be69e646a1b27988914ce9ec4a Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Sat, 15 Mar 2014 18:52:43 -0400 Subject: #712 - Support grouping multiple versions of a movie --- MediaBrowser.Api/VideosService.cs | 50 ++++++- MediaBrowser.Controller/Entities/BaseItem.cs | 77 ++++++++++ MediaBrowser.Controller/Entities/Folder.cs | 112 ++++---------- MediaBrowser.Controller/Entities/Video.cs | 161 ++++++++++++++++++++- .../Resolvers/EntityResolutionHelper.cs | 16 +- MediaBrowser.Model/Dto/BaseItemDto.cs | 1 + .../Dto/DtoService.cs | 1 + .../Library/Resolvers/Movies/MovieResolver.cs | 86 +++++++++-- MediaBrowser.Tests/Resolvers/MovieResolverTests.cs | 32 ++-- 9 files changed, 413 insertions(+), 123 deletions(-) (limited to 'MediaBrowser.Server.Implementations/Library') diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs index fb58e58b7..31fda199e 100644 --- a/MediaBrowser.Api/VideosService.cs +++ b/MediaBrowser.Api/VideosService.cs @@ -22,6 +22,21 @@ namespace MediaBrowser.Api [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] public string Id { get; set; } } + + [Route("/Videos/{Id}/AlternateVersions", "GET")] + [Api(Description = "Gets alternate versions of a video.")] + public class GetAlternateVersions : IReturn + { + [ApiMember(Name = "UserId", Description = "Optional. Filter by user id, and attach user data", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")] + public Guid? UserId { get; set; } + + /// + /// Gets or sets the id. + /// + /// The id. + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Id { get; set; } + } public class VideosService : BaseApiService { @@ -48,7 +63,37 @@ namespace MediaBrowser.Api var item = string.IsNullOrEmpty(request.Id) ? (request.UserId.HasValue ? user.RootFolder - : (Folder)_libraryManager.RootFolder) + : _libraryManager.RootFolder) + : _dtoService.GetItemByDtoId(request.Id, request.UserId); + + // Get everything + var fields = Enum.GetNames(typeof(ItemFields)) + .Select(i => (ItemFields)Enum.Parse(typeof(ItemFields), i, true)) + .ToList(); + + var video = (Video)item; + + var items = video.GetAdditionalParts() + .Select(i => _dtoService.GetBaseItemDto(i, fields, user, video)) + .ToArray(); + + var result = new ItemsResult + { + Items = items, + TotalRecordCount = items.Length + }; + + return ToOptimizedSerializedResultUsingCache(result); + } + + public object Get(GetAlternateVersions request) + { + var user = request.UserId.HasValue ? _userManager.GetUserById(request.UserId.Value) : null; + + var item = string.IsNullOrEmpty(request.Id) + ? (request.UserId.HasValue + ? user.RootFolder + : _libraryManager.RootFolder) : _dtoService.GetItemByDtoId(request.Id, request.UserId); // Get everything @@ -58,8 +103,7 @@ namespace MediaBrowser.Api var video = (Video)item; - var items = video.AdditionalPartIds.Select(_libraryManager.GetItemById) - .OrderBy(i => i.SortName) + var items = video.GetAlternateVersions() .Select(i => _dtoService.GetBaseItemDto(i, fields, user, video)) .ToArray(); diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index e0c792307..be64d20c3 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -954,6 +954,83 @@ namespace MediaBrowser.Controller.Entities return (DateTime.UtcNow - DateCreated).TotalDays < ConfigurationManager.Configuration.RecentItemDays; } + /// + /// Gets the linked child. + /// + /// The info. + /// BaseItem. + protected BaseItem GetLinkedChild(LinkedChild info) + { + // First get using the cached Id + if (info.ItemId.HasValue) + { + if (info.ItemId.Value == Guid.Empty) + { + return null; + } + + var itemById = LibraryManager.GetItemById(info.ItemId.Value); + + if (itemById != null) + { + return itemById; + } + } + + var item = FindLinkedChild(info); + + // If still null, log + if (item == null) + { + // Don't keep searching over and over + info.ItemId = Guid.Empty; + } + else + { + // Cache the id for next time + info.ItemId = item.Id; + } + + return item; + } + + private BaseItem FindLinkedChild(LinkedChild info) + { + if (!string.IsNullOrEmpty(info.Path)) + { + var itemByPath = LibraryManager.RootFolder.FindByPath(info.Path); + + if (itemByPath == null) + { + Logger.Warn("Unable to find linked item at path {0}", info.Path); + } + + return itemByPath; + } + + if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) + { + return LibraryManager.RootFolder.RecursiveChildren.FirstOrDefault(i => + { + if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) + { + if (string.Equals(i.GetType().Name, info.ItemType, StringComparison.OrdinalIgnoreCase)) + { + if (info.ItemYear.HasValue) + { + return info.ItemYear.Value == (i.ProductionYear ?? -1); + } + return true; + } + } + + return false; + }); + } + + return null; + } + /// /// Adds a person to the item /// diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index ee371680e..45daaba0b 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -354,20 +354,45 @@ namespace MediaBrowser.Controller.Entities private bool IsValidFromResolver(BaseItem current, BaseItem newItem) { - var currentAsPlaceHolder = current as ISupportsPlaceHolders; + var currentAsVideo = current as Video; - if (currentAsPlaceHolder != null) + if (currentAsVideo != null) { - var newHasPlaceHolder = newItem as ISupportsPlaceHolders; + var newAsVideo = newItem as Video; - if (newHasPlaceHolder != null) + if (newAsVideo != null) { - if (currentAsPlaceHolder.IsPlaceHolder != newHasPlaceHolder.IsPlaceHolder) + if (currentAsVideo.IsPlaceHolder != newAsVideo.IsPlaceHolder) + { + return false; + } + if (currentAsVideo.IsMultiPart != newAsVideo.IsMultiPart) + { + return false; + } + if (currentAsVideo.HasLocalAlternateVersions != newAsVideo.HasLocalAlternateVersions) { return false; } } } + else + { + var currentAsPlaceHolder = current as ISupportsPlaceHolders; + + if (currentAsPlaceHolder != null) + { + var newHasPlaceHolder = newItem as ISupportsPlaceHolders; + + if (newHasPlaceHolder != null) + { + if (currentAsPlaceHolder.IsPlaceHolder != newHasPlaceHolder.IsPlaceHolder) + { + return false; + } + } + } + } return current.IsInMixedFolder == newItem.IsInMixedFolder; } @@ -898,83 +923,6 @@ namespace MediaBrowser.Controller.Entities .Where(i => i != null); } - /// - /// Gets the linked child. - /// - /// The info. - /// BaseItem. - private BaseItem GetLinkedChild(LinkedChild info) - { - // First get using the cached Id - if (info.ItemId.HasValue) - { - if (info.ItemId.Value == Guid.Empty) - { - return null; - } - - var itemById = LibraryManager.GetItemById(info.ItemId.Value); - - if (itemById != null) - { - return itemById; - } - } - - var item = FindLinkedChild(info); - - // If still null, log - if (item == null) - { - // Don't keep searching over and over - info.ItemId = Guid.Empty; - } - else - { - // Cache the id for next time - info.ItemId = item.Id; - } - - return item; - } - - private BaseItem FindLinkedChild(LinkedChild info) - { - if (!string.IsNullOrEmpty(info.Path)) - { - var itemByPath = LibraryManager.RootFolder.FindByPath(info.Path); - - if (itemByPath == null) - { - Logger.Warn("Unable to find linked item at path {0}", info.Path); - } - - return itemByPath; - } - - if (!string.IsNullOrWhiteSpace(info.ItemName) && !string.IsNullOrWhiteSpace(info.ItemType)) - { - return LibraryManager.RootFolder.RecursiveChildren.FirstOrDefault(i => - { - if (string.Equals(i.Name, info.ItemName, StringComparison.OrdinalIgnoreCase)) - { - if (string.Equals(i.GetType().Name, info.ItemType, StringComparison.OrdinalIgnoreCase)) - { - if (info.ItemYear.HasValue) - { - return info.ItemYear.Value == (i.ProductionYear ?? -1); - } - return true; - } - } - - return false; - }); - } - - return null; - } - protected override async Task RefreshedOwnedItems(MetadataRefreshOptions options, List fileSystemChildren, CancellationToken cancellationToken) { var changesFound = false; diff --git a/MediaBrowser.Controller/Entities/Video.cs b/MediaBrowser.Controller/Entities/Video.cs index 10034d7e5..e30458dd8 100644 --- a/MediaBrowser.Controller/Entities/Video.cs +++ b/MediaBrowser.Controller/Entities/Video.cs @@ -19,15 +19,63 @@ namespace MediaBrowser.Controller.Entities public class Video : BaseItem, IHasMediaStreams, IHasAspectRatio, IHasTags, ISupportsPlaceHolders { public bool IsMultiPart { get; set; } + public bool HasLocalAlternateVersions { get; set; } public List AdditionalPartIds { get; set; } + public List AlternateVersionIds { get; set; } public Video() { PlayableStreamFileNames = new List(); AdditionalPartIds = new List(); + AlternateVersionIds = new List(); Tags = new List(); SubtitleFiles = new List(); + LinkedAlternateVersions = new List(); + } + + [IgnoreDataMember] + public bool HasAlternateVersions + { + get + { + return HasLocalAlternateVersions || LinkedAlternateVersions.Count > 0; + } + } + + public List LinkedAlternateVersions { get; set; } + + /// + /// Gets the linked children. + /// + /// IEnumerable{BaseItem}. + public IEnumerable GetAlternateVersions() + { + var filesWithinSameDirectory = AlternateVersionIds + .Select(i => LibraryManager.GetItemById(i)) + .Where(i => i != null) + .OfType