diff options
Diffstat (limited to 'MediaBrowser.Controller/Entities')
18 files changed, 557 insertions, 190 deletions
diff --git a/MediaBrowser.Controller/Entities/AggregateFolder.cs b/MediaBrowser.Controller/Entities/AggregateFolder.cs index 4aa99ae87..efc450248 100644 --- a/MediaBrowser.Controller/Entities/AggregateFolder.cs +++ b/MediaBrowser.Controller/Entities/AggregateFolder.cs @@ -5,6 +5,8 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; +using System.Threading; +using System.Threading.Tasks; using CommonIO; using MediaBrowser.Controller.Providers; @@ -84,7 +86,7 @@ namespace MediaBrowser.Controller.Entities } } - private void ResetCachedChildren() + private void ClearCache() { lock (_childIdsLock) { @@ -114,7 +116,7 @@ namespace MediaBrowser.Controller.Entities public override bool BeforeMetadataRefresh() { - ResetCachedChildren(); + ClearCache(); var changed = base.BeforeMetadataRefresh() || _requiresRefresh; _requiresRefresh = false; @@ -123,7 +125,7 @@ namespace MediaBrowser.Controller.Entities private ItemResolveArgs CreateResolveArgs(IDirectoryService directoryService, bool setPhysicalLocations) { - ResetCachedChildren(); + ClearCache(); var path = ContainingFolderPath; @@ -165,6 +167,21 @@ namespace MediaBrowser.Controller.Entities return args; } + protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService) + { + return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); + } + + protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) + { + ClearCache(); + + await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService) + .ConfigureAwait(false); + + ClearCache(); + } + /// <summary> /// Adds the virtual child. /// </summary> @@ -181,15 +198,6 @@ namespace MediaBrowser.Controller.Entities } /// <summary> - /// Get the children of this folder from the actual file system - /// </summary> - /// <returns>IEnumerable{BaseItem}.</returns> - protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService) - { - return base.GetNonCachedChildren(directoryService).Concat(_virtualChildren); - } - - /// <summary> /// Finds the virtual child. /// </summary> /// <param name="id">The id.</param> diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index 56f9a5b88..81d1deaa2 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -270,5 +270,54 @@ namespace MediaBrowser.Controller.Entities.Audio return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.ArtistsPath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + if (IsAccessedByName) + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + } + return base.RequiresRefresh(); + } + + /// <summary> + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// </summary> + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + if (IsAccessedByName) + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs index 9aa5625fa..bd991d9f4 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicGenre.cs @@ -92,5 +92,48 @@ namespace MediaBrowser.Controller.Entities.Audio return LibraryManager.GetItemList(query); } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.MusicGenrePath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// <summary> + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// </summary> + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index cc3646cdc..cbbb9a89a 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -2213,6 +2213,15 @@ namespace MediaBrowser.Controller.Entities } } + [IgnoreDataMember] + public virtual bool StopRefreshIfLocalMetadataFound + { + get + { + return true; + } + } + public virtual IEnumerable<Guid> GetIdsForAncestorQuery() { return new[] { Id }; diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs index 23055690c..b5c76c0eb 100644 --- a/MediaBrowser.Controller/Entities/Folder.cs +++ b/MediaBrowser.Controller/Entities/Folder.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using CommonIO; using MediaBrowser.Controller.Channels; +using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Entities.TV; using MediaBrowser.Model.Channels; @@ -701,7 +702,7 @@ namespace MediaBrowser.Controller.Entities items = GetRecursiveChildren(user, query); } - return PostFilterAndSort(items, query); + return PostFilterAndSort(items, query, true, true); } if (!(this is UserRootFolder) && !(this is AggregateFolder)) @@ -902,7 +903,15 @@ namespace MediaBrowser.Controller.Entities if (query.ItemIds.Length > 0) { var specificItems = query.ItemIds.Select(LibraryManager.GetItemById).Where(i => i != null).ToList(); - return Task.FromResult(PostFilterAndSort(specificItems, query)); + + if (query.SortBy.Length == 0) + { + var ids = query.ItemIds.ToList(); + + // Try to preserve order + specificItems = specificItems.OrderBy(i => ids.IndexOf(i.Id.ToString("N"))).ToList(); + } + return Task.FromResult(PostFilterAndSort(specificItems, query, true, true)); } return GetItemsInternal(query); @@ -958,12 +967,12 @@ namespace MediaBrowser.Controller.Entities : GetChildren(user, true).Where(filter); } - return PostFilterAndSort(items, query); + return PostFilterAndSort(items, query, true, true); } - protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query) + protected QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, InternalItemsQuery query, bool collapseBoxSetItems, bool enableSorting) { - return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager); + return UserViewBuilder.PostFilterAndSort(items, this, null, query, LibraryManager, ConfigurationManager, collapseBoxSetItems, enableSorting); } public virtual IEnumerable<BaseItem> GetChildren(User user, bool includeLinkedChildren) @@ -1427,7 +1436,7 @@ namespace MediaBrowser.Controller.Entities itemDto.RecursiveItemCount = allItemsQueryResult.TotalRecordCount; } - double recursiveItemCount = allItemsQueryResult.TotalRecordCount; + var recursiveItemCount = allItemsQueryResult.TotalRecordCount; double unplayedCount = unplayedQueryResult.TotalRecordCount; if (recursiveItemCount > 0) @@ -1437,6 +1446,14 @@ namespace MediaBrowser.Controller.Entities dto.Played = dto.PlayedPercentage.Value >= 100; dto.UnplayedItemCount = unplayedQueryResult.TotalRecordCount; } + + if (itemDto != null) + { + if (this is Season || this is MusicAlbum) + { + itemDto.ChildCount = recursiveItemCount; + } + } } } }
\ No newline at end of file diff --git a/MediaBrowser.Controller/Entities/GameGenre.cs b/MediaBrowser.Controller/Entities/GameGenre.cs index 5d66bf3ab..6448828fb 100644 --- a/MediaBrowser.Controller/Entities/GameGenre.cs +++ b/MediaBrowser.Controller/Entities/GameGenre.cs @@ -84,5 +84,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GameGenrePath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// <summary> + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// </summary> + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/Genre.cs b/MediaBrowser.Controller/Entities/Genre.cs index c7fe25a96..1736ba8c7 100644 --- a/MediaBrowser.Controller/Entities/Genre.cs +++ b/MediaBrowser.Controller/Entities/Genre.cs @@ -87,5 +87,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.GenrePath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// <summary> + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// </summary> + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/IHasMetadata.cs b/MediaBrowser.Controller/Entities/IHasMetadata.cs index d5891c655..26f425ff0 100644 --- a/MediaBrowser.Controller/Entities/IHasMetadata.cs +++ b/MediaBrowser.Controller/Entities/IHasMetadata.cs @@ -58,6 +58,6 @@ namespace MediaBrowser.Controller.Entities string GetPresentationUniqueKey(); string CreatePresentationUniqueKey(); - + bool StopRefreshIfLocalMetadataFound { get; } } } diff --git a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs index 69cab5ec5..deea63112 100644 --- a/MediaBrowser.Controller/Entities/InternalItemsQuery.cs +++ b/MediaBrowser.Controller/Entities/InternalItemsQuery.cs @@ -37,6 +37,7 @@ namespace MediaBrowser.Controller.Entities public string[] Genres { get; set; } public string[] Keywords { get; set; } + public bool? IsSpecialSeason { get; set; } public bool? IsMissing { get; set; } public bool? IsUnaired { get; set; } public bool? IsVirtualUnaired { get; set; } @@ -50,6 +51,7 @@ namespace MediaBrowser.Controller.Entities public string PresentationUniqueKey { get; set; } public string Path { get; set; } + public string PathNotStartsWith { get; set; } public string Name { get; set; } public string SlugName { get; set; } diff --git a/MediaBrowser.Controller/Entities/Movies/Movie.cs b/MediaBrowser.Controller/Entities/Movies/Movie.cs index c7a833c58..f0270497c 100644 --- a/MediaBrowser.Controller/Entities/Movies/Movie.cs +++ b/MediaBrowser.Controller/Entities/Movies/Movie.cs @@ -179,5 +179,15 @@ namespace MediaBrowser.Controller.Entities.Movies return list; } + + [IgnoreDataMember] + public override bool StopRefreshIfLocalMetadataFound + { + get + { + // Need people id's from internet metadata + return false; + } + } } } diff --git a/MediaBrowser.Controller/Entities/Person.cs b/MediaBrowser.Controller/Entities/Person.cs index 4ee140b2b..f21bc0a71 100644 --- a/MediaBrowser.Controller/Entities/Person.cs +++ b/MediaBrowser.Controller/Entities/Person.cs @@ -122,6 +122,64 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validFilename = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + string subFolderPrefix = null; + + foreach (char c in validFilename) + { + if (char.IsLetterOrDigit(c)) + { + subFolderPrefix = c.ToString(); + break; + } + } + + var path = ConfigurationManager.ApplicationPaths.PeoplePath; + + return string.IsNullOrEmpty(subFolderPrefix) ? + System.IO.Path.Combine(path, validFilename) : + System.IO.Path.Combine(path, subFolderPrefix, validFilename); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// <summary> + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// </summary> + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } /// <summary> diff --git a/MediaBrowser.Controller/Entities/Studio.cs b/MediaBrowser.Controller/Entities/Studio.cs index 7e3d6fe8e..04b09b744 100644 --- a/MediaBrowser.Controller/Entities/Studio.cs +++ b/MediaBrowser.Controller/Entities/Studio.cs @@ -85,5 +85,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.StudioPath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// <summary> + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// </summary> + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } diff --git a/MediaBrowser.Controller/Entities/TV/Season.cs b/MediaBrowser.Controller/Entities/TV/Season.cs index c64de399f..842b2fd60 100644 --- a/MediaBrowser.Controller/Entities/TV/Season.cs +++ b/MediaBrowser.Controller/Entities/TV/Season.cs @@ -85,7 +85,11 @@ namespace MediaBrowser.Controller.Entities.TV public override int GetChildCount(User user) { - return GetChildren(user, true).Count(); + Logger.Debug("Season {0} getting child cound", (Path ?? Name)); + var result = GetChildren(user, true).Count(); + Logger.Debug("Season {0} child cound: ", result); + + return result; } /// <summary> @@ -137,24 +141,6 @@ namespace MediaBrowser.Controller.Entities.TV return IndexNumber != null ? IndexNumber.Value.ToString("0000") : Name; } - [IgnoreDataMember] - public bool IsMissingSeason - { - get { return (IsVirtualItem) && !IsUnaired; } - } - - [IgnoreDataMember] - public bool IsVirtualUnaired - { - get { return (IsVirtualItem) && IsUnaired; } - } - - [IgnoreDataMember] - public bool IsSpecialSeason - { - get { return (IndexNumber ?? -1) == 0; } - } - protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query) { if (query.User == null) @@ -166,10 +152,15 @@ namespace MediaBrowser.Controller.Entities.TV Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); + var id = Guid.NewGuid().ToString("N"); + + Logger.Debug("Season.GetItemsInternal entering GetEpisodes. Request id: " + id); var items = GetEpisodes(user).Where(filter); - var result = PostFilterAndSort(items, query); + Logger.Debug("Season.GetItemsInternal entering PostFilterAndSort. Request id: " + id); + var result = PostFilterAndSort(items, query, false, false); + Logger.Debug("Season.GetItemsInternal complete. Request id: " + id); return Task.FromResult(result); } @@ -180,19 +171,17 @@ namespace MediaBrowser.Controller.Entities.TV /// <returns>IEnumerable{Episode}.</returns> public IEnumerable<Episode> GetEpisodes(User user) { - var config = user.Configuration; - - return GetEpisodes(Series, user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); + return GetEpisodes(Series, user); } - public IEnumerable<Episode> GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes) + public IEnumerable<Episode> GetEpisodes(Series series, User user) { - return GetEpisodes(series, user, includeMissingEpisodes, includeVirtualUnairedEpisodes, null); + return GetEpisodes(series, user, null); } - public IEnumerable<Episode> GetEpisodes(Series series, User user, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> allSeriesEpisodes) + public IEnumerable<Episode> GetEpisodes(Series series, User user, IEnumerable<Episode> allSeriesEpisodes) { - return series.GetEpisodes(user, this, includeMissingEpisodes, includeVirtualUnairedEpisodes, allSeriesEpisodes); + return series.GetSeasonEpisodes(user, this, allSeriesEpisodes); } public IEnumerable<Episode> GetEpisodes() diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs index f01eddceb..4915cfedc 100644 --- a/MediaBrowser.Controller/Entities/TV/Series.cs +++ b/MediaBrowser.Controller/Entities/TV/Series.cs @@ -207,7 +207,30 @@ namespace MediaBrowser.Controller.Entities.TV { var config = user.Configuration; - return GetSeasons(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); + var seriesKey = GetUniqueSeriesKey(this); + + Logger.Debug("GetSeasons SeriesKey: {0}", seriesKey); + var query = new InternalItemsQuery(user) + { + AncestorWithPresentationUniqueKey = seriesKey, + IncludeItemTypes = new[] {typeof (Season).Name}, + SortBy = new[] {ItemSortBy.SortName} + }; + + if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes) + { + query.IsVirtualItem = false; + } + else if (!config.DisplayMissingEpisodes) + { + query.IsMissing = false; + } + else if (!config.DisplayUnairedEpisodes) + { + query.IsVirtualUnaired = false; + } + + return LibraryManager.GetItemList(query).Cast<Season>(); } protected override Task<QueryResult<BaseItem>> GetItemsInternal(InternalItemsQuery query) @@ -237,55 +260,43 @@ namespace MediaBrowser.Controller.Entities.TV Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); var items = GetSeasons(user).Where(filter); - var result = PostFilterAndSort(items, query); + var result = PostFilterAndSort(items, query, false, true); return Task.FromResult(result); } - public IEnumerable<Season> GetSeasons(User user, bool includeMissingSeasons, bool includeVirtualUnaired) + public IEnumerable<Episode> GetEpisodes(User user) { - IEnumerable<Season> seasons; + var seriesKey = GetUniqueSeriesKey(this); + Logger.Debug("GetEpisodes seriesKey: {0}", seriesKey); - seasons = LibraryManager.GetItemList(new InternalItemsQuery(user) + var query = new InternalItemsQuery(user) { - AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this), - IncludeItemTypes = new[] { typeof(Season).Name }, - SortBy = new[] { ItemSortBy.SortName } - - }).Cast<Season>(); - - if (!includeMissingSeasons) + AncestorWithPresentationUniqueKey = seriesKey, + IncludeItemTypes = new[] {typeof (Episode).Name, typeof (Season).Name}, + SortBy = new[] {ItemSortBy.SortName} + }; + var config = user.Configuration; + if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes) { - seasons = seasons.Where(i => !(i.IsMissingSeason)); + query.IsVirtualItem = false; } - if (!includeVirtualUnaired) + else if (!config.DisplayMissingEpisodes) { - seasons = seasons.Where(i => !i.IsVirtualUnaired); + query.IsMissing = false; } - - return seasons; - } - - public IEnumerable<Episode> GetEpisodes(User user) - { - var config = user.Configuration; - - return GetEpisodes(user, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); - } - - public IEnumerable<Episode> GetEpisodes(User user, bool includeMissing, bool includeVirtualUnaired) - { - var allItems = LibraryManager.GetItemList(new InternalItemsQuery(user) + else if (!config.DisplayUnairedEpisodes) { - AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this), - IncludeItemTypes = new[] { typeof(Episode).Name, typeof(Season).Name }, - SortBy = new[] { ItemSortBy.SortName } + query.IsVirtualUnaired = false; + } + + var allItems = LibraryManager.GetItemList(query).ToList(); - }).ToList(); + Logger.Debug("GetEpisodes return {0} items from database", allItems.Count); var allSeriesEpisodes = allItems.OfType<Episode>().ToList(); var allEpisodes = allItems.OfType<Season>() - .SelectMany(i => i.GetEpisodes(this, user, includeMissing, includeVirtualUnaired, allSeriesEpisodes)) + .SelectMany(i => i.GetEpisodes(this, user, allSeriesEpisodes)) .Reverse() .ToList(); @@ -362,78 +373,68 @@ namespace MediaBrowser.Controller.Entities.TV progress.Report(100); } - public IEnumerable<Episode> GetEpisodes(User user, Season season) - { - var config = user.Configuration; - - return GetEpisodes(user, season, config.DisplayMissingEpisodes, config.DisplayUnairedEpisodes); - } - private IEnumerable<Episode> GetAllEpisodes(User user) { - return LibraryManager.GetItemList(new InternalItemsQuery(user) + Logger.Debug("Series.GetAllEpisodes entering GetItemList"); + + var result = LibraryManager.GetItemList(new InternalItemsQuery(user) { AncestorWithPresentationUniqueKey = GetUniqueSeriesKey(this), IncludeItemTypes = new[] { typeof(Episode).Name }, SortBy = new[] { ItemSortBy.SortName } - }).Cast<Episode>(); - } + }).Cast<Episode>().ToList(); - public IEnumerable<Episode> GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes) - { - IEnumerable<Episode> episodes = GetAllEpisodes(user); + Logger.Debug("Series.GetAllEpisodes returning {0} episodes", result.Count); - return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes, episodes); + return result; } - public IEnumerable<Episode> GetEpisodes(User user, Season parentSeason, bool includeMissingEpisodes, bool includeVirtualUnairedEpisodes, IEnumerable<Episode> allSeriesEpisodes) + public IEnumerable<Episode> GetSeasonEpisodes(User user, Season parentSeason) { - if (allSeriesEpisodes == null) + var seriesKey = GetUniqueSeriesKey(this); + Logger.Debug("GetSeasonEpisodes seriesKey: {0}", seriesKey); + + var query = new InternalItemsQuery(user) + { + AncestorWithPresentationUniqueKey = seriesKey, + IncludeItemTypes = new[] { typeof(Episode).Name }, + SortBy = new[] { ItemSortBy.SortName } + }; + var config = user.Configuration; + if (!config.DisplayMissingEpisodes && !config.DisplayUnairedEpisodes) { - return GetEpisodes(user, parentSeason, includeMissingEpisodes, includeVirtualUnairedEpisodes); + query.IsVirtualItem = false; } - - var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons); - - if (!includeMissingEpisodes) + else if (!config.DisplayMissingEpisodes) { - episodes = episodes.Where(i => !i.IsMissingEpisode); + query.IsMissing = false; } - if (!includeVirtualUnairedEpisodes) + else if (!config.DisplayUnairedEpisodes) { - episodes = episodes.Where(i => !i.IsVirtualUnaired); + query.IsVirtualUnaired = false; } - var sortBy = (parentSeason.IndexNumber ?? -1) == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder; + var allItems = LibraryManager.GetItemList(query).OfType<Episode>(); - return LibraryManager.Sort(episodes, user, new[] { sortBy }, SortOrder.Ascending) - .Cast<Episode>(); + return GetSeasonEpisodes(user, parentSeason, allItems); } - /// <summary> - /// Filters the episodes by season. - /// </summary> - public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, int seasonNumber, bool includeSpecials) + public IEnumerable<Episode> GetSeasonEpisodes(User user, Season parentSeason, IEnumerable<Episode> allSeriesEpisodes) { - if (!includeSpecials || seasonNumber < 1) + if (allSeriesEpisodes == null) { - return episodes.Where(i => (i.ParentIndexNumber ?? -1) == seasonNumber); + Logger.Debug("GetSeasonEpisodes allSeriesEpisodes is null"); + return GetSeasonEpisodes(user, parentSeason); } - return episodes.Where(i => - { - var episode = i; - - if (episode != null) - { - var currentSeasonNumber = episode.AiredSeasonNumber; + Logger.Debug("GetSeasonEpisodes FilterEpisodesBySeason"); + var episodes = FilterEpisodesBySeason(allSeriesEpisodes, parentSeason, ConfigurationManager.Configuration.DisplaySpecialsWithinSeasons); - return currentSeasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber; - } + var sortBy = (parentSeason.IndexNumber ?? -1) == 0 ? ItemSortBy.SortName : ItemSortBy.AiredEpisodeOrder; - return false; - }); + return LibraryManager.Sort(episodes, user, new[] { sortBy }, SortOrder.Ascending) + .Cast<Episode>(); } /// <summary> @@ -464,6 +465,32 @@ namespace MediaBrowser.Controller.Entities.TV }); } + /// <summary> + /// Filters the episodes by season. + /// </summary> + public static IEnumerable<Episode> FilterEpisodesBySeason(IEnumerable<Episode> episodes, int seasonNumber, bool includeSpecials) + { + if (!includeSpecials || seasonNumber < 1) + { + return episodes.Where(i => (i.ParentIndexNumber ?? -1) == seasonNumber); + } + + return episodes.Where(i => + { + var episode = i; + + if (episode != null) + { + var currentSeasonNumber = episode.AiredSeasonNumber; + + return currentSeasonNumber.HasValue && currentSeasonNumber.Value == seasonNumber; + } + + return false; + }); + } + + protected override bool GetBlockUnratedValue(UserPolicy config) { return config.BlockUnratedItems.Contains(UnratedItem.Series); @@ -519,5 +546,15 @@ namespace MediaBrowser.Controller.Entities.TV return list; } + + [IgnoreDataMember] + public override bool StopRefreshIfLocalMetadataFound + { + get + { + // Need people id's from internet metadata + return false; + } + } } } diff --git a/MediaBrowser.Controller/Entities/Trailer.cs b/MediaBrowser.Controller/Entities/Trailer.cs index 6604be977..306ce35ec 100644 --- a/MediaBrowser.Controller/Entities/Trailer.cs +++ b/MediaBrowser.Controller/Entities/Trailer.cs @@ -124,5 +124,15 @@ namespace MediaBrowser.Controller.Entities return list; } + + [IgnoreDataMember] + public override bool StopRefreshIfLocalMetadataFound + { + get + { + // Need people id's from internet metadata + return false; + } + } } } diff --git a/MediaBrowser.Controller/Entities/UserRootFolder.cs b/MediaBrowser.Controller/Entities/UserRootFolder.cs index d043cba47..aff1f5e28 100644 --- a/MediaBrowser.Controller/Entities/UserRootFolder.cs +++ b/MediaBrowser.Controller/Entities/UserRootFolder.cs @@ -33,7 +33,7 @@ namespace MediaBrowser.Controller.Entities } } - private void ResetCachedChildren() + private void ClearCache() { lock (_childIdsLock) { @@ -58,7 +58,7 @@ namespace MediaBrowser.Controller.Entities var user = query.User; Func<BaseItem, bool> filter = i => UserViewBuilder.Filter(i, user, query, UserDataManager, LibraryManager); - return PostFilterAndSort(result.Where(filter), query); + return PostFilterAndSort(result.Where(filter), query, true, true); } public override int GetChildCount(User user) @@ -94,7 +94,7 @@ namespace MediaBrowser.Controller.Entities public override bool BeforeMetadataRefresh() { - ResetCachedChildren(); + ClearCache(); var hasChanges = base.BeforeMetadataRefresh(); @@ -107,13 +107,22 @@ namespace MediaBrowser.Controller.Entities return hasChanges; } + protected override IEnumerable<BaseItem> GetNonCachedChildren(IDirectoryService directoryService) + { + ClearCache(); + + return base.GetNonCachedChildren(directoryService); + } + protected override async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService) { - ResetCachedChildren(); + ClearCache(); await base.ValidateChildrenInternal(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService) .ConfigureAwait(false); + ClearCache(); + // Not the best way to handle this, but it solves an issue // CollectionFolders aren't always getting saved after changes // This means that grabbing the item by Id may end up returning the old one diff --git a/MediaBrowser.Controller/Entities/UserViewBuilder.cs b/MediaBrowser.Controller/Entities/UserViewBuilder.cs index d0f7efa8c..9f3acc3fc 100644 --- a/MediaBrowser.Controller/Entities/UserViewBuilder.cs +++ b/MediaBrowser.Controller/Entities/UserViewBuilder.cs @@ -424,7 +424,7 @@ namespace MediaBrowser.Controller.Entities query.SortBy = new string[] { }; - return PostFilterAndSort(items, parent, null, query); + return PostFilterAndSort(items, parent, null, query, false, true); } private QueryResult<BaseItem> GetFavoriteSongs(Folder parent, User user, InternalItemsQuery query) @@ -780,7 +780,7 @@ namespace MediaBrowser.Controller.Entities { items = items.Where(i => Filter(i, query.User, query, _userDataManager, _libraryManager)); - return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config); + return PostFilterAndSort(items, queryParent, null, query, _libraryManager, _config, true, true); } public static bool FilterItem(BaseItem item, InternalItemsQuery query) @@ -791,9 +791,11 @@ namespace MediaBrowser.Controller.Entities private QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, BaseItem queryParent, int? totalRecordLimit, - InternalItemsQuery query) + InternalItemsQuery query, + bool collapseBoxSetItems, + bool enableSorting) { - return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config); + return PostFilterAndSort(items, queryParent, totalRecordLimit, query, _libraryManager, _config, collapseBoxSetItems, enableSorting); } public static QueryResult<BaseItem> PostFilterAndSort(IEnumerable<BaseItem> items, @@ -801,7 +803,9 @@ namespace MediaBrowser.Controller.Entities int? totalRecordLimit, InternalItemsQuery query, ILibraryManager libraryManager, - IServerConfigurationManager configurationManager) + IServerConfigurationManager configurationManager, + bool collapseBoxSetItems, + bool enableSorting) { var user = query.User; @@ -810,7 +814,10 @@ namespace MediaBrowser.Controller.Entities query.IsVirtualUnaired, query.IsUnaired); - items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager); + if (collapseBoxSetItems) + { + items = CollapseBoxSetItemsIfNeeded(items, query, queryParent, user, configurationManager); + } // This must be the last filter if (!string.IsNullOrEmpty(query.AdjacentTo)) @@ -818,7 +825,7 @@ namespace MediaBrowser.Controller.Entities items = FilterForAdjacency(items, query.AdjacentTo); } - return Sort(items, totalRecordLimit, query, libraryManager); + return SortAndPage(items, totalRecordLimit, query, libraryManager, enableSorting); } public static IEnumerable<BaseItem> CollapseBoxSetItemsIfNeeded(IEnumerable<BaseItem> items, @@ -1093,8 +1100,6 @@ namespace MediaBrowser.Controller.Entities bool? isVirtualUnaired, bool? isUnaired) { - items = FilterVirtualSeasons(items, isMissing, isVirtualUnaired, isUnaired); - if (isMissing.HasValue) { var val = isMissing.Value; @@ -1140,61 +1145,10 @@ namespace MediaBrowser.Controller.Entities return items; } - private static IEnumerable<BaseItem> FilterVirtualSeasons( - IEnumerable<BaseItem> items, - bool? isMissing, - bool? isVirtualUnaired, - bool? isUnaired) - { - if (isMissing.HasValue) - { - var val = isMissing.Value; - items = items.Where(i => - { - var e = i as Season; - if (e != null) - { - return (e.IsMissingSeason) == val; - } - return true; - }); - } - - if (isUnaired.HasValue) - { - var val = isUnaired.Value; - items = items.Where(i => - { - var e = i as Season; - if (e != null) - { - return e.IsUnaired == val; - } - return true; - }); - } - - if (isVirtualUnaired.HasValue) - { - var val = isVirtualUnaired.Value; - items = items.Where(i => - { - var e = i as Season; - if (e != null) - { - return e.IsVirtualUnaired == val; - } - return true; - }); - } - - return items; - } - - public static QueryResult<BaseItem> Sort(IEnumerable<BaseItem> items, + public static QueryResult<BaseItem> SortAndPage(IEnumerable<BaseItem> items, int? totalRecordLimit, InternalItemsQuery query, - ILibraryManager libraryManager) + ILibraryManager libraryManager, bool enableSorting) { var user = query.User; diff --git a/MediaBrowser.Controller/Entities/Year.cs b/MediaBrowser.Controller/Entities/Year.cs index db896f1fc..4197ea93e 100644 --- a/MediaBrowser.Controller/Entities/Year.cs +++ b/MediaBrowser.Controller/Entities/Year.cs @@ -112,5 +112,48 @@ namespace MediaBrowser.Controller.Entities return false; } } + + public static string GetPath(string name, bool normalizeName = true) + { + // Trim the period at the end because windows will have a hard time with that + var validName = normalizeName ? + FileSystem.GetValidFilename(name).Trim().TrimEnd('.') : + name; + + return System.IO.Path.Combine(ConfigurationManager.ApplicationPaths.YearPath, validName); + } + + private string GetRebasedPath() + { + return GetPath(System.IO.Path.GetFileName(Path), false); + } + + public override bool RequiresRefresh() + { + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Logger.Debug("{0} path has changed from {1} to {2}", GetType().Name, Path, newPath); + return true; + } + return base.RequiresRefresh(); + } + + /// <summary> + /// This is called before any metadata refresh and returns true or false indicating if changes were made + /// </summary> + public override bool BeforeMetadataRefresh() + { + var hasChanges = base.BeforeMetadataRefresh(); + + var newPath = GetRebasedPath(); + if (!string.Equals(Path, newPath, StringComparison.Ordinal)) + { + Path = newPath; + hasChanges = true; + } + + return hasChanges; + } } } |
