From 0d518ebf170eefc29fd164eabcbd8d4152177fee Mon Sep 17 00:00:00 2001 From: Luke Pulverenti Date: Thu, 20 Mar 2014 11:55:22 -0400 Subject: [PATCH] #712 - group multiple versions --- MediaBrowser.Api/VideosService.cs | 10 +- .../Entities/CollectionFolder.cs | 29 +--- MediaBrowser.Controller/Entities/Folder.cs | 29 ++-- MediaBrowser.Model/Dto/BaseItemDto.cs | 6 + MediaBrowser.Model/Dto/MediaVersionInfo.cs | 2 - MediaBrowser.Model/Querying/ItemFields.cs | 5 + .../Dto/DtoService.cs | 162 ++++++++++++++++++ .../Library/LibraryManager.cs | 80 ++------- 8 files changed, 217 insertions(+), 106 deletions(-) diff --git a/MediaBrowser.Api/VideosService.cs b/MediaBrowser.Api/VideosService.cs index 476ea405c7..f7f864d7e5 100644 --- a/MediaBrowser.Api/VideosService.cs +++ b/MediaBrowser.Api/VideosService.cs @@ -158,8 +158,7 @@ namespace MediaBrowser.Api Path = GetMappedPath(i), RunTimeTicks = i.RunTimeTicks, Video3DFormat = i.Video3DFormat, - VideoType = i.VideoType, - IsHD = i.IsHD + VideoType = i.VideoType }; } @@ -234,7 +233,12 @@ namespace MediaBrowser.Api { if (stream.Width.HasValue) { - if (stream.Width.Value >= 1900) + if (stream.Width.Value >= 3800) + { + name = name + " " + "4K"; + name = name.Trim(); + } + else if (stream.Width.Value >= 1900) { name = name + " " + "1080P"; name = name.Trim(); diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 6628ffc234..0ce88bee79 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -130,7 +130,6 @@ namespace MediaBrowser.Controller.Entities } private List _linkedChildren; - /// /// Our children are actually just references to the ones in the physical root... /// @@ -145,21 +144,9 @@ namespace MediaBrowser.Controller.Entities } private List GetLinkedChildrenInternal() { - Dictionary locationsDicionary; - - try - { - locationsDicionary = PhysicalLocations.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - } - catch (IOException ex) - { - Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); - return new List(); - } - return LibraryManager.RootFolder.Children .OfType() - .Where(i => i.Path != null && locationsDicionary.ContainsKey(i.Path)) + .Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase)) .SelectMany(c => c.LinkedChildren) .ToList(); } @@ -177,22 +164,10 @@ namespace MediaBrowser.Controller.Entities private IEnumerable GetActualChildren() { - Dictionary locationsDicionary; - - try - { - locationsDicionary = PhysicalLocations.Distinct(StringComparer.OrdinalIgnoreCase).ToDictionary(i => i, StringComparer.OrdinalIgnoreCase); - } - catch (IOException ex) - { - Logger.ErrorException("Error getting ResolveArgs for {0}", ex, Path); - return new BaseItem[] { }; - } - return LibraryManager.RootFolder.Children .OfType() - .Where(i => i.Path != null && locationsDicionary.ContainsKey(i.Path)) + .Where(i => i.Path != null && PhysicalLocations.Contains(i.Path, StringComparer.OrdinalIgnoreCase)) .SelectMany(c => c.Children) .ToList(); } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 45daaba0b2..21b34c7338 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -446,24 +446,31 @@ namespace MediaBrowser.Controller.Entities { BaseItem currentChild; - if (currentChildren.TryGetValue(child.Id, out currentChild) && IsValidFromResolver(currentChild, child)) + if (currentChildren.TryGetValue(child.Id, out currentChild)) { - var currentChildLocationType = currentChild.LocationType; - if (currentChildLocationType != LocationType.Remote && - currentChildLocationType != LocationType.Virtual) + if (IsValidFromResolver(currentChild, child)) { - currentChild.DateModified = child.DateModified; - } + var currentChildLocationType = currentChild.LocationType; + if (currentChildLocationType != LocationType.Remote && + currentChildLocationType != LocationType.Virtual) + { + currentChild.DateModified = child.DateModified; + } - currentChild.IsOffline = false; + currentChild.IsOffline = false; + validChildren.Add(currentChild); + } + else + { + validChildren.Add(child); + } } else { - //brand new item - needs to be added + // Brand new item - needs to be added newItems.Add(child); + validChildren.Add(child); } - - validChildren.Add(currentChild); } // If any items were added or removed.... @@ -736,7 +743,7 @@ namespace MediaBrowser.Controller.Entities /// BaseItem. private BaseItem RetrieveChild(Guid child) { - var item = LibraryManager.RetrieveItem(child); + var item = LibraryManager.GetItemById(child); if (item != null) { diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 451afee6ba..aba7e217e2 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -88,6 +88,12 @@ namespace MediaBrowser.Model.Dto /// The external urls. public ExternalUrl[] ExternalUrls { get; set; } + /// + /// Gets or sets the media versions. + /// + /// The media versions. + public List MediaVersions { get; set; } + /// /// Gets or sets the critic rating. /// diff --git a/MediaBrowser.Model/Dto/MediaVersionInfo.cs b/MediaBrowser.Model/Dto/MediaVersionInfo.cs index 809a1e3d9b..dfbf81416f 100644 --- a/MediaBrowser.Model/Dto/MediaVersionInfo.cs +++ b/MediaBrowser.Model/Dto/MediaVersionInfo.cs @@ -24,7 +24,5 @@ namespace MediaBrowser.Model.Dto public List MediaStreams { get; set; } public List Chapters { get; set; } - - public bool? IsHD { get; set; } } } diff --git a/MediaBrowser.Model/Querying/ItemFields.cs b/MediaBrowser.Model/Querying/ItemFields.cs index 85f49ce3eb..405ba3d777 100644 --- a/MediaBrowser.Model/Querying/ItemFields.cs +++ b/MediaBrowser.Model/Querying/ItemFields.cs @@ -76,6 +76,11 @@ namespace MediaBrowser.Model.Querying /// Keywords, + /// + /// The media versions + /// + MediaVersions, + /// /// The metadata settings /// diff --git a/MediaBrowser.Server.Implementations/Dto/DtoService.cs b/MediaBrowser.Server.Implementations/Dto/DtoService.cs index a66cb148f8..c03f327edc 100644 --- a/MediaBrowser.Server.Implementations/Dto/DtoService.cs +++ b/MediaBrowser.Server.Implementations/Dto/DtoService.cs @@ -1088,6 +1088,11 @@ namespace MediaBrowser.Server.Implementations.Dto { dto.Chapters = _itemRepo.GetChapters(video.Id).Select(c => GetChapterInfoDto(c, item)).ToList(); } + + if (fields.Contains(ItemFields.MediaVersions)) + { + //dto.MediaVersions = GetMediaVersions(video); + } } if (fields.Contains(ItemFields.MediaStreams)) @@ -1223,6 +1228,163 @@ namespace MediaBrowser.Server.Implementations.Dto } } + private List GetMediaVersions(Video video) + { + var result = video.GetAlternateVersions().Select(GetVersionInfo).ToList(); + + result.Add(GetVersionInfo(video)); + + return result.OrderBy(i => + { + if (video.VideoType == VideoType.VideoFile) + { + return 0; + } + + return 1; + + }).ThenBy(i => i.Video3DFormat.HasValue ? 1 : 0) + .ThenByDescending(i => + { + var stream = i.MediaStreams.FirstOrDefault(m => m.Type == MediaStreamType.Video); + + return stream == null || stream.Width == null ? 0 : stream.Width.Value; + }) + .ToList(); + } + + private MediaVersionInfo GetVersionInfo(Video i) + { + return new MediaVersionInfo + { + Chapters = _itemRepo.GetChapters(i.Id).Select(c => GetChapterInfoDto(c, i)).ToList(), + + Id = i.Id.ToString("N"), + IsoType = i.IsoType, + LocationType = i.LocationType, + MediaStreams = _itemRepo.GetMediaStreams(new MediaStreamQuery { ItemId = i.Id }).ToList(), + Name = GetAlternateVersionName(i), + Path = GetMappedPath(i), + RunTimeTicks = i.RunTimeTicks, + Video3DFormat = i.Video3DFormat, + VideoType = i.VideoType + }; + } + + private string GetMappedPath(Video video) + { + var path = video.Path; + + var locationType = video.LocationType; + + if (locationType != LocationType.FileSystem && locationType != LocationType.Offline) + { + return path; + } + + foreach (var map in _config.Configuration.PathSubstitutions) + { + path = _fileSystem.SubstitutePath(path, map.From, map.To); + } + + return path; + } + + private string GetAlternateVersionName(Video video) + { + var name = ""; + + var stream = video.GetDefaultVideoStream(); + + if (video.Video3DFormat.HasValue) + { + name = "3D " + name; + name = name.Trim(); + } + + if (video.VideoType == VideoType.BluRay) + { + name = name + " " + "Bluray"; + name = name.Trim(); + } + else if (video.VideoType == VideoType.Dvd) + { + name = name + " " + "DVD"; + name = name.Trim(); + } + else if (video.VideoType == VideoType.HdDvd) + { + name = name + " " + "HD-DVD"; + name = name.Trim(); + } + else if (video.VideoType == VideoType.Iso) + { + if (video.IsoType.HasValue) + { + if (video.IsoType.Value == IsoType.BluRay) + { + name = name + " " + "Bluray"; + } + else if (video.IsoType.Value == IsoType.Dvd) + { + name = name + " " + "DVD"; + } + } + else + { + name = name + " " + "ISO"; + } + name = name.Trim(); + } + else if (video.VideoType == VideoType.VideoFile) + { + if (stream != null) + { + if (stream.Width.HasValue) + { + if (stream.Width.Value >= 3800) + { + name = name + " " + "4K"; + name = name.Trim(); + } + else if (stream.Width.Value >= 1900) + { + name = name + " " + "1080P"; + name = name.Trim(); + } + else if (stream.Width.Value >= 1270) + { + name = name + " " + "720P"; + name = name.Trim(); + } + else if (stream.Width.Value >= 700) + { + name = name + " " + "480p"; + name = name.Trim(); + } + else + { + name = name + " " + "SD"; + name = name.Trim(); + } + } + } + } + + if (stream != null && !string.IsNullOrWhiteSpace(stream.Codec)) + { + name = name + " " + stream.Codec.ToUpper(); + name = name.Trim(); + } + + if (string.IsNullOrWhiteSpace(name)) + { + return video.Name; + } + + return name; + } + private string GetMappedPath(string path) { foreach (var map in _config.Configuration.PathSubstitutions) diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 91abb6b4f7..817e14d4d8 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -133,15 +133,7 @@ namespace MediaBrowser.Server.Implementations.Library /// /// The _library items cache /// - private ConcurrentDictionary _libraryItemsCache; - /// - /// The _library items cache sync lock - /// - private object _libraryItemsCacheSyncLock = new object(); - /// - /// The _library items cache initialized - /// - private bool _libraryItemsCacheInitialized; + private readonly ConcurrentDictionary _libraryItemsCache; /// /// Gets the library items cache. /// @@ -150,7 +142,6 @@ namespace MediaBrowser.Server.Implementations.Library { get { - LazyInitializer.EnsureInitialized(ref _libraryItemsCache, ref _libraryItemsCacheInitialized, ref _libraryItemsCacheSyncLock, CreateLibraryItemsCache); return _libraryItemsCache; } } @@ -176,6 +167,7 @@ namespace MediaBrowser.Server.Implementations.Library _fileSystem = fileSystem; _providerManagerFactory = providerManagerFactory; ByReferenceItems = new ConcurrentDictionary(); + _libraryItemsCache = new ConcurrentDictionary(); ConfigurationManager.ConfigurationUpdated += ConfigurationUpdated; @@ -358,48 +350,6 @@ namespace MediaBrowser.Server.Implementations.Library } } - /// - /// Creates the library items cache. - /// - /// ConcurrentDictionary{GuidBaseItem}. - private ConcurrentDictionary CreateLibraryItemsCache() - { - var items = RootFolder.GetRecursiveChildren(); - - items.Add(RootFolder); - - // Need to use Distinct because there could be multiple instances with the same id - // due to sharing the default library - var userRootFolders = _userManager.Users.Select(i => i.RootFolder) - .Distinct() - .ToList(); - - foreach (var folder in userRootFolders) - { - items.Add(folder); - } - - // Get all user collection folders - // Skip BasePluginFolders because we already got them from RootFolder.RecursiveChildren - var userFolders = userRootFolders.SelectMany(i => i.Children) - .Where(i => !(i is BasePluginFolder)) - .ToList(); - - foreach (var folder in userFolders) - { - items.Add(folder); - } - - var dictionary = new ConcurrentDictionary(); - - foreach (var item in items) - { - dictionary[item.Id] = item; - } - - return dictionary; - } - /// /// Updates the item in library cache. /// @@ -411,6 +361,10 @@ namespace MediaBrowser.Server.Implementations.Library public void RegisterItem(BaseItem item) { + if (item == null) + { + throw new ArgumentNullException("item"); + } RegisterItem(item.Id, item); } @@ -529,13 +483,6 @@ namespace MediaBrowser.Server.Implementations.Library if (item != null) { ResolverHelper.SetInitialItemValues(item, args, _fileSystem); - - // Now handle the issue with posibly having the same item referenced from multiple physical - // places within the library. Be sure we always end up with just one instance. - if (item is IByReferenceItem) - { - item = GetOrAddByReferenceItem(item); - } } return item; @@ -720,7 +667,7 @@ namespace MediaBrowser.Server.Implementations.Library Directory.CreateDirectory(rootFolderPath); - var rootFolder = RetrieveItem(rootFolderPath.GetMBId(typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath)); + var rootFolder = GetItemById(rootFolderPath.GetMBId(typeof(AggregateFolder))) as AggregateFolder ?? (AggregateFolder)ResolvePath(new DirectoryInfo(rootFolderPath)); // Add in the plug-in folders foreach (var child in PluginFolderCreators) @@ -747,7 +694,7 @@ namespace MediaBrowser.Server.Implementations.Library Directory.CreateDirectory(userRootPath); - _userRootFolder = RetrieveItem(userRootPath.GetMBId(typeof(UserRootFolder))) as UserRootFolder ?? + _userRootFolder = GetItemById(userRootPath.GetMBId(typeof(UserRootFolder))) as UserRootFolder ?? (UserRootFolder)ResolvePath(new DirectoryInfo(userRootPath)); } @@ -919,7 +866,7 @@ namespace MediaBrowser.Server.Implementations.Library isNew = true; } - var item = isNew ? null : RetrieveItem(id) as T; + var item = isNew ? null : GetItemById(id) as T; if (item == null) { @@ -1228,7 +1175,14 @@ namespace MediaBrowser.Server.Implementations.Library return item; } - return RetrieveItem(id); + item = RetrieveItem(id); + + if (item != null) + { + RegisterItem(item); + } + + return item; } ///