diff --git a/MediaBrowser.Api/FilterService.cs b/MediaBrowser.Api/FilterService.cs index 6d1c5d868d..c4419531c5 100644 --- a/MediaBrowser.Api/FilterService.cs +++ b/MediaBrowser.Api/FilterService.cs @@ -103,7 +103,8 @@ namespace MediaBrowser.Api User = user, MediaTypes = request.GetMediaTypes(), IncludeItemTypes = request.GetIncludeItemTypes(), - Recursive = true + Recursive = true, + EnableTotalRecordCount = false }; return query; diff --git a/MediaBrowser.Api/GamesService.cs b/MediaBrowser.Api/GamesService.cs index 040872fcc8..387771b6d5 100644 --- a/MediaBrowser.Api/GamesService.cs +++ b/MediaBrowser.Api/GamesService.cs @@ -162,7 +162,10 @@ namespace MediaBrowser.Api var items = user == null ? system.GetRecursiveChildren(i => i is Game) : - system.GetRecursiveChildren(user, i => i is Game); + system.GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Game).Name } + }); var games = items.Cast().ToList(); diff --git a/MediaBrowser.Api/StartupWizardService.cs b/MediaBrowser.Api/StartupWizardService.cs index 14bd6b61f6..28265c72f9 100644 --- a/MediaBrowser.Api/StartupWizardService.cs +++ b/MediaBrowser.Api/StartupWizardService.cs @@ -65,11 +65,7 @@ namespace MediaBrowser.Api public void Post(ReportStartupWizardComplete request) { _config.Configuration.IsStartupWizardCompleted = true; - _config.Configuration.EnableLocalizedGuids = true; - _config.Configuration.EnableCustomPathSubFolders = true; - _config.Configuration.EnableDateLastRefresh = true; - _config.Configuration.EnableStandaloneMusicKeys = true; - _config.Configuration.EnableCaseSensitiveItemIds = true; + SetWizardFinishValues(_config.Configuration); _config.SaveConfiguration(); } @@ -111,6 +107,15 @@ namespace MediaBrowser.Api return result; } + private void SetWizardFinishValues(ServerConfiguration config) + { + config.EnableLocalizedGuids = true; + config.EnableCustomPathSubFolders = true; + config.EnableDateLastRefresh = true; + config.EnableStandaloneMusicKeys = true; + config.EnableCaseSensitiveItemIds = true; + } + public void Post(UpdateStartupConfiguration request) { _config.Configuration.UICulture = request.UICulture; diff --git a/MediaBrowser.Api/TvShowsService.cs b/MediaBrowser.Api/TvShowsService.cs index e3dfb7f5a0..c4c603f917 100644 --- a/MediaBrowser.Api/TvShowsService.cs +++ b/MediaBrowser.Api/TvShowsService.cs @@ -415,21 +415,10 @@ namespace MediaBrowser.Api private IEnumerable FilterVirtualSeasons(GetSeasons request, IEnumerable items) { - if (request.IsMissing.HasValue && request.IsVirtualUnaired.HasValue) - { - var isMissing = request.IsMissing.Value; - var isVirtualUnaired = request.IsVirtualUnaired.Value; - - if (!isMissing && !isVirtualUnaired) - { - return items.Where(i => !i.IsMissingOrVirtualUnaired); - } - } - if (request.IsMissing.HasValue) { var val = request.IsMissing.Value; - items = items.Where(i => (i.IsMissingSeason ?? false) == val); + items = items.Where(i => (i.IsMissingSeason) == val); } if (request.IsVirtualUnaired.HasValue) diff --git a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs index b3164ce3f7..565bed0531 100644 --- a/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs +++ b/MediaBrowser.Api/UserLibrary/BaseItemsByNameService.cs @@ -121,6 +121,13 @@ namespace MediaBrowser.Api.UserLibrary var includeItemTypes = request.GetIncludeItemTypes(); var mediaTypes = request.GetMediaTypes(); + var query = new InternalItemsQuery(user) + { + ExcludeItemTypes = excludeItemTypes, + IncludeItemTypes = includeItemTypes, + MediaTypes = mediaTypes + }; + Func filter = i => FilterItem(request, i, excludeItemTypes, includeItemTypes, mediaTypes); if (parentItem.IsFolder) @@ -130,7 +137,7 @@ namespace MediaBrowser.Api.UserLibrary if (!string.IsNullOrWhiteSpace(request.UserId)) { items = request.Recursive ? - folder.GetRecursiveChildren(user, filter) : + folder.GetRecursiveChildren(user, query) : folder.GetChildren(user, true).Where(filter); } else diff --git a/MediaBrowser.Api/UserLibrary/ItemsService.cs b/MediaBrowser.Api/UserLibrary/ItemsService.cs index ff937078e6..dac1a6b1a8 100644 --- a/MediaBrowser.Api/UserLibrary/ItemsService.cs +++ b/MediaBrowser.Api/UserLibrary/ItemsService.cs @@ -138,25 +138,19 @@ namespace MediaBrowser.Api.UserLibrary if (request.Recursive) { - var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); - - return result; + return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); } if (user == null) { - var result = await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); - - return result; + return await ((Folder)item).GetItems(GetItemsQuery(request, null)).ConfigureAwait(false); } var userRoot = item as UserRootFolder; if (userRoot == null) { - var result = await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); - - return result; + return await ((Folder)item).GetItems(GetItemsQuery(request, user)).ConfigureAwait(false); } IEnumerable items = ((Folder)item).GetChildren(user, true); diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index 8da1beb687..70489d7142 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -55,7 +55,7 @@ ..\packages\morelinq.1.4.0\lib\net35\MoreLinq.dll - ..\packages\NLog.4.3.1\lib\net45\NLog.dll + ..\packages\NLog.4.3.4\lib\net45\NLog.dll True @@ -65,8 +65,8 @@ False ..\ThirdParty\SharpCompress\SharpCompress.dll - - ..\packages\SimpleInjector.3.1.3\lib\net45\SimpleInjector.dll + + ..\packages\SimpleInjector.3.1.4\lib\net45\SimpleInjector.dll True diff --git a/MediaBrowser.Common.Implementations/packages.config b/MediaBrowser.Common.Implementations/packages.config index 6d7d861823..d1d135b20c 100644 --- a/MediaBrowser.Common.Implementations/packages.config +++ b/MediaBrowser.Common.Implementations/packages.config @@ -2,7 +2,7 @@ - + - + \ No newline at end of file diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 018ff6da07..588a65e98d 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -64,10 +64,37 @@ namespace MediaBrowser.Controller.Entities protected override IEnumerable GetFileSystemChildren(IDirectoryService directoryService) { - return CreateResolveArgs(directoryService).FileSystemChildren; + return CreateResolveArgs(directoryService, true).FileSystemChildren; } - private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService) + private bool _requiresRefresh; + public override bool RequiresRefresh() + { + var changed = base.RequiresRefresh() || _requiresRefresh; + + if (!changed) + { + var locations = PhysicalLocations.ToList(); + + var newLocations = CreateResolveArgs(new DirectoryService(BaseItem.FileSystem), false).PhysicalLocations.ToList(); + + if (!locations.SequenceEqual(newLocations)) + { + changed = true; + } + } + + return changed; + } + + public override bool BeforeMetadataRefresh() + { + var changed = base.BeforeMetadataRefresh() || _requiresRefresh; + _requiresRefresh = false; + return changed; + } + + private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations) { var path = ContainingFolderPath; @@ -100,7 +127,11 @@ namespace MediaBrowser.Controller.Entities args.FileSystemDictionary = fileSystemDictionary; } - PhysicalLocationsList = args.PhysicalLocations.ToList(); + _requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations); + if (setPhysicalLocations) + { + PhysicalLocationsList = args.PhysicalLocations.ToList(); + } return args; } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index fb8a24061a..02dad93cbe 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -56,38 +56,23 @@ namespace MediaBrowser.Controller.Entities.Audio public IEnumerable GetTaggedItems(InternalItemsQuery query) { - var itemByNameFilter = GetItemFilter(); - - if (query.User != null) + if (query.IncludeItemTypes.Length == 0) { - return query.User.RootFolder - .GetRecursiveChildren(query.User, i => - { - if (query.IsFolder.HasValue) - { - if (query.IsFolder.Value != i.IsFolder) - { - return false; - } - } - return itemByNameFilter(i); - }); + query.IncludeItemTypes = new[] { typeof(Audio).Name, typeof(MusicVideo).Name, typeof(MusicAlbum).Name }; + query.ArtistNames = new[] { Name }; } - return LibraryManager.RootFolder - .GetRecursiveChildren(i => - { - if (query.IsFolder.HasValue) - { - if (query.IsFolder.Value != i.IsFolder) - { - return false; - } - } - return itemByNameFilter(i); - }); + // Need this for now since the artist filter isn't yet supported by the db + if (ConfigurationManager.Configuration.SchemaVersion < 79) + { + var filter = GetItemFilter(); + return LibraryManager.GetItemList(query).Where(filter); + } + + return LibraryManager.GetItemList(query); } + [IgnoreDataMember] protected override IEnumerable ActualChildren { get diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs index 5e0cf6e88b..35dfd52e9d 100644 --- a/MediaBrowser.Controller/Entities/CollectionFolder.cs +++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs @@ -23,19 +23,6 @@ namespace MediaBrowser.Controller.Entities PhysicalLocationsList = new List(); } - /// - /// Gets a value indicating whether this instance is virtual folder. - /// - /// true if this instance is virtual folder; otherwise, false. - [IgnoreDataMember] - public override bool IsVirtualFolder - { - get - { - return true; - } - } - [IgnoreDataMember] protected override bool SupportsShortcutChildren { @@ -83,7 +70,34 @@ namespace MediaBrowser.Controller.Entities protected override IEnumerable GetFileSystemChildren(IDirectoryService directoryService) { - return CreateResolveArgs(directoryService).FileSystemChildren; + return CreateResolveArgs(directoryService, true).FileSystemChildren; + } + + private bool _requiresRefresh; + public override bool RequiresRefresh() + { + var changed = base.RequiresRefresh() || _requiresRefresh; + + if (!changed) + { + var locations = PhysicalLocations.ToList(); + + var newLocations = CreateResolveArgs(new DirectoryService(BaseItem.FileSystem), false).PhysicalLocations.ToList(); + + if (!locations.SequenceEqual(newLocations)) + { + changed = true; + } + } + + return changed; + } + + public override bool BeforeMetadataRefresh() + { + var changed = base.BeforeMetadataRefresh() || _requiresRefresh; + _requiresRefresh = false; + return changed; } internal override bool IsValidFromResolver(BaseItem newItem) @@ -101,7 +115,7 @@ namespace MediaBrowser.Controller.Entities return base.IsValidFromResolver(newItem); } - private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService) + private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations) { var path = ContainingFolderPath; @@ -135,7 +149,11 @@ namespace MediaBrowser.Controller.Entities args.FileSystemDictionary = fileSystemDictionary; } - PhysicalLocationsList = args.PhysicalLocations.ToList(); + _requiresRefresh = _requiresRefresh || !args.PhysicalLocations.SequenceEqual(PhysicalLocations); + if (setPhysicalLocations) + { + PhysicalLocationsList = args.PhysicalLocations.ToList(); + } return args; } @@ -153,15 +171,6 @@ namespace MediaBrowser.Controller.Entities /// Task. protected override Task ValidateChildrenInternal(IProgress progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { - var list = PhysicalLocationsList.ToList(); - - CreateResolveArgs(directoryService); - - if (!list.SequenceEqual(PhysicalLocationsList)) - { - return UpdateToRepository(ItemUpdateType.MetadataImport, cancellationToken); - } - return Task.FromResult(true); } @@ -188,6 +197,7 @@ namespace MediaBrowser.Controller.Entities /// Our children are actually just references to the ones in the physical root... /// /// The actual children. + [IgnoreDataMember] protected override IEnumerable ActualChildren { get { return GetActualChildren(); } diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 77e3624191..e7b1df55ad 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -126,19 +126,6 @@ namespace MediaBrowser.Controller.Entities /// true if this instance is root; otherwise, false. public bool IsRoot { get; set; } - /// - /// Gets a value indicating whether this instance is virtual folder. - /// - /// true if this instance is virtual folder; otherwise, false. - [IgnoreDataMember] - public virtual bool IsVirtualFolder - { - get - { - return false; - } - } - public virtual List LinkedChildren { get; set; } [IgnoreDataMember] @@ -285,6 +272,7 @@ namespace MediaBrowser.Controller.Entities /// Gets the actual children. /// /// The actual children. + [IgnoreDataMember] protected virtual IEnumerable ActualChildren { get @@ -749,7 +737,7 @@ namespace MediaBrowser.Controller.Entities { var user = query.User; - if (RequiresPostFiltering(query)) + if (!query.ForceDirect && RequiresPostFiltering(query)) { IEnumerable items; Func filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); @@ -760,7 +748,7 @@ namespace MediaBrowser.Controller.Entities } else { - items = GetRecursiveChildren(user, filter); + items = GetRecursiveChildren(user, query); } return PostFilterAndSort(items, query); @@ -784,7 +772,7 @@ namespace MediaBrowser.Controller.Entities return true; } } - + var supportsUserDataQueries = ConfigurationManager.Configuration.SchemaVersion >= 76; if (query.SortBy != null && query.SortBy.Length > 0) @@ -817,21 +805,26 @@ namespace MediaBrowser.Controller.Entities return true; } } + + if (ConfigurationManager.Configuration.SchemaVersion < 79) + { + if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist"); + return true; + } + if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase)) + { + Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist"); + return true; + } + } + if (query.SortBy.Contains(ItemSortBy.AiredEpisodeOrder, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.AiredEpisodeOrder"); return true; } - if (query.SortBy.Contains(ItemSortBy.AlbumArtist, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.AlbumArtist"); - return true; - } - if (query.SortBy.Contains(ItemSortBy.Artist, StringComparer.OrdinalIgnoreCase)) - { - Logger.Debug("Query requires post-filtering due to ItemSortBy.Artist"); - return true; - } if (query.SortBy.Contains(ItemSortBy.Budget, StringComparer.OrdinalIgnoreCase)) { Logger.Debug("Query requires post-filtering due to ItemSortBy.Budget"); @@ -1109,10 +1102,13 @@ namespace MediaBrowser.Controller.Entities return true; } - if (query.ArtistNames.Length > 0) + if (ConfigurationManager.Configuration.SchemaVersion < 79) { - Logger.Debug("Query requires post-filtering due to ArtistNames"); - return true; + if (query.ArtistNames.Length > 0) + { + Logger.Debug("Query requires post-filtering due to ArtistNames"); + return true; + } } return false; @@ -1178,7 +1174,7 @@ namespace MediaBrowser.Controller.Entities else { items = query.Recursive - ? GetRecursiveChildren(user, filter) + ? GetRecursiveChildren(user, query) : GetChildren(user, true).Where(filter); } @@ -1215,19 +1211,14 @@ namespace MediaBrowser.Controller.Entities /// /// Adds the children to list. /// - /// The user. - /// if set to true [include linked children]. - /// The result. - /// if set to true [recursive]. - /// The filter. /// true if XXXX, false otherwise - private void AddChildren(User user, bool includeLinkedChildren, Dictionary result, bool recursive, Func filter) + private void AddChildren(User user, bool includeLinkedChildren, Dictionary result, bool recursive, InternalItemsQuery query) { foreach (var child in GetEligibleChildrenForRecursiveChildren(user)) { if (child.IsVisible(user)) { - if (filter == null || filter(child)) + if (query == null || UserViewBuilder.FilterItem(child, query)) { result[child.Id] = child; } @@ -1236,7 +1227,7 @@ namespace MediaBrowser.Controller.Entities { var folder = (Folder)child; - folder.AddChildren(user, includeLinkedChildren, result, true, filter); + folder.AddChildren(user, includeLinkedChildren, result, true, query); } } } @@ -1247,7 +1238,7 @@ namespace MediaBrowser.Controller.Entities { if (child.IsVisible(user)) { - if (filter == null || filter(child)) + if (query == null || UserViewBuilder.FilterItem(child, query)) { result[child.Id] = child; } @@ -1265,10 +1256,10 @@ namespace MediaBrowser.Controller.Entities /// public IEnumerable GetRecursiveChildren(User user, bool includeLinkedChildren = true) { - return GetRecursiveChildren(user, i => true); + return GetRecursiveChildren(user, null); } - public virtual IEnumerable GetRecursiveChildren(User user, Func filter) + public virtual IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { if (user == null) { @@ -1277,7 +1268,7 @@ namespace MediaBrowser.Controller.Entities var result = new Dictionary(); - AddChildren(user, true, result, true, filter); + AddChildren(user, true, result, true, query); return result.Values; } @@ -1303,7 +1294,7 @@ namespace MediaBrowser.Controller.Entities /// /// Adds the children to list. /// - private void AddChildrenToList(Dictionary result, bool includeLinkedChildren, bool recursive, Func filter) + private void AddChildrenToList(Dictionary result, bool includeLinkedChildren, bool recursive, Func filter) { foreach (var child in Children) { @@ -1534,13 +1525,12 @@ namespace MediaBrowser.Controller.Entities User = user, Recursive = true, IsFolder = false, - IsUnaired = false - + EnableTotalRecordCount = false }; - if (!user.Configuration.DisplayMissingEpisodes) + if (!user.Configuration.DisplayMissingEpisodes || !user.Configuration.DisplayUnairedEpisodes) { - query.IsMissing = false; + query.ExcludeLocationTypes = new[] { LocationType.Virtual }; } var itemsResult = await GetItems(query).ConfigureAwait(false); @@ -1562,7 +1552,8 @@ namespace MediaBrowser.Controller.Entities { User = user, Recursive = true, - IsFolder = false + IsFolder = false, + EnableTotalRecordCount = false }).ConfigureAwait(false); @@ -1578,7 +1569,8 @@ namespace MediaBrowser.Controller.Entities { Recursive = true, IsFolder = false, - ExcludeLocationTypes = new[] { LocationType.Virtual } + ExcludeLocationTypes = new[] { LocationType.Virtual }, + EnableTotalRecordCount = false }).Result; @@ -1630,7 +1622,8 @@ namespace MediaBrowser.Controller.Entities { Recursive = true, IsFolder = false, - ExcludeLocationTypes = new[] { LocationType.Virtual } + ExcludeLocationTypes = new[] { LocationType.Virtual }, + EnableTotalRecordCount = false }).Result; diff --git a/MediaBrowser.Controller/Entities/IItemByName.cs b/MediaBrowser.Controller/Entities/IItemByName.cs index 7747e738cb..2ac4af1af7 100644 --- a/MediaBrowser.Controller/Entities/IItemByName.cs +++ b/MediaBrowser.Controller/Entities/IItemByName.cs @@ -15,12 +15,6 @@ namespace MediaBrowser.Controller.Entities /// IEnumerable{BaseItem}. IEnumerable GetTaggedItems(IEnumerable inputItems); - /// - /// Gets the item filter. - /// - /// Func<BaseItem, System.Boolean>. - Func GetItemFilter(); - IEnumerable GetTaggedItems(InternalItemsQuery query); } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index ae38f6143d..823f4066c4 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -19,8 +19,6 @@ namespace MediaBrowser.Controller.Entities public User User { get; set; } - public Func Filter { get; set; } - public bool? IsFolder { get; set; } public bool? IsFavorite { get; set; } public bool? IsFavoriteOrLiked { get; set; } @@ -138,6 +136,7 @@ namespace MediaBrowser.Controller.Entities public bool GroupByPresentationUniqueKey { get; set; } public bool EnableTotalRecordCount { get; set; } + public bool ForceDirect { get; set; } public InternalItemsQuery() { diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index ab125eecb6..68170884c5 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -134,7 +134,7 @@ namespace MediaBrowser.Controller.Entities.TV if (!result) { - if (!IsMissingSeason.HasValue) + if (!IsVirtualItem.HasValue) { return true; } @@ -144,18 +144,23 @@ namespace MediaBrowser.Controller.Entities.TV } [IgnoreDataMember] - public bool? IsMissingSeason { get; set; } + public bool? IsVirtualItem { get; set; } + + [IgnoreDataMember] + public bool IsMissingSeason + { + get { return (IsVirtualItem ?? DetectIsVirtualItem()) && !IsUnaired; } + } [IgnoreDataMember] public bool IsVirtualUnaired { - get { return LocationType == LocationType.Virtual && IsUnaired; } + get { return (IsVirtualItem ?? DetectIsVirtualItem()) && IsUnaired; } } - [IgnoreDataMember] - public bool IsMissingOrVirtualUnaired + private bool DetectIsVirtualItem() { - get { return (IsMissingSeason ?? false) || (LocationType == LocationType.Virtual && IsUnaired); } + return LocationType == LocationType.Virtual && GetEpisodes().All(i => i.LocationType == LocationType.Virtual); } [IgnoreDataMember] @@ -319,19 +324,14 @@ namespace MediaBrowser.Controller.Entities.TV { var hasChanges = base.BeforeMetadataRefresh(); - var locationType = LocationType; - - if (locationType == LocationType.FileSystem || locationType == LocationType.Offline) + if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) { - if (!IndexNumber.HasValue && !string.IsNullOrEmpty(Path)) - { - IndexNumber = IndexNumber ?? LibraryManager.GetSeasonNumberFromPath(Path); + IndexNumber = IndexNumber ?? LibraryManager.GetSeasonNumberFromPath(Path); - // If a change was made record it - if (IndexNumber.HasValue) - { - hasChanges = true; - } + // If a change was made record it + if (IndexNumber.HasValue) + { + hasChanges = true; } } diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index 82ab99980d..17fc0c0d29 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -238,20 +238,13 @@ namespace MediaBrowser.Controller.Entities.TV seasons = LibraryManager.Sort(base.GetChildren(user, true), user, new[] { ItemSortBy.SortName }, SortOrder.Ascending).OfType(); } - if (!includeMissingSeasons && !includeVirtualUnaired) + if (!includeMissingSeasons) { - seasons = seasons.Where(i => !i.IsMissingOrVirtualUnaired); + seasons = seasons.Where(i => !(i.IsMissingSeason)); } - else + if (!includeVirtualUnaired) { - if (!includeMissingSeasons) - { - seasons = seasons.Where(i => !(i.IsMissingSeason ?? false)); - } - if (!includeVirtualUnaired) - { - seasons = seasons.Where(i => !i.IsVirtualUnaired); - } + seasons = seasons.Where(i => !i.IsVirtualUnaired); } return seasons; @@ -381,14 +374,18 @@ namespace MediaBrowser.Controller.Entities.TV } else { - episodes = GetRecursiveChildren(user, i => i is Episode) - .Cast(); + episodes = GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Episode).Name } + }).Cast(); } } else { - episodes = GetRecursiveChildren(user, i => i is Episode) - .Cast(); + episodes = GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Episode).Name } + }).Cast(); } episodes = FilterEpisodesBySeason(episodes, seasonNumber, DisplaySpecialsWithSeasons); diff --git a/MediaBrowser.Controller/Entities/User.cs b/MediaBrowser.Controller/Entities/User.cs index e5b39003d0..5c68308f5c 100644 --- a/MediaBrowser.Controller/Entities/User.cs +++ b/MediaBrowser.Controller/Entities/User.cs @@ -305,14 +305,7 @@ namespace MediaBrowser.Controller.Entities public bool IsFolderGrouped(Guid id) { - var config = Configuration; - - if (config.ExcludeFoldersFromGrouping != null) - { - return !config.ExcludeFoldersFromGrouping.Select(i => new Guid(i)).Contains(id); - } - - return config.GroupedFolders.Select(i => new Guid(i)).Contains(id); + return Configuration.GroupedFolders.Select(i => new Guid(i)).Contains(id); } [IgnoreDataMember] diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index b9e997d175..37c4c91b17 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -64,15 +64,6 @@ namespace MediaBrowser.Controller.Entities return list; } - /// - /// Get the children of this folder from the actual file system - /// - /// IEnumerable{BaseItem}. - protected override IEnumerable GetNonCachedChildren(IDirectoryService directoryService) - { - return base.GetNonCachedChildren(directoryService); - } - public override bool BeforeMetadataRefresh() { var hasChanges = base.BeforeMetadataRefresh(); diff --git a/MediaBrowser.Controller/Entities/UserView.cs b/MediaBrowser.Controller/Entities/UserView.cs index 40fec3e288..e40d9ca381 100644 --- a/MediaBrowser.Controller/Entities/UserView.cs +++ b/MediaBrowser.Controller/Entities/UserView.cs @@ -66,7 +66,8 @@ namespace MediaBrowser.Controller.Entities { var result = GetItems(new InternalItemsQuery { - User = user + User = user, + EnableTotalRecordCount = false }).Result; @@ -83,17 +84,19 @@ namespace MediaBrowser.Controller.Entities return true; } - public override IEnumerable GetRecursiveChildren(User user, Func filter) + public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { var result = GetItems(new InternalItemsQuery { User = user, Recursive = true, - Filter = filter + EnableTotalRecordCount = false, + + ForceDirect = true }).Result; - return result.Items; + return result.Items.Where(i => UserViewBuilder.FilterItem(i, query)); } protected override IEnumerable GetEligibleChildrenForRecursiveChildren(User user) diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index b88e8493d2..d4a8b07305 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -128,7 +128,11 @@ namespace MediaBrowser.Controller.Entities { if (query.Recursive) { - return GetResult(queryParent.GetRecursiveChildren(user, true), queryParent, query); + query.Recursive = true; + query.ParentId = queryParent.Id; + query.SetUser(user); + + return _libraryManager.GetItemsResult(query); } return GetResult(queryParent.GetChildren(user, true), queryParent, query); } @@ -251,7 +255,6 @@ namespace MediaBrowser.Controller.Entities if (query.Recursive) { query.Recursive = true; - query.ParentId = parent.Id; query.SetUser(user); if (query.IncludeItemTypes.Length == 0) @@ -259,7 +262,7 @@ namespace MediaBrowser.Controller.Entities query.IncludeItemTypes = new[] { typeof(MusicArtist).Name, typeof(MusicAlbum).Name, typeof(Audio.Audio).Name, typeof(MusicVideo).Name }; } - return _libraryManager.GetItemsResult(query); + return parent.QueryRecursive(query); } var list = new List(); @@ -329,9 +332,13 @@ namespace MediaBrowser.Controller.Entities private QueryResult GetMusicAlbumArtists(Folder parent, User user, InternalItemsQuery query) { - var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) - .Where(i => !i.IsFolder) - .OfType(); + var items = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + Recursive = true, + ParentId = parent.Id, + IncludeItemTypes = new[] { typeof(Audio.Audio).Name } + + }).Cast(); var artists = _libraryManager.GetAlbumArtists(items); @@ -340,9 +347,13 @@ namespace MediaBrowser.Controller.Entities private QueryResult GetMusicArtists(Folder parent, User user, InternalItemsQuery query) { - var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) - .Where(i => !i.IsFolder) - .OfType(); + var items = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + Recursive = true, + ParentId = parent.Id, + IncludeItemTypes = new[] { typeof(Audio.Audio).Name, typeof(MusicVideo).Name } + + }).Cast(); var artists = _libraryManager.GetArtists(items); @@ -351,9 +362,13 @@ namespace MediaBrowser.Controller.Entities private QueryResult GetFavoriteArtists(Folder parent, User user, InternalItemsQuery query) { - var items = GetRecursiveChildren(parent, user, new[] { CollectionType.Music, CollectionType.MusicVideos }) - .Where(i => !i.IsFolder) - .OfType(); + var items = _libraryManager.GetItemList(new InternalItemsQuery(user) + { + Recursive = true, + ParentId = parent.Id, + IncludeItemTypes = new[] { typeof(Audio.Audio).Name } + + }).Cast(); var artists = _libraryManager.GetAlbumArtists(items).Where(i => _userDataManager.GetUserData(user, i).IsFavorite); @@ -448,7 +463,6 @@ namespace MediaBrowser.Controller.Entities if (query.Recursive) { query.Recursive = true; - query.ParentId = parent.Id; query.SetUser(user); if (query.IncludeItemTypes.Length == 0) @@ -456,7 +470,7 @@ namespace MediaBrowser.Controller.Entities query.IncludeItemTypes = new[] { typeof(Movie).Name, typeof(BoxSet).Name }; } - return _libraryManager.GetItemsResult(query); + return parent.QueryRecursive(query); } var list = new List(); @@ -613,7 +627,6 @@ namespace MediaBrowser.Controller.Entities if (query.Recursive) { query.Recursive = true; - query.ParentId = parent.Id; query.SetUser(user); if (query.IncludeItemTypes.Length == 0) @@ -621,7 +634,7 @@ namespace MediaBrowser.Controller.Entities query.IncludeItemTypes = new[] { typeof(Series).Name, typeof(Season).Name, typeof(Episode).Name }; } - return _libraryManager.GetItemsResult(query); + return parent.QueryRecursive(query); } var list = new List(); @@ -756,9 +769,9 @@ namespace MediaBrowser.Controller.Entities return PostFilterAndSort(items, queryParent, null, query, _libraryManager); } - public bool FilterItem(BaseItem item, InternalItemsQuery query) + public static bool FilterItem(BaseItem item, InternalItemsQuery query) { - return Filter(item, query.User, query, _userDataManager, _libraryManager); + return Filter(item, query.User, query, BaseItem.UserDataManager, BaseItem.LibraryManager); } private QueryResult PostFilterAndSort(IEnumerable items, @@ -1121,22 +1134,6 @@ namespace MediaBrowser.Controller.Entities bool? isVirtualUnaired, bool? isUnaired) { - if (isMissing.HasValue && isVirtualUnaired.HasValue) - { - if (!isMissing.Value && !isVirtualUnaired.Value) - { - return items.Where(i => - { - var e = i as Season; - if (e != null) - { - return !e.IsMissingOrVirtualUnaired; - } - return true; - }); - } - } - if (isMissing.HasValue) { var val = isMissing.Value; @@ -1145,7 +1142,7 @@ namespace MediaBrowser.Controller.Entities var e = i as Season; if (e != null) { - return (e.IsMissingSeason ?? false) == val; + return (e.IsMissingSeason) == val; } return true; }); @@ -1277,11 +1274,6 @@ namespace MediaBrowser.Controller.Entities return false; } - if (query.Filter != null && !query.Filter(item)) - { - return false; - } - UserItemData userData = null; if (query.IsLiked.HasValue) diff --git a/MediaBrowser.Controller/Playlists/Playlist.cs b/MediaBrowser.Controller/Playlists/Playlist.cs index 67b1d479b9..5ffe3d5daf 100644 --- a/MediaBrowser.Controller/Playlists/Playlist.cs +++ b/MediaBrowser.Controller/Playlists/Playlist.cs @@ -63,13 +63,13 @@ namespace MediaBrowser.Controller.Playlists return GetPlayableItems(user).Result; } - public override IEnumerable GetRecursiveChildren(User user, Func filter) + public override IEnumerable GetRecursiveChildren(User user, InternalItemsQuery query) { var items = GetPlayableItems(user).Result; - if (filter != null) + if (query != null) { - items = items.Where(filter); + items = items.Where(i => UserViewBuilder.FilterItem(i, query)); } return items; @@ -129,7 +129,11 @@ namespace MediaBrowser.Controller.Playlists var items = user == null ? LibraryManager.RootFolder.GetRecursiveChildren(filter) - : user.RootFolder.GetRecursiveChildren(user, filter); + : user.RootFolder.GetRecursiveChildren(user, new InternalItemsQuery(user) + { + IncludeItemTypes = new[] { typeof(Audio).Name }, + ArtistNames = new[] { musicArtist.Name } + }); return LibraryManager.Sort(items, user, new[] { ItemSortBy.AlbumArtist, ItemSortBy.Album, ItemSortBy.SortName }, SortOrder.Ascending); } diff --git a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs index bc9fa1d7e7..233ec9546f 100644 --- a/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs +++ b/MediaBrowser.Dlna/ContentDirectory/ControlHandler.cs @@ -401,10 +401,10 @@ namespace MediaBrowser.Dlna.ContentDirectory SortOrder = sort.SortOrder, User = user, Recursive = true, - Filter = FilterUnsupportedContent, + IsMissing = false, + ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name }, IsFolder = isFolder, MediaTypes = mediaTypes.ToArray() - }); } @@ -461,8 +461,10 @@ namespace MediaBrowser.Dlna.ContentDirectory SortBy = sortOrders.ToArray(), SortOrder = sort.SortOrder, User = user, - Filter = FilterUnsupportedContent, - PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music } + IsMissing = false, + PresetViews = new[] { CollectionType.Movies, CollectionType.TvShows, CollectionType.Music }, + ExcludeItemTypes = new[] { typeof(Game).Name, typeof(Book).Name }, + IsPlaceHolder = false }).ConfigureAwait(false); @@ -579,29 +581,6 @@ namespace MediaBrowser.Dlna.ContentDirectory }); } - private bool FilterUnsupportedContent(BaseItem i) - { - // Unplayable - if (i.LocationType == LocationType.Virtual && !i.IsFolder) - { - return false; - } - - // Unplayable - var supportsPlaceHolder = i as ISupportsPlaceHolders; - if (supportsPlaceHolder != null && supportsPlaceHolder.IsPlaceHolder) - { - return false; - } - - if (i is Game || i is Book) - { - //return false; - } - - return true; - } - private ServerItem GetItemFromObjectId(string id, User user) { return DidlBuilder.IsIdRoot(id) diff --git a/MediaBrowser.Model/Configuration/ServerConfiguration.cs b/MediaBrowser.Model/Configuration/ServerConfiguration.cs index b115440d60..1cb19afdf2 100644 --- a/MediaBrowser.Model/Configuration/ServerConfiguration.cs +++ b/MediaBrowser.Model/Configuration/ServerConfiguration.cs @@ -215,6 +215,9 @@ namespace MediaBrowser.Model.Configuration { Migrations = new string[] { }; + EnableLocalizedGuids = true; + EnableCustomPathSubFolders = true; + ImageSavingConvention = ImageSavingConvention.Compatible; PublicPort = 8096; PublicHttpsPort = 8920; diff --git a/MediaBrowser.Model/Entities/MediaStream.cs b/MediaBrowser.Model/Entities/MediaStream.cs index 9b814c5ccc..64c7d9aa6c 100644 --- a/MediaBrowser.Model/Entities/MediaStream.cs +++ b/MediaBrowser.Model/Entities/MediaStream.cs @@ -1,8 +1,8 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using MediaBrowser.Model.Dlna; using MediaBrowser.Model.Extensions; using System.Diagnostics; +using MediaBrowser.Model.MediaInfo; namespace MediaBrowser.Model.Entities { @@ -53,18 +53,22 @@ namespace MediaBrowser.Model.Entities if (!string.IsNullOrEmpty(Language)) { - attributes.Add(Language); + attributes.Add(StringHelper.FirstToUpper(Language)); } if (!string.IsNullOrEmpty(Codec) && !StringHelper.EqualsIgnoreCase(Codec, "dca")) { - attributes.Add(Codec); - } - if (!string.IsNullOrEmpty(Profile) && !StringHelper.EqualsIgnoreCase(Profile, "lc")) + attributes.Add(AudioCodec.GetFriendlyName(Codec)); + } + else if (!string.IsNullOrEmpty(Profile) && !StringHelper.EqualsIgnoreCase(Profile, "lc")) { attributes.Add(Profile); } - if (Channels.HasValue) + if (!string.IsNullOrEmpty(ChannelLayout)) + { + attributes.Add(ChannelLayout); + } + else if (Channels.HasValue) { attributes.Add(StringHelper.ToStringCultureInvariant(Channels.Value) + " ch"); } diff --git a/MediaBrowser.Model/Extensions/StringHelper.cs b/MediaBrowser.Model/Extensions/StringHelper.cs index 99bec68a73..9cde3bfa45 100644 --- a/MediaBrowser.Model/Extensions/StringHelper.cs +++ b/MediaBrowser.Model/Extensions/StringHelper.cs @@ -125,5 +125,10 @@ namespace MediaBrowser.Model.Extensions return sb.ToString(); } + + public static string FirstToUpper(this string str) + { + return string.IsNullOrEmpty(str) ? "" : str.Substring(0, 1).ToUpper() + str.Substring(1); + } } } diff --git a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs index 4211fbd59f..e00443d191 100644 --- a/MediaBrowser.Model/LiveTv/LiveTvOptions.cs +++ b/MediaBrowser.Model/LiveTv/LiveTvOptions.cs @@ -20,12 +20,15 @@ namespace MediaBrowser.Model.LiveTv public int PrePaddingSeconds { get; set; } public int PostPaddingSeconds { get; set; } + public string[] MediaLocationsCreated { get; set; } + public LiveTvOptions() { EnableMovieProviders = true; EnableRecordingSubfolders = true; TunerHosts = new List(); ListingProviders = new List(); + MediaLocationsCreated = new string[] { }; } } diff --git a/MediaBrowser.Model/MediaInfo/AudioCodec.cs b/MediaBrowser.Model/MediaInfo/AudioCodec.cs index 5353f2b3ec..93aba2f434 100644 --- a/MediaBrowser.Model/MediaInfo/AudioCodec.cs +++ b/MediaBrowser.Model/MediaInfo/AudioCodec.cs @@ -5,5 +5,22 @@ public const string AAC = "aac"; public const string MP3 = "mp3"; public const string AC3 = "ac3"; + + public static string GetFriendlyName(string codec) + { + if (string.IsNullOrEmpty(codec)) return ""; + + switch (codec.ToLower()) + { + case "ac3": + return "Dolby Digital"; + case "eac3": + return "Dolby Digital+"; + case "dca": + return "DTS"; + default: + return codec.ToUpper(); + } + } } } \ No newline at end of file diff --git a/MediaBrowser.Model/Querying/ItemQuery.cs b/MediaBrowser.Model/Querying/ItemQuery.cs index 5a88c0d43e..11c0464522 100644 --- a/MediaBrowser.Model/Querying/ItemQuery.cs +++ b/MediaBrowser.Model/Querying/ItemQuery.cs @@ -288,6 +288,8 @@ namespace MediaBrowser.Model.Querying [Obsolete] public string Person { get; set; } + public bool EnableTotalRecordCount { get; set; } + /// /// Initializes a new instance of the class. /// @@ -306,6 +308,8 @@ namespace MediaBrowser.Model.Querying VideoTypes = new VideoType[] { }; + EnableTotalRecordCount = true; + Artists = new string[] { }; Studios = new string[] { }; diff --git a/MediaBrowser.Providers/Manager/MetadataService.cs b/MediaBrowser.Providers/Manager/MetadataService.cs index a0c6bd889a..7184302f19 100644 --- a/MediaBrowser.Providers/Manager/MetadataService.cs +++ b/MediaBrowser.Providers/Manager/MetadataService.cs @@ -145,11 +145,15 @@ namespace MediaBrowser.Providers.Manager bool hasRefreshedMetadata = true; bool hasRefreshedImages = true; + var requiresRefresh = false; // Next run metadata providers if (refreshOptions.MetadataRefreshMode != MetadataRefreshMode.None) { - var providers = GetProviders(item, refreshResult, refreshOptions) + // TODO: If this returns true, should we instead just change metadata refresh mode to Full? + requiresRefresh = item.RequiresRefresh(); + + var providers = GetProviders(item, refreshResult, refreshOptions, requiresRefresh) .ToList(); var dateLastRefresh = EnableDateLastRefreshed(item) @@ -217,11 +221,11 @@ namespace MediaBrowser.Providers.Manager var isFirstRefresh = GetLastRefreshDate(item) == default(DateTime); - var beforeSaveResult = await BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh, updateType).ConfigureAwait(false); + var beforeSaveResult = await BeforeSave(itemOfType, isFirstRefresh || refreshOptions.ReplaceAllMetadata || refreshOptions.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || requiresRefresh, updateType).ConfigureAwait(false); updateType = updateType | beforeSaveResult; // Save if changes were made, or it's never been saved before - if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata) + if (refreshOptions.ForceSave || updateType > ItemUpdateType.None || isFirstRefresh || refreshOptions.ReplaceAllMetadata || requiresRefresh) { // If any of these properties are set then make sure the updateType is not None, just to force everything to save if (refreshOptions.ForceSave || refreshOptions.ReplaceAllMetadata) @@ -461,11 +465,8 @@ namespace MediaBrowser.Providers.Manager /// /// Gets the providers. /// - /// The item. - /// The status. - /// The options. /// IEnumerable{`0}. - protected IEnumerable GetProviders(IHasMetadata item, MetadataStatus status, MetadataRefreshOptions options) + protected IEnumerable GetProviders(IHasMetadata item, MetadataStatus status, MetadataRefreshOptions options, bool requiresRefresh) { // Get providers to refresh var providers = ((ProviderManager)ProviderManager).GetMetadataProviders(item).ToList(); @@ -475,7 +476,7 @@ namespace MediaBrowser.Providers.Manager : status.DateLastMetadataRefresh ?? default(DateTime); // Run all if either of these flags are true - var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || item.RequiresRefresh(); + var runAllProviders = options.ReplaceAllMetadata || options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || dateLastRefresh == default(DateTime) || requiresRefresh; if (!runAllProviders) { @@ -668,12 +669,6 @@ namespace MediaBrowser.Providers.Manager // If a local provider fails, consider that a failure refreshResult.ErrorMessage = ex.Message; - - if (options.MetadataRefreshMode != MetadataRefreshMode.FullRefresh) - { - // If the local provider fails don't continue with remote providers because the user's saved metadata could be lost - //return refreshResult; - } } } diff --git a/MediaBrowser.Providers/TV/DummySeasonProvider.cs b/MediaBrowser.Providers/TV/DummySeasonProvider.cs index 2c6e27294d..909760feef 100644 --- a/MediaBrowser.Providers/TV/DummySeasonProvider.cs +++ b/MediaBrowser.Providers/TV/DummySeasonProvider.cs @@ -69,7 +69,7 @@ namespace MediaBrowser.Providers.TV if (!hasSeason) { - await AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false); + await AddSeason(series, seasonNumber, false, cancellationToken).ConfigureAwait(false); hasChanges = true; } @@ -83,7 +83,7 @@ namespace MediaBrowser.Providers.TV if (!hasSeason) { - await AddSeason(series, null, cancellationToken).ConfigureAwait(false); + await AddSeason(series, null, false, cancellationToken).ConfigureAwait(false); hasChanges = true; } @@ -95,12 +95,9 @@ namespace MediaBrowser.Providers.TV /// /// Adds the season. /// - /// The series. - /// The season number. - /// The cancellation token. - /// Task{Season}. public async Task AddSeason(Series series, int? seasonNumber, + bool isVirtualItem, CancellationToken cancellationToken) { var seasonName = seasonNumber == 0 ? @@ -113,7 +110,8 @@ namespace MediaBrowser.Providers.TV { Name = seasonName, IndexNumber = seasonNumber, - Id = _libraryManager.GetNewItemId((series.Id + (seasonNumber ?? -1).ToString(_usCulture) + seasonName), typeof(Season)) + Id = _libraryManager.GetNewItemId((series.Id + (seasonNumber ?? -1).ToString(_usCulture) + seasonName), typeof(Season)), + IsVirtualItem = isVirtualItem }; season.SetParent(series); diff --git a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs index e79ad2dfbd..2a3150c78b 100644 --- a/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs +++ b/MediaBrowser.Providers/TV/MissingEpisodeProvider.cs @@ -418,7 +418,7 @@ namespace MediaBrowser.Providers.TV if (season == null) { var provider = new DummySeasonProvider(_config, _logger, _localization, _libraryManager, _fileSystem); - season = await provider.AddSeason(series, seasonNumber, cancellationToken).ConfigureAwait(false); + season = await provider.AddSeason(series, seasonNumber, true, cancellationToken).ConfigureAwait(false); } var name = string.Format("Episode {0}", episodeNumber.ToString(_usCulture)); diff --git a/MediaBrowser.Providers/TV/SeasonMetadataService.cs b/MediaBrowser.Providers/TV/SeasonMetadataService.cs index 292923d824..ae19a6a448 100644 --- a/MediaBrowser.Providers/TV/SeasonMetadataService.cs +++ b/MediaBrowser.Providers/TV/SeasonMetadataService.cs @@ -36,7 +36,7 @@ namespace MediaBrowser.Providers.TV { var episodes = item.GetEpisodes().ToList(); updateType |= SavePremiereDate(item, episodes); - updateType |= SaveIsMissing(item, episodes); + updateType |= SaveIsVirtualItem(item, episodes); } return updateType; @@ -67,13 +67,13 @@ namespace MediaBrowser.Providers.TV return ItemUpdateType.None; } - private ItemUpdateType SaveIsMissing(Season item, List episodes) + private ItemUpdateType SaveIsVirtualItem(Season item, List episodes) { - var isMissing = item.LocationType == LocationType.Virtual && episodes.All(i => i.IsMissingEpisode); + var isVirtualItem = item.LocationType == LocationType.Virtual && (episodes.Count == 0 || episodes.All(i => i.LocationType == LocationType.Virtual)); - if (item.IsMissingSeason != isMissing) + if (item.IsVirtualItem != isVirtualItem) { - item.IsMissingSeason = isMissing; + item.IsVirtualItem = isVirtualItem; return ItemUpdateType.MetadataEdit; } diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs index 1407cdce30..56d3bd4de1 100644 --- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs +++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs @@ -1448,8 +1448,12 @@ namespace MediaBrowser.Server.Implementations.Library // Handle grouping if (user != null && !string.IsNullOrWhiteSpace(view.ViewType) && UserView.IsEligibleForGrouping(view.ViewType)) { - var collectionFolders = user.RootFolder.GetChildren(user, true).OfType().Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase)); - return collectionFolders.SelectMany(i => GetTopParentsForQuery(i, user)); + return user.RootFolder + .GetChildren(user, true) + .OfType() + .Where(i => string.IsNullOrWhiteSpace(i.CollectionType) || string.Equals(i.CollectionType, view.ViewType, StringComparison.OrdinalIgnoreCase)) + .Where(i => user.IsFolderGrouped(i.Id)) + .SelectMany(i => GetTopParentsForQuery(i, user)); } return new BaseItem[] { }; } diff --git a/MediaBrowser.Server.Implementations/Library/MusicManager.cs b/MediaBrowser.Server.Implementations/Library/MusicManager.cs index c82c4cdf7b..ef13ba9960 100644 --- a/MediaBrowser.Server.Implementations/Library/MusicManager.cs +++ b/MediaBrowser.Server.Implementations/Library/MusicManager.cs @@ -30,7 +30,10 @@ namespace MediaBrowser.Server.Implementations.Library public IEnumerable